From e4beab66a70d4e1085f7f2274c26a9085ee14a2d Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 26 Jul 2023 11:59:32 -0700 Subject: [PATCH 01/14] refactor: crashlytics service --- .../extension-app/src/app/app.component.html | 1 - .../extension-app/src/app/app.component.ts | 17 +++-- .../src/services/core/crashlytics.service.ts | 64 +++++++++++++++++++ .../services/native/crashlytics.service.ts | 37 ----------- 4 files changed, 74 insertions(+), 45 deletions(-) create mode 100644 libs/shared/src/services/core/crashlytics.service.ts delete mode 100644 libs/shared/src/services/native/crashlytics.service.ts diff --git a/apps/picsa-apps/extension-app/src/app/app.component.html b/apps/picsa-apps/extension-app/src/app/app.component.html index 8ca942e39..d5e086097 100644 --- a/apps/picsa-apps/extension-app/src/app/app.component.html +++ b/apps/picsa-apps/extension-app/src/app/app.component.html @@ -1,4 +1,3 @@ -
diff --git a/apps/picsa-apps/extension-app/src/app/app.component.ts b/apps/picsa-apps/extension-app/src/app/app.component.ts index 0f58d4e62..0dc3e8e79 100644 --- a/apps/picsa-apps/extension-app/src/app/app.component.ts +++ b/apps/picsa-apps/extension-app/src/app/app.component.ts @@ -1,11 +1,11 @@ /* eslint-disable @nrwl/nx/enforce-module-boundaries */ import { Component } from '@angular/core'; import { Router } from '@angular/router'; -import { Capacitor } from '@capacitor/core'; import { ENVIRONMENT } from '@picsa/environments'; import { AnalyticsService } from '@picsa/shared/services/core/analytics.service'; +import { CompatibilityService } from '@picsa/shared/services/core/compatibility.service'; +import { CrashlyticsService } from '@picsa/shared/services/core/crashlytics.service'; import { PerformanceService } from '@picsa/shared/services/core/performance.service'; -import { CrashlyticsService } from '@picsa/shared/services/native/crashlytics.service'; @Component({ selector: 'picsa-root', @@ -18,15 +18,18 @@ export class AppComponent { constructor( analyticsService: AnalyticsService, router: Router, - crashlyticsService: CrashlyticsService, - performanceService: PerformanceService + performanceService: PerformanceService, + compatibilityService: CompatibilityService, + crashlyticsService: CrashlyticsService ) { performanceService.setEnabled({ enabled: ENVIRONMENT.production }); if (ENVIRONMENT.production) { analyticsService.init(router); } - if (Capacitor.isNativePlatform()) { - crashlyticsService.init(); - } + crashlyticsService.ready().then(() => null); + + compatibilityService.checkDeviceCompatibility().then((res) => { + console.log('compatibility', res); + }); } } diff --git a/libs/shared/src/services/core/crashlytics.service.ts b/libs/shared/src/services/core/crashlytics.service.ts new file mode 100644 index 000000000..b619d77b6 --- /dev/null +++ b/libs/shared/src/services/core/crashlytics.service.ts @@ -0,0 +1,64 @@ +import { Injectable } from '@angular/core'; +import { Capacitor } from '@capacitor/core'; +import { Device } from '@capacitor/device'; +import { FirebaseCrashlytics, RecordExceptionOptions } from '@capacitor-community/firebase-crashlytics'; +import { ENVIRONMENT } from '@picsa/environments'; + +import { PicsaAsyncService } from '../asyncService.service'; + +@Injectable({ + providedIn: 'root', +}) +/** + * Automates reporting of crash data to firebase crashlytics, and adds methods + * to allow custom reporting for non-fatal exceptions (e.g. error messages) + * https://github.com/capacitor-community/firebase-crashlytics + */ +export class CrashlyticsService extends PicsaAsyncService { + /** Service will only be enabled in production on native device (not supported on web) */ + private enabled = false; + + constructor() { + super(); + this.enabled = Capacitor.isNativePlatform() && ENVIRONMENT.production; + } + public override async init() { + if (this.enabled) { + const { setEnabled, setUserId, setContext, sendUnsentReports } = FirebaseCrashlytics; + await setEnabled({ enabled: true }); + const { uuid } = await Device.getId(); + await setUserId({ userId: uuid }); + // populate webview useragent info + const { webViewVersion } = await Device.getInfo(); + await setContext({ + key: 'userAgent', + type: 'string', + value: navigator.userAgent || '', + }); + await setContext({ + key: 'webViewVersion', + type: 'string', + value: webViewVersion || '', + }); + await setContext({ + key: 'pathname', + type: 'string', + value: location.pathname || '', + }); + sendUnsentReports(); + } else { + this.loadDummyMethods(); + } + } + + public recordException = FirebaseCrashlytics.recordException; + + /** When using on unsupported device fill dummy methods for interoperability */ + private loadDummyMethods() { + this.recordException = async (options: RecordExceptionOptions) => { + console.warn('[Crashlytics] skipping report', options); + }; + } + + private crash = FirebaseCrashlytics.crash; +} diff --git a/libs/shared/src/services/native/crashlytics.service.ts b/libs/shared/src/services/native/crashlytics.service.ts deleted file mode 100644 index e39c7b7f9..000000000 --- a/libs/shared/src/services/native/crashlytics.service.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Capacitor } from '@capacitor/core'; -import { Device } from '@capacitor/device'; -import { FirebaseCrashlytics } from '@capacitor-community/firebase-crashlytics'; - -@Injectable({ - providedIn: 'root', -}) -/** - * Automates reporting of crash data to firebase crashlytics, and adds methods - * to allow custom reporting for non-fatal exceptions (e.g. error messages) - * https://github.com/capacitor-community/firebase-crashlytics - */ -export class CrashlyticsService { - public async init() { - if (Capacitor.isNativePlatform()) { - await this.setEnabled({ enabled: true }); - const { uuid } = await Device.getId(); - await this.setUserId({ userId: uuid }); - this.sendUnsentReports(); - } - } - - public recordException = FirebaseCrashlytics.recordException; - - public addLogMessage = FirebaseCrashlytics.addLogMessage; - - public setContext = FirebaseCrashlytics.setContext; - - private setUserId = FirebaseCrashlytics.setUserId; - - private setEnabled = FirebaseCrashlytics.setEnabled; - - private sendUnsentReports = FirebaseCrashlytics.sendUnsentReports; - - private crash = FirebaseCrashlytics.crash; -} From e5604ab4d5ef9b237ed75fe92f3e7c780222c44c Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 26 Jul 2023 12:35:49 -0700 Subject: [PATCH 02/14] feat: wip device support module --- .../extension-app/src/app/app.component.ts | 9 ++- .../extension-app/src/app/app.module.ts | 2 + .../device-support/device-support.models.ts | 5 ++ .../device-support/device-support.service.ts | 79 +++++++++++++++++++ .../device-troubleshooter.component.html | 1 + .../device-troubleshooter.component.scss | 0 .../device-troubleshooter.component.spec.ts | 22 ++++++ .../device-troubleshooter.component.ts | 8 ++ .../src/modules/device-support/index.ts | 38 +++++++++ libs/shared/src/modules/index.ts | 2 + 10 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 libs/shared/src/modules/device-support/device-support.models.ts create mode 100644 libs/shared/src/modules/device-support/device-support.service.ts create mode 100644 libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.html create mode 100644 libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.scss create mode 100644 libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.spec.ts create mode 100644 libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.ts create mode 100644 libs/shared/src/modules/device-support/index.ts diff --git a/apps/picsa-apps/extension-app/src/app/app.component.ts b/apps/picsa-apps/extension-app/src/app/app.component.ts index 0dc3e8e79..bf21e0d6c 100644 --- a/apps/picsa-apps/extension-app/src/app/app.component.ts +++ b/apps/picsa-apps/extension-app/src/app/app.component.ts @@ -2,8 +2,8 @@ import { Component } from '@angular/core'; import { Router } from '@angular/router'; import { ENVIRONMENT } from '@picsa/environments'; +import { DeviceSupportService } from '@picsa/shared/modules/device-support'; import { AnalyticsService } from '@picsa/shared/services/core/analytics.service'; -import { CompatibilityService } from '@picsa/shared/services/core/compatibility.service'; import { CrashlyticsService } from '@picsa/shared/services/core/crashlytics.service'; import { PerformanceService } from '@picsa/shared/services/core/performance.service'; @@ -19,7 +19,7 @@ export class AppComponent { analyticsService: AnalyticsService, router: Router, performanceService: PerformanceService, - compatibilityService: CompatibilityService, + deviceSupport: DeviceSupportService, crashlyticsService: CrashlyticsService ) { performanceService.setEnabled({ enabled: ENVIRONMENT.production }); @@ -28,8 +28,9 @@ export class AppComponent { } crashlyticsService.ready().then(() => null); - compatibilityService.checkDeviceCompatibility().then((res) => { - console.log('compatibility', res); + deviceSupport.checkDeviceCompatibility().then(async () => { + await deviceSupport.showDeviceTroubleshooter(); + // TODO - only show main display after troubleshooter closed? }); } } diff --git a/apps/picsa-apps/extension-app/src/app/app.module.ts b/apps/picsa-apps/extension-app/src/app/app.module.ts index 7701bd41e..937e24665 100644 --- a/apps/picsa-apps/extension-app/src/app/app.module.ts +++ b/apps/picsa-apps/extension-app/src/app/app.module.ts @@ -10,6 +10,7 @@ import { PicsaDb_V2_Module, PicsaDbModule, PicsaDeepLinksModule, + PicsaDeviceSupportModule, PicsaNativeModule, PicsaTranslateModule, } from '@picsa/shared/modules'; @@ -35,6 +36,7 @@ import { AppRoutingModule } from './app-routing.module'; baseUrl: 'https://picsa.app', appDynamicLink: 'https://picsa.page.link/dynamic', }), + PicsaDeviceSupportModule.forRoot(), PicsaTranslateModule, PicsaAnimationsModule.forRoot(), PicsaCommonComponentsModule, diff --git a/libs/shared/src/modules/device-support/device-support.models.ts b/libs/shared/src/modules/device-support/device-support.models.ts new file mode 100644 index 000000000..0c8246268 --- /dev/null +++ b/libs/shared/src/modules/device-support/device-support.models.ts @@ -0,0 +1,5 @@ +export interface ICompatibilityWarning { + message: string; + severity: 'warning' | 'error'; + link?: string; +} diff --git a/libs/shared/src/modules/device-support/device-support.service.ts b/libs/shared/src/modules/device-support/device-support.service.ts new file mode 100644 index 000000000..0b426a14f --- /dev/null +++ b/libs/shared/src/modules/device-support/device-support.service.ts @@ -0,0 +1,79 @@ +import { Injectable } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { Device, DeviceInfo } from '@capacitor/device'; + +import { ICompatibilityWarning } from './device-support.models'; +import { DeviceTroubleshooterComponent } from './device-troubleshooter/device-troubleshooter.component'; + +@Injectable({ providedIn: 'root' }) +export class DeviceSupportService { + private compatibilityWarnings: ICompatibilityWarning[] = []; + private deviceInfo: DeviceInfo; + + constructor(private dialog: MatDialog) {} + + /** */ + public async checkDeviceCompatibility() { + this.compatibilityWarnings = []; + this.deviceInfo = await Device.getInfo(); + const { platform } = this.deviceInfo; + const platformChecks = { + android: () => this.runAndroidChecks(), + web: () => this.runWebChecks(), + }; + const platformChecker = platformChecks[platform]; + if (platformChecker) { + platformChecker(); + } else { + throw new Error('Compatibility service not support for platform: ' + platform); + } + return this.compatibilityWarnings; + } + + public async showDeviceTroubleshooter() { + if (this.compatibilityWarnings.length > 0) { + const dialog = this.dialog.open(DeviceTroubleshooterComponent); + } + } + + private runAndroidChecks() { + // get underlying chrome/webkit version + } + private runWebChecks() { + const { webViewVersion, operatingSystem, manufacturer } = this.deviceInfo; + console.log({ webViewVersion, operatingSystem, manufacturer }); + const browserName = this.getBrowserName(); + const browserChecks: { [browserName: string]: () => void } = { + chrome: () => { + const version = Number(webViewVersion.split('.')[0]); + // TODO - confirm what level of compatibility required (link to browserslist?) + if (version < 100) { + this.recordWarning('Your browser version is outdated, please update for an improved experience'); + } + }, + // TODO + firefox: () => null, + safari: () => { + this.recordWarning('It is recommended to use Google Chrome browser for improved experience'); + }, + }; + const browserChecker = browserChecks[browserName]; + if (browserChecker) { + browserChecker(); + } else { + this.recordWarning('It is recommended to use Google Chrome browser for improved experience'); + throw new Error('Compatibility service not support for browser: ' + browserName); + } + } + + private recordWarning(message: string, link?: string) { + this.compatibilityWarnings.push({ severity: 'warning', message, link }); + } + private getBrowserName() { + // TODO - could be more exact with user-agents (?) + const { manufacturer } = this.deviceInfo; + // NOTE - could also be edge... possibly use user agent? + if (manufacturer.includes('Google')) return 'chrome'; + return 'unknown'; + } +} diff --git a/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.html b/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.html new file mode 100644 index 000000000..9b76e77db --- /dev/null +++ b/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.html @@ -0,0 +1 @@ +

device-troubleshooter works!

diff --git a/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.scss b/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.spec.ts b/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.spec.ts new file mode 100644 index 000000000..eac0dfc6d --- /dev/null +++ b/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DeviceTroubleshooterComponent } from './device-troubleshooter.component'; + +describe('DeviceTroubleshooterComponent', () => { + let component: DeviceTroubleshooterComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [DeviceTroubleshooterComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(DeviceTroubleshooterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.ts b/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.ts new file mode 100644 index 000000000..f82fce889 --- /dev/null +++ b/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'picsa-device-troubleshooter', + templateUrl: './device-troubleshooter.component.html', + styleUrls: ['./device-troubleshooter.component.scss'], +}) +export class DeviceTroubleshooterComponent {} diff --git a/libs/shared/src/modules/device-support/index.ts b/libs/shared/src/modules/device-support/index.ts new file mode 100644 index 000000000..8b65b46bc --- /dev/null +++ b/libs/shared/src/modules/device-support/index.ts @@ -0,0 +1,38 @@ +import { ModuleWithProviders, NgModule } from '@angular/core'; + +import { DeviceSupportService } from './device-support.service'; +import { DeviceTroubleshooterComponent } from './device-troubleshooter/device-troubleshooter.component'; + +export { DeviceSupportService }; + +/** + * Support module used to troubleshoot common device issues + * + * The module should be imported `forRoot` in the main app module, e.g. + ``` + NgModule({ + imports: [DeviceSupportModule.forRoot()], + }) + export class AppModule + ``` + * The module should be imported regularly for any lazy-loaded child modules + * + * Checks can be run via the included service + * ```ts + * deviceSupportService.checkDeviceCompatibility().then(()=>{ + * deviceSupportService.showDeviceTroubleshooter() + * }) + * ``` + */ +@NgModule({ + imports: [], + declarations: [DeviceTroubleshooterComponent], +}) +export class PicsaDeviceSupportModule { + static forRoot(): ModuleWithProviders { + return { + ngModule: PicsaDeviceSupportModule, + providers: [DeviceSupportService], + }; + } +} diff --git a/libs/shared/src/modules/index.ts b/libs/shared/src/modules/index.ts index 22269d4f4..d08fa5c4b 100644 --- a/libs/shared/src/modules/index.ts +++ b/libs/shared/src/modules/index.ts @@ -1,6 +1,7 @@ import { PicsaDb_V2_Module } from './database_v2/db.module'; import { PicsaDbModule } from './db.module'; import { PicsaDeepLinksModule } from './deep-links/deep-links.module'; +import { PicsaDeviceSupportModule } from './device-support'; import { PicsaNativeModule } from './native'; import { PicsaTranslateModule, PicsaTranslateService } from './translate'; @@ -8,6 +9,7 @@ export { PicsaDb_V2_Module, PicsaDbModule, PicsaDeepLinksModule, + PicsaDeviceSupportModule, PicsaNativeModule, PicsaTranslateModule, PicsaTranslateService, From f73d836a05ea989f3103d4e1225729559c24e18e Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 26 Jul 2023 12:36:30 -0700 Subject: [PATCH 03/14] chore: code tidying --- .../services/core/error-handler.service.ts | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/libs/shared/src/services/core/error-handler.service.ts b/libs/shared/src/services/core/error-handler.service.ts index a7a0761f6..69155ebe8 100644 --- a/libs/shared/src/services/core/error-handler.service.ts +++ b/libs/shared/src/services/core/error-handler.service.ts @@ -1,16 +1,14 @@ -import { ErrorHandler, Injectable, Injector } from '@angular/core'; +import { ErrorHandler, Injectable } from '@angular/core'; import { Capacitor } from '@capacitor/core'; import { fromError as getStacktraceFromError } from 'stacktrace-js'; -import { CrashlyticsService } from '../native/crashlytics.service'; +import { CrashlyticsService } from './crashlytics.service'; @Injectable({ providedIn: 'root', }) export class ErrorHandlerService extends ErrorHandler { - // Error handling is important and needs to be loaded first. - // Because of this we should manually inject the services with Injector. - constructor(private injector: Injector) { + constructor(private crashlyticsService: CrashlyticsService) { super(); } @@ -19,8 +17,9 @@ export class ErrorHandlerService extends ErrorHandler { * (console logs and modal in dev mode, ignored in production), on android * this logs to firebase crashlytics */ - override handleError(error: Error) { + override async handleError(error: Error) { if (Capacitor.isNativePlatform()) { + await this.crashlyticsService.ready(); return this.logToCrashlytics(error); } else { super.handleError(error); @@ -29,13 +28,10 @@ export class ErrorHandlerService extends ErrorHandler { } private async logToCrashlytics(error: Error) { - const crashlyticsService = this.injector.get(CrashlyticsService); - if (crashlyticsService) { - const stacktrace = await getStacktraceFromError(error); - crashlyticsService.recordException({ - message: error.message, - stacktrace, - }); - } + const stacktrace = await getStacktraceFromError(error); + return this.crashlyticsService.recordException({ + message: error.message, + stacktrace, + }); } } From dc83b3acafb256bfc16e5f6723f2bd1fc07a7877 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Fri, 15 Sep 2023 14:10:09 -0700 Subject: [PATCH 04/14] chore: wip device support components --- .../extension-app/src/app/app.component.html | 2 +- .../extension-app/src/app/app.component.ts | 30 +++++++++++-------- apps/picsa-apps/extension-app/src/index.html | 5 ++++ .../device-support/device-support.models.ts | 8 ++++- .../device-support/device-support.service.ts | 25 ++++++++-------- .../device-troubleshooter.component.html | 4 ++- .../src/modules/device-support/index.ts | 7 ++--- 7 files changed, 50 insertions(+), 31 deletions(-) diff --git a/apps/picsa-apps/extension-app/src/app/app.component.html b/apps/picsa-apps/extension-app/src/app/app.component.html index d5e086097..e7f8eaf1d 100644 --- a/apps/picsa-apps/extension-app/src/app/app.component.html +++ b/apps/picsa-apps/extension-app/src/app/app.component.html @@ -1,4 +1,4 @@ -
+
diff --git a/apps/picsa-apps/extension-app/src/app/app.component.ts b/apps/picsa-apps/extension-app/src/app/app.component.ts index bf21e0d6c..83e5dcc56 100644 --- a/apps/picsa-apps/extension-app/src/app/app.component.ts +++ b/apps/picsa-apps/extension-app/src/app/app.component.ts @@ -15,22 +15,28 @@ import { PerformanceService } from '@picsa/shared/services/core/performance.serv export class AppComponent { title = 'extension-toolkit'; + public showUI = false; + constructor( - analyticsService: AnalyticsService, - router: Router, - performanceService: PerformanceService, - deviceSupport: DeviceSupportService, - crashlyticsService: CrashlyticsService + private analyticsService: AnalyticsService, + private router: Router, + private performanceService: PerformanceService, + private deviceSupport: DeviceSupportService, + private crashlyticsService: CrashlyticsService ) { - performanceService.setEnabled({ enabled: ENVIRONMENT.production }); + this.init(); + } + + private async init() { + this.performanceService.setEnabled({ enabled: ENVIRONMENT.production }); + this.crashlyticsService.ready().then(() => null); + await this.deviceSupport.runDeviceTroubleshooter(); if (ENVIRONMENT.production) { - analyticsService.init(router); + this.analyticsService.init(this.router); } - crashlyticsService.ready().then(() => null); + console.log('showing ui'); + this.showUI = true; - deviceSupport.checkDeviceCompatibility().then(async () => { - await deviceSupport.showDeviceTroubleshooter(); - // TODO - only show main display after troubleshooter closed? - }); + // TODO - only show main display after troubleshooter closed? } } diff --git a/apps/picsa-apps/extension-app/src/index.html b/apps/picsa-apps/extension-app/src/index.html index 692d0bc79..0abe9635e 100644 --- a/apps/picsa-apps/extension-app/src/index.html +++ b/apps/picsa-apps/extension-app/src/index.html @@ -8,6 +8,11 @@ + diff --git a/libs/shared/src/modules/device-support/device-support.models.ts b/libs/shared/src/modules/device-support/device-support.models.ts index 0c8246268..73b25fd4f 100644 --- a/libs/shared/src/modules/device-support/device-support.models.ts +++ b/libs/shared/src/modules/device-support/device-support.models.ts @@ -1,5 +1,11 @@ -export interface ICompatibilityWarning { +export interface IDeviceRecommendation { message: string; severity: 'warning' | 'error'; link?: string; } + +export const TROUBLESHOOTER_CODES = { + browser_unkown: {}, + chrome_outdated: {}, + storage_low: {}, +} as const; diff --git a/libs/shared/src/modules/device-support/device-support.service.ts b/libs/shared/src/modules/device-support/device-support.service.ts index 0b426a14f..860e4a09d 100644 --- a/libs/shared/src/modules/device-support/device-support.service.ts +++ b/libs/shared/src/modules/device-support/device-support.service.ts @@ -2,19 +2,26 @@ import { Injectable } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Device, DeviceInfo } from '@capacitor/device'; -import { ICompatibilityWarning } from './device-support.models'; +import { IDeviceRecommendation } from './device-support.models'; import { DeviceTroubleshooterComponent } from './device-troubleshooter/device-troubleshooter.component'; @Injectable({ providedIn: 'root' }) export class DeviceSupportService { - private compatibilityWarnings: ICompatibilityWarning[] = []; + public recommendations: IDeviceRecommendation[] = []; private deviceInfo: DeviceInfo; constructor(private dialog: MatDialog) {} + public async runDeviceTroubleshooter() { + await this.checkDeviceCompatibility(); + // if (this.recommendations.length > 0) { + const dialog = this.dialog.open(DeviceTroubleshooterComponent); + // } + } + /** */ - public async checkDeviceCompatibility() { - this.compatibilityWarnings = []; + private async checkDeviceCompatibility() { + this.recommendations = []; this.deviceInfo = await Device.getInfo(); const { platform } = this.deviceInfo; const platformChecks = { @@ -27,13 +34,7 @@ export class DeviceSupportService { } else { throw new Error('Compatibility service not support for platform: ' + platform); } - return this.compatibilityWarnings; - } - - public async showDeviceTroubleshooter() { - if (this.compatibilityWarnings.length > 0) { - const dialog = this.dialog.open(DeviceTroubleshooterComponent); - } + return this.recommendations; } private runAndroidChecks() { @@ -67,7 +68,7 @@ export class DeviceSupportService { } private recordWarning(message: string, link?: string) { - this.compatibilityWarnings.push({ severity: 'warning', message, link }); + this.recommendations.push({ severity: 'warning', message, link }); } private getBrowserName() { // TODO - could be more exact with user-agents (?) diff --git a/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.html b/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.html index 9b76e77db..521437f61 100644 --- a/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.html +++ b/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.html @@ -1 +1,3 @@ -

device-troubleshooter works!

+

{{ 'Device Compatibility' | translate }}

+ + diff --git a/libs/shared/src/modules/device-support/index.ts b/libs/shared/src/modules/device-support/index.ts index 8b65b46bc..dcd3bfa22 100644 --- a/libs/shared/src/modules/device-support/index.ts +++ b/libs/shared/src/modules/device-support/index.ts @@ -1,5 +1,6 @@ import { ModuleWithProviders, NgModule } from '@angular/core'; +import { PicsaTranslateModule } from '../translate'; import { DeviceSupportService } from './device-support.service'; import { DeviceTroubleshooterComponent } from './device-troubleshooter/device-troubleshooter.component'; @@ -19,13 +20,11 @@ export { DeviceSupportService }; * * Checks can be run via the included service * ```ts - * deviceSupportService.checkDeviceCompatibility().then(()=>{ - * deviceSupportService.showDeviceTroubleshooter() - * }) + * deviceSupportService.runDeviceTroubleshooter() * ``` */ @NgModule({ - imports: [], + imports: [PicsaTranslateModule], declarations: [DeviceTroubleshooterComponent], }) export class PicsaDeviceSupportModule { From a317732cfd71c940d4e5304deb12c2f7d7d4f5bd Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Fri, 15 Sep 2023 20:43:04 -0700 Subject: [PATCH 05/14] feat: vanilla js compatibility check --- .../extension-app/src/assets/compatibility.js | 165 ++++++++++++++++++ apps/picsa-apps/extension-app/src/index.html | 12 +- 2 files changed, 172 insertions(+), 5 deletions(-) create mode 100644 apps/picsa-apps/extension-app/src/assets/compatibility.js diff --git a/apps/picsa-apps/extension-app/src/assets/compatibility.js b/apps/picsa-apps/extension-app/src/assets/compatibility.js new file mode 100644 index 000000000..6cec53828 --- /dev/null +++ b/apps/picsa-apps/extension-app/src/assets/compatibility.js @@ -0,0 +1,165 @@ +/******************************************************************************** + * Script to ensure user has up-to-date version of google chrome for Android + * Should be included in main `index.html` via script tag, e.g. + * + * + *******************************************************************************/ + +/** Min android version as mapped from `minSdkVersion` (API 23, Android 6.0) */ +const minAndroidVersion = 6.0; + +/** + * Minimum version of chrome required to run app + * Min baseline 45 to support arrow functions: https://caniuse.com/arrow-functions + * Capacitor requirement 60, according to: https://capacitorjs.com/docs/android + * Codebase pdf viewer 92 (https://caniuse.com/mdn-javascript_builtins_string_at) + * Legacy chrome versions available at: https://www.chromium.org/getting-involved/download-chromium/ + * + * NOTE - whilst capacitor does have functionality to detect version and present custom error page, + * using the `capacitor.config.ts` android property `minWebViewVersion`, however this requires capacitor + * to load correctly which often does not happen + */ +const minAndroidWebviewVersion = 93; + +/** + * Check for compatibiliy issues that may arise before main app loads + * This script is designed to be called from main index.html file to detect + * + * Uses web navigator instead of native APIs as Capacitor will fail to initialise + * in some legacy browsers + */ +function checkCompatibility() { + const info = getInfo(); + console.log('[Compatibility check]', info); + if (info.operatingSystem === 'android') { + // Catch case where app may be sideloaded onto a device with sdk lower than `minSdkVersion` (API 23, Android 6.0) + if (info.androidVersion && info.androidVersion < minAndroidVersion) { + alert('This app is not supported on Android 5.\nPlease use a device running Android 6 or higher'); + } + // Check chrome webview version up-to-date + if (info.chromeVersion && info.chromeVersion < minAndroidWebviewVersion) { + // Webview version is controlled by different apps depending on android version + // For android 7-9 this is the controlled by the preinstalled Google Chrome app + // For android 6 and 10+ this is controlled by the standalone Android Webview app + // https://chromium.googlesource.com/chromium/src/+/HEAD/android_webview/docs/faq.md#what_s-the-relationship-between-webview-and-chrome + // https://techblogs.42gears.com/webkit-provider-changes-in-various-android-versions/ + + if (7 <= info.androidVersion <= 9) { + renderUpdatePrompt('Google Chrome', 'https://play.google.com/store/apps/details?id=com.android.chrome'); + } else { + renderUpdatePrompt( + 'Android Webview', + 'https://play.google.com/store/apps/details?id=com.google.android.webview' + ); + } + } + } +} +checkCompatibility(); + +/** + * Attempt to get core device info by parsing the navigator user object + * Adapted from Capacitor Device api methods to support case where Capacitor itself + * fails to correctly initialise (e.g. some legacy browsers) + * https://github.com/ionic-team/capacitor-plugins/blob/main/device/src/web.ts + * @returns + */ +function getInfo() { + const uaFields = {}; + const ua = navigator.userAgent; + const start = ua.indexOf('(') + 1; + const end = ua.indexOf(') AppleWebKit'); + const fields = ua.substring(start, end); + if (ua.indexOf('Android') !== -1) { + const tmpFields = fields.replace('; wv', '').split('; ').pop(); + if (tmpFields) { + uaFields.model = tmpFields.split(' Build')[0]; + } + uaFields.osVersion = fields.split('; ')[1]; + } + if (/android/i.test(ua)) { + uaFields.operatingSystem = 'android'; + } + // Additional fields that would normally be determined using native code (adapted for web) + if (uaFields.operatingSystem === 'android') { + uaFields.androidVersion = parseFloat(uaFields.osVersion.toLowerCase().replace('android', '')); + uaFields.chromeVersion = getChromeVersion(); + } + return uaFields; +} + +function getChromeVersion() { + const ua = navigator.userAgent.toLowerCase(); + const regex = /chrome\/([0-9]*)\./; + const res = regex.exec(ua); + if (res) { + const chromeVersion = parseInt(res[1]); + return chromeVersion; + } +} + +/** Create a custom popup element that blocks the screen to force user to update before continuing */ +function renderUpdatePrompt(appName, appLink) { + const backdropEl = document.createElement('div'); + /** + * @types {CSSStyleDeclaration} + */ + const styles = ` + position:absolute; + height:100vh; + width:100vw; + z-index:2; + background:#000c; + display:flex; + flex-direction:column; + align-items:center; + justify-content:center + `; + backdropEl.style.cssText = styles; + + const contentEl = document.createElement('div'); + contentEl.style.cssText = ` + width:300px; + background:#e9e9e9; + padding: 16px; + border-radius: 8px; + `; + + const buttonEl = document.createElement('button'); + buttonEl.textContent = 'Go To Play Store'; + buttonEl.style.cssText = ` + width: 100%; + height: 48px; + margin: 16px 0; + font-size: 16px; + padding: 8px; + background: #01875f; + color: white; + border-radius: 8px; + font-weight: bold; + border: none; + cursor: pointer; + `; + const linkEl = document.createElement('a'); + + linkEl.href = appLink; + linkEl.target = '_blank'; + linkEl.appendChild(buttonEl); + + contentEl.innerHTML = ` +

Update Required

+

Please update the ${appName} app from the play store and restart the app

+ `.trim(); + + contentEl.appendChild(linkEl); + + backdropEl.appendChild(contentEl); + const bodyEl = document.querySelector('body'); + bodyEl.appendChild(backdropEl); +} diff --git a/apps/picsa-apps/extension-app/src/index.html b/apps/picsa-apps/extension-app/src/index.html index 0abe9635e..904d5cf21 100644 --- a/apps/picsa-apps/extension-app/src/index.html +++ b/apps/picsa-apps/extension-app/src/index.html @@ -8,11 +8,13 @@ - + From bb8fe9e6185c21311aee4e823efc8bdeec1c3f9e Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Fri, 15 Sep 2023 20:45:35 -0700 Subject: [PATCH 06/14] chore: revert device support service changes --- .../device-support/device-support.models.ts | 11 --- .../device-support/device-support.service.ts | 80 ------------------- .../device-troubleshooter.component.html | 3 - .../device-troubleshooter.component.scss | 0 .../device-troubleshooter.component.spec.ts | 22 ----- .../device-troubleshooter.component.ts | 8 -- .../src/modules/device-support/index.ts | 37 --------- 7 files changed, 161 deletions(-) delete mode 100644 libs/shared/src/modules/device-support/device-support.models.ts delete mode 100644 libs/shared/src/modules/device-support/device-support.service.ts delete mode 100644 libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.html delete mode 100644 libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.scss delete mode 100644 libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.spec.ts delete mode 100644 libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.ts delete mode 100644 libs/shared/src/modules/device-support/index.ts diff --git a/libs/shared/src/modules/device-support/device-support.models.ts b/libs/shared/src/modules/device-support/device-support.models.ts deleted file mode 100644 index 73b25fd4f..000000000 --- a/libs/shared/src/modules/device-support/device-support.models.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface IDeviceRecommendation { - message: string; - severity: 'warning' | 'error'; - link?: string; -} - -export const TROUBLESHOOTER_CODES = { - browser_unkown: {}, - chrome_outdated: {}, - storage_low: {}, -} as const; diff --git a/libs/shared/src/modules/device-support/device-support.service.ts b/libs/shared/src/modules/device-support/device-support.service.ts deleted file mode 100644 index 860e4a09d..000000000 --- a/libs/shared/src/modules/device-support/device-support.service.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { Injectable } from '@angular/core'; -import { MatDialog } from '@angular/material/dialog'; -import { Device, DeviceInfo } from '@capacitor/device'; - -import { IDeviceRecommendation } from './device-support.models'; -import { DeviceTroubleshooterComponent } from './device-troubleshooter/device-troubleshooter.component'; - -@Injectable({ providedIn: 'root' }) -export class DeviceSupportService { - public recommendations: IDeviceRecommendation[] = []; - private deviceInfo: DeviceInfo; - - constructor(private dialog: MatDialog) {} - - public async runDeviceTroubleshooter() { - await this.checkDeviceCompatibility(); - // if (this.recommendations.length > 0) { - const dialog = this.dialog.open(DeviceTroubleshooterComponent); - // } - } - - /** */ - private async checkDeviceCompatibility() { - this.recommendations = []; - this.deviceInfo = await Device.getInfo(); - const { platform } = this.deviceInfo; - const platformChecks = { - android: () => this.runAndroidChecks(), - web: () => this.runWebChecks(), - }; - const platformChecker = platformChecks[platform]; - if (platformChecker) { - platformChecker(); - } else { - throw new Error('Compatibility service not support for platform: ' + platform); - } - return this.recommendations; - } - - private runAndroidChecks() { - // get underlying chrome/webkit version - } - private runWebChecks() { - const { webViewVersion, operatingSystem, manufacturer } = this.deviceInfo; - console.log({ webViewVersion, operatingSystem, manufacturer }); - const browserName = this.getBrowserName(); - const browserChecks: { [browserName: string]: () => void } = { - chrome: () => { - const version = Number(webViewVersion.split('.')[0]); - // TODO - confirm what level of compatibility required (link to browserslist?) - if (version < 100) { - this.recordWarning('Your browser version is outdated, please update for an improved experience'); - } - }, - // TODO - firefox: () => null, - safari: () => { - this.recordWarning('It is recommended to use Google Chrome browser for improved experience'); - }, - }; - const browserChecker = browserChecks[browserName]; - if (browserChecker) { - browserChecker(); - } else { - this.recordWarning('It is recommended to use Google Chrome browser for improved experience'); - throw new Error('Compatibility service not support for browser: ' + browserName); - } - } - - private recordWarning(message: string, link?: string) { - this.recommendations.push({ severity: 'warning', message, link }); - } - private getBrowserName() { - // TODO - could be more exact with user-agents (?) - const { manufacturer } = this.deviceInfo; - // NOTE - could also be edge... possibly use user agent? - if (manufacturer.includes('Google')) return 'chrome'; - return 'unknown'; - } -} diff --git a/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.html b/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.html deleted file mode 100644 index 521437f61..000000000 --- a/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.html +++ /dev/null @@ -1,3 +0,0 @@ -

{{ 'Device Compatibility' | translate }}

- - diff --git a/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.scss b/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.spec.ts b/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.spec.ts deleted file mode 100644 index eac0dfc6d..000000000 --- a/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { DeviceTroubleshooterComponent } from './device-troubleshooter.component'; - -describe('DeviceTroubleshooterComponent', () => { - let component: DeviceTroubleshooterComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [DeviceTroubleshooterComponent], - }).compileComponents(); - - fixture = TestBed.createComponent(DeviceTroubleshooterComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.ts b/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.ts deleted file mode 100644 index f82fce889..000000000 --- a/libs/shared/src/modules/device-support/device-troubleshooter/device-troubleshooter.component.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'picsa-device-troubleshooter', - templateUrl: './device-troubleshooter.component.html', - styleUrls: ['./device-troubleshooter.component.scss'], -}) -export class DeviceTroubleshooterComponent {} diff --git a/libs/shared/src/modules/device-support/index.ts b/libs/shared/src/modules/device-support/index.ts deleted file mode 100644 index dcd3bfa22..000000000 --- a/libs/shared/src/modules/device-support/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ModuleWithProviders, NgModule } from '@angular/core'; - -import { PicsaTranslateModule } from '../translate'; -import { DeviceSupportService } from './device-support.service'; -import { DeviceTroubleshooterComponent } from './device-troubleshooter/device-troubleshooter.component'; - -export { DeviceSupportService }; - -/** - * Support module used to troubleshoot common device issues - * - * The module should be imported `forRoot` in the main app module, e.g. - ``` - NgModule({ - imports: [DeviceSupportModule.forRoot()], - }) - export class AppModule - ``` - * The module should be imported regularly for any lazy-loaded child modules - * - * Checks can be run via the included service - * ```ts - * deviceSupportService.runDeviceTroubleshooter() - * ``` - */ -@NgModule({ - imports: [PicsaTranslateModule], - declarations: [DeviceTroubleshooterComponent], -}) -export class PicsaDeviceSupportModule { - static forRoot(): ModuleWithProviders { - return { - ngModule: PicsaDeviceSupportModule, - providers: [DeviceSupportService], - }; - } -} From af72321e07490ece0d1d6658802f8075273e5832 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Fri, 15 Sep 2023 20:46:20 -0700 Subject: [PATCH 07/14] chore: code tidying --- apps/picsa-apps/extension-app/src/app/app.component.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/picsa-apps/extension-app/src/app/app.component.ts b/apps/picsa-apps/extension-app/src/app/app.component.ts index 83e5dcc56..7bd5404dd 100644 --- a/apps/picsa-apps/extension-app/src/app/app.component.ts +++ b/apps/picsa-apps/extension-app/src/app/app.component.ts @@ -2,7 +2,6 @@ import { Component } from '@angular/core'; import { Router } from '@angular/router'; import { ENVIRONMENT } from '@picsa/environments'; -import { DeviceSupportService } from '@picsa/shared/modules/device-support'; import { AnalyticsService } from '@picsa/shared/services/core/analytics.service'; import { CrashlyticsService } from '@picsa/shared/services/core/crashlytics.service'; import { PerformanceService } from '@picsa/shared/services/core/performance.service'; @@ -21,7 +20,6 @@ export class AppComponent { private analyticsService: AnalyticsService, private router: Router, private performanceService: PerformanceService, - private deviceSupport: DeviceSupportService, private crashlyticsService: CrashlyticsService ) { this.init(); @@ -30,7 +28,6 @@ export class AppComponent { private async init() { this.performanceService.setEnabled({ enabled: ENVIRONMENT.production }); this.crashlyticsService.ready().then(() => null); - await this.deviceSupport.runDeviceTroubleshooter(); if (ENVIRONMENT.production) { this.analyticsService.init(this.router); } From 486ed6957e18e6483e3828c24ac1e8c8a94bdedc Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Fri, 15 Sep 2023 20:55:18 -0700 Subject: [PATCH 08/14] chore: code tidying --- libs/shared/src/modules/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/shared/src/modules/index.ts b/libs/shared/src/modules/index.ts index d08fa5c4b..c1ab2f366 100644 --- a/libs/shared/src/modules/index.ts +++ b/libs/shared/src/modules/index.ts @@ -1,7 +1,6 @@ import { PicsaDb_V2_Module } from './database_v2/db.module'; import { PicsaDbModule } from './db.module'; import { PicsaDeepLinksModule } from './deep-links/deep-links.module'; -import { PicsaDeviceSupportModule } from './device-support'; import { PicsaNativeModule } from './native'; import { PicsaTranslateModule, PicsaTranslateService } from './translate'; From 2ea8bc1ed627da08c538de69b9fb1ea164c82ea2 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Fri, 15 Sep 2023 20:55:46 -0700 Subject: [PATCH 09/14] chore: code tidying --- libs/shared/src/modules/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/shared/src/modules/index.ts b/libs/shared/src/modules/index.ts index c1ab2f366..22269d4f4 100644 --- a/libs/shared/src/modules/index.ts +++ b/libs/shared/src/modules/index.ts @@ -8,7 +8,6 @@ export { PicsaDb_V2_Module, PicsaDbModule, PicsaDeepLinksModule, - PicsaDeviceSupportModule, PicsaNativeModule, PicsaTranslateModule, PicsaTranslateService, From 1460d66ffa29199af7a82dd86cce3744ab02756b Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Fri, 15 Sep 2023 20:56:18 -0700 Subject: [PATCH 10/14] chore: code tidying --- apps/picsa-apps/extension-app/src/app/app.module.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/picsa-apps/extension-app/src/app/app.module.ts b/apps/picsa-apps/extension-app/src/app/app.module.ts index 937e24665..7701bd41e 100644 --- a/apps/picsa-apps/extension-app/src/app/app.module.ts +++ b/apps/picsa-apps/extension-app/src/app/app.module.ts @@ -10,7 +10,6 @@ import { PicsaDb_V2_Module, PicsaDbModule, PicsaDeepLinksModule, - PicsaDeviceSupportModule, PicsaNativeModule, PicsaTranslateModule, } from '@picsa/shared/modules'; @@ -36,7 +35,6 @@ import { AppRoutingModule } from './app-routing.module'; baseUrl: 'https://picsa.app', appDynamicLink: 'https://picsa.page.link/dynamic', }), - PicsaDeviceSupportModule.forRoot(), PicsaTranslateModule, PicsaAnimationsModule.forRoot(), PicsaCommonComponentsModule, From e6407fe3b81e0570941789c4138f5116a466044a Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Fri, 15 Sep 2023 21:04:16 -0700 Subject: [PATCH 11/14] feat: compatibility script updates --- apps/picsa-apps/extension-app/src/assets/compatibility.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/picsa-apps/extension-app/src/assets/compatibility.js b/apps/picsa-apps/extension-app/src/assets/compatibility.js index 6cec53828..d51eca02e 100644 --- a/apps/picsa-apps/extension-app/src/assets/compatibility.js +++ b/apps/picsa-apps/extension-app/src/assets/compatibility.js @@ -36,7 +36,6 @@ const minAndroidWebviewVersion = 93; */ function checkCompatibility() { const info = getInfo(); - console.log('[Compatibility check]', info); if (info.operatingSystem === 'android') { // Catch case where app may be sideloaded onto a device with sdk lower than `minSdkVersion` (API 23, Android 6.0) if (info.androidVersion && info.androidVersion < minAndroidVersion) { @@ -44,13 +43,15 @@ function checkCompatibility() { } // Check chrome webview version up-to-date if (info.chromeVersion && info.chromeVersion < minAndroidWebviewVersion) { + console.log('[Compatibility check]'); + console.log(JSON.stringify(info, null, 2)); // Webview version is controlled by different apps depending on android version // For android 7-9 this is the controlled by the preinstalled Google Chrome app // For android 6 and 10+ this is controlled by the standalone Android Webview app // https://chromium.googlesource.com/chromium/src/+/HEAD/android_webview/docs/faq.md#what_s-the-relationship-between-webview-and-chrome // https://techblogs.42gears.com/webkit-provider-changes-in-various-android-versions/ - if (7 <= info.androidVersion <= 9) { + if (info.androidVersion >= 7 && info.androidVersion <= 10) { renderUpdatePrompt('Google Chrome', 'https://play.google.com/store/apps/details?id=com.android.chrome'); } else { renderUpdatePrompt( From b6c360becc9d8e9f245dc2fff865d3505a8082cd Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Fri, 15 Sep 2023 21:07:27 -0700 Subject: [PATCH 12/14] chore: revert ui changes --- apps/picsa-apps/extension-app/src/app/app.component.html | 2 +- apps/picsa-apps/extension-app/src/app/app.component.ts | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/apps/picsa-apps/extension-app/src/app/app.component.html b/apps/picsa-apps/extension-app/src/app/app.component.html index e7f8eaf1d..d5e086097 100644 --- a/apps/picsa-apps/extension-app/src/app/app.component.html +++ b/apps/picsa-apps/extension-app/src/app/app.component.html @@ -1,4 +1,4 @@ -
+
diff --git a/apps/picsa-apps/extension-app/src/app/app.component.ts b/apps/picsa-apps/extension-app/src/app/app.component.ts index 7bd5404dd..5055b5bc7 100644 --- a/apps/picsa-apps/extension-app/src/app/app.component.ts +++ b/apps/picsa-apps/extension-app/src/app/app.component.ts @@ -14,8 +14,6 @@ import { PerformanceService } from '@picsa/shared/services/core/performance.serv export class AppComponent { title = 'extension-toolkit'; - public showUI = false; - constructor( private analyticsService: AnalyticsService, private router: Router, @@ -31,9 +29,5 @@ export class AppComponent { if (ENVIRONMENT.production) { this.analyticsService.init(this.router); } - console.log('showing ui'); - this.showUI = true; - - // TODO - only show main display after troubleshooter closed? } } From 369463739f5da8a34a11bfefeec7a902c498cd83 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Sat, 16 Sep 2023 09:05:09 -0700 Subject: [PATCH 13/14] feat: compatibility check dismiss --- .../extension-app/src/assets/compatibility.js | 43 ++++++++++++++----- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/apps/picsa-apps/extension-app/src/assets/compatibility.js b/apps/picsa-apps/extension-app/src/assets/compatibility.js index d51eca02e..181b0a58b 100644 --- a/apps/picsa-apps/extension-app/src/assets/compatibility.js +++ b/apps/picsa-apps/extension-app/src/assets/compatibility.js @@ -51,7 +51,7 @@ function checkCompatibility() { // https://chromium.googlesource.com/chromium/src/+/HEAD/android_webview/docs/faq.md#what_s-the-relationship-between-webview-and-chrome // https://techblogs.42gears.com/webkit-provider-changes-in-various-android-versions/ - if (info.androidVersion >= 7 && info.androidVersion <= 10) { + if (info.androidVersion >= 7 && info.androidVersion <= 9) { renderUpdatePrompt('Google Chrome', 'https://play.google.com/store/apps/details?id=com.android.chrome'); } else { renderUpdatePrompt( @@ -108,11 +108,11 @@ function getChromeVersion() { /** Create a custom popup element that blocks the screen to force user to update before continuing */ function renderUpdatePrompt(appName, appLink) { const backdropEl = document.createElement('div'); - /** - * @types {CSSStyleDeclaration} - */ + backdropEl.id = 'updatePrompt'; const styles = ` position:absolute; + top:0; + left:0; height:100vh; width:100vw; z-index:2; @@ -124,6 +124,7 @@ function renderUpdatePrompt(appName, appLink) { `; backdropEl.style.cssText = styles; + // Main content container const contentEl = document.createElement('div'); contentEl.style.cssText = ` width:300px; @@ -132,6 +133,26 @@ function renderUpdatePrompt(appName, appLink) { border-radius: 8px; `; + // Close button + const closeButtonEl = document.createElement('button'); + closeButtonEl.style.cssText = ` + float:right; + `; + closeButtonEl.textContent = 'X'; + closeButtonEl.onclick = closePrompt; + contentEl.appendChild(closeButtonEl); + + // Heading + const headingEl = document.createElement('h2'); + (headingEl.textContent = 'Update Required'), (headingEl.style.cssText = `text-align:center`); + contentEl.appendChild(headingEl); + + // Text + const textEl = document.createElement('p'); + textEl.innerHTML = `Please update the ${appName} app from the play store and restart the app`; + contentEl.appendChild(textEl); + + // Action button const buttonEl = document.createElement('button'); buttonEl.textContent = 'Go To Play Store'; buttonEl.style.cssText = ` @@ -147,20 +168,20 @@ function renderUpdatePrompt(appName, appLink) { border: none; cursor: pointer; `; - const linkEl = document.createElement('a'); + // Action button link + const linkEl = document.createElement('a'); linkEl.href = appLink; linkEl.target = '_blank'; linkEl.appendChild(buttonEl); - - contentEl.innerHTML = ` -

Update Required

-

Please update the ${appName} app from the play store and restart the app

- `.trim(); - contentEl.appendChild(linkEl); + // Append to main content backdropEl.appendChild(contentEl); const bodyEl = document.querySelector('body'); bodyEl.appendChild(backdropEl); } + +function closePrompt() { + document.getElementById('updatePrompt').remove(); +} From 05d7a3417a8c60dc19cd1937334f8b08302d13d9 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Sat, 16 Sep 2023 09:35:35 -0700 Subject: [PATCH 14/14] chore: android 5 compat tests --- apps/picsa-apps/extension-app/src/assets/compatibility.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/picsa-apps/extension-app/src/assets/compatibility.js b/apps/picsa-apps/extension-app/src/assets/compatibility.js index 181b0a58b..01a7d72c6 100644 --- a/apps/picsa-apps/extension-app/src/assets/compatibility.js +++ b/apps/picsa-apps/extension-app/src/assets/compatibility.js @@ -38,8 +38,10 @@ function checkCompatibility() { const info = getInfo(); if (info.operatingSystem === 'android') { // Catch case where app may be sideloaded onto a device with sdk lower than `minSdkVersion` (API 23, Android 6.0) + // Additionally the render prompt update will fail due to use of template literals if (info.androidVersion && info.androidVersion < minAndroidVersion) { alert('This app is not supported on Android 5.\nPlease use a device running Android 6 or higher'); + return; } // Check chrome webview version up-to-date if (info.chromeVersion && info.chromeVersion < minAndroidWebviewVersion) { @@ -62,6 +64,7 @@ function checkCompatibility() { } } } + checkCompatibility(); /**