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
This commit is contained in:
@@ -139,22 +139,7 @@ export default class DataExportSection extends Vue {
|
||||
const blob = await db.export({ prettyJson: true });
|
||||
const fileName = `${db.name}-backup.json`;
|
||||
|
||||
if (this.platformService.isWeb()) {
|
||||
// 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());
|
||||
}
|
||||
await this.platformService.exportDatabase(blob, fileName);
|
||||
|
||||
this.$notify(
|
||||
{
|
||||
|
||||
@@ -46,6 +46,15 @@ export interface PlatformService {
|
||||
*/
|
||||
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
|
||||
/**
|
||||
* Activates the device camera to take a picture.
|
||||
|
||||
@@ -2,6 +2,7 @@ import { ImageResult, PlatformService } from "../PlatformService";
|
||||
import { Filesystem, Directory } from "@capacitor/filesystem";
|
||||
import { Camera, CameraResultType, CameraSource } from "@capacitor/camera";
|
||||
import { logger } from "../../utils/logger";
|
||||
import { Share } from "@capacitor/share";
|
||||
|
||||
/**
|
||||
* Platform service implementation for Capacitor (mobile) platform.
|
||||
@@ -188,4 +189,55 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
// This is just a placeholder for the interface
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,4 +209,13 @@ export class WebPlatformService implements PlatformService {
|
||||
// Web platform can handle deep links through URL parameters
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user