1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00
joplin/packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx

117 lines
3.9 KiB
TypeScript

import * as React from 'react';
import { Text, Alert, View } from 'react-native';
import { _ } from '@joplin/lib/locale';
import Logger from '@joplin/utils/Logger';
import { ProgressBar } from 'react-native-paper';
import { FunctionComponent, useCallback, useState } from 'react';
import shim from '@joplin/lib/shim';
import { join } from 'path';
import Share from 'react-native-share';
import exportAllFolders, { makeExportCacheDirectory } from './utils/exportAllFolders';
import { ExportProgressState } from '@joplin/lib/services/interop/types';
import { ConfigScreenStyles } from '../configScreenStyles';
import SettingsButton from '../SettingsButton';
const logger = Logger.create('NoteExportButton');
interface Props {
styles: ConfigScreenStyles;
}
enum ExportStatus {
NotStarted,
Exporting,
Exported,
}
export const exportButtonTitle = () => _('Export all notes as JEX');
export const exportButtonDescription = () => _('Share a copy of all notes in a file format that can be imported by Joplin on a computer.');
const NoteExportButton: FunctionComponent<Props> = props => {
const [exportStatus, setExportStatus] = useState<ExportStatus>(ExportStatus.NotStarted);
const [exportProgress, setExportProgress] = useState<number|undefined>(0);
const [warnings, setWarnings] = useState<string>('');
const startExport = useCallback(async () => {
// Don't run multiple exports at the same time.
if (exportStatus === ExportStatus.Exporting) {
return;
}
setExportStatus(ExportStatus.Exporting);
const exportTargetPath = join(await makeExportCacheDirectory(), 'jex-export.jex');
logger.info(`Exporting all folders to path ${exportTargetPath}`);
try {
// Initially, undetermined progress
setExportProgress(undefined);
const status = await exportAllFolders(exportTargetPath, (status, progress) => {
if (progress !== null) {
setExportProgress(progress);
} else if (status === ExportProgressState.Closing || status === ExportProgressState.QueuingItems) {
// We don't have a numeric progress value and the closing/queuing state may take a while.
// Set a special progress value:
setExportProgress(undefined);
}
});
setExportStatus(ExportStatus.Exported);
setWarnings(status.warnings.join('\n'));
await Share.open({
type: 'application/jex',
filename: 'export.jex',
url: `file://${exportTargetPath}`,
failOnCancel: false,
});
} catch (e) {
logger.error('Unable to export:', e);
// Display a message to the user (e.g. in the case where the user is out of disk space).
Alert.alert(_('Error'), _('Unable to export or share data. Reason: %s', e.toString()));
setExportStatus(ExportStatus.NotStarted);
} finally {
await shim.fsDriver().remove(exportTargetPath);
}
}, [exportStatus]);
if (exportStatus === ExportStatus.NotStarted || exportStatus === ExportStatus.Exporting) {
const progressComponent = (
<ProgressBar
visible={exportStatus === ExportStatus.Exporting}
indeterminate={exportProgress === undefined}
progress={exportProgress}/>
);
const startOrCancelExportButton = (
<SettingsButton
title={exportStatus === ExportStatus.Exporting ? _('Exporting...') : exportButtonTitle()}
disabled={exportStatus === ExportStatus.Exporting}
description={exportStatus === ExportStatus.NotStarted ? exportButtonDescription() : null}
statusComponent={progressComponent}
clickHandler={startExport}
styles={props.styles}
/>
);
return startOrCancelExportButton;
} else {
const warningComponent = (
<Text style={props.styles.styleSheet.warningText}>
{_('Warnings:\n%s', warnings)}
</Text>
);
const exportSummary = (
<View style={props.styles.styleSheet.settingContainer}>
<Text style={props.styles.styleSheet.descriptionText}>{_('Exported successfully!')}</Text>
{warnings.length > 0 ? warningComponent : null}
</View>
);
return exportSummary;
}
};
export default NoteExportButton;