From 5a020c6d9bd50bedf87dd018a3229e333170c577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Tue, 18 Jan 2022 20:53:17 +0200 Subject: [PATCH 1/6] State service --- .../file-workload.component.html | 1 - .../file-workload/file-workload.component.ts | 9 ++--- .../page-indicator.component.ts | 37 ++++++++++-------- .../pdf-viewer/pdf-viewer.component.ts | 39 +++++++++++-------- .../view-switch/view-switch.component.ts | 3 +- .../file-preview-screen.component.html | 4 +- .../file-preview-screen.component.ts | 39 +++++++++++-------- .../services/file-preview-state.service.ts | 21 ++++++++++ .../modules/dossier/utils/pdf-viewer.utils.ts | 4 +- 9 files changed, 95 insertions(+), 62 deletions(-) create mode 100644 apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/file-preview-state.service.ts diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html index 720716f51..71c41366d 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html @@ -96,7 +96,6 @@ [file]="file" [number]="pageNumber" [showDottedIcon]="hasOnlyManualRedactionsAndIsExcluded(pageNumber)" - [viewedPages]="viewedPages" > diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.ts index e6afc8d32..584a25e84 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.ts @@ -28,7 +28,7 @@ import { PermissionsService } from '@services/permissions.service'; import { WebViewerInstance } from '@pdftron/webviewer'; import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; import { map, tap } from 'rxjs/operators'; -import { File, IViewedPage } from '@red/domain'; +import { File } from '@red/domain'; import { ExcludedPagesService } from '../../services/excluded-pages.service'; import { MultiSelectService } from '../../services/multi-select.service'; import { DocumentInfoService } from '../../services/document-info.service'; @@ -52,7 +52,6 @@ export class FileWorkloadComponent { @Input() activeViewerPage: number; @Input() shouldDeselectAnnotationsOnPageChange: boolean; @Input() dialogRef: MatDialogRef; - @Input() viewedPages: IViewedPage[]; @Input() file!: File; @Input() annotationActionsTemplate: TemplateRef; @Input() viewer: WebViewerInstance; @@ -225,7 +224,7 @@ export class FileWorkloadComponent { scrollAnnotationsToPage(page: number, mode: 'always' | 'if-needed' = 'if-needed'): void { if (this._annotationsElement) { - const elements = this._annotationsElement.nativeElement.querySelectorAll(`div[anotation-page-header="${page}"]`); + const elements: HTMLElement[] = this._annotationsElement.nativeElement.querySelectorAll(`div[anotation-page-header="${page}"]`); FileWorkloadComponent._scrollToFirstElement(elements, mode); } } @@ -235,7 +234,7 @@ export class FileWorkloadComponent { if (!this.selectedAnnotations || this.selectedAnnotations.length === 0 || !this._annotationsElement) { return; } - const elements = this._annotationsElement.nativeElement.querySelectorAll( + const elements: HTMLElement[] = this._annotationsElement.nativeElement.querySelectorAll( `div[annotation-id="${this._firstSelectedAnnotation?.id}"].active`, ); FileWorkloadComponent._scrollToFirstElement(elements); @@ -412,7 +411,7 @@ export class FileWorkloadComponent { private _scrollQuickNavigationToPage(page: number) { if (this._quickNavigationElement) { - const elements = this._quickNavigationElement.nativeElement.querySelectorAll(`#quick-nav-page-${page}`); + const elements: HTMLElement[] = this._quickNavigationElement.nativeElement.querySelectorAll(`#quick-nav-page-${page}`); FileWorkloadComponent._scrollToFirstElement(elements); } } diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/page-indicator/page-indicator.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/page-indicator/page-indicator.component.ts index 922dd5516..785a6153f 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/page-indicator/page-indicator.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/page-indicator/page-indicator.component.ts @@ -6,6 +6,7 @@ import { ViewedPagesService } from '@services/entity-services/viewed-pages.servi import { File, IViewedPage } from '@red/domain'; import { AutoUnsubscribe } from '@iqser/common-ui'; import { FilesMapService } from '@services/entity-services/files-map.service'; +import { FilePreviewStateService } from '../../services/file-preview-state.service'; @Component({ selector: 'redaction-page-indicator', @@ -18,7 +19,6 @@ export class PageIndicatorComponent extends AutoUnsubscribe implements OnDestroy @Input() active = false; @Input() showDottedIcon = false; @Input() number: number; - @Input() viewedPages: IViewedPage[]; @Input() activeSelection = false; @Output() readonly pageSelected = new EventEmitter(); @@ -33,25 +33,17 @@ export class PageIndicatorComponent extends AutoUnsubscribe implements OnDestroy private readonly _configService: ConfigService, private readonly _changeDetectorRef: ChangeDetectorRef, private readonly _permissionService: PermissionsService, + private readonly _stateService: FilePreviewStateService, ) { super(); } get activePage() { - return this.viewedPages?.find(p => p.page === this.number); + return this._viewedPages.find(p => p.page === this.number); } - private _setReadState() { - const readBefore = this.read; - const activePage = this.activePage; - if (!activePage) { - this.read = false; - } else { - // console.log('setting read to',activePage.showAsUnseen, !activePage.showAsUnseen); - this.read = !activePage.showAsUnseen; - } - // console.log(this.number, readBefore, activePage, this.read); - this._changeDetectorRef.detectChanges(); + private get _viewedPages(): IViewedPage[] { + return this._stateService.fileData?.viewedPages || []; } ngOnChanges() { @@ -87,20 +79,33 @@ export class PageIndicatorComponent extends AutoUnsubscribe implements OnDestroy } } + private _setReadState() { + const readBefore = this.read; + const activePage = this.activePage; + if (!activePage) { + this.read = false; + } else { + // console.log('setting read to',activePage.showAsUnseen, !activePage.showAsUnseen); + this.read = !activePage.showAsUnseen; + } + // console.log(this.number, readBefore, activePage, this.read); + this._changeDetectorRef.detectChanges(); + } + private async _markPageRead() { await this._viewedPagesService.addPage({ page: this.number }, this.file.dossierId, this.file.fileId).toPromise(); if (this.activePage) { this.activePage.showAsUnseen = false; } else { - this.viewedPages?.push({ page: this.number, fileId: this.file.fileId }); + this._viewedPages.push({ page: this.number, fileId: this.file.fileId }); } this._setReadState(); } private async _markPageUnread() { await this._viewedPagesService.removePage(this.file.dossierId, this.file.fileId, this.number).toPromise(); - this.viewedPages?.splice( - this.viewedPages?.findIndex(p => p.page === this.number), + this._viewedPages.splice( + this._viewedPages.findIndex(p => p.page === this.number), 1, ); this._setReadState(); diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/pdf-viewer/pdf-viewer.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/pdf-viewer/pdf-viewer.component.ts index a60280479..b8639aee8 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/pdf-viewer/pdf-viewer.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/pdf-viewer/pdf-viewer.component.ts @@ -36,11 +36,12 @@ import { ActivatedRoute } from '@angular/router'; import { toPosition } from '../../../../utils/pdf-calculation.utils'; import { ViewModeService } from '../../services/view-mode.service'; import { MultiSelectService } from '../../services/multi-select.service'; +import { FilePreviewStateService } from '../../services/file-preview-state.service'; import Tools = Core.Tools; import TextTool = Tools.TextTool; import Annotation = Core.Annotations.Annotation; -const ALLOWED_KEYBOARD_SHORTCUTS = ['+', '-', 'p', 'r', 'Escape'] as const; +const ALLOWED_KEYBOARD_SHORTCUTS: readonly string[] = ['+', '-', 'p', 'r', 'Escape'] as const; const dataElements = { ADD_REDACTION: 'add-redaction', ADD_DICTIONARY: 'add-dictionary', @@ -62,7 +63,6 @@ const dataElements = { styleUrls: ['./pdf-viewer.component.scss'], }) export class PdfViewerComponent implements OnInit, OnChanges { - @Input() fileData: Blob; @Input() file: File; @Input() dossier: Dossier; @Input() canPerformActions = false; @@ -95,6 +95,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { private readonly _annotationActionsService: AnnotationActionsService, private readonly _configService: ConfigService, private readonly _loadingService: LoadingService, + private readonly _stateService: FilePreviewStateService, readonly viewModeService: ViewModeService, readonly multiSelectService: MultiSelectService, ) {} @@ -113,6 +114,10 @@ export class PdfViewerComponent implements OnInit, OnChanges { ); } + private get _fileData(): Blob { + return this._stateService.fileData.fileData; + } + async ngOnInit() { this._setReadyAndInitialState = this._setReadyAndInitialState.bind(this); await this.loadViewer(); @@ -132,7 +137,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { } } - uploadFile(files: any) { + uploadFile(files: FileList) { const fileToCompare = files[0]; this.compareFileInput.nativeElement.value = null; @@ -148,7 +153,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null); const compareDocument = await pdfNet.PDFDoc.createFromBuffer(fileReader.result as ArrayBuffer); - const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await this.fileData.arrayBuffer()); + const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await this._fileData.arrayBuffer()); const loadCompareDocument = async () => { this._loadingService.start(); @@ -201,7 +206,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { this.viewModeService.compareMode = false; const pdfNet = this.instance.Core.PDFNet; await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null); - const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await this.fileData.arrayBuffer()); + const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await this._fileData.arrayBuffer()); this.instance.UI.loadDocument(currentDocument, { filename: this.file ? this.file.filename : 'document.pdf', }); @@ -219,7 +224,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { css: this._convertPath('/assets/pdftron/stylesheet.css'), backendType: 'ems', }, - this.viewer.nativeElement, + this.viewer.nativeElement as HTMLElement, ); this.documentViewer = this.instance.Core.documentViewer; @@ -231,7 +236,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { this.utils.disableHotkeys(); this._configureTextPopup(); - this.annotationManager.addEventListener('annotationSelected', (annotations, action) => { + this.annotationManager.addEventListener('annotationSelected', (annotations: Annotation[], action) => { this.annotationSelected.emit(this.annotationManager.getSelectedAnnotations().map(ann => ann.Id)); if (action === 'deselected') { this._toggleRectangleAnnotationAction(true); @@ -241,7 +246,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { } }); - this.annotationManager.addEventListener('annotationChanged', annotations => { + this.annotationManager.addEventListener('annotationChanged', (annotations: Annotation[]) => { // when a rectangle is drawn, // it returns one annotation with tool name 'AnnotationCreateRectangle; // this will auto select rectangle after drawing @@ -251,7 +256,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { } }); - this.documentViewer.addEventListener('pageNumberUpdated', pageNumber => { + this.documentViewer.addEventListener('pageNumberUpdated', (pageNumber: number) => { if (this.shouldDeselectAnnotationsOnPageChange) { this.utils.deselectAllAnnotations(); } @@ -261,9 +266,9 @@ export class PdfViewerComponent implements OnInit, OnChanges { this.documentViewer.addEventListener('documentLoaded', this._setReadyAndInitialState); - this.documentViewer.addEventListener('keyUp', $event => { + this.documentViewer.addEventListener('keyUp', ($event: KeyboardEvent) => { // arrows and full-screen - if ($event.target?.tagName?.toLowerCase() !== 'input') { + if (($event.target as HTMLElement)?.tagName?.toLowerCase() !== 'input') { if ($event.key.startsWith('Arrow') || $event.key === 'f') { this._ngZone.run(() => { this.keyUp.emit($event); @@ -273,7 +278,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { } } - if (ALLOWED_KEYBOARD_SHORTCUTS.indexOf($event.key) < 0) { + if (!ALLOWED_KEYBOARD_SHORTCUTS.includes($event.key)) { $event.preventDefault(); $event.stopPropagation(); } @@ -568,7 +573,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { } private _addManualRedactionOfType(type: ManualRedactionEntryType) { - const selectedQuads = this.documentViewer.getSelectedTextQuads(); + const selectedQuads: Readonly> = this.documentViewer.getSelectedTextQuads(); const text = this.documentViewer.getSelectedText(); const manualRedaction = this._getManualRedaction(selectedQuads, text, true); this.manualAnnotationRequested.emit(new ManualRedactionEntryWrapper(selectedQuads, manualRedaction, type)); @@ -624,7 +629,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { for (const quad of quads[key]) { const page = parseInt(key, 10); const pageHeight = this.documentViewer.getPageHeight(page); - entry.positions.push(toPosition(page, pageHeight, convertQuads ? this.utils.translateQuads(page, quad) : quad)); + entry.positions.push(toPosition(page, pageHeight, convertQuads ? this.utils.translateQuad(page, quad) : quad)); } } @@ -634,11 +639,11 @@ export class PdfViewerComponent implements OnInit, OnChanges { } private _loadDocument() { - if (!this.fileData) { + if (!this._fileData) { return; } - this.instance.UI.loadDocument(this.fileData, { + this.instance.UI.loadDocument(this._fileData, { filename: this.file ? this.file.filename : 'document.pdf', }); } @@ -647,7 +652,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { this._ngZone.run(() => { this.utils.ready = true; this.viewerReady.emit(this.instance); - const routePageNumber = this._activatedRoute.snapshot.queryParams.page; + const routePageNumber: number = this._activatedRoute.snapshot.queryParams.page; this.pageChanged.emit(routePageNumber || 1); this._setInitialDisplayMode(); this._updateTooltipsVisibility(); diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/view-switch/view-switch.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/view-switch/view-switch.component.ts index 283aa7f62..5b45956f6 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/view-switch/view-switch.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/view-switch/view-switch.component.ts @@ -4,7 +4,7 @@ import { ViewModeService } from '../../services/view-mode.service'; import { FileDataModel } from '@models/file/file-data.model'; @Component({ - selector: 'redaction-view-switch [file] [fileData]', + selector: 'redaction-view-switch [file]', templateUrl: './view-switch.component.html', styleUrls: ['./view-switch.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, @@ -12,7 +12,6 @@ import { FileDataModel } from '@models/file/file-data.model'; export class ViewSwitchComponent implements OnChanges { @Output() readonly switchView = new EventEmitter(); @Input() file: File; - @Input() fileData: FileDataModel; canSwitchToDeltaView = false; canSwitchToRedactedView = false; diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html index ccc7b9f21..a7271bf42 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html @@ -3,7 +3,7 @@