From cefe7e2a761a1806240af83e9e793449e4f73ee4 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Sat, 1 Mar 2025 08:46:03 -0800 Subject: [PATCH] feat: forecast viewer service --- .../pdf-viewer/pdf-viewer.component.html | 72 ++++++++++--------- .../pdf-viewer/pdf-viewer.component.ts | 42 +++++------ .../features/pdf-viewer/pdf-viewer.service.ts | 45 ++++++++++++ .../src/services/asyncService.service.ts | 4 +- 4 files changed, 104 insertions(+), 59 deletions(-) create mode 100644 libs/shared/src/features/pdf-viewer/pdf-viewer.service.ts diff --git a/libs/shared/src/features/pdf-viewer/pdf-viewer.component.html b/libs/shared/src/features/pdf-viewer/pdf-viewer.component.html index b03ad4c44..1febb23a9 100644 --- a/libs/shared/src/features/pdf-viewer/pdf-viewer.component.html +++ b/libs/shared/src/features/pdf-viewer/pdf-viewer.component.html @@ -1,38 +1,50 @@ -@if(legacyBrowser){
+ @if(serviceReady()){ @if(isCompatible()){ + + + + } @else { +
{{ 'PDF Viewer not supported on this device' | translate }}
-
{{ 'Please install the latest version of Google Chrome and restart' | translate }}
- +
{{ 'Please install the latest version of Google Chrome and restart' | translate }}
+
{{ 'Update' | translate }} - +
+ + } } + + @else { + +
{{ 'Loading' | translate }}...
+ }
-} @else { - - -} + + @@ -55,11 +67,3 @@ - - - diff --git a/libs/shared/src/features/pdf-viewer/pdf-viewer.component.ts b/libs/shared/src/features/pdf-viewer/pdf-viewer.component.ts index 881299d6a..5c46f60ff 100644 --- a/libs/shared/src/features/pdf-viewer/pdf-viewer.component.ts +++ b/libs/shared/src/features/pdf-viewer/pdf-viewer.component.ts @@ -1,52 +1,46 @@ import { CommonModule } from '@angular/common'; -import { Component, Input, ViewEncapsulation } from '@angular/core'; +import { AfterViewInit, Component, Input, signal, ViewEncapsulation } from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { App } from '@capacitor/app'; import { Capacitor } from '@capacitor/core'; -import { pdfDefaultOptions, PDFScriptLoaderService } from 'ngx-extended-pdf-viewer'; +import { pdfDefaultOptions } from 'ngx-extended-pdf-viewer'; import { NgxExtendedPdfViewerModule } from 'ngx-extended-pdf-viewer'; +import { PicsaTranslateModule } from '../../modules'; +import { PicsaPDFViewerService } from './pdf-viewer.service'; + @Component({ selector: 'picsa-pdf-viewer', templateUrl: './pdf-viewer.component.html', styleUrls: ['./pdf-viewer.component.scss'], encapsulation: ViewEncapsulation.None, - imports: [NgxExtendedPdfViewerModule, MatButtonModule, CommonModule], + imports: [NgxExtendedPdfViewerModule, MatButtonModule, CommonModule, PicsaTranslateModule], }) -export class PdfViewerComponent { - legacyBrowser = true; +export class PdfViewerComponent implements AfterViewInit { sidebarOpen = false; // additional locales are currently excluded from main build locale = 'en-GB'; public isNative = Capacitor.isNativePlatform(); @Input() page?: number; @Input() src: string; - constructor() { + + public serviceReady = toSignal(this.service.ready$, { initialValue: false }); + public isCompatible = signal(false); + + constructor(public service: PicsaPDFViewerService) { // name of folder pdf viewer assets copied to as declared in `angular.json` pdfDefaultOptions.assetsFolder = 'assets/pdf-viewer'; // force viewer to not use es5 fallback (not included in build) // use comparable check below to share message if not available for legacy browser - this.runCompatibilityCheck(); } - public restartApp() { - App.exitApp(); + async ngAfterViewInit() { + await this.service.ready(); + this.isCompatible.set(this.service.isCompatible); } - private async runCompatibilityCheck() { - // use same check that ngx-extended-pdf calls when checking compatibility locally - - // NOTE - as of v19 requires quite modern features available in native browser (pdfJS v4.1+), - // and cannot be polyfilled as required by worker/iframe. E.g. Promise.withResolvers - // https://github.com/stephanrauh/ngx-extended-pdf-viewer/issues/2500 - // https://github.com/mozilla/pdf.js/pull/17854 - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers#browser_compatibility - - // This is currently known to be resolved as of chrome 119 - - // Use inline scripts. Note if Using CSP security should set to false and include - // `op-chaining-support.js` in list of assets copied to run compatibility checks from js file instead of inline - const useInlineScripts = true; - this.legacyBrowser = await new PDFScriptLoaderService(null as any, null as any)['needsES5'](useInlineScripts); + public restartApp() { + App.exitApp(); } } diff --git a/libs/shared/src/features/pdf-viewer/pdf-viewer.service.ts b/libs/shared/src/features/pdf-viewer/pdf-viewer.service.ts new file mode 100644 index 000000000..2df431780 --- /dev/null +++ b/libs/shared/src/features/pdf-viewer/pdf-viewer.service.ts @@ -0,0 +1,45 @@ +import { Injectable, Injector, runInInjectionContext } from '@angular/core'; +import { PDFScriptLoaderService } from 'ngx-extended-pdf-viewer'; + +import { PicsaAsyncService } from '../../services/asyncService.service'; +import { ErrorHandlerService } from '../../services/core/error-handler.service'; + +@Injectable({ providedIn: 'root' }) +export class PicsaPDFViewerService extends PicsaAsyncService { + public isCompatible = false; + + constructor(private injector: Injector, private errorService: ErrorHandlerService) { + super(); + } + + public override async init() { + await this.runCompatibilityCheck(); + } + + private async runCompatibilityCheck() { + // Use same check that ngx-extended-pdf calls when checking compatibility locally + // As es5 bundles not included will fallback to update prompt in UI if compatibility fails + + // NOTE - as of v19 requires quite modern features available in native browser (pdfJS v4.1+), + // and cannot be polyfilled as required by worker/iframe. E.g. Promise.withResolvers + // https://github.com/stephanrauh/ngx-extended-pdf-viewer/issues/2500 + // https://github.com/mozilla/pdf.js/pull/17854 + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers#browser_compatibility + + // This is currently known to be resolved as of chrome 119 + + // Use inline scripts. Note if Using CSP security should set to false and include + // `op-chaining-support.js` in list of assets copied to run compatibility checks from js file instead of inline + const useInlineScripts = true; + try { + // As ngx-extended viewer uses effect signal for it's own service use injection context to ensure availability + runInInjectionContext(this.injector, async () => { + const needsES5 = await new PDFScriptLoaderService(null as any, null as any)['needsES5'](useInlineScripts); + this.isCompatible = !needsES5; + }); + } catch (error) { + this.isCompatible = false; + this.errorService.handleError(error as any); + } + } +} diff --git a/libs/shared/src/services/asyncService.service.ts b/libs/shared/src/services/asyncService.service.ts index 8ed1761ce..73022b122 100644 --- a/libs/shared/src/services/asyncService.service.ts +++ b/libs/shared/src/services/asyncService.service.ts @@ -31,6 +31,8 @@ export class PicsaAsyncService { this.callInitFunction(); } } + /** Observable for service ready state */ + public ready$ = this.initialised$.pipe(filter((v) => v === true)); private callInitFunction(...args: any) { this.initCalled = true; @@ -45,7 +47,7 @@ export class PicsaAsyncService { if (!this.initCalled) { this.callInitFunction(args); } - return firstValueFrom(this.initialised$.pipe(filter((v) => v === true))); + return firstValueFrom(this.ready$); }; /** Specify any async initialisation logic in method */