Browse Source

feat: Improve database export with native sharing on mobile

- Enhance CapacitorPlatformService to use native share sheet via Web Share API
- Add fallback to Capacitor Share API with temporary file storage
- Implement WebPlatformService export with direct download for desktop
- Clean up temporary files and URLs after sharing/download

The changes provide a more platform-appropriate experience:
- Mobile: Uses system share sheet for flexible saving/sharing options
- Desktop: Direct download to user's download folder
cross-platform-factory
Matthew Raymer 2 months ago
parent
commit
1c8528fb20
  1. 17
      src/components/DataExportSection.vue
  2. 9
      src/services/PlatformService.ts
  3. 52
      src/services/platforms/CapacitorPlatformService.ts
  4. 9
      src/services/platforms/WebPlatformService.ts

17
src/components/DataExportSection.vue

@ -139,22 +139,7 @@ export default class DataExportSection extends Vue {
const blob = await db.export({ prettyJson: true }); const blob = await db.export({ prettyJson: true });
const fileName = `${db.name}-backup.json`; const fileName = `${db.name}-backup.json`;
if (this.platformService.isWeb()) { await this.platformService.exportDatabase(blob, fileName);
// Web platform: Use download link
this.downloadUrl = URL.createObjectURL(blob);
const downloadAnchor = this.$refs.downloadLink as HTMLAnchorElement;
downloadAnchor.href = this.downloadUrl;
downloadAnchor.download = fileName;
downloadAnchor.click();
setTimeout(() => URL.revokeObjectURL(this.downloadUrl), 1000);
} else if (this.platformService.isCapacitor()) {
// Capacitor platform: Write to app directory
const content = await blob.text();
await this.platformService.writeFile(fileName, content);
} else {
// Other platforms: Use platform service
await this.platformService.writeFile(fileName, await blob.text());
}
this.$notify( this.$notify(
{ {

9
src/services/PlatformService.ts

@ -46,6 +46,15 @@ export interface PlatformService {
*/ */
listFiles(directory: string): Promise<string[]>; listFiles(directory: string): Promise<string[]>;
/**
* Exports a database blob to a file, handling platform-specific save operations.
* @param blob - The database blob to export
* @param fileName - The name of the file to save
* @returns Promise that resolves when the export is complete
* @throws Error if export fails
*/
exportDatabase(blob: Blob, fileName: string): Promise<void>;
// Camera operations // Camera operations
/** /**
* Activates the device camera to take a picture. * Activates the device camera to take a picture.

52
src/services/platforms/CapacitorPlatformService.ts

@ -2,6 +2,7 @@ import { ImageResult, PlatformService } from "../PlatformService";
import { Filesystem, Directory } from "@capacitor/filesystem"; import { Filesystem, Directory } from "@capacitor/filesystem";
import { Camera, CameraResultType, CameraSource } from "@capacitor/camera"; import { Camera, CameraResultType, CameraSource } from "@capacitor/camera";
import { logger } from "../../utils/logger"; import { logger } from "../../utils/logger";
import { Share } from "@capacitor/share";
/** /**
* Platform service implementation for Capacitor (mobile) platform. * Platform service implementation for Capacitor (mobile) platform.
@ -188,4 +189,55 @@ export class CapacitorPlatformService implements PlatformService {
// This is just a placeholder for the interface // This is just a placeholder for the interface
return Promise.resolve(); return Promise.resolve();
} }
async exportDatabase(blob: Blob, fileName: string): Promise<void> {
// Create a File object from the Blob
const file = new File([blob], fileName, { type: 'application/json' });
try {
// Use the native share sheet
await navigator.share({
files: [file],
title: fileName,
});
} catch (error) {
// Fallback to Capacitor Share API if Web Share API fails
// First save to temporary file
const base64Data = await this.blobToBase64(blob);
const result = await Filesystem.writeFile({
path: fileName,
data: base64Data,
directory: Directory.Cache, // Use Cache instead of Documents for temporary files
recursive: true
});
// Then share using Capacitor Share API
await Share.share({
title: fileName,
url: result.uri
});
// Clean up the temporary file
try {
await Filesystem.deleteFile({
path: fileName,
directory: Directory.Cache
});
} catch (cleanupError) {
logger.warn('Failed to clean up temporary file:', cleanupError);
}
}
}
private async blobToBase64(blob: Blob): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => {
const base64data = reader.result as string;
resolve(base64data.split(',')[1]);
};
reader.onerror = reject;
reader.readAsDataURL(blob);
});
}
} }

9
src/services/platforms/WebPlatformService.ts

@ -209,4 +209,13 @@ export class WebPlatformService implements PlatformService {
// Web platform can handle deep links through URL parameters // Web platform can handle deep links through URL parameters
return Promise.resolve(); return Promise.resolve();
} }
async exportDatabase(blob: Blob, fileName: string): Promise<void> {
const downloadUrl = URL.createObjectURL(blob);
const downloadAnchor = document.createElement('a');
downloadAnchor.href = downloadUrl;
downloadAnchor.download = fileName;
downloadAnchor.click();
setTimeout(() => URL.revokeObjectURL(downloadUrl), 1000);
}
} }

Loading…
Cancel
Save