From a989708d086a778d861ac3c8883337f1a0149685 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 20 May 2022 23:57:03 +0300 Subject: [PATCH] RED-3988: improve annotation manager --- .../annotation-actions.component.ts | 10 +-- .../annotations-list.component.ts | 2 +- .../file-workload.component.html | 2 +- .../file-workload/file-workload.component.ts | 4 +- .../pdf-paginator/pdf-paginator.component.ts | 14 ++-- .../file-preview-screen.component.ts | 28 +++---- .../services/annotation-actions.service.ts | 10 +-- .../services/annotations-listing.service.ts | 21 ++---- .../file-preview/services/skipped.service.ts | 6 +- .../file-actions/file-actions.component.ts | 59 +++++++++------ .../pdf-viewer/annotation-manager.service.ts | 75 +++++++++---------- .../shared/components/pdf-viewer/functions.ts | 26 ++++++- .../pdf-viewer/page-rotation.service.ts | 22 +++--- .../pdf-viewer/pdf-viewer.service.ts | 2 +- .../pdf-viewer/viewer-header.service.ts | 2 +- 15 files changed, 152 insertions(+), 131 deletions(-) diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.ts b/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.ts index 38189cf80..bd7c2828c 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.ts @@ -59,7 +59,7 @@ export class AnnotationActionsComponent implements OnChanges { } get viewerAnnotations() { - return this._annotationManager.getAnnotations(this._annotations); + return this._annotationManager.get(this._annotations); } get isVisible() { @@ -94,15 +94,15 @@ export class AnnotationActionsComponent implements OnChanges { hideAnnotation($event: MouseEvent) { $event.stopPropagation(); - this._annotationManager.hideAnnotations(this.viewerAnnotations); - this._annotationManager.deselectAnnotations(); + this._annotationManager.hide(this.viewerAnnotations); + this._annotationManager.deselect(); this._fileDataService.updateHiddenAnnotations(this.viewerAnnotations, true); } showAnnotation($event: MouseEvent) { $event.stopPropagation(); - this._annotationManager.showAnnotations(this.viewerAnnotations); - this._annotationManager.deselectAnnotations(); + this._annotationManager.show(this.viewerAnnotations); + this._annotationManager.deselect(); this._fileDataService.updateHiddenAnnotations(this.viewerAnnotations, false); } diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotations-list/annotations-list.component.ts b/apps/red-ui/src/app/modules/file-preview/components/annotations-list/annotations-list.component.ts index 0ae2f38ee..aa4bf2173 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotations-list/annotations-list.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/annotations-list/annotations-list.component.ts @@ -70,7 +70,7 @@ export class AnnotationsListComponent extends HasScrollbarDirective implements O this.pagesPanelActive.emit(false); if (this._listingService.isSelected(annotation)) { - this._annotationManager.deselectAnnotation(annotation); + this._annotationManager.deselect(annotation); } else { const canMultiSelect = this._multiSelectService.isEnabled; if (canMultiSelect && ($event?.ctrlKey || $event?.metaKey) && this._listingService.selected.length > 0) { diff --git a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html index f39983a70..013e33e8a 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html @@ -48,7 +48,7 @@
diff --git a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts index b85b27c47..f2fb3e69b 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts @@ -136,7 +136,7 @@ export class FileWorkloadComponent { return this.multiSelectService.inactive$.pipe( tap(value => { if (value) { - this.annotationManager.deselectAnnotations(); + this.annotationManager.deselect(); } }), shareDistinctLast(), @@ -185,7 +185,7 @@ export class FileWorkloadComponent { } deselectAllOnActivePage(): void { - this.annotationManager.deselectAnnotations(this.activeAnnotations); + this.annotationManager.deselect(this.activeAnnotations); } @HostListener('window:keyup', ['$event']) diff --git a/apps/red-ui/src/app/modules/file-preview/components/pdf-paginator/pdf-paginator.component.ts b/apps/red-ui/src/app/modules/file-preview/components/pdf-paginator/pdf-paginator.component.ts index cc50e792a..770fe0ea0 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/pdf-paginator/pdf-paginator.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/pdf-paginator/pdf-paginator.component.ts @@ -190,13 +190,13 @@ export class PdfPaginatorComponent extends AutoUnsubscribe implements OnInit, On if (action === 'deselected') { // Remove deselected annotations from selected list - nextAnnotations = this._annotationManager.selectedAnnotations.filter(ann => !annotations.some(a => a.Id === ann.Id)); + nextAnnotations = this._annotationManager.selected.filter(ann => !annotations.some(a => a.Id === ann.Id)); } else if (!this._multiSelectService.isEnabled) { // Only choose the last selected annotation, to bypass viewer multi select nextAnnotations = annotations; } else { // Get selected annotations from the manager, no intervention needed - nextAnnotations = this._annotationManager.selectedAnnotations; + nextAnnotations = this._annotationManager.selected; } // this.annotationSelected.emit(nextAnnotations.map(ann => ann.Id)); @@ -207,7 +207,7 @@ export class PdfPaginatorComponent extends AutoUnsubscribe implements OnInit, On if (!this._multiSelectService.isEnabled) { const notSelected = this._fileDataService.all.filter(wrapper => !nextAnnotations.some(ann => ann.Id === wrapper.id)); - this._annotationManager.deselectAnnotations(notSelected); + this._annotationManager.deselect(notSelected); } this.#configureAnnotationSpecificActions(annotations); @@ -286,11 +286,11 @@ export class PdfPaginatorComponent extends AutoUnsubscribe implements OnInit, On onClick: () => { this._ngZone.run(() => { if (allAreVisible) { - this._annotationManager.hideAnnotations(viewerAnnotations); + this._annotationManager.hide(viewerAnnotations); } else { - this._annotationManager.showAnnotations(viewerAnnotations); + this._annotationManager.show(viewerAnnotations); } - this._annotationManager.deselectAnnotations(); + this._annotationManager.deselect(); this._fileDataService.updateHiddenAnnotations(viewerAnnotations, allAreVisible); }); }, @@ -317,7 +317,7 @@ export class PdfPaginatorComponent extends AutoUnsubscribe implements OnInit, On } private _addRectangleManualRedaction() { - const activeAnnotation = this._annotationManager.selectedAnnotations[0]; + const activeAnnotation = this._annotationManager.selected[0]; const activePage = activeAnnotation.getPageNumber(); const quads = [this._annotationDrawService.annotationToQuads(activeAnnotation)]; const manualRedactionEntry = this._getManualRedaction({ [activePage]: quads }); diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts index bd8306aec..ccc850b31 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts @@ -120,7 +120,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } get changed() { - return this._pageRotationService.hasRotations(); + return this._pageRotationService.hasRotations; } get scrollableParentView(): ScrollableParentView { @@ -147,7 +147,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni async updateViewMode(): Promise { this._logger.info(`[PDF] Update ${this._viewModeService.viewMode} view mode`); - const annotations = this._annotationManager.getAnnotations(a => Boolean(a.getCustomData('redact-manager'))); + const annotations = this._annotationManager.get(a => Boolean(a.getCustomData('redact-manager'))); const redactions = annotations.filter(a => a.getCustomData('redaction')); switch (this._viewModeService.viewMode) { @@ -160,8 +160,8 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni .filter(a => !ocrAnnotationIds.includes(a.Id)); const nonStandardEntries = annotations.filter(a => a.getCustomData('changeLogRemoved') === 'true'); this._setAnnotationsOpacity(standardEntries, true); - this._annotationManager.showAnnotations(standardEntries); - this._annotationManager.hideAnnotations(nonStandardEntries); + this._annotationManager.show(standardEntries); + this._annotationManager.hide(nonStandardEntries); break; } case 'DELTA': { @@ -169,21 +169,21 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni const nonChangeLogEntries = annotations.filter(a => a.getCustomData('changeLog') === 'false'); this._setAnnotationsColor(redactions, 'annotationColor'); this._setAnnotationsOpacity(changeLogEntries, true); - this._annotationManager.showAnnotations(changeLogEntries); - this._annotationManager.hideAnnotations(nonChangeLogEntries); + this._annotationManager.show(changeLogEntries); + this._annotationManager.hide(nonChangeLogEntries); break; } case 'REDACTED': { const nonRedactionEntries = annotations.filter(a => a.getCustomData('redaction') === 'false'); this._setAnnotationsOpacity(redactions); this._setAnnotationsColor(redactions, 'redactionColor'); - this._annotationManager.showAnnotations(redactions); - this._annotationManager.hideAnnotations(nonRedactionEntries); + this._annotationManager.show(redactions); + this._annotationManager.hide(nonRedactionEntries); break; } case 'TEXT_HIGHLIGHTS': { this._loadingService.start(); - this._annotationManager.hideAnnotations(annotations); + this._annotationManager.hide(annotations); const highlights = await this._fileDataService.loadTextHighlights(); await this._annotationDrawService.draw(highlights); this._loadingService.stop(); @@ -253,9 +253,9 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni null, { manualRedactionEntryWrapper, dossierId: this.dossierId, file }, (wrappers: ManualRedactionEntryWrapper[]) => { - const selectedAnnotations = this._annotationManager.selectedAnnotations; + const selectedAnnotations = this._annotationManager.selected; if (selectedAnnotations.length > 0) { - this._annotationManager.deleteAnnotations([selectedAnnotations[0].Id]); + this._annotationManager.delete([selectedAnnotations[0].Id]); } const manualRedactionService = this._injector.get(ManualRedactionService); const add$ = manualRedactionService.addAnnotation( @@ -380,7 +380,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } this._logger.info('[ANNOTATIONS] To delete: ', annotationsToDelete); - this._annotationManager.deleteAnnotations(annotationsToDelete); + this._annotationManager.delete(annotationsToDelete); } drawChangedAnnotations(oldAnnotations: AnnotationWrapper[], newAnnotations: AnnotationWrapper[]) { @@ -400,7 +400,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } this._logger.info('[ANNOTATIONS] To draw: ', annotationsToDraw); - this._annotationManager.deleteAnnotations(annotationsToDraw); + this._annotationManager.delete(annotationsToDraw); return this._cleanupAndRedrawAnnotations(annotationsToDraw); } @@ -476,7 +476,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni #deactivateMultiSelect() { this.multiSelectService.deactivate(); - this._annotationManager.deselectAnnotations(); + this._annotationManager.deselect(); this.handleAnnotationSelected([]); } diff --git a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts index 8c45e5b07..400a98909 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts @@ -397,9 +397,9 @@ export class AnnotationActionsService { annotationWrapper.resizing = true; - const viewerAnnotation = this._annotationManager.getAnnotation(annotationWrapper); + const viewerAnnotation = this._annotationManager.get(annotationWrapper); if (annotationWrapper.rectangle || annotationWrapper.imported || annotationWrapper.isImage) { - this._annotationManager.deleteAnnotation(annotationWrapper); + this._annotationManager.delete(annotationWrapper); const rectangleAnnotation = this.#generateRectangle(annotationWrapper); this._pdf.annotationManager.addAnnotation(rectangleAnnotation, { imported: true }); await this._pdf.annotationManager.drawAnnotationsFromList([rectangleAnnotation]); @@ -437,9 +437,9 @@ export class AnnotationActionsService { annotationWrapper.resizing = false; - this._annotationManager.deleteAnnotation(annotationWrapper); + this._annotationManager.delete(annotationWrapper); await this._annotationDrawService.draw([annotationWrapper]); - this._annotationManager.deselectAnnotations(); + this._annotationManager.deselect(); await this._fileDataService.annotationsChanged(); } @@ -529,7 +529,7 @@ export class AnnotationActionsService { } private async _extractTextAndPositions(annotationId: string) { - const viewerAnnotation = this._annotationManager.getAnnotation(annotationId); + const viewerAnnotation = this._annotationManager.get(annotationId); const document = await this._pdf.PDFDoc; const page = await document.getPage(viewerAnnotation.getPageNumber()); diff --git a/apps/red-ui/src/app/modules/file-preview/services/annotations-listing.service.ts b/apps/red-ui/src/app/modules/file-preview/services/annotations-listing.service.ts index d02617731..0ebf3b822 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/annotations-listing.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/annotations-listing.service.ts @@ -28,39 +28,30 @@ export class AnnotationsListingService extends ListingService selectAnnotations(annotations?: AnnotationWrapper[]) { if (!annotations) { - return this._annotationManager.deselectAnnotations(); + return this._annotationManager.deselect(); } const annotationsToSelect = this._multiSelectService.isActive ? [...this.selected, ...annotations] : annotations; this.#selectAnnotations(annotationsToSelect); } - #selectAnnotations(annotations: AnnotationWrapper[] = []) { - const filteredAnnotationsIds = annotations.filter(a => !!a).map(a => a.id); - - if (!filteredAnnotationsIds.length) { + #selectAnnotations(annotations: AnnotationWrapper[]) { + if (!annotations.length) { return; } if (!this._multiSelectService.isActive) { - this._annotationManager.deselectAnnotations(); + this._annotationManager.deselect(); } const pageNumber = annotations[0].pageNumber; if (pageNumber === this._pdf.currentPage) { - return this.#jumpAndSelectAnnotations(filteredAnnotationsIds); + return this._annotationManager.jumpAndSelect(annotations); } this._pdf.navigateTo(pageNumber); // wait for page to be loaded and to draw annotations - setTimeout(() => this.#jumpAndSelectAnnotations(filteredAnnotationsIds), 300); - } - - #jumpAndSelectAnnotations(annotationIds: readonly string[]) { - const annotationsFromViewer = this._annotationManager.getAnnotations(annotationIds); - - this._pdf.annotationManager.jumpToAnnotation(annotationsFromViewer[0]); - this._pdf.annotationManager.selectAnnotations(annotationsFromViewer); + setTimeout(() => this._annotationManager.jumpAndSelect(annotations), 300); } } diff --git a/apps/red-ui/src/app/modules/file-preview/services/skipped.service.ts b/apps/red-ui/src/app/modules/file-preview/services/skipped.service.ts index 3b51e9d31..1f2ebb018 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/skipped.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/skipped.service.ts @@ -28,11 +28,11 @@ export class SkippedService { } private _handleIgnoreAnnotationsDrawing(hideSkipped: boolean): void { - const ignored = this._annotationManager.getAnnotations(a => Boolean(a.getCustomData('skipped'))); + const ignored = this._annotationManager.get(a => Boolean(a.getCustomData('skipped'))); if (hideSkipped) { - this._annotationManager.hideAnnotations(ignored); + this._annotationManager.hide(ignored); } else { - this._annotationManager.showAnnotations(ignored); + this._annotationManager.show(ignored); } } } diff --git a/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts b/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts index 6f5a8eff1..e3d569d45 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts +++ b/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts @@ -1,4 +1,14 @@ -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, Input, OnChanges, Optional, ViewChild } from '@angular/core'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + HostBinding, + Injector, + Input, + OnChanges, + Optional, + ViewChild, +} from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; import { Action, ActionTypes, Dossier, File } from '@red/domain'; import { DossiersDialogService } from '../../services/dossiers-dialog.service'; @@ -36,7 +46,7 @@ import { ROTATION_ACTION_BUTTONS } from '../../../shared/components/pdf-viewer/c }) export class FileActionsComponent implements OnChanges { readonly circleButtonTypes = CircleButtonTypes; - readonly currentUser = this._userService.currentUser; + readonly currentUser; @Input() file: File; @Input() dossier: Dossier; @@ -77,24 +87,25 @@ export class FileActionsComponent implements OnChanges { private readonly _expandableActionsComponent: ExpandableFileActionsComponent; constructor( - @Optional() private readonly _excludedPagesService: ExcludedPagesService, - @Optional() private readonly _documentInfoService: DocumentInfoService, - private readonly _pageRotationService: PageRotationService, - private readonly _viewerHeaderService: ViewerHeaderService, - private readonly _permissionsService: PermissionsService, - private readonly _activeDossiersService: ActiveDossiersService, + userService: UserService, + private readonly _injector: Injector, + private readonly _filesService: FilesService, + private readonly _changeRef: ChangeDetectorRef, + private readonly _loadingService: LoadingService, private readonly _dialogService: DossiersDialogService, private readonly _fileAssignService: FileAssignService, - private readonly _loadingService: LoadingService, - private readonly _fileManagementService: FileManagementService, - private readonly _filesService: FilesService, - private readonly _userService: UserService, - private readonly _toaster: Toaster, - private readonly _userPreferenceService: UserPreferenceService, private readonly _reanalysisService: ReanalysisService, - private readonly _router: Router, - private readonly _changeRef: ChangeDetectorRef, - ) {} + private readonly _permissionsService: PermissionsService, + private readonly _pageRotationService: PageRotationService, + private readonly _viewerHeaderService: ViewerHeaderService, + private readonly _activeDossiersService: ActiveDossiersService, + private readonly _fileManagementService: FileManagementService, + private readonly _userPreferenceService: UserPreferenceService, + @Optional() private readonly _documentInfoService: DocumentInfoService, + @Optional() private readonly _excludedPagesService: ExcludedPagesService, + ) { + this.currentUser = userService.currentUser; + } @HostBinding('class.keep-visible') get expanded() { @@ -312,9 +323,9 @@ export class FileActionsComponent implements OnChanges { try { const dossier = this._activeDossiersService.find(this.file.dossierId); await firstValueFrom(this._fileManagementService.delete([this.file], this.file.dossierId)); - await this._router.navigate([dossier.routerLink]); + await this._injector.get(Router).navigate([dossier.routerLink]); } catch (error) { - this._toaster.error(_('error.http.generic'), { params: error }); + this._injector.get(Toaster).error(_('error.http.generic'), { params: error }); } this._loadingService.stop(); }, @@ -363,10 +374,12 @@ export class FileActionsComponent implements OnChanges { return; } } - if (this._pageRotationService) { - await firstValueFrom(this._pageRotationService.showConfirmationDialogIfHasRotations()); - this._viewerHeaderService.disable(ROTATION_ACTION_BUTTONS); - } + + const pageRotationService = this._injector.get(PageRotationService); + await firstValueFrom(pageRotationService.showConfirmationDialogIfHasRotations()); + const viewerHeaderService = this._injector.get(ViewerHeaderService); + viewerHeaderService.disable(ROTATION_ACTION_BUTTONS); + this._loadingService.start(); await firstValueFrom(this._reanalysisService.ocrFiles([this.file], this.file.dossierId)); this._loadingService.stop(); diff --git a/apps/red-ui/src/app/modules/shared/components/pdf-viewer/annotation-manager.service.ts b/apps/red-ui/src/app/modules/shared/components/pdf-viewer/annotation-manager.service.ts index 4f9cf21c4..9f79574ab 100644 --- a/apps/red-ui/src/app/modules/shared/components/pdf-viewer/annotation-manager.service.ts +++ b/apps/red-ui/src/app/modules/shared/components/pdf-viewer/annotation-manager.service.ts @@ -2,10 +2,10 @@ import { Injectable } from '@angular/core'; import { Core } from '@pdftron/webviewer'; import type { List } from '@iqser/common-ui'; import { AnnotationPredicate, DeleteAnnotationsOptions } from '@shared/components/pdf-viewer/types'; -import type { AnnotationWrapper } from '@models/file/annotation.wrapper'; +import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { fromEvent, Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; -import { getIds } from '@shared/components/pdf-viewer/functions'; +import { getId, isStringOrWrapper } from '@shared/components/pdf-viewer/functions'; import AnnotationManager = Core.AnnotationManager; import Annotation = Core.Annotations.Annotation; @@ -16,12 +16,12 @@ export class REDAnnotationManager { annotationSelected$: Observable<[Annotation[], string]>; #manager: AnnotationManager; - get selectedAnnotations() { + get selected() { return this.#manager.getSelectedAnnotations(); } get annotations() { - return this.#getAnnotations(); + return this.#get(); } get #annotationSelected$() { @@ -35,57 +35,56 @@ export class REDAnnotationManager { this.#autoSelectRectangleAfterCreation(); } - deleteAnnotation(annotation: AnnotationWrapper | string) { - const id = typeof annotation === 'string' ? annotation : annotation.id; - return this.deleteAnnotations([id]); - } - - deleteAnnotations(annotations: List); - - deleteAnnotations(annotationsIds?: List); - - deleteAnnotations(annotationsIds?: List) { - const annotations = this.getAnnotations(getIds(annotationsIds)); + delete(annotations?: List | List | string | AnnotationWrapper) { + const items = isStringOrWrapper(annotations) ? [this.get(annotations)] : this.get(annotations); const options: DeleteAnnotationsOptions = { force: true }; - this.#manager.deleteAnnotations(annotations, options); + this.#manager.deleteAnnotations(items, options); } - getAnnotations(annotations: List): Annotation[]; + get(annotation: AnnotationWrapper | string): Annotation; + get(annotations: List | List): Annotation[]; - getAnnotations(predicate?: (value: Annotation) => boolean): Annotation[]; + get(predicate?: (value: Annotation) => boolean): Annotation[]; + + get(argument?: AnnotationPredicate | List | List | AnnotationWrapper | string): Annotation | Annotation[] { + if (isStringOrWrapper(argument)) { + return this.#getById(argument); + } - getAnnotations(argument?: AnnotationPredicate | List): Annotation[] { const isList = argument instanceof Array; - return isList ? this.#getAnnotationsById(getIds(argument)) : this.#getAnnotations(argument); + return isList ? this.#getByIds(argument) : this.#get(argument); } - getAnnotation(annotation: AnnotationWrapper | string) { - const id = typeof annotation === 'string' ? annotation : annotation.id; - return this.#manager.getAnnotationById(id); - } - - deselectAnnotations(annotations?: List) { - if (!annotations) { + deselect(annotation: string | AnnotationWrapper); + deselect(annotations?: List | List); + deselect(argument?: string | AnnotationWrapper | List | List) { + if (!argument) { return this.#manager.deselectAllAnnotations(); } - const ann = this.#getAnnotationsById(getIds(annotations)); + const ann = isStringOrWrapper(argument) ? [this.#getById(argument)] : this.#getByIds(argument); this.#manager.deselectAnnotations(ann); } - deselectAnnotation(annotation: AnnotationWrapper | string) { - const id = typeof annotation === 'string' ? annotation : annotation.id; - this.deselectAnnotations([id]); - } - - hideAnnotations(annotations: Annotation[]): void { + hide(annotations: Annotation[]): void { this.#manager.hideAnnotations(annotations); } - showAnnotations(annotations: Annotation[]): void { + show(annotations: Annotation[]): void { this.#manager.showAnnotations(annotations); } + jumpAndSelect(annotations: List | List) { + const annotationsFromViewer = this.get(annotations); + + this.#manager.jumpToAnnotation(annotationsFromViewer[0]); + this.#manager.selectAnnotations(annotationsFromViewer); + } + + #getById(annotation: AnnotationWrapper | string) { + return this.#manager.getAnnotationById(getId(annotation)); + } + #autoSelectRectangleAfterCreation() { this.#manager.addEventListener('annotationChanged', (annotations: Annotation[]) => { // when a rectangle is drawn, @@ -98,11 +97,11 @@ export class REDAnnotationManager { }); } - #getAnnotationsById(ids: List) { - return ids.map(id => this.#manager.getAnnotationById(id)).filter(a => !!a); + #getByIds(annotations: List | List) { + return annotations.map((item: string | AnnotationWrapper) => this.#getById(item)).filter(a => !!a); } - #getAnnotations(predicate?: AnnotationPredicate) { + #get(predicate?: AnnotationPredicate) { const annotations = this.#manager.getAnnotationsList(); return predicate ? annotations.filter(predicate) : annotations; } diff --git a/apps/red-ui/src/app/modules/shared/components/pdf-viewer/functions.ts b/apps/red-ui/src/app/modules/shared/components/pdf-viewer/functions.ts index 0a3c7f937..ba299e9f3 100644 --- a/apps/red-ui/src/app/modules/shared/components/pdf-viewer/functions.ts +++ b/apps/red-ui/src/app/modules/shared/components/pdf-viewer/functions.ts @@ -13,10 +13,28 @@ export function stopAndPreventIfNotAllowed($event: KeyboardEvent) { } } -export function getIds(items?: List): List | undefined { - return items?.map(value => (typeof value === 'string' ? value : value.id)); +export function getId(item: string | AnnotationWrapper) { + return typeof item === 'string' ? item : item.annotationId; } -export function asList(dataElements: string[] | string): string[] { - return typeof dataElements === 'string' ? [dataElements] : dataElements; +export function getIds(items?: List | List): List | undefined { + return items?.map(getId); +} + +export function isStringOrWrapper(value: unknown): value is string | AnnotationWrapper { + return typeof value === 'string' || value instanceof AnnotationWrapper; +} + +export function asList(items: string[] | string): string[]; +export function asList(items: AnnotationWrapper[] | AnnotationWrapper): AnnotationWrapper[]; +export function asList(items: string[] | string | AnnotationWrapper[] | AnnotationWrapper): string[] | AnnotationWrapper[] { + if (typeof items === 'string') { + return [items]; + } + + if (items instanceof AnnotationWrapper) { + return [items]; + } + + return items; } diff --git a/apps/red-ui/src/app/modules/shared/components/pdf-viewer/page-rotation.service.ts b/apps/red-ui/src/app/modules/shared/components/pdf-viewer/page-rotation.service.ts index 2b5dac3d7..ffd606eb0 100644 --- a/apps/red-ui/src/app/modules/shared/components/pdf-viewer/page-rotation.service.ts +++ b/apps/red-ui/src/app/modules/shared/components/pdf-viewer/page-rotation.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, Injector } from '@angular/core'; import { BehaviorSubject, firstValueFrom, of } from 'rxjs'; import { RotationType, RotationTypes } from '@red/domain'; import { FileManagementService } from '../../../../services/files/file-management.service'; @@ -28,15 +28,19 @@ export class PageRotationService { constructor( private readonly _pdf: PdfViewer, - private readonly _dialog: MatDialog, private readonly _loadingService: LoadingService, private readonly _activatedRoute: ActivatedRoute, private readonly _logger: NGXLogger, + private readonly _injector: Injector, private readonly _fileManagementService: FileManagementService, private readonly _filesService: FilesService, private readonly _filesMapService: FilesMapService, ) {} + get hasRotations() { + return Object.values(this.#rotations$.value).filter(v => !!v).length > 0; + } + isRotated$(page: number) { return this.#rotations$.pipe( map(rotations => !!rotations[page]), @@ -44,10 +48,6 @@ export class PageRotationService { ); } - hasRotations() { - return Object.values(this.#rotations$.value).filter(v => !!v).length > 0; - } - applyRotation() { this._loadingService.start(); const pages = this.#rotations$.value; @@ -104,11 +104,11 @@ export class PageRotationService { } showConfirmationDialogIfHasRotations() { - return this.hasRotations() ? this.#showConfirmationDialog() : of(ConfirmOptions.DISCARD_CHANGES); + return this.hasRotations ? this.#showConfirmationDialog() : of(false); } #showConfirmationDialog() { - const ref = this._dialog.open(ConfirmationDialogComponent, { + const ref = this._injector.get(MatDialog).open(ConfirmationDialogComponent, { ...defaultDialogConfig, data: new ConfirmationDialogInput({ title: _('page-rotation.confirmation-dialog.title'), @@ -118,8 +118,8 @@ export class PageRotationService { }), }); - return ref - .afterClosed() - .pipe(tap((option: ConfirmOptions) => (option === ConfirmOptions.CONFIRM ? this.applyRotation() : this.discardRotation()))); + const closed$ = ref.afterClosed().pipe(map((option: ConfirmOptions) => option === ConfirmOptions.CONFIRM)); + + return closed$.pipe(tap(apply => (apply ? this.applyRotation() : this.discardRotation()))); } } diff --git a/apps/red-ui/src/app/modules/shared/components/pdf-viewer/pdf-viewer.service.ts b/apps/red-ui/src/app/modules/shared/components/pdf-viewer/pdf-viewer.service.ts index 692373856..386a88b5c 100644 --- a/apps/red-ui/src/app/modules/shared/components/pdf-viewer/pdf-viewer.service.ts +++ b/apps/red-ui/src/app/modules/shared/components/pdf-viewer/pdf-viewer.service.ts @@ -141,7 +141,7 @@ export class PdfViewer { get #pageChanged$() { const page$ = fromEvent(this.documentViewer, 'pageNumberUpdated'); - return page$.pipe(tap(() => this._annotationManager.deselectAnnotations())); + return page$.pipe(tap(() => this._annotationManager.deselect())); } navigateTo(page: string | number) { diff --git a/apps/red-ui/src/app/modules/shared/components/pdf-viewer/viewer-header.service.ts b/apps/red-ui/src/app/modules/shared/components/pdf-viewer/viewer-header.service.ts index a70891896..67082f1f9 100644 --- a/apps/red-ui/src/app/modules/shared/components/pdf-viewer/viewer-header.service.ts +++ b/apps/red-ui/src/app/modules/shared/components/pdf-viewer/viewer-header.service.ts @@ -170,7 +170,7 @@ export class ViewerHeaderService { } #toggleRotationActionButtons() { - if (this._rotationService.hasRotations()) { + if (this._rotationService.hasRotations) { this.enable(ROTATION_ACTION_BUTTONS); } else { this.disable(ROTATION_ACTION_BUTTONS);