performance-optimizations-testing #159

Open
anomalist wants to merge 132 commits from performance-optimizations-testing into build-improvement
5 changed files with 194 additions and 25 deletions
Showing only changes of commit 6007bc34e4 - Show all commits

View File

@@ -846,6 +846,12 @@ export const NOTIFY_CONTACTS_ADDED = {
message: "They were added.",
};
// Used in: ContactsView.vue (addContact method - export data prompt after contact addition)
export const NOTIFY_EXPORT_DATA_PROMPT = {
title: "Export Your Data",
message: "Would you like to export your contact data as a backup?",
};
// Used in: ContactsView.vue (showCopySelectionsInfo method - info about copying contacts)
export const NOTIFY_CONTACT_INFO_COPY = {
title: "Info",

View File

@@ -0,0 +1,99 @@
import { PlatformServiceFactory } from "./PlatformServiceFactory";
import { PlatformService } from "./PlatformService";
import { logger } from "@/utils/logger";
/**
* QR Navigation Service
*
* Handles platform-specific routing logic for QR scanning operations.
* Removes coupling between views and routing logic by centralizing
* navigation decisions based on platform capabilities.
*
* @author Matthew Raymer
*/
export class QRNavigationService {
private static instance: QRNavigationService | null = null;
private platformService: PlatformService;
private constructor() {
this.platformService = PlatformServiceFactory.getInstance();
}
/**
* Get singleton instance of QRNavigationService
*/
public static getInstance(): QRNavigationService {
if (!QRNavigationService.instance) {
QRNavigationService.instance = new QRNavigationService();
}
return QRNavigationService.instance;
}
/**
* Get the appropriate QR scanner route based on platform
*
* @returns Object with route name and parameters for QR scanning
*/
public getQRScannerRoute(): {
name: string;
params?: Record<string, string | number>;
} {
const isCapacitor = this.platformService.isCapacitor();
logger.debug("QR Navigation - Platform detection:", {
isCapacitor,
platform: this.platformService.getCapabilities(),
});
if (isCapacitor) {
// Use native scanner on mobile platforms
return { name: "contact-qr-scan-full" };
} else {
// Use web scanner on other platforms
return { name: "contact-qr" };
}
}
/**
* Get the appropriate QR display route based on platform
*
* @returns Object with route name and parameters for QR display
*/
public getQRDisplayRoute(): {
name: string;
params?: Record<string, string | number>;
} {
const isCapacitor = this.platformService.isCapacitor();
logger.debug("QR Navigation - Display route detection:", {
isCapacitor,
platform: this.platformService.getCapabilities(),
});
if (isCapacitor) {
// Use dedicated display view on mobile
return { name: "contact-qr-scan-show" };
} else {
// Use combined view on web
return { name: "contact-qr" };
}
}
/**
* Check if native QR scanning is available on current platform
*
* @returns true if native scanning is available, false otherwise
*/
public isNativeScanningAvailable(): boolean {
return this.platformService.isCapacitor();
}
/**
* Get platform capabilities for QR operations
*
* @returns Platform capabilities object
*/
public getPlatformCapabilities() {
return this.platformService.getCapabilities();
}
}

View File

@@ -127,7 +127,7 @@ import * as R from "ramda";
import { Component, Vue } from "vue-facing-decorator";
import { RouteLocationNormalizedLoaded, Router } from "vue-router";
import { useClipboard } from "@vueuse/core";
import { Capacitor } from "@capacitor/core";
// Capacitor import removed - using PlatformService instead
import QuickNav from "../components/QuickNav.vue";
import EntityIcon from "../components/EntityIcon.vue";
@@ -161,13 +161,17 @@ import { GiveSummaryRecord } from "@/interfaces/records";
import { UserInfo } from "@/interfaces/common";
import { VerifiableCredential } from "@/interfaces/claims-result";
import * as libsUtil from "../libs/util";
import { generateSaveAndActivateIdentity } from "../libs/util";
import {
generateSaveAndActivateIdentity,
contactsToExportJson,
} from "../libs/util";
import { logger } from "../utils/logger";
// No longer needed - using PlatformServiceMixin methods
// import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
import { APP_SERVER } from "@/constants/app";
import { QRNavigationService } from "@/services/QRNavigationService";
import {
NOTIFY_CONTACT_NO_INFO,
NOTIFY_CONTACTS_ADD_ERROR,
@@ -193,6 +197,7 @@ import {
NOTIFY_REGISTRATION_ERROR_FALLBACK,
NOTIFY_REGISTRATION_ERROR_GENERIC,
NOTIFY_VISIBILITY_ERROR_FALLBACK,
NOTIFY_EXPORT_DATA_PROMPT,
getRegisterPersonSuccessMessage,
getVisibilitySuccessMessage,
getGivesRetrievalErrorMessage,
@@ -780,6 +785,9 @@ export default class ContactsView extends Vue {
// Show success notification
this.notify.success(addedMessage);
// Show export data prompt after successful contact addition
await this.showExportDataPrompt();
} catch (err) {
this.handleContactAddError(err);
}
@@ -1243,19 +1251,75 @@ export default class ContactsView extends Vue {
/**
* Handle QR code button click - route to appropriate scanner
* Uses native scanner on mobile platforms, web scanner otherwise
* Uses QRNavigationService to determine scanner type and route
*/
public handleQRCodeClick() {
this.$logAndConsole(
"[ContactsView] handleQRCodeClick method called",
false,
);
if (Capacitor.isNativePlatform()) {
this.$router.push({ name: "contact-qr-scan-full" });
} else {
this.$router.push({ name: "contact-qr" });
const qrNavigationService = QRNavigationService.getInstance();
const route = qrNavigationService.getQRScannerRoute();
this.$router.push(route);
}
/**
* Show export data prompt after adding a contact
* Prompts user to export their contact data as a backup
*/
private async showExportDataPrompt(): Promise<void> {
setTimeout(() => {
this.$notify(
{
group: "modal",
type: "confirm",
title: NOTIFY_EXPORT_DATA_PROMPT.title,
text: NOTIFY_EXPORT_DATA_PROMPT.message,
onYes: async () => {
await this.exportContactData();
},
yesText: "Export Data",
onNo: async () => {
// User chose not to export - no action needed
},
noText: "Not Now",
},
-1,
);
}, 1000); // Small delay to ensure success notification is shown first
}
/**
* Export contact data to JSON file
* Uses platform service to handle platform-specific export logic
*/
private async exportContactData(): Promise<void> {
try {
// Fetch all contacts from database
const allContacts = await this.$contacts();
// Convert contacts to export format
const exportData = contactsToExportJson(allContacts);
const jsonStr = JSON.stringify(exportData, null, 2);
// Generate filename with current date
const today = new Date();
const dateString = today.toISOString().split("T")[0]; // YYYY-MM-DD format
const fileName = `timesafari-backup-contacts-${dateString}.json`;
// Use platform service to handle export
await this.platformService.writeAndShareFile(fileName, jsonStr);
this.notify.success(
"Contact export completed successfully. Check your downloads or share dialog.",
);
} catch (error) {
logger.error("Export Error:", error);
this.notify.error(
`There was an error exporting the data: ${error instanceof Error ? error.message : "Unknown error"}`,
);
}
}
}

View File

@@ -565,22 +565,22 @@
<h2 class="text-xl font-semibold">What app version is this?</h2>
<p>{{ package.version }} ({{ commitHash }})</p>
<div v-if="Capacitor.isNativePlatform()">
<div v-if="isCapacitor">
<h2 class="text-xl font-semibold">
Do I have the latest version?
</h2>
<p v-if="Capacitor.getPlatform() === 'ios'">
<p v-if="capabilities.isIOS">
<a href="https://apps.apple.com/us/app/time-safari/id6742664907" target="_blank" class="text-blue-500">
Check the App Store.
</a>
</p>
<p v-else-if="Capacitor.getPlatform() === 'android'">
<p v-else-if="!capabilities.isIOS && capabilities.isMobile">
<a href="https://play.google.com/store/apps/details?id=app.timesafari.app" target="_blank" class="text-blue-500">
Check the Play Store.
</a>
</p>
<p v-else>
Sorry, your platform of '{{ Capacitor.getPlatform() }}' is not recognized.
Sorry, your platform is not recognized.
</p>
</div>
</div>
@@ -592,12 +592,13 @@
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { useClipboard } from "@vueuse/core";
import { Capacitor } from "@capacitor/core";
// Capacitor import removed - using QRNavigationService instead
import * as Package from "../../package.json";
import QuickNav from "../components/QuickNav.vue";
import { APP_SERVER } from "../constants/app";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { QRNavigationService } from "@/services/QRNavigationService";
/**
* HelpView.vue - Comprehensive Help System Component
@@ -643,7 +644,7 @@ export default class HelpView extends Vue {
showVerifiable = false;
APP_SERVER = APP_SERVER;
Capacitor = Capacitor;
// Capacitor reference removed - using QRNavigationService instead
// Ideally, we put no functionality in here, especially in the setup,
// because we never want this page to have a chance of throwing an error.
@@ -711,11 +712,10 @@ export default class HelpView extends Vue {
* @private
*/
private handleQRCodeClick(): void {
if (Capacitor.isNativePlatform()) {
this.$router.push({ name: "contact-qr-scan-full" });
} else {
this.$router.push({ name: "contact-qr" });
}
const qrNavigationService = QRNavigationService.getInstance();
const route = qrNavigationService.getQRScannerRoute();
this.$router.push(route);
}
/**

View File

@@ -264,7 +264,7 @@
import { AxiosRequestConfig } from "axios";
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { Capacitor } from "@capacitor/core";
// Capacitor import removed - using QRNavigationService instead
import { NotificationIface } from "../constants/app";
import EntityIcon from "../components/EntityIcon.vue";
@@ -281,6 +281,7 @@ import { OnboardPage, iconForUnitCode } from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
import { QRNavigationService } from "@/services/QRNavigationService";
import {
NOTIFY_NO_ACCOUNT_ERROR,
NOTIFY_PROJECT_LOAD_ERROR,
@@ -755,11 +756,10 @@ export default class ProjectsView extends Vue {
* - Web-based QR interface for browser environments
*/
private handleQRCodeClick() {
if (Capacitor.isNativePlatform()) {
this.$router.push({ name: "contact-qr-scan-full" });
} else {
this.$router.push({ name: "contact-qr" });
}
const qrNavigationService = QRNavigationService.getInstance();
const route = qrNavigationService.getQRScannerRoute();
this.$router.push(route);
}
/**