forked from jsnbuchanan/crowd-funder-for-time-pwa
feat(android): implement file picker for data export
- Add @capawesome/capacitor-file-picker dependency - Update DataExportSection UI text to reflect new file picker behavior - Implement file picker in CapacitorPlatformService - Add debug logging for path handling - Fix logger to show messages in Capacitor environment WIP: File path handling still needs refinement
This commit is contained in:
@@ -45,16 +45,15 @@ backup and database export, with platform-specific download instructions. * *
|
||||
v-if="platformCapabilities.isIOS"
|
||||
class="list-disc list-outside ml-4"
|
||||
>
|
||||
On iOS: Choose "More..." and select a place in iCloud, or go "Back"
|
||||
and save to another location.
|
||||
On iOS: You will be prompted to choose a location to save your backup
|
||||
file.
|
||||
</li>
|
||||
<li
|
||||
v-if="platformCapabilities.isMobile && !platformCapabilities.isIOS"
|
||||
class="list-disc list-outside ml-4"
|
||||
>
|
||||
On Android: Choose "Open" and then share
|
||||
<font-awesome icon="share-nodes" class="fa-fw" />
|
||||
to your prefered place.
|
||||
On Android: You will be prompted to choose a location to save your
|
||||
backup file.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -156,7 +155,7 @@ export default class DataExportSection extends Vue {
|
||||
title: "Export Successful",
|
||||
text: this.platformCapabilities.hasFileDownload
|
||||
? "See your downloads directory for the backup. It is in the Dexie format."
|
||||
: "The backup has been saved to your device.",
|
||||
: "Please choose a location to save your backup file.",
|
||||
},
|
||||
-1,
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
} from "../PlatformService";
|
||||
import { Filesystem, Directory } from "@capacitor/filesystem";
|
||||
import { Camera, CameraResultType, CameraSource } from "@capacitor/camera";
|
||||
import { FilePicker } from "@capawesome/capacitor-file-picker";
|
||||
import { logger } from "../../utils/logger";
|
||||
|
||||
/**
|
||||
@@ -48,17 +49,57 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes content to a file in the app's data directory.
|
||||
* @param path - Relative path where to write the file
|
||||
* Writes content to a file in the user-selected directory.
|
||||
* Opens a directory picker for the user to choose where to save.
|
||||
* @param path - Suggested filename
|
||||
* @param content - Content to write to the file
|
||||
* @throws Error if write operation fails
|
||||
*/
|
||||
async writeFile(path: string, content: string): Promise<void> {
|
||||
await Filesystem.writeFile({
|
||||
path,
|
||||
data: content,
|
||||
directory: Directory.Data,
|
||||
});
|
||||
try {
|
||||
// Let user pick save location first
|
||||
const result = await FilePicker.pickDirectory();
|
||||
logger.log("FilePicker result path:", result.path);
|
||||
|
||||
// Handle paths based on platform
|
||||
let cleanPath = result.path;
|
||||
if (this.getCapabilities().isIOS) {
|
||||
// For iOS, keep content: prefix
|
||||
cleanPath = result.path;
|
||||
} else {
|
||||
// For Android, extract the actual path from the content URI
|
||||
const pathMatch = result.path.match(/tree\/(.*?)(?:\/|$)/);
|
||||
logger.log("Path match result:", pathMatch);
|
||||
if (pathMatch) {
|
||||
const decodedPath = decodeURIComponent(pathMatch[1]);
|
||||
logger.log("Decoded path:", decodedPath);
|
||||
// Convert primary:Download to /storage/emulated/0/Download
|
||||
cleanPath = decodedPath.replace('primary:', '/storage/emulated/0/');
|
||||
}
|
||||
}
|
||||
|
||||
// For Android, ensure we're using the correct external storage path
|
||||
if (this.getCapabilities().isMobile && !this.getCapabilities().isIOS) {
|
||||
logger.log("Before Android path conversion:", cleanPath);
|
||||
cleanPath = cleanPath.replace('primary:', '/storage/emulated/0/');
|
||||
logger.log("After Android path conversion:", cleanPath);
|
||||
}
|
||||
|
||||
const finalPath = `${cleanPath}/${path}`;
|
||||
logger.log("Final path for writeFile:", finalPath);
|
||||
|
||||
// Write to the selected directory
|
||||
await Filesystem.writeFile({
|
||||
path: finalPath,
|
||||
data: content,
|
||||
directory: Directory.External,
|
||||
recursive: true,
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logger.error("Error saving file:", error);
|
||||
throw new Error("Failed to save file to selected location");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,7 @@ function safeStringify(obj: unknown) {
|
||||
|
||||
export const logger = {
|
||||
log: (message: string, ...args: unknown[]) => {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (process.env.NODE_ENV !== "production" || process.env.VITE_PLATFORM === "capacitor") {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(message, ...args);
|
||||
const argsString = args.length > 0 ? " - " + safeStringify(args) : "";
|
||||
@@ -29,7 +29,7 @@ export const logger = {
|
||||
}
|
||||
},
|
||||
warn: (message: string, ...args: unknown[]) => {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (process.env.NODE_ENV !== "production" || process.env.VITE_PLATFORM === "capacitor") {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(message, ...args);
|
||||
const argsString = args.length > 0 ? " - " + safeStringify(args) : "";
|
||||
|
||||
Reference in New Issue
Block a user