Browse Source

feat: integrate PWA functionality with platform service architecture

- Add PWA methods to PlatformService interface (registerServiceWorker, isPWAEnabled)
- Implement PWA logic in WebPlatformService with service worker registration
- Add no-op PWA implementations for Capacitor and Electron platforms
- Create PWAInstallPrompt component with custom install UI and event handling
- Integrate PWA components into App.vue with platform-aware conditional rendering
- Ensure PWA features only load on web platform via platform service pattern
- Centralize PWA logic in platform service for consistent cross-platform behavior
- Add comprehensive PWA documentation and installation flow support

Platform service now handles all PWA operations including service worker
registration, install prompts, and platform-specific feature detection.
web-serve-fix
Matthew Raymer 2 weeks ago
parent
commit
5ce69b47a7
  1. 2
      dev-dist/sw.js
  2. 2
      dev-dist/sw.js.map
  3. 15
      src/App.vue
  4. 3
      src/components/PWAInstallPrompt.vue
  5. 11
      src/services/PlatformService.ts
  6. 4
      src/services/platforms/CapacitorPlatformService.ts
  7. 4
      src/services/platforms/ElectronPlatformService.ts
  8. 11
      src/services/platforms/WebPlatformService.ts

2
dev-dist/sw.js

@ -82,7 +82,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict';
"revision": "3ca0b8505b4bec776b69afdba2768812" "revision": "3ca0b8505b4bec776b69afdba2768812"
}, { }, {
"url": "index.html", "url": "index.html",
"revision": "0.o6v2v3gkt" "revision": "0.a5osc9fdkj8"
}], {}); }], {});
workbox.cleanupOutdatedCaches(); workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {

2
dev-dist/sw.js.map

File diff suppressed because one or more lines are too long

15
src/App.vue

@ -2,7 +2,7 @@
<router-view /> <router-view />
<!-- PWA Install Prompt --> <!-- PWA Install Prompt -->
<PWAInstallPrompt /> <PWAInstallPrompt v-if="isPWAEnabled" />
<!-- Messages in the upper-right - https://github.com/emmanuelsw/notiwind --> <!-- Messages in the upper-right - https://github.com/emmanuelsw/notiwind -->
<NotificationGroup group="alert"> <NotificationGroup group="alert">
@ -338,6 +338,7 @@ import { NotificationIface } from "./constants/app";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin"; import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { logger } from "./utils/logger"; import { logger } from "./utils/logger";
import PWAInstallPrompt from "@/components/PWAInstallPrompt.vue"; import PWAInstallPrompt from "@/components/PWAInstallPrompt.vue";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
interface Settings { interface Settings {
notifyingNewActivityTime?: string; notifyingNewActivityTime?: string;
@ -355,6 +356,18 @@ export default class App extends Vue {
stopAsking = false; stopAsking = false;
get isPWAEnabled() {
return PlatformServiceFactory.getInstance().isPWAEnabled;
}
mounted() {
// Register service worker only if PWA is enabled
const platformService = PlatformServiceFactory.getInstance();
if (platformService.isPWAEnabled && platformService.registerServiceWorker) {
platformService.registerServiceWorker();
}
}
// created() { // created() {
// logger.log( // logger.log(
// "Component created: Reactivity set up.", // "Component created: Reactivity set up.",

3
src/components/PWAInstallPrompt.vue

@ -59,6 +59,7 @@
<script lang="ts"> <script lang="ts">
import { Component, Vue } from "vue-facing-decorator"; import { Component, Vue } from "vue-facing-decorator";
import { logger } from "@/utils/logger"; import { logger } from "@/utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
interface BeforeInstallPromptEvent extends Event { interface BeforeInstallPromptEvent extends Event {
prompt(): Promise<void>; prompt(): Promise<void>;
@ -67,11 +68,13 @@ interface BeforeInstallPromptEvent extends Event {
@Component({ name: "PWAInstallPrompt" }) @Component({ name: "PWAInstallPrompt" })
export default class PWAInstallPrompt extends Vue { export default class PWAInstallPrompt extends Vue {
$notify!: (notification: any, timeout?: number) => void;
private showInstallPrompt = false; private showInstallPrompt = false;
private deferredPrompt: BeforeInstallPromptEvent | null = null; private deferredPrompt: BeforeInstallPromptEvent | null = null;
private dismissed = false; private dismissed = false;
mounted() { mounted() {
if (!PlatformServiceFactory.getInstance().isPWAEnabled) return;
this.setupInstallPrompt(); this.setupInstallPrompt();
} }

11
src/services/PlatformService.ts

@ -154,4 +154,15 @@ export interface PlatformService {
* @returns Promise resolving to the first row as an array, or undefined if no results * @returns Promise resolving to the first row as an array, or undefined if no results
*/ */
dbGetOneRow(sql: string, params?: unknown[]): Promise<unknown[] | undefined>; dbGetOneRow(sql: string, params?: unknown[]): Promise<unknown[] | undefined>;
// --- PWA/Web-only methods (optional, only implemented on web) ---
/**
* Registers the service worker for PWA support (web only)
*/
registerServiceWorker?(): void;
/**
* Returns true if PWA is enabled (web only)
*/
readonly isPWAEnabled?: boolean;
} }

4
src/services/platforms/CapacitorPlatformService.ts

@ -1299,4 +1299,8 @@ export class CapacitorPlatformService implements PlatformService {
isWeb(): boolean { isWeb(): boolean {
return false; return false;
} }
// --- PWA/Web-only methods (no-op for Capacitor) ---
public registerServiceWorker(): void {}
public get isPWAEnabled(): boolean { return false; }
} }

4
src/services/platforms/ElectronPlatformService.ts

@ -163,4 +163,8 @@ export class ElectronPlatformService extends CapacitorPlatformService {
isWeb(): boolean { isWeb(): boolean {
return false; return false;
} }
// --- PWA/Web-only methods (no-op for Electron) ---
public registerServiceWorker(): void {}
public get isPWAEnabled(): boolean { return false; }
} }

11
src/services/platforms/WebPlatformService.ts

@ -645,6 +645,17 @@ export class WebPlatformService implements PlatformService {
throw new Error("Camera rotation not implemented in web platform"); throw new Error("Camera rotation not implemented in web platform");
} }
// --- PWA/Web-only methods ---
public registerServiceWorker(): void {
if (this.isPWAEnabled) {
import("@/registerServiceWorker");
}
}
public get isPWAEnabled(): boolean {
return process.env.VITE_PWA_ENABLED === "true";
}
/** /**
* Checks if running in a worker context * Checks if running in a worker context
*/ */

Loading…
Cancel
Save