mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
fix: file saving not working on Ubuntu snap #4901
This commit is contained in:
parent
ec44bd1391
commit
62c2649320
7 changed files with 122 additions and 1828 deletions
5
electron/electronAPI.d.ts
vendored
5
electron/electronAPI.d.ts
vendored
|
|
@ -65,6 +65,11 @@ export interface ElectronAPI {
|
|||
|
||||
openExternalUrl(url: string): void;
|
||||
|
||||
saveFileDialog(
|
||||
filename: string,
|
||||
data: string,
|
||||
): Promise<{ success: boolean; path?: string }>;
|
||||
|
||||
isLinux(): boolean;
|
||||
|
||||
isMacOS(): boolean;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,23 @@ export const initIpcInterfaces = (): void => {
|
|||
ipcMain.on(IPC.OPEN_PATH, (ev, path: string) => shell.openPath(path));
|
||||
ipcMain.on(IPC.OPEN_EXTERNAL, (ev, url: string) => shell.openExternal(url));
|
||||
|
||||
ipcMain.handle(IPC.SAVE_FILE_DIALOG, async (ev, { filename, data }) => {
|
||||
const result = await dialog.showSaveDialog(getWin(), {
|
||||
defaultPath: filename,
|
||||
filters: [
|
||||
{ name: 'JSON Files', extensions: ['json'] },
|
||||
{ name: 'All Files', extensions: ['*'] },
|
||||
],
|
||||
});
|
||||
|
||||
if (!result.canceled && result.filePath) {
|
||||
const fs = await import('fs');
|
||||
await fs.promises.writeFile(result.filePath, data, 'utf-8');
|
||||
return { success: true, path: result.filePath };
|
||||
}
|
||||
return { success: false };
|
||||
});
|
||||
|
||||
ipcMain.on(IPC.LOCK_SCREEN, () => {
|
||||
if ((app as any).isLocked) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -75,6 +75,11 @@ const ea: ElectronAPI = {
|
|||
|
||||
openPath: (path: string) => _send('OPEN_PATH', path),
|
||||
openExternalUrl: (url: string) => _send('OPEN_EXTERNAL', url),
|
||||
saveFileDialog: (filename: string, data: string) =>
|
||||
_invoke('SAVE_FILE_DIALOG', { filename, data }) as Promise<{
|
||||
success: boolean;
|
||||
path?: string;
|
||||
}>,
|
||||
scheduleRegisterBeforeClose: (id) => _send('REGISTER_BEFORE_CLOSE', { id }),
|
||||
unscheduleRegisterBeforeClose: (id) => _send('UNREGISTER_BEFORE_CLOSE', { id }),
|
||||
setDoneRegisterBeforeClose: (id) => _send('BEFORE_CLOSE_DONE', { id }),
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ export enum IPC {
|
|||
OPEN_PATH = 'OPEN_PATH',
|
||||
OPEN_EXTERNAL = 'OPEN_EXTERNAL',
|
||||
|
||||
SAVE_FILE_DIALOG = 'SAVE_FILE_DIALOG',
|
||||
|
||||
// Plugin Node Execution
|
||||
PLUGIN_EXEC_NODE_SCRIPT = 'PLUGIN_EXEC_NODE_SCRIPT',
|
||||
|
||||
|
|
|
|||
1879
package-lock.json
generated
1879
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -194,11 +194,13 @@ export class FileImexComponent implements OnInit {
|
|||
|
||||
async downloadBackup(): Promise<void> {
|
||||
const data = await this._pfapiService.pf.loadCompleteBackup();
|
||||
download('super-productivity-backup.json', JSON.stringify(data));
|
||||
if (IS_ANDROID_WEB_VIEW) {
|
||||
const result = await download('super-productivity-backup.json', JSON.stringify(data));
|
||||
if (IS_ANDROID_WEB_VIEW || result.isSnap) {
|
||||
this._snackService.open({
|
||||
type: 'SUCCESS',
|
||||
msg: T.FILE_IMEX.S_BACKUP_DOWNLOADED,
|
||||
msg: result.path
|
||||
? `Backup saved to: ${result.path}`
|
||||
: T.FILE_IMEX.S_BACKUP_DOWNLOADED,
|
||||
});
|
||||
}
|
||||
// download('super-productivity-backup.json', privacyExport(data));
|
||||
|
|
@ -206,11 +208,13 @@ export class FileImexComponent implements OnInit {
|
|||
|
||||
async privacyAppDataDownload(): Promise<void> {
|
||||
const data = await this._pfapiService.pf.loadCompleteBackup();
|
||||
download('super-productivity-backup.json', privacyExport(data));
|
||||
if (IS_ANDROID_WEB_VIEW) {
|
||||
const result = await download('super-productivity-backup.json', privacyExport(data));
|
||||
if (IS_ANDROID_WEB_VIEW || result.isSnap) {
|
||||
this._snackService.open({
|
||||
type: 'SUCCESS',
|
||||
msg: T.FILE_IMEX.S_BACKUP_DOWNLOADED,
|
||||
msg: result.path
|
||||
? `Backup saved to: ${result.path}`
|
||||
: T.FILE_IMEX.S_BACKUP_DOWNLOADED,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,31 @@ import { saveAs } from 'file-saver';
|
|||
import { Directory, Encoding, Filesystem, WriteFileResult } from '@capacitor/filesystem';
|
||||
import { IS_ANDROID_WEB_VIEW } from './is-android-web-view';
|
||||
import { Log } from '../core/log';
|
||||
import '../core/window-ea';
|
||||
|
||||
export const download = async (filename: string, stringData: string): Promise<void> => {
|
||||
const blob = new Blob([stringData], { type: 'text/plain;charset=utf-8' });
|
||||
const isRunningInSnap = (): boolean => {
|
||||
return !!window.ea?.isSnap?.();
|
||||
};
|
||||
|
||||
export const download = async (
|
||||
filename: string,
|
||||
stringData: string,
|
||||
): Promise<{ isSnap?: boolean; path?: string }> => {
|
||||
if (IS_ANDROID_WEB_VIEW) {
|
||||
await saveStringAsFile(filename, stringData);
|
||||
return {};
|
||||
} else if (isRunningInSnap() && window.ea?.saveFileDialog) {
|
||||
// Use native dialog for snap to avoid AppArmor permission issues
|
||||
const result = await window.ea.saveFileDialog(filename, stringData);
|
||||
if (result.success && result.path) {
|
||||
Log.log('File saved to:', result.path);
|
||||
return { isSnap: true, path: result.path };
|
||||
}
|
||||
return { isSnap: true };
|
||||
} else {
|
||||
const blob = new Blob([stringData], { type: 'text/plain;charset=utf-8' });
|
||||
saveAs(blob, filename);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -33,6 +51,6 @@ const saveStringAsFile = async (
|
|||
};
|
||||
|
||||
// interestingly this can't live in the logs.ts or it leads to weird "window" not found errors
|
||||
export const downloadLogs = (): void => {
|
||||
download('SP-logs.json', Log.exportLogHistory());
|
||||
export const downloadLogs = async (): Promise<void> => {
|
||||
await download('SP-logs.json', Log.exportLogHistory());
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue