feat(platform): implement dual-flow file sharing with Save to Device option

Add new platform service methods for direct file saving alongside existing share functionality:
- Add saveToDevice() and saveAs() methods to PlatformService interface
- Implement cross-platform support in WebPlatformService, ElectronPlatformService, and CapacitorPlatformService
- Update DataExportSection UI to provide Share Contacts and Save to Device buttons
- Add AndroidFileSaver plugin architecture with fallback implementation
- Include comprehensive documentation for native Android plugin implementation

This addresses the Android simulator file sharing limitation by providing users with clear choices between app-to-app sharing and direct device storage, while maintaining backward compatibility across all platforms.

- CapacitorPlatformService: Add MediaStore/SAF support with graceful fallbacks
- UI Components: Replace single download button with dual-action interface
- Documentation: Add AndroidFileSaver plugin implementation guide
- Type Safety: Maintain interface consistency across all platform services
This commit is contained in:
Matthew Raymer
2025-08-19 07:39:57 +00:00
parent 3c44dc0921
commit b735aac1fc
7 changed files with 800 additions and 20 deletions

View File

@@ -97,9 +97,7 @@ export class WebPlatformService implements PlatformService {
}
} else {
// We're in a worker context - skip initBackend call
// Use console for critical startup message to avoid circular dependency
// eslint-disable-next-line no-console
console.log(
logger.info(
"[WebPlatformService] Skipping initBackend call in worker context",
);
}
@@ -594,6 +592,48 @@ export class WebPlatformService implements PlatformService {
}
}
/**
* Saves content directly to the device's Downloads folder (web platform).
* Uses the browser's download mechanism to save files.
*
* @param fileName - The filename of the file to save
* @param content - The content to write to the file
* @returns Promise that resolves when the file is saved
*/
async saveToDevice(fileName: string, content: string): Promise<void> {
try {
// Web platform: Use the same download mechanism as writeAndShareFile
await this.writeAndShareFile(fileName, content);
logger.log("[WebPlatformService] File saved to device:", fileName);
} catch (error) {
logger.error("[WebPlatformService] Error saving file to device:", error);
throw new Error(
`Failed to save file to device: ${error instanceof Error ? error.message : "Unknown error"}`,
);
}
}
/**
* Opens the system file picker to let the user choose where to save a file (web platform).
* Uses the browser's download mechanism with a suggested filename.
*
* @param fileName - The suggested filename for the file
* @param content - The content to write to the file
* @returns Promise that resolves when the file is saved
*/
async saveAs(fileName: string, content: string): Promise<void> {
try {
// Web platform: Use the same download mechanism as writeAndShareFile
await this.writeAndShareFile(fileName, content);
logger.log("[WebPlatformService] File saved as:", fileName);
} catch (error) {
logger.error("[WebPlatformService] Error saving file as:", error);
throw new Error(
`Failed to save file as: ${error instanceof Error ? error.message : "Unknown error"}`,
);
}
}
/**
* @see PlatformService.dbQuery
*/