RED-3837: finish select annotations on multiple pages

This commit is contained in:
Dan Percic 2022-06-16 18:42:30 +03:00
parent c1e3d342fa
commit 85f9cd85cf
6 changed files with 53 additions and 42 deletions

View File

@ -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<AnnotationWrapper>),
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) {

View File

@ -26,19 +26,15 @@ export class AnnotationsListingService extends ListingService<AnnotationWrapper>
.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<AnnotationWrapper>
this._annotationManager.deselect();
}
const pageNumber = annotations[0].pageNumber;
if (pageNumber === this._pdf.currentPage) {
return this._annotationManager.jumpAndSelect(annotations);
}

View File

@ -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)),
);

View File

@ -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<AnnotationWrapper>) {
const annotationsFromViewer = this.get(annotations);
this.#manager.jumpToAnnotation(annotationsFromViewer[0]);
this.#manager.jumpToAnnotation(getLast(annotationsFromViewer));
this.#manager.selectAnnotations(annotationsFromViewer);
}

View File

@ -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<number>(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) {

View File

@ -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<unknown>, 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<T>(list: List<T>) {
return list[list.length - 1];
}