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 9cb35048c..5124d2521 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 @@ -9,6 +9,7 @@ import { Debounce, ErrorService, FilterService, + List, LoadingService, NestedFilter, OnAttach, @@ -26,7 +27,7 @@ import { File, ViewMode, ViewModes } from '@red/domain'; import { PermissionsService } from '@services/permissions.service'; import { combineLatest, firstValueFrom, from, of, pairwise } from 'rxjs'; import { UserPreferenceService } from '@services/user-preference.service'; -import { download, handleFilterDelta } from '../../utils'; +import { byId, byPage, download, handleFilterDelta } from '../../utils'; import { FilesService } from '@services/files/files.service'; import { FileManagementService } from '@services/files/file-management.service'; import { catchError, filter, map, startWith, switchMap, tap } from 'rxjs/operators'; @@ -361,8 +362,15 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni return this.viewerReady(); }), ); + const currentPageAnnotations$ = combineLatest([this.pdf.currentPage$, this._fileDataService.annotations$]).pipe( - map(([page, annotations]) => annotations.filter(annotation => annotation.pageNumber === page)), + map(([, annotations]) => annotations), + startWith([] as List), + pairwise(), + map(([oldAnnotations, newAnnotations]) => { + const page = this.pdf.currentPage; + return [oldAnnotations.filter(byPage(page)), newAnnotations.filter(byPage(page))] as const; + }), ); let start; @@ -370,8 +378,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni filter(([, loaded]) => loaded), tap(() => (start = new Date().getTime())), map(([annotations]) => annotations), - startWith([] as AnnotationWrapper[]), - pairwise(), tap(annotations => this.deleteAnnotations(...annotations)), switchMap(annotations => this.drawChangedAnnotations(...annotations)), tap(([, newAnnotations]) => this.#highlightSelectedAnnotations(newAnnotations)), @@ -381,28 +387,20 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } deleteAnnotations(oldAnnotations: AnnotationWrapper[], newAnnotations: AnnotationWrapper[]) { - const annotationsToDelete = oldAnnotations.filter( - oldAnnotation => !newAnnotations.some(newAnnotation => newAnnotation.id === oldAnnotation.id), - ); + const annotationsToDelete = oldAnnotations.filter(oldAnnotation => !newAnnotations.some(byId(oldAnnotation.id))); + if (annotationsToDelete.length === 0) { return; } - this._logger.info('[ANNOTATIONS] To delete: ', annotationsToDelete); - this._annotationManager.delete(annotationsToDelete); + const toDelete = annotationsToDelete.filter(byPage(this.pdf.currentPage)); + + this._logger.info('[ANNOTATIONS] To delete: ', toDelete); + this._annotationManager.delete(toDelete); } async drawChangedAnnotations(oldAnnotations: AnnotationWrapper[], newAnnotations: AnnotationWrapper[]) { - let annotationsToDraw: readonly AnnotationWrapper[]; - const annotations = this._annotationManager.annotations; - const ann = annotations.map(a => oldAnnotations.some(oldAnnotation => oldAnnotation.id === a.Id)); - const hasAnnotations = ann.filter(a => !!a).length > 0; - - if (hasAnnotations) { - annotationsToDraw = this.#getAnnotationsToDraw(newAnnotations, oldAnnotations); - } else { - annotationsToDraw = newAnnotations; - } + const annotationsToDraw = this.#getAnnotationsToDraw(oldAnnotations, newAnnotations); if (annotationsToDraw.length === 0) { return [oldAnnotations, newAnnotations]; @@ -423,6 +421,18 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni return ActionsHelpModeKeys[type]; } + #getAnnotationsToDraw(oldAnnotations: AnnotationWrapper[], newAnnotations: AnnotationWrapper[]) { + const annotations = this._annotationManager.annotations; + const ann = annotations.map(a => oldAnnotations.some(byId(a.Id))); + const hasAnnotations = ann.filter(a => !!a).length > 0; + + if (hasAnnotations) { + return this.#findAnnotationsToDraw(newAnnotations, oldAnnotations); + } else { + return newAnnotations; + } + } + #rebuildFilters() { const startTime = new Date().getTime(); @@ -457,7 +467,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni this._changeDetectorRef.markForCheck(); } - #getAnnotationsToDraw(newAnnotations: AnnotationWrapper[], oldAnnotations: AnnotationWrapper[]) { + #findAnnotationsToDraw(newAnnotations: AnnotationWrapper[], oldAnnotations: AnnotationWrapper[]) { return newAnnotations.filter(newAnnotation => { const oldAnnotation = oldAnnotations.find(annotation => annotation.id === newAnnotation.id); if (!oldAnnotation) { 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 ddce07afe..3f47e42bc 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 @@ -26,19 +26,15 @@ export class AnnotationsListingService extends ListingService .subscribe(); } - selectAnnotations(annotation: AnnotationWrapper); - selectAnnotations(annotations?: AnnotationWrapper[]); - selectAnnotations(annotations?: AnnotationWrapper[] | AnnotationWrapper) { - if (!annotations) { - return this._annotationManager.deselect(); - } + selectAnnotations(annotations: AnnotationWrapper[] | AnnotationWrapper) { annotations = Array.isArray(annotations) ? annotations : [annotations]; + const pageNumber = annotations[annotations.length - 1].pageNumber; const annotationsToSelect = this._multiSelectService.isActive ? [...this.selected, ...annotations] : annotations; - this.#selectAnnotations(annotationsToSelect); + this.#selectAnnotations(annotationsToSelect, pageNumber); } - #selectAnnotations(annotations: AnnotationWrapper[]) { + #selectAnnotations(annotations: AnnotationWrapper[], pageNumber: number) { if (!annotations.length) { return; } @@ -47,8 +43,6 @@ export class AnnotationsListingService extends ListingService this._annotationManager.deselect(); } - const pageNumber = annotations[0].pageNumber; - if (pageNumber === this._pdf.currentPage) { return this._annotationManager.jumpAndSelect(annotations); } 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 ac25fe331..8857208d6 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 @@ -16,7 +16,7 @@ import { shareDistinctLast } from '@iqser/common-ui'; import { toPosition } from '../utils/pdf-calculation.utils'; import { MultiSelectService } from './multi-select.service'; import { FilePreviewStateService } from './file-preview-state.service'; -import { filter, map, tap } from 'rxjs/operators'; +import { map, tap } from 'rxjs/operators'; import { HeaderElements, TextPopups } from '../utils/constants'; import { FileDataService } from './file-data.service'; import { ViewerHeaderService } from '../../pdf-viewer/services/viewer-header.service'; @@ -89,7 +89,6 @@ export class PdfProxyService { get #annotationSelected$() { return this._annotationManager.annotationSelected$.pipe( - filter(([, action]) => !(this._multiSelectService.isActive && action === 'deselected')), map(value => this.#processSelectedAnnotations(...value)), tap(annotations => this.handleAnnotationSelected(annotations)), ); 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 1fc99b8bf..2934f5f4c 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 @@ -6,6 +6,7 @@ import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { fromEvent, Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; import { asList, getId, isStringOrWrapper } from '../utils/functions'; +import { getLast } from '@utils/functions'; import AnnotationManager = Core.AnnotationManager; import Annotation = Core.Annotations.Annotation; @@ -79,7 +80,7 @@ export class REDAnnotationManager { jumpAndSelect(annotations: List | List) { const annotationsFromViewer = this.get(annotations); - this.#manager.jumpToAnnotation(annotationsFromViewer[0]); + this.#manager.jumpToAnnotation(getLast(annotationsFromViewer)); this.#manager.selectAnnotations(annotationsFromViewer); } diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts index a47bb6ea7..b021c4f8e 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts @@ -5,7 +5,7 @@ import { File, IHeaderElement } from '@red/domain'; import { ErrorService, shareDistinctLast } from '@iqser/common-ui'; import { ActivatedRoute } from '@angular/router'; import { map, startWith } from 'rxjs/operators'; -import { BehaviorSubject, combineLatest, fromEvent, Observable } from 'rxjs'; +import { BehaviorSubject, combineLatest, fromEvent, Observable, switchMap } from 'rxjs'; import { ConfigService } from '@services/config.service'; import { NGXLogger } from 'ngx-logger'; import { DISABLED_HOTKEYS, DOCUMENT_LOADING_ERROR, SEARCH_OPTIONS, USELESS_ELEMENTS } from '../utils/constants'; @@ -70,8 +70,9 @@ export class PdfViewer { get pageCount() { try { - return this.#instance.Core.documentViewer.getPageCount(); - } catch { + return this.documentViewer.getPageCount(); + } catch (e) { + console.log(e); // might throw Error: getPageCount was called before the 'documentLoaded' event return 1; } @@ -83,7 +84,8 @@ export class PdfViewer { get #totalPages$() { const layoutChanged$ = fromEvent(this.documentViewer, 'layoutChanged').pipe(startWith('')); - const pageCount$ = layoutChanged$.pipe(map(() => this.pageCount)); + const docLoaded$ = fromEvent(this.documentViewer, 'documentLoaded'); + const pageCount$ = docLoaded$.pipe(switchMap(() => layoutChanged$.pipe(map(() => this.pageCount)))); const docChanged$ = combineLatest([pageCount$, this.compareMode$]); return docChanged$.pipe(map(([pageCount]) => this.#adjustPage(pageCount))); @@ -99,10 +101,7 @@ export class PdfViewer { get #pageChanged$() { const page$ = fromEvent(this.documentViewer, 'pageNumberUpdated'); - return page$.pipe( - // tap(() => this._annotationManager.deselect()), - map(page => this.#adjustPage(page)), - ); + return page$.pipe(map(page => this.#adjustPage(page))); } navigateTo(page: string | number) { diff --git a/apps/red-ui/src/app/utils/functions.ts b/apps/red-ui/src/app/utils/functions.ts index 3d0fdbeac..9071047a0 100644 --- a/apps/red-ui/src/app/utils/functions.ts +++ b/apps/red-ui/src/app/utils/functions.ts @@ -1,4 +1,5 @@ -import { List } from '@iqser/common-ui'; +import type { List } from '@iqser/common-ui'; +import type { AnnotationWrapper } from '@models/file/annotation.wrapper'; export function groupBy(xs: List, key: string) { return xs.reduce((rv, x) => { @@ -92,3 +93,10 @@ export function compareLists(l1: string[], l2: string[]) { return false; } + +export const byPage = (page: number) => (annotation: AnnotationWrapper) => annotation.pageNumber === page; +export const byId = (id: string) => (annotation: AnnotationWrapper) => annotation.annotationId === id; + +export function getLast(list: List) { + return list[list.length - 1]; +}