Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add wallet sync export feature #7650

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions static/app-strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2316,5 +2316,13 @@
"Installing, please wait...": "Installing, please wait...",
"There was an error during installation. Please, try again.": "There was an error during installation. Please, try again.",
"Odysee Connect --[Section in Help Page]--": "Odysee Connect",
"Export Wallet": "Export Wallet",
"Export encrypted sync data for import in another app.": "Export encrypted sync data for import in another app.",
"Export wallet sync data. Choose a secure password you will need for import.": "Export wallet sync data. Choose a secure password you will need for import.",
"Choose Password": "Choose Password",
"Sync data copied.": "Sync data copied.",
"Your Sync Data is prepared. You can now copy or save it.": "Your Sync Data is prepared. You can now copy or save it.",
"Export wallet": "Export wallet",
"Sync data saved.": "Sync data saved.",
"--end--": "--end--"
}
2 changes: 2 additions & 0 deletions ui/component/settingSystem/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
doNotifyDecryptWallet,
doNotifyEncryptWallet,
doNotifyForgetPassword,
doOpenModal,
doToggle3PAnalytics,
} from 'redux/actions/app';
import { doSetDaemonSetting, doClearDaemonSetting, doFindFFmpeg } from 'redux/actions/settings';
Expand All @@ -25,6 +26,7 @@ const select = (state) => ({
});

