diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.html b/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.html index 29a792c60..06ef6596b 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.html @@ -134,7 +134,7 @@ this.#annotations.reduce((acc, annotation) => !hidden.has(annotation.id) && acc, true)), - shareLast(), - ); + #annotations: AnnotationWrapper[] = []; + readonly isVisible = computed(() => { + const hidden = this._annotationManager.hidden(); + return this.#annotations.reduce((acc, annotation) => !hidden.has(annotation.id) && acc, true); + }); constructor( readonly viewModeService: ViewModeService, 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 924dba47f..515b53474 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 @@ -14,7 +14,7 @@ import { IqserEventTarget, } from '@iqser/common-ui'; import { combineLatest, delay, Observable } from 'rxjs'; -import { map, tap } from 'rxjs/operators'; +import { map } from 'rxjs/operators'; import { ExcludedPagesService } from '../../services/excluded-pages.service'; import { MultiSelectService } from '../../services/multi-select.service'; import { DocumentInfoService } from '../../services/document-info.service'; @@ -137,7 +137,6 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnDestroy delay(0), map(([annotations, primary, secondary]) => this._filterAnnotations(annotations, primary, secondary)), map(annotations => this._mapListItemsFromAnnotationWrapperArray(annotations)), - tap(() => setTimeout(() => this._changeDetectorRef.detectChanges())), ); } diff --git a/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts b/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts index 20d823ac2..ec5b1de76 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts @@ -97,14 +97,13 @@ export class PdfProxyService { get #annotationSelected$() { return this._annotationManager.annotationSelected$.pipe( - map(value => this.#processSelectedAnnotations(...value)), - tap(annotations => this.handleAnnotationSelected(annotations)), + map(value => this._ngZone.run(() => this.#processSelectedAnnotations(...value))), + tap(annotations => this._ngZone.run(() => this.handleAnnotationSelected(annotations))), ); } handleAnnotationSelected(annotationIds: string[]) { this._listingService.setSelected(annotationIds.map(id => this._fileDataService.find(id)).filter(ann => ann !== undefined)); - this._changeDetectorRef.markForCheck(); } configureElements() { @@ -120,7 +119,7 @@ export class PdfProxyService { dataElement: TextPopups.ADD_RECTANGLE, img: this.#addRedactionIcon, title: this.#getTitle(ManualRedactionEntryTypes.REDACTION), - onClick: () => this._addRectangleManualRedaction(), + onClick: () => this._ngZone.run(() => this._addRectangleManualRedaction()), }; this._pdf.instance.UI.annotationPopup.add([addRectangleButton]); @@ -153,7 +152,7 @@ export class PdfProxyService { dataElement: TextPopups.ADD_FALSE_POSITIVE, img: this.#falsePositiveIcon, title: this.#getTitle(ManualRedactionEntryTypes.FALSE_POSITIVE), - onClick: () => this._addManualRedactionOfType(ManualRedactionEntryTypes.FALSE_POSITIVE), + onClick: () => this._ngZone.run(() => this._addManualRedactionOfType(ManualRedactionEntryTypes.FALSE_POSITIVE)), }); } @@ -163,7 +162,7 @@ export class PdfProxyService { dataElement: TextPopups.ADD_REDACTION, img: this.#addRedactionIcon, title: this.#getTitle(ManualRedactionEntryTypes.REDACTION), - onClick: () => this._addManualRedactionOfType(ManualRedactionEntryTypes.REDACTION), + onClick: () => this._ngZone.run(() => this._addManualRedactionOfType(ManualRedactionEntryTypes.REDACTION)), }); if (!this._iqserPermissionsService.has(Roles.getRss)) { @@ -172,7 +171,7 @@ export class PdfProxyService { dataElement: TextPopups.ADD_DICTIONARY, img: this.#addDictIcon, title: this.#getTitle(ManualRedactionEntryTypes.DICTIONARY), - onClick: () => this._addManualRedactionOfType(ManualRedactionEntryTypes.DICTIONARY), + onClick: () => this._ngZone.run(() => this._addManualRedactionOfType(ManualRedactionEntryTypes.DICTIONARY)), }); } } diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-manager.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-manager.service.ts index 88aca43ff..2394c07bb 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-manager.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-manager.service.ts @@ -1,9 +1,9 @@ -import { Injectable } from '@angular/core'; +import { Injectable, signal } from '@angular/core'; import { Core } from '@pdftron/webviewer'; import type { List } from '@iqser/common-ui'; import { AnnotationPredicate, DeleteAnnotationsOptions } from '../utils/types'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; -import { BehaviorSubject, fromEvent, Observable } from 'rxjs'; +import { fromEvent, Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; import { asList, getId, isStringOrWrapper } from '../utils/functions'; import { getLast } from '@utils/functions'; @@ -15,8 +15,8 @@ import Annotation = Core.Annotations.Annotation; export class REDAnnotationManager { annotationSelected$: Observable<[Annotation[], string]>; resizingAnnotationId?: string = undefined; - readonly #hidden$ = new BehaviorSubject>(new Set()); - readonly hidden$ = this.#hidden$.asObservable(); + readonly #hidden = signal(new Set()); + readonly hidden = this.#hidden.asReadonly(); #manager: AnnotationManager; @@ -28,21 +28,17 @@ export class REDAnnotationManager { return this.#get(); } - get hidden() { - return this.#hidden$.value; - } - get #annotationSelected$() { const onSelect$ = fromEvent<[Annotation[], string]>(this.#manager, 'annotationSelected'); return onSelect$.pipe(tap(value => console.log('Annotation selected: ', value))); } addToHidden(value: string) { - this.#hidden$.next(new Set([...this.hidden, value])); + this.#hidden.mutate(set => set.add(value)); } removeFromHidden(value: string) { - this.#hidden$.next(new Set([...this.hidden].filter(v => v !== value))); + this.#hidden.mutate(set => set.delete(value)); } init(annotationManager: AnnotationManager) { @@ -52,7 +48,7 @@ export class REDAnnotationManager { } isHidden(annotationId: string) { - return this.hidden.has(annotationId); + return this.hidden().has(annotationId); } delete(annotations?: List | List | string | AnnotationWrapper) { @@ -122,7 +118,7 @@ export class REDAnnotationManager { } showHidden() { - const hidden = this.#getByIds([...this.hidden.values()]); + const hidden = this.#getByIds([...this.hidden().values()]); this.show(hidden); } diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/page-rotation.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/page-rotation.service.ts index e564ffcea..e8bba745a 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/page-rotation.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/page-rotation.service.ts @@ -84,7 +84,6 @@ export class PageRotationService { const rotationValue = pageRotation ? (pageRotation + Number(rotation)) % 360 : rotation; this.#rotations.update(value => ({ ...value, [pageNumber]: rotationValue })); - this._documentViewer.rotate(rotation); } diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/viewer-header.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/viewer-header.service.ts index 65ef664ea..9264c2fe7 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/viewer-header.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/viewer-header.service.ts @@ -1,4 +1,4 @@ -import { inject, Injectable } from '@angular/core'; +import { inject, Injectable, NgZone } from '@angular/core'; import { IHeaderElement, RotationTypes } from '@red/domain'; import { HeaderElements, HeaderElementType } from '../../file-preview/utils/constants'; import { TranslateService } from '@ngx-translate/core'; @@ -9,7 +9,6 @@ import { PdfViewer } from './pdf-viewer.service'; import { ROTATION_ACTION_BUTTONS, ROTATION_BUTTONS, ViewerEvents } from '../utils/constants'; import { FilesMapService } from '@services/files/files-map.service'; import { REDDocumentViewer } from './document-viewer.service'; -import { UserPreferenceService } from '@users/user-preference.service'; import { fromEvent, Observable, Subject } from 'rxjs'; import { ViewerEvent, VisibilityChangedEvent } from '../utils/types'; import { ReadableRedactionsService } from './readable-redactions.service'; @@ -48,7 +47,7 @@ export class ViewerHeaderService { private readonly _rotationService: PageRotationService, private readonly _tooltipsService: TooltipsService, private readonly _readableRedactionsService: ReadableRedactionsService, - private readonly _userPreferenceService: UserPreferenceService, + private readonly _ngZone: NgZone, ) { this.events$ = this.#events$.asObservable(); } @@ -70,9 +69,7 @@ export class ViewerHeaderService { dataElement: HeaderElements.TOGGLE_TOOLTIPS, title: this._tooltipsService.toggleTooltipsBtnTitle, img: this._tooltipsService.toggleTooltipsBtnIcon, - onClick: async () => { - await this._tooltipsService.toggleTooltips(); - }, + onClick: () => this._ngZone.run(() => this._tooltipsService.toggleTooltips()), }; } @@ -83,9 +80,7 @@ export class ViewerHeaderService { dataElement: HeaderElements.TOGGLE_READABLE_REDACTIONS, title: this._readableRedactionsService.toggleReadableRedactionsBtnTitle, img: this._readableRedactionsService.toggleReadableRedactionsBtnIcon, - onClick: () => { - this._readableRedactionsService.toggleReadableRedactions(); - }, + onClick: () => this._ngZone.run(() => this._readableRedactionsService.toggleReadableRedactions()), }; } @@ -94,7 +89,7 @@ export class ViewerHeaderService { type: 'actionButton', title: this._translateService.instant('viewer-header.load-all-annotations'), img: this._convertPath('/assets/icons/general/pdftron-action-load-all-annotations.svg'), - onClick: () => this.#events$.next({ type: ViewerEvents.LOAD_ALL_ANNOTATIONS }), + onClick: () => this._ngZone.run(() => this.#events$.next({ type: ViewerEvents.LOAD_ALL_ANNOTATIONS })), dataElement: HeaderElements.LOAD_ALL_ANNOTATIONS, }; } @@ -106,7 +101,7 @@ export class ViewerHeaderService { dataElement: HeaderElements.CLOSE_COMPARE_BUTTON, img: this._convertPath('/assets/icons/general/pdftron-action-close-compare.svg'), title: 'Leave Compare Mode', - onClick: () => this._closeCompareMode(), + onClick: () => this._ngZone.run(() => this._closeCompareMode()), }; } @@ -117,10 +112,11 @@ export class ViewerHeaderService { dataElement: HeaderElements.ROTATE_LEFT_BUTTON, img: this._convertPath('/assets/icons/general/rotate-left.svg'), title: 'Rotate page left', - onClick: () => { - this._rotationService.addRotation(RotationTypes.LEFT); - this.#toggleRotationActionButtons(); - }, + onClick: () => + this._ngZone.run(() => { + this._rotationService.addRotation(RotationTypes.LEFT); + this.#toggleRotationActionButtons(); + }), }; } @@ -138,10 +134,12 @@ export class ViewerHeaderService { cursor: pointer; margin: 0 12px; `; - paragraph.addEventListener('click', async () => { - await this._rotationService.applyRotation(); - this.disable(ROTATION_ACTION_BUTTONS); - }); + paragraph.addEventListener('click', () => + this._ngZone.run(async () => { + await this._rotationService.applyRotation(); + this.disable(ROTATION_ACTION_BUTTONS); + }), + ); return paragraph; }, }; @@ -161,7 +159,7 @@ export class ViewerHeaderService { cursor: pointer; opacity: 0.7; `; - paragraph.addEventListener('click', () => this.#discardRotation()); + paragraph.addEventListener('click', () => this._ngZone.run(() => this.#discardRotation())); return paragraph; }, }; @@ -174,10 +172,11 @@ export class ViewerHeaderService { dataElement: HeaderElements.ROTATE_RIGHT_BUTTON, img: this._convertPath('/assets/icons/general/rotate-right.svg'), title: 'Rotate page right', - onClick: () => { - this._rotationService.addRotation(RotationTypes.RIGHT); - this.#toggleRotationActionButtons(); - }, + onClick: () => + this._ngZone.run(() => { + this._rotationService.addRotation(RotationTypes.RIGHT); + this.#toggleRotationActionButtons(); + }), }; } @@ -188,10 +187,11 @@ export class ViewerHeaderService { dataElement: HeaderElements.COMPARE_BUTTON, img: this._convertPath('/assets/icons/general/pdftron-action-compare.svg'), title: 'Compare', - onClick: async () => { - document.getElementById('compareFileInput').click(); - this.#docBeforeCompare = await this._documentViewer.blob(); - }, + onClick: () => + this._ngZone.run(async () => { + document.getElementById('compareFileInput').click(); + this.#docBeforeCompare = await this._documentViewer.blob(); + }), }; } @@ -293,7 +293,7 @@ export class ViewerHeaderService { enableLoadAllAnnotations(): void { this._pdf.instance.UI.updateElement(HeaderElements.LOAD_ALL_ANNOTATIONS, { img: this._convertPath('/assets/icons/general/pdftron-action-load-all-annotations.svg'), - onClick: () => this.#events$.next({ type: ViewerEvents.LOAD_ALL_ANNOTATIONS }), + onClick: () => this._ngZone.run(() => this.#events$.next({ type: ViewerEvents.LOAD_ALL_ANNOTATIONS })), }); }