Merge pull request #73 from andrerfneves/feature/deep-link
Feature/deep link
This commit is contained in:
commit
7860f23d5c
|
@ -15,23 +15,25 @@ afterEach(() => app.stop());
|
||||||
|
|
||||||
describe('Send', () => {
|
describe('Send', () => {
|
||||||
test('should load "Send Page"', async () => {
|
test('should load "Send Page"', async () => {
|
||||||
expect(app.client.element('#send-wrapper')
|
expect(app.client.element('#send-wrapper').isVisible()).resolves.toEqual(true);
|
||||||
.isVisible()).resolves.toEqual(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should show Additional Options click', async () => {
|
test('should show Additional Options click', async () => {
|
||||||
expect(app.client.element('#send-wrapper #send-fee-wrapper')
|
expect(app.client.element('#send-wrapper #send-fee-wrapper').isVisible()).resolves.toEqual(
|
||||||
.isVisible()).resolves.toEqual(false);
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
await app.client.element('#send-show-additional-options-button').click();
|
await app.client.element('#send-show-additional-options-button').click();
|
||||||
|
|
||||||
expect(app.client.element('#send-wrapper #send-fee-wrapper')
|
expect(app.client.element('#send-wrapper #send-fee-wrapper').isVisible()).resolves.toEqual(
|
||||||
.isVisible()).resolves.toEqual(true);
|
true,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should disable send button if required fields are empty', async () => {
|
test('should disable send button if required fields are empty', async () => {
|
||||||
expect(app.client.element('#send-submit-button')
|
expect(app.client.element('#send-submit-button').getAttribute('disabled')).resolves.toEqual(
|
||||||
.getAttribute('disabled')).resolves.toEqual(true);
|
true,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should enable send button if required fields are filled', async () => {
|
test('should enable send button if required fields are filled', async () => {
|
||||||
|
@ -68,8 +70,9 @@ describe('Send', () => {
|
||||||
|
|
||||||
await app.client.element('#send-submit-button').click();
|
await app.client.element('#send-submit-button').click();
|
||||||
|
|
||||||
expect(app.client.element('#send-confirm-transaction-modal')
|
expect(app.client.element('#send-confirm-transaction-modal').isVisible()).resolves.toEqual(
|
||||||
.isVisible()).resolves.toEqual(true);
|
true,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display a load indicator while the transaction is processed', async () => {
|
test('should display a load indicator while the transaction is processed', async () => {
|
||||||
|
@ -91,15 +94,14 @@ describe('Send', () => {
|
||||||
expect(app.client.getAttribute('#send-confirm-transaction-modal img', 'src')).resolves.toEqual(
|
expect(app.client.getAttribute('#send-confirm-transaction-modal img', 'src')).resolves.toEqual(
|
||||||
expect.stringContaining('/assets/sync_icon.png'),
|
expect.stringContaining('/assets/sync_icon.png'),
|
||||||
);
|
);
|
||||||
expect(app.client.getText('#send-confirm-transaction-modal p'))
|
expect(app.client.getText('#send-confirm-transaction-modal p')).resolves.toEqual(
|
||||||
.resolves.toEqual('Processing transaction...');
|
'Processing transaction...',
|
||||||
expect(app.client.element('#confirm-modal-button')
|
);
|
||||||
.isVisible()).resolves.toEqual(false);
|
expect(app.client.element('#confirm-modal-button').isVisible()).resolves.toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should show an error in invalid transaction', async () => {
|
test('should show an error in invalid transaction', async () => {
|
||||||
expect(app.client.element('#send-error-text')
|
expect(app.client.element('#send-error-text').isVisible()).resolves.toEqual(false);
|
||||||
.isVisible()).resolves.toEqual(false);
|
|
||||||
|
|
||||||
await app.client.element('#sidebar a:nth-child(1)').click();
|
await app.client.element('#sidebar a:nth-child(1)').click();
|
||||||
await app.client.element('#sidebar a:nth-child(2)').click();
|
await app.client.element('#sidebar a:nth-child(2)').click();
|
||||||
|
@ -124,8 +126,7 @@ describe('Send', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should show a success screen after transaction and show a transaction item', async () => {
|
test('should show a success screen after transaction and show a transaction item', async () => {
|
||||||
expect(app.client.element('#send-success-wrapper')
|
expect(app.client.element('#send-success-wrapper').isVisible()).resolves.toEqual(false);
|
||||||
.isVisible()).resolves.toEqual(false);
|
|
||||||
|
|
||||||
await app.client.element('#sidebar a:nth-child(1)').click();
|
await app.client.element('#sidebar a:nth-child(1)').click();
|
||||||
await app.client.element('#sidebar a:nth-child(2)').click();
|
await app.client.element('#sidebar a:nth-child(2)').click();
|
||||||
|
@ -149,10 +150,11 @@ describe('Send', () => {
|
||||||
|
|
||||||
await app.client.waitUntilTextExists('#transaction-item-operation-id-1', 'Send');
|
await app.client.waitUntilTextExists('#transaction-item-operation-id-1', 'Send');
|
||||||
|
|
||||||
expect(await app.client.element('#transaction-item-operation-id-1 img')
|
expect(await app.client.element('#transaction-item-operation-id-1 img').isVisible()).toEqual(
|
||||||
.isVisible()).toEqual(true);
|
true,
|
||||||
|
);
|
||||||
expect(
|
expect(
|
||||||
await app.client.element('#transaction-item-operation-id-1 img').getAttribute('src'),
|
await app.client.element('#transaction-item-operation-id-1 img').getAttribute('src'),
|
||||||
).toEndWith('/assets/transaction_sent_icon.svg');
|
).toEndWith('/assets/transaction_sent_icon_dark.svg');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled, { withTheme } from 'styled-components';
|
||||||
import { Transition, animated } from 'react-spring';
|
import { Transition, animated } from 'react-spring';
|
||||||
|
|
||||||
import CircleProgressComponent from 'react-circle';
|
import CircleProgressComponent from 'react-circle';
|
||||||
|
@ -9,8 +9,6 @@ import { TextComponent } from './text';
|
||||||
|
|
||||||
import zcashLogo from '../assets/images/zcash-simple-icon.svg';
|
import zcashLogo from '../assets/images/zcash-simple-icon.svg';
|
||||||
|
|
||||||
import { appTheme } from '../theme';
|
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
@ -55,6 +53,7 @@ const LoadingText = styled(TextComponent)`
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
progress: number,
|
progress: number,
|
||||||
|
theme: AppTheme,
|
||||||
message: string,
|
message: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -64,7 +63,7 @@ type State = {
|
||||||
|
|
||||||
const TIME_DELAY_ANIM = 100;
|
const TIME_DELAY_ANIM = 100;
|
||||||
|
|
||||||
export class LoadingScreen extends PureComponent<Props, State> {
|
class Component extends PureComponent<Props, State> {
|
||||||
state = { start: false };
|
state = { start: false };
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -75,7 +74,7 @@ export class LoadingScreen extends PureComponent<Props, State> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { start } = this.state;
|
const { start } = this.state;
|
||||||
const { progress, message } = this.props;
|
const { progress, message, theme } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper data-testid='LoadingScreen'>
|
<Wrapper data-testid='LoadingScreen'>
|
||||||
|
@ -109,8 +108,8 @@ export class LoadingScreen extends PureComponent<Props, State> {
|
||||||
progress={progress}
|
progress={progress}
|
||||||
responsive
|
responsive
|
||||||
showPercentage={false}
|
showPercentage={false}
|
||||||
progressColor={appTheme.colors.activeItem}
|
progressColor={theme.colors.activeItem}
|
||||||
bgColor={appTheme.colors.inactiveItem}
|
bgColor={theme.colors.inactiveItem}
|
||||||
/>
|
/>
|
||||||
</CircleWrapper>
|
</CircleWrapper>
|
||||||
<LoadingText value={message} />
|
<LoadingText value={message} />
|
||||||
|
@ -122,3 +121,5 @@ export class LoadingScreen extends PureComponent<Props, State> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const LoadingScreen = withTheme(Component);
|
||||||
|
|
|
@ -86,7 +86,9 @@ export const Component = ({
|
||||||
}: Props) => (
|
}: Props) => (
|
||||||
<Wrapper id='sidebar'>
|
<Wrapper id='sidebar'>
|
||||||
{(options || []).map((item) => {
|
{(options || []).map((item) => {
|
||||||
const isActive = location.pathname === item.route;
|
const isActive = item.route === '/'
|
||||||
|
? location.pathname === item.route
|
||||||
|
: location.pathname.startsWith(item.route);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledLink
|
<StyledLink
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
// @flow
|
||||||
|
import React, { type ComponentType, Component } from 'react';
|
||||||
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
|
import { ipcRenderer, remote } from 'electron';
|
||||||
|
import { type RouterHistory, type Location } from 'react-router-dom';
|
||||||
|
import { searchUriInArgv } from '../../config/handle-deeplink';
|
||||||
|
import electronStore from '../../config/electron-store';
|
||||||
|
|
||||||
|
type PassedProps = {
|
||||||
|
history: RouterHistory,
|
||||||
|
location: Location,
|
||||||
|
isRunning: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
const OSX_DEEPLINK_URL_KEY = 'OSX_DEEPLINK_URL';
|
||||||
|
|
||||||
|
export const withDeepLink = (
|
||||||
|
WrappedComponent: ComponentType<PassedProps>,
|
||||||
|
): ComponentType<$Diff<PassedProps, {}>> => class extends Component<PassedProps> {
|
||||||
|
componentDidMount() {
|
||||||
|
const arg = searchUriInArgv([
|
||||||
|
...remote.process.argv,
|
||||||
|
electronStore.get(OSX_DEEPLINK_URL_KEY) || '',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (arg) this.redirect(arg);
|
||||||
|
|
||||||
|
remote.app.on('open-url', (event, url) => {
|
||||||
|
this.redirect(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('on-deep-link', (event: Object, message: string) => {
|
||||||
|
this.redirect(message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
ipcRenderer.removeAllListeners('on-deep-link');
|
||||||
|
}
|
||||||
|
|
||||||
|
redirect(message: string) {
|
||||||
|
const { history } = this.props;
|
||||||
|
|
||||||
|
// clean osx deeplink storage
|
||||||
|
if (electronStore.has(OSX_DEEPLINK_URL_KEY)) {
|
||||||
|
electronStore.delete(OSX_DEEPLINK_URL_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
history.replace(`/send/${message.replace(/zcash:(\/\/)?/, '')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <WrappedComponent {...this.props} {...this.state} />;
|
||||||
|
}
|
||||||
|
};
|
|
@ -36,7 +36,17 @@ export type SendTransactionInput = {
|
||||||
memo: string,
|
memo: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = ({ sendStatus, receive }: AppState) => ({
|
export type MapStateToProps = {|
|
||||||
|
balance: number,
|
||||||
|
zecPrice: number,
|
||||||
|
addresses: string[],
|
||||||
|
error: string | null,
|
||||||
|
isSending: boolean,
|
||||||
|
operationId: string | null,
|
||||||
|
isToAddressValid: boolean,
|
||||||
|
|};
|
||||||
|
|
||||||
|
const mapStateToProps = ({ sendStatus, receive }: AppState): MapStateToProps => ({
|
||||||
balance: sendStatus.addressBalance,
|
balance: sendStatus.addressBalance,
|
||||||
zecPrice: sendStatus.zecPrice,
|
zecPrice: sendStatus.zecPrice,
|
||||||
addresses: receive.addresses,
|
addresses: receive.addresses,
|
||||||
|
@ -46,10 +56,19 @@ const mapStateToProps = ({ sendStatus, receive }: AppState) => ({
|
||||||
isToAddressValid: sendStatus.isToAddressValid,
|
isToAddressValid: sendStatus.isToAddressValid,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
export type MapDispatchToProps = {|
|
||||||
|
sendTransaction: SendTransactionInput => Promise<void>,
|
||||||
|
loadAddresses: () => Promise<void>,
|
||||||
|
resetSendView: () => void,
|
||||||
|
validateAddress: ({ address: string }) => Promise<void>,
|
||||||
|
loadZECPrice: () => void,
|
||||||
|
getAddressBalance: ({ address: string }) => Promise<void>,
|
||||||
|
|};
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch: Dispatch): MapDispatchToProps => ({
|
||||||
sendTransaction: async ({
|
sendTransaction: async ({
|
||||||
from, to, amount, fee, memo,
|
from, to, amount, fee, memo,
|
||||||
}: SendTransactionInput) => {
|
}) => {
|
||||||
dispatch(sendTransaction());
|
dispatch(sendTransaction());
|
||||||
|
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
|
@ -142,7 +161,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||||
|
|
||||||
if (zAddressesErr || tAddressesErr) return dispatch(loadAddressesError({ error: 'Something went wrong!' }));
|
if (zAddressesErr || tAddressesErr) return dispatch(loadAddressesError({ error: 'Something went wrong!' }));
|
||||||
|
|
||||||
dispatch(
|
return dispatch(
|
||||||
loadAddressesSuccess({
|
loadAddressesSuccess({
|
||||||
addresses: [...zAddresses, ...transparentAddresses],
|
addresses: [...zAddresses, ...transparentAddresses],
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -4,8 +4,10 @@ import { compose } from 'redux';
|
||||||
import { withRouter } from 'react-router-dom';
|
import { withRouter } from 'react-router-dom';
|
||||||
import { RouterComponent } from './router';
|
import { RouterComponent } from './router';
|
||||||
import { withDaemonStatusCheck } from '../components/with-daemon-status-check';
|
import { withDaemonStatusCheck } from '../components/with-daemon-status-check';
|
||||||
|
import { withDeepLink } from '../components/with-deeplink';
|
||||||
|
|
||||||
export const Router = compose(
|
export const Router = compose(
|
||||||
withRouter,
|
withRouter,
|
||||||
withDaemonStatusCheck,
|
withDaemonStatusCheck,
|
||||||
|
withDeepLink,
|
||||||
)(RouterComponent);
|
)(RouterComponent);
|
||||||
|
|
|
@ -42,7 +42,7 @@ const ContentWrapper = styled.div`
|
||||||
const getTitle = (path: string) => {
|
const getTitle = (path: string) => {
|
||||||
if (path === '/') return 'Dashboard';
|
if (path === '/') return 'Dashboard';
|
||||||
|
|
||||||
return path.replace('/', '');
|
return path.split('/')[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RouterComponent = ({
|
export const RouterComponent = ({
|
||||||
|
@ -60,7 +60,7 @@ export const RouterComponent = ({
|
||||||
<ScrollTopComponent>
|
<ScrollTopComponent>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path={DASHBOARD_ROUTE} component={DashboardContainer} />
|
<Route exact path={DASHBOARD_ROUTE} component={DashboardContainer} />
|
||||||
<Route path={SEND_ROUTE} component={SendContainer} />
|
<Route path={`${SEND_ROUTE}/:to?`} component={SendContainer} />
|
||||||
<Route path={RECEIVE_ROUTE} component={ReceiveContainer} />
|
<Route path={RECEIVE_ROUTE} component={ReceiveContainer} />
|
||||||
<Route path={SETTINGS_ROUTE} component={SettingsContainer} />
|
<Route path={SETTINGS_ROUTE} component={SettingsContainer} />
|
||||||
<Route path={CONSOLE_ROUTE} component={ConsoleView} />
|
<Route path={CONSOLE_ROUTE} component={ConsoleView} />
|
||||||
|
|
|
@ -4,6 +4,7 @@ import React, { Fragment, PureComponent } from 'react';
|
||||||
import styled, { withTheme, keyframes } from 'styled-components';
|
import styled, { withTheme, keyframes } from 'styled-components';
|
||||||
import { BigNumber } from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
import { Transition, animated } from 'react-spring';
|
import { Transition, animated } from 'react-spring';
|
||||||
|
import { type Match } from 'react-router-dom';
|
||||||
import Tooltip from 'rc-tooltip';
|
import Tooltip from 'rc-tooltip';
|
||||||
|
|
||||||
import { FEES } from '../constants/fees';
|
import { FEES } from '../constants/fees';
|
||||||
|
@ -31,7 +32,7 @@ import LoadingIcon from '../assets/images/sync_icon_dark.png';
|
||||||
import ArrowUpIconDark from '../assets/images/arrow_up_dark.png';
|
import ArrowUpIconDark from '../assets/images/arrow_up_dark.png';
|
||||||
import ArrowUpIconLight from '../assets/images/arrow_up_light.png';
|
import ArrowUpIconLight from '../assets/images/arrow_up_light.png';
|
||||||
|
|
||||||
import type { SendTransactionInput } from '../containers/send';
|
import type { SendTransactionInput, MapDispatchToProps, MapStateToProps } from '../containers/send';
|
||||||
import type { State as SendState } from '../redux/modules/send';
|
import type { State as SendState } from '../redux/modules/send';
|
||||||
|
|
||||||
const rotate = keyframes`
|
const rotate = keyframes`
|
||||||
|
@ -264,7 +265,6 @@ const ValidateWrapper = styled(RowComponent)`
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
const ActionsWrapper = styled(RowComponent)`
|
const ActionsWrapper = styled(RowComponent)`
|
||||||
padding: 30px 0;
|
padding: 30px 0;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -287,19 +287,9 @@ const HexadecimalText = styled(TextComponent)`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
...SendState,
|
match: Match,
|
||||||
balance: number,
|
|
||||||
zecPrice: number,
|
|
||||||
addresses: string[],
|
|
||||||
sendTransaction: SendTransactionInput => void,
|
|
||||||
loadAddresses: () => void,
|
|
||||||
resetSendView: () => void,
|
|
||||||
validateAddress: ({ address: string }) => void,
|
|
||||||
loadAddresses: () => void,
|
|
||||||
loadZECPrice: () => void,
|
|
||||||
getAddressBalance: ({ address: string }) => void,
|
|
||||||
theme: AppTheme,
|
theme: AppTheme,
|
||||||
};
|
} & MapStateToProps & MapDispatchToProps;
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
showFee: boolean,
|
showFee: boolean,
|
||||||
|
@ -329,11 +319,24 @@ class Component extends PureComponent<Props, State> {
|
||||||
state = initialState;
|
state = initialState;
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { resetSendView, loadAddresses, loadZECPrice } = this.props;
|
const {
|
||||||
|
resetSendView, loadAddresses, loadZECPrice, match,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
resetSendView();
|
resetSendView();
|
||||||
loadAddresses();
|
loadAddresses();
|
||||||
loadZECPrice();
|
loadZECPrice();
|
||||||
|
|
||||||
|
if (match.params.to) {
|
||||||
|
this.handleChange('to')(match.params.to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps: Props) {
|
||||||
|
const previousToAddress = prevProps.match.params.to;
|
||||||
|
const toAddress = this.props.match.params.to; // eslint-disable-line
|
||||||
|
|
||||||
|
if (toAddress && previousToAddress !== toAddress) this.handleChange('to')(toAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTooltipVisibility = ({ balance, amount }: { balance: number, amount: number }) => {
|
updateTooltipVisibility = ({ balance, amount }: { balance: number, amount: number }) => {
|
||||||
|
|
|
@ -5,10 +5,12 @@ set -eu
|
||||||
# Create default zcash.conf
|
# Create default zcash.conf
|
||||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
if [ ! -e "$HOME/Library/Application Support/Zcash/zcash.conf" ] ; then
|
if [ ! -e "$HOME/Library/Application Support/Zcash/zcash.conf" ] ; then
|
||||||
|
mkdir -p "$HOME/Library/Application Support/Zcash"
|
||||||
echo "server=1" > "$HOME/Library/Application Support/Zcash/zcash.conf"
|
echo "server=1" > "$HOME/Library/Application Support/Zcash/zcash.conf"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if [ ! -e "$HOME/.zcash/zcash.conf" ] ; then
|
if [ ! -e "$HOME/.zcash/zcash.conf" ] ; then
|
||||||
|
mkdir -p "$HOME/.zcash"
|
||||||
echo "server=1" > "$HOME/.zcash/zcash.conf"
|
echo "server=1" > "$HOME/.zcash/zcash.conf"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -14,6 +14,7 @@ import runDaemon from './daemon/zcashd-child-process';
|
||||||
import zcashLog from './daemon/logger';
|
import zcashLog from './daemon/logger';
|
||||||
import getZecPrice from '../services/zec-price';
|
import getZecPrice from '../services/zec-price';
|
||||||
import store from './electron-store';
|
import store from './electron-store';
|
||||||
|
import { handleDeeplink } from './handle-deeplink';
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
|
@ -79,10 +80,38 @@ const createWindow = () => {
|
||||||
exports.mainWindow = mainWindow;
|
exports.mainWindow = mainWindow;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
app.setAsDefaultProtocolClient('zcash');
|
||||||
|
|
||||||
|
const instanceLock = app.requestSingleInstanceLock();
|
||||||
|
if (instanceLock) {
|
||||||
|
app.on('second-instance', (event: Object, argv: string[]) => {
|
||||||
|
handleDeeplink({
|
||||||
|
app,
|
||||||
|
mainWindow,
|
||||||
|
argv,
|
||||||
|
listenOpenUrl: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (mainWindow) {
|
||||||
|
if (mainWindow.isMinimized()) {
|
||||||
|
mainWindow.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
mainWindow.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDeeplink({ app, mainWindow });
|
||||||
|
|
||||||
/* eslint-disable-next-line consistent-return */
|
/* eslint-disable-next-line consistent-return */
|
||||||
app.on('ready', async () => {
|
app.on('ready', async () => {
|
||||||
createWindow();
|
createWindow();
|
||||||
|
|
||||||
|
console.log('[Process Argv]', process.argv); // eslint-disable-line
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'test') {
|
if (process.env.NODE_ENV === 'test') {
|
||||||
zcashLog('Not running daemon, please run the mock API');
|
zcashLog('Not running daemon, please run the mock API');
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
// @flow
|
||||||
|
import { typeof app as ElectronApp, type electron$BrowserWindow, remote } from 'electron'; // eslint-disable-line
|
||||||
|
import store from './electron-store';
|
||||||
|
|
||||||
|
const sendMessage = (mainWindow, url) => {
|
||||||
|
if (mainWindow) {
|
||||||
|
if (mainWindow.isVisible()) {
|
||||||
|
mainWindow.webContents.send('on-deep-link', url);
|
||||||
|
} else {
|
||||||
|
mainWindow.on('show', () => mainWindow.webContents.send('on-deep-link', url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const searchUriInArgv = (argv: string[]): ?string => {
|
||||||
|
const argIndex = argv.findIndex(item => /zcash:(\/\/)?/.test(item));
|
||||||
|
return argv[argIndex];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const handleDeeplink = ({
|
||||||
|
app,
|
||||||
|
mainWindow,
|
||||||
|
argv = process.argv,
|
||||||
|
listenOpenUrl = true,
|
||||||
|
}: {
|
||||||
|
app: ElectronApp,
|
||||||
|
mainWindow: electron$BrowserWindow,
|
||||||
|
argv?: string[],
|
||||||
|
listenOpenUrl?: boolean,
|
||||||
|
}) => {
|
||||||
|
if (listenOpenUrl) {
|
||||||
|
app.on('open-url', (event: Object, url: string) => {
|
||||||
|
event.preventDefault();
|
||||||
|
// Save the url on electron-store, so we can get the value on withDeeplink HOC
|
||||||
|
store.set('OSX_DEEPLINK_URL', url);
|
||||||
|
sendMessage(mainWindow, url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.platform === 'win32' || process.platform === 'linux') {
|
||||||
|
const arg = searchUriInArgv(argv);
|
||||||
|
|
||||||
|
if (arg) {
|
||||||
|
sendMessage(mainWindow, arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -118,10 +118,11 @@ type electron$app = {
|
||||||
getName(): string,
|
getName(): string,
|
||||||
setName(name: string): void,
|
setName(name: string): void,
|
||||||
getLocale(): string,
|
getLocale(): string,
|
||||||
makeSingleInstance(callback: (argv: Array<string>, workingDirectory: string) => void): boolean,
|
requestSingleInstanceLock(): boolean,
|
||||||
|
setAsDefaultProtocolClient(schema: string): void,
|
||||||
releaseSingleInstance(): void,
|
releaseSingleInstance(): void,
|
||||||
disableHardwareAcceleration(): void,
|
disableHardwareAcceleration(): void,
|
||||||
on(event: string, callback: () => any): void,
|
on(event: string, callback: Function): void,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
"eslint-plugin-jsx-a11y": "^6.0.3",
|
"eslint-plugin-jsx-a11y": "^6.0.3",
|
||||||
"eslint-plugin-react": "^7.12.4",
|
"eslint-plugin-react": "^7.12.4",
|
||||||
"file-loader": "^2.0.0",
|
"file-loader": "^2.0.0",
|
||||||
"flow-bin": "^0.92.1",
|
"flow-bin": "^0.93.0",
|
||||||
"flow-coverage-report": "^0.6.1",
|
"flow-coverage-report": "^0.6.1",
|
||||||
"flow-typed": "^2.5.1",
|
"flow-typed": "^2.5.1",
|
||||||
"glow": "^1.2.2",
|
"glow": "^1.2.2",
|
||||||
|
@ -179,6 +179,12 @@
|
||||||
"win": {
|
"win": {
|
||||||
"target": "nsis",
|
"target": "nsis",
|
||||||
"icon": "./build/icons/win/icon.ico"
|
"icon": "./build/icons/win/icon.ico"
|
||||||
|
},
|
||||||
|
"protocols": {
|
||||||
|
"name": "zcash",
|
||||||
|
"schemes": [
|
||||||
|
"zcash"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
|
|
|
@ -4,7 +4,5 @@
|
||||||
import { globalShortcut, typeof BrowserWindow, typeof app as ElectronApp } from 'electron';
|
import { globalShortcut, typeof BrowserWindow, typeof app as ElectronApp } from 'electron';
|
||||||
|
|
||||||
export const registerDebugShortcut = (app: ElectronApp, mainWindow: BrowserWindow) => globalShortcut.register('CommandOrControl+Option+B', () => {
|
export const registerDebugShortcut = (app: ElectronApp, mainWindow: BrowserWindow) => globalShortcut.register('CommandOrControl+Option+B', () => {
|
||||||
// $FlowFixMe
|
|
||||||
app.dock.show();
|
|
||||||
mainWindow.webContents.openDevTools();
|
mainWindow.webContents.openDevTools();
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue