RED-6412: pdf actions run with cleanup
This commit is contained in:
parent
07abfefe56
commit
a7eca09d8e
@ -146,6 +146,7 @@ const routes: IqserRoutes = [
|
||||
},
|
||||
{
|
||||
path: 'downloads',
|
||||
// TODO: transform into a lazy loaded module
|
||||
component: DownloadsListScreenComponent,
|
||||
canActivate: [CompositeRouteGuard, IqserPermissionsGuard],
|
||||
data: {
|
||||
@ -224,7 +225,7 @@ const routes: IqserRoutes = [
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled' })],
|
||||
providers: [{ provide: RouteReuseStrategy, useClass: CustomRouteReuseStrategy }],
|
||||
providers: [{ provide: RouteReuseStrategy, useExisting: CustomRouteReuseStrategy }],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AppRoutingModule {}
|
||||
|
||||
@ -40,7 +40,7 @@ import { AnnotationDrawService } from '../pdf-viewer/services/annotation-draw.se
|
||||
import { AnnotationProcessingService } from './services/annotation-processing.service';
|
||||
import { Dictionary, File, ViewModes } from '@red/domain';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { combineLatest, firstValueFrom, from, Observable, of, pairwise } from 'rxjs';
|
||||
import { combineLatest, firstValueFrom, Observable, of, pairwise } from 'rxjs';
|
||||
import { PreferencesKeys, UserPreferenceService } from '@users/user-preference.service';
|
||||
import { byId, byPage, download, handleFilterDelta, hasChanges } from '../../utils';
|
||||
import { FilesService } from '@services/files/files.service';
|
||||
@ -617,9 +617,8 @@ export class FilePreviewScreenComponent
|
||||
|
||||
this.addActiveScreenSubscription = this.state.blob$
|
||||
.pipe(
|
||||
switchMap(blob => from(this._documentViewer.lock()).pipe(map(() => blob))),
|
||||
tap(() => this._errorService.clear()),
|
||||
tap(blob => this.pdf.loadDocument(blob, this.state.file, () => this.state.reloadBlob())),
|
||||
switchMap(blob => this.pdf.loadDocument(blob, this.state.file, () => this.state.reloadBlob())),
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ export class AnnotationDrawService {
|
||||
|
||||
async draw(annotations: List<AnnotationWrapper>, hideSkipped: boolean, dossierTemplateId: string) {
|
||||
try {
|
||||
await this._draw(annotations, hideSkipped, dossierTemplateId);
|
||||
await this._pdf.runWithCleanup(async () => await this._draw(annotations, hideSkipped, dossierTemplateId));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { Core } from '@pdftron/webviewer';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { fromEvent, merge, Observable } from 'rxjs';
|
||||
import { fromEvent, merge, Observable, Subject } from 'rxjs';
|
||||
import { debounceTime, filter, map, tap } from 'rxjs/operators';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { PdfViewer } from './pdf-viewer.service';
|
||||
import { UserPreferenceService } from '@users/user-preference.service';
|
||||
import { log, shareLast } from '@iqser/common-ui';
|
||||
import { log, shareDistinctLast, shareLast } from '@iqser/common-ui';
|
||||
import { stopAndPrevent, stopAndPreventIfNotAllowed } from '../utils/functions';
|
||||
import { RotationType, RotationTypes } from '@red/domain';
|
||||
import { AnnotationToolNames } from '../utils/constants';
|
||||
@ -23,6 +23,8 @@ export class REDDocumentViewer {
|
||||
selectedText = '';
|
||||
#document: DocumentViewer;
|
||||
|
||||
readonly #documentClosed$ = new Subject<undefined>();
|
||||
|
||||
readonly #logger = inject(NGXLogger);
|
||||
readonly #userPreferenceService = inject(UserPreferenceService);
|
||||
readonly #pdf = inject(PdfViewer);
|
||||
@ -37,7 +39,7 @@ export class REDDocumentViewer {
|
||||
}
|
||||
|
||||
get #documentUnloaded$() {
|
||||
const event$ = fromEvent(this.#document, 'documentUnloaded');
|
||||
const event$ = merge(fromEvent(this.#document, 'documentUnloaded'), this.#documentClosed$);
|
||||
const toBool$ = event$.pipe(map(() => false));
|
||||
|
||||
return toBool$.pipe(tap(() => this.#logger.info('[PDF] Document unloaded')));
|
||||
@ -48,10 +50,14 @@ export class REDDocumentViewer {
|
||||
const toBool$ = event$.pipe(map(() => true));
|
||||
|
||||
return toBool$.pipe(
|
||||
tap(() => this.#flattenAnnotations()),
|
||||
tap(() => this.#setCurrentPage()),
|
||||
tap(() => this.#setInitialDisplayMode()),
|
||||
tap(() => this.updateTooltipsVisibility()),
|
||||
tap(() =>
|
||||
this.#pdf.runWithCleanup(async () => {
|
||||
await this.#flattenAnnotations();
|
||||
this.#setCurrentPage();
|
||||
this.#setInitialDisplayMode();
|
||||
this.updateTooltipsVisibility();
|
||||
}),
|
||||
),
|
||||
tap(() => this.#logger.info('[PDF] Document loaded')),
|
||||
);
|
||||
}
|
||||
@ -86,7 +92,7 @@ export class REDDocumentViewer {
|
||||
}
|
||||
|
||||
get #loaded$() {
|
||||
return merge(this.#documentUnloaded$, this.#documentLoaded$).pipe(shareLast());
|
||||
return merge(this.#documentUnloaded$, this.#documentLoaded$).pipe(shareDistinctLast());
|
||||
}
|
||||
|
||||
clearSelection() {
|
||||
@ -95,9 +101,16 @@ export class REDDocumentViewer {
|
||||
}
|
||||
|
||||
close() {
|
||||
this.#logger.info('[PDF] Closing document');
|
||||
this.#document.closeDocument();
|
||||
this.#pdf.closeCompareMode();
|
||||
this.#documentClosed$.next(undefined);
|
||||
|
||||
const closeAction = async () => {
|
||||
this.#logger.info('[PDF] Closing document');
|
||||
this.#document.closeDocument();
|
||||
this.#pdf.closeCompareMode();
|
||||
await this.#pdf.instance.UI.closeDocument();
|
||||
};
|
||||
|
||||
this.#pdf.runWithCleanup(closeAction).then();
|
||||
}
|
||||
|
||||
updateTooltipsVisibility(): void {
|
||||
@ -113,17 +126,6 @@ export class REDDocumentViewer {
|
||||
this.textSelected$ = this.#textSelected$;
|
||||
}
|
||||
|
||||
async lock() {
|
||||
const document = await this.PDFDoc;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
|
||||
await document.lock();
|
||||
this.#logger.info('[PDF] Locked');
|
||||
return true;
|
||||
}
|
||||
|
||||
async blob() {
|
||||
const data = await this.document.getFileData();
|
||||
return new Blob([new Uint8Array(data)], { type: 'application/pdf' });
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
import { Inject, Injectable, Injector } from '@angular/core';
|
||||
import { inject, Inject, Injectable, Injector } from '@angular/core';
|
||||
import WebViewer, { Core, WebViewerInstance, WebViewerOptions } from '@pdftron/webviewer';
|
||||
import { BASE_HREF_FN, BaseHrefFn, ErrorService, shareDistinctLast } from '@iqser/common-ui';
|
||||
import { File, IHeaderElement } from '@red/domain';
|
||||
import { BASE_HREF_FN, BaseHrefFn, ErrorService, getConfig, shareDistinctLast } from '@iqser/common-ui';
|
||||
import { AppConfig, File, IHeaderElement } from '@red/domain';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { map, startWith } from 'rxjs/operators';
|
||||
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';
|
||||
import { Rgb } from '../utils/types';
|
||||
@ -22,7 +21,7 @@ import Quad = Core.Math.Quad;
|
||||
|
||||
@Injectable()
|
||||
export class PdfViewer {
|
||||
readonly currentPage$ = this._activatedRoute.queryParamMap.pipe(
|
||||
readonly currentPage$ = inject(ActivatedRoute).queryParamMap.pipe(
|
||||
map(params => Number(params.get('page') ?? '1')),
|
||||
shareDistinctLast(),
|
||||
);
|
||||
@ -37,11 +36,13 @@ export class PdfViewer {
|
||||
totalPages$: Observable<number>;
|
||||
|
||||
#instance: WebViewerInstance;
|
||||
readonly #licenseKey = inject(LicenseService).activeLicenseKey;
|
||||
readonly #config = getConfig<AppConfig>();
|
||||
readonly #compareMode$ = new BehaviorSubject(false);
|
||||
readonly #searchButton: IHeaderElement = {
|
||||
type: 'actionButton',
|
||||
img: this._convertPath('/assets/icons/general/pdftron-action-search.svg'),
|
||||
title: this._translateService.instant('pdf-viewer.text-popup.actions.search'),
|
||||
title: inject(TranslateService).instant('pdf-viewer.text-popup.actions.search'),
|
||||
onClick: () => {
|
||||
this.#instance.UI.openElements(['searchPanel']);
|
||||
setTimeout(() => this.#searchForSelectedText(), 250);
|
||||
@ -51,10 +52,7 @@ export class PdfViewer {
|
||||
constructor(
|
||||
private readonly _logger: NGXLogger,
|
||||
private readonly _injector: Injector,
|
||||
private readonly _activatedRoute: ActivatedRoute,
|
||||
private readonly _licenseService: LicenseService,
|
||||
private readonly _errorService: ErrorService,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _userPreferenceService: UserPreferenceService,
|
||||
@Inject(BASE_HREF_FN) private readonly _convertPath: BaseHrefFn,
|
||||
) {}
|
||||
@ -154,26 +152,28 @@ export class PdfViewer {
|
||||
this.#instance.Core.setCustomFontURL('https://' + window.location.host + this._convertPath('/assets/pdftron'));
|
||||
}
|
||||
|
||||
try {
|
||||
await this.PDFNet.initialize(this._licenseService.activeLicenseKey);
|
||||
} catch (e) {
|
||||
this._errorService.set(e);
|
||||
throw e;
|
||||
}
|
||||
await this.runWithCleanup(async () => {
|
||||
try {
|
||||
await this.PDFNet.initialize(this.#licenseKey);
|
||||
} catch (e) {
|
||||
this._errorService.set(e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
this.#instance.UI.setTheme(this._userPreferenceService.getTheme());
|
||||
this._logger.info('[PDF] Initialized');
|
||||
this.#instance.UI.setTheme(this._userPreferenceService.getTheme());
|
||||
this._logger.info('[PDF] Initialized');
|
||||
|
||||
this.documentViewer = this.#instance.Core.documentViewer;
|
||||
this.documentViewer = this.#instance.Core.documentViewer;
|
||||
|
||||
this.compareMode$ = this.#compareMode$.asObservable();
|
||||
this.pageChanged$ = this.#pageChanged$.pipe(shareDistinctLast());
|
||||
this.totalPages$ = this.#totalPages$.pipe(shareDistinctLast());
|
||||
this.#setSelectionMode();
|
||||
this.#configureElements();
|
||||
this.#disableHotkeys();
|
||||
this.#clearSearchResultsWhenVisibilityChanged();
|
||||
this.#listenForCommandF();
|
||||
this.compareMode$ = this.#compareMode$.asObservable();
|
||||
this.pageChanged$ = this.#pageChanged$.pipe(shareDistinctLast());
|
||||
this.totalPages$ = this.#totalPages$.pipe(shareDistinctLast());
|
||||
this.#setSelectionMode();
|
||||
this.#configureElements();
|
||||
this.#disableHotkeys();
|
||||
this.#clearSearchResultsWhenVisibilityChanged();
|
||||
this.#listenForCommandF();
|
||||
});
|
||||
|
||||
return this.#instance;
|
||||
}
|
||||
@ -196,6 +196,10 @@ export class PdfViewer {
|
||||
this.#compareMode$.next(false);
|
||||
}
|
||||
|
||||
runWithCleanup(action: () => Promise<void> | void) {
|
||||
return this.PDFNet.runWithCleanup(action, this.#licenseKey);
|
||||
}
|
||||
|
||||
async loadDocument(blob: Blob, file: File, actionOnError?: () => void) {
|
||||
const onError = () => {
|
||||
this._injector.get(ErrorService).set(DOCUMENT_LOADING_ERROR);
|
||||
@ -208,7 +212,11 @@ export class PdfViewer {
|
||||
|
||||
this._logger.info('[PDF] Loading document...');
|
||||
|
||||
this.#instance.UI.loadDocument(blob, { documentId: file.fileId, filename: file?.filename ?? 'document.pdf', onError });
|
||||
await this.runWithCleanup(async () => {
|
||||
const document = await this.documentViewer.getDocument()?.getPDFDoc();
|
||||
await document?.lock();
|
||||
this.#instance.UI.loadDocument(blob, { documentId: file.fileId, filename: file?.filename ?? 'document.pdf', onError });
|
||||
});
|
||||
}
|
||||
|
||||
quad(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number) {
|
||||
@ -307,13 +315,12 @@ export class PdfViewer {
|
||||
|
||||
#setSelectionMode(): void {
|
||||
const textTool = this.#instance.Core.Tools.TextTool as unknown as TextTool;
|
||||
const configService = this._injector.get(ConfigService);
|
||||
textTool.SELECTION_MODE = configService.values.SELECTION_MODE;
|
||||
textTool.SELECTION_MODE = this.#config.SELECTION_MODE;
|
||||
}
|
||||
|
||||
#getInstance(htmlElement: HTMLElement) {
|
||||
const options: WebViewerOptions = {
|
||||
licenseKey: this._licenseService.activeLicenseKey,
|
||||
licenseKey: this.#licenseKey,
|
||||
fullAPI: true,
|
||||
path: this._convertPath('/assets/wv-resources'),
|
||||
css: this._convertPath('/assets/pdftron/stylesheet.css'),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user