const perform = (dispatch) => ({
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
setDaemonSetting: (key, value) => dispatch(doSetDaemonSetting(key, value)),
clearDaemonSetting: (key) => dispatch(doClearDaemonSetting(key)),
clearCache: () => dispatch(doClearCache()),
Expand Down
17 changes: 17 additions & 0 deletions ui/component/settingSystem/view.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { getPasswordFromCookie } from 'util/saved-passwords';
import * as DAEMON_SETTINGS from 'constants/daemon_settings';
import SettingEnablePrereleases from 'component/settingEnablePrereleases';
import SettingDisableAutoUpdates from 'component/settingDisableAutoUpdates';
import * as MODALS from 'constants/modal_types';

const IS_MAC = process.platform === 'darwin';

Expand Down Expand Up @@ -56,6 +57,7 @@ type Props = {
updateWalletStatus: () => void,
confirmForgetPassword: ({}) => void,
toggle3PAnalytics: (boolean) => void,
openModal: (string, any) => void,
};

export default function SettingSystem(props: Props) {
Expand All @@ -75,6 +77,7 @@ export default function SettingSystem(props: Props) {
updateWalletStatus,
confirmForgetPassword,
toggle3PAnalytics,
openModal,
} = props;

const [clearingCache, setClearingCache] = React.useState(false);
Expand Down Expand Up @@ -376,6 +379,20 @@ export default function SettingSystem(props: Props) {
<SettingsRow title={__('Share url')} multirow>
<SettingShareUrl />
</SettingsRow>
<SettingsRow
title={__('Export Wallet')}
subtitle={__('Export encrypted sync data for import in another app.')}
>
<Button
button="primary"
className="expandable__button"
label={__('Export')}
aria-label={__('Export wallet')}
onClick={() => {
openModal(MODALS.WALLET_EXPORT, {});
}}
/>
</SettingsRow>
<SettingsRow
title={__('Clear application cache')}
subtitle={__('This might fix issues that you are having. Your wallet will not be affected.')}
Expand Down
9 changes: 9 additions & 0 deletions ui/component/walletExport/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import WalletExport from './view';
import { doToast } from 'redux/actions/notifications';
import { connect } from 'react-redux';

const perform = (dispatch) => ({
toast: (message, isError) => dispatch(doToast({ message, isError })),
});

export default connect(null, perform)(WalletExport);
112 changes: 112 additions & 0 deletions ui/component/walletExport/view.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// @flow
import React from 'react';
import Button from 'component/button';
import { Form, FormField } from 'component/common/form';
import Card from 'component/common/card';
import Lbry from 'lbry';
import fs from 'fs';
import { clipboard } from 'electron';
import * as ICONS from 'constants/icons';
import * as remote from '@electron/remote';

type Props = {
onDone: () => void,
toast: (string, boolean) => void,
};

function WalletExport(props: Props) {
const { onDone, toast } = props;

const [password, setPassword] = React.useState();
const [data, setData] = React.useState();
const [fetching, setFetching] = React.useState();
const getData = async (password) => {
setFetching(true);
const data = await Lbry.sync_apply({ password });
setFetching(false);
setData(data);
};

const handleSaveFile = () => {
let defaultPath;
let isWin = process.platform === 'win32';

if (isWin === true) {
defaultPath = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
}

remote.dialog
.showSaveDialog({
title: 'Select File Path',
defaultPath,
buttonLabel: 'Save',
filters: [
{
name: 'JSON Files',
extensions: ['json'],
},
],
})
.then((file) => {
if (!file.canceled) {
fs.writeFile(file.filePath.toString(), JSON.stringify(data), function (err) {
if (err) throw err;
toast(__('Sync data saved.'), false);
onDone();
});
}
})
.catch((err) => {
console.log(err);
toast(__('Data could not be saved'), true);
});
};

return (
<Card
title={__('Export Wallet')}
subtitle={
data
? __('Your Sync Data is prepared. You can now copy or save it.')
: __('Export wallet sync data. Choose a secure password you will need for import.')
}
actions={
<React.Fragment>
{!data && (
<Form onSubmit={() => alert()}>
<FormField
autoFocus
type="password"
name="password_set"
label={__('Choose Password')}
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<div className="section__actions--between">
<Button button={'primary'} onClick={() => getData(password)} label={'Get Data'} disabled={fetching} />
</div>
</Form>
)}
{data && (
<div className="section__actions">
<div className="section__actions--between">
<Button button={'primary'} onClick={handleSaveFile} label={'Save Data'} icon={ICONS.DOWNLOAD} />
<Button
button={'secondary'}
onClick={() => {
clipboard.writeText(JSON.stringify(data));
toast(__('Sync data copied.'), false);
}}
label={'Copy Data'}
icon={ICONS.COPY}
/>
</div>
</div>
)}
</React.Fragment>
}
/>
);
}

export default WalletExport;
1 change: 1 addition & 0 deletions ui/constants/modal_types.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ export const COLLECTION_ADD = 'collection_add';
export const COLLECTION_DELETE = 'collection_delete';
export const CONFIRM_REMOVE_CARD = 'CONFIRM_REMOVE_CARD';
export const CONFIRM_REMOVE_COMMENT = 'CONFIRM_REMOVE_COMMENT';
export const WALLET_EXPORT = 'WALLET_EXPORT';
3 changes: 3 additions & 0 deletions ui/modal/modalRouter/view.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import ModalWalletDecrypt from 'modal/modalWalletDecrypt';
import ModalWalletEncrypt from 'modal/modalWalletEncrypt';

import ModalWalletUnlock from 'modal/modalWalletUnlock';
import ModalWalletExport from 'modal/modalWalletExport';

function getModal(id) {
switch (id) {
Expand Down Expand Up @@ -149,6 +150,8 @@ function getModal(id) {
return ModalRemoveCard;
case MODALS.CONFIRM_REMOVE_COMMENT:
return ModalRemoveComment;
case MODALS.WALLET_EXPORT:
return ModalWalletExport;
default:
return null;
}
Expand Down
9 changes: 9 additions & 0 deletions ui/modal/modalWalletExport/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app';
import ModalWalletExport from './view';

const perform = (dispatch) => ({
closeModal: () => dispatch(doHideModal()),
});

export default connect(null, perform)(ModalWalletExport);
18 changes: 18 additions & 0 deletions ui/modal/modalWalletExport/view.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// @flow
import React from 'react';
import { Modal } from 'modal/modal';
import WalletExport from 'component/walletExport';

type Props = {
closeModal: () => void,
};

export default function ModalWalletExport(props: Props) {
const { closeModal } = props;

return (
<Modal isOpen contentLabel={'Export Wallet'} type="card" onAborted={closeModal}>
<WalletExport onDone={closeModal} />
</Modal>
);
}