Skip to content
This repository was archived by the owner on Feb 23, 2021. It is now read-only.

Commit e6a9488

Browse files
Implement loader - syncing chain screen
1 parent 8017441 commit e6a9488

File tree

8 files changed

+217
-48
lines changed

8 files changed

+217
-48
lines changed

src/component/spinner.js

Lines changed: 3 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import {
66
ViewPropTypes,
77
} from 'react-native';
88
import PropTypes from 'prop-types';
9-
import { color, font } from './style';
9+
import { color } from './style';
1010
import Icon from './icon';
11-
import Text from './text';
1211
import Svg, { Path, Circle, Defs, Stop, LinearGradient } from './svg';
1312

1413
//
@@ -30,48 +29,6 @@ export const SmallSpinner = ({ ...props }) => (
3029
/>
3130
);
3231

33-
//
34-
// Load Network Spinner
35-
//
36-
37-
const sizeM = 80;
38-
const progressWidthM = 3;
39-
40-
const loadNetworkStyles = StyleSheet.create({
41-
spinner: {
42-
margin: 20,
43-
},
44-
bolt: {
45-
height: 126 / 4.5,
46-
width: 64 / 4.5,
47-
},
48-
copy: {
49-
fontSize: font.sizeXS,
50-
marginTop: 5,
51-
color: color.white,
52-
textAlign: 'center',
53-
},
54-
});
55-
56-
export const LoadNetworkSpinner = ({ percentage, msg }) => (
57-
<View style={loadNetworkStyles.spinner}>
58-
<ResizeableSpinner
59-
percentage={percentage}
60-
size={sizeM}
61-
progressWidth={progressWidthM}
62-
gradient="loadNetworkGrad"
63-
icon="lightning-bolt"
64-
iconStyles={loadNetworkStyles.bolt}
65-
/>
66-
<Text style={loadNetworkStyles.copy}>{msg}</Text>
67-
</View>
68-
);
69-
70-
LoadNetworkSpinner.propTypes = {
71-
percentage: PropTypes.number.isRequired,
72-
msg: PropTypes.string.isRequired,
73-
};
74-
7532
//
7633
// Resizeable Spinner
7734
//
@@ -88,7 +45,7 @@ const resizeableStyles = StyleSheet.create({
8845
},
8946
});
9047

91-
const ResizeableSpinner = ({
48+
export const ResizeableSpinner = ({
9249
percentage,
9350
size,
9451
gradient,
@@ -140,7 +97,7 @@ const Gradients = () => (
14097
<Stop offset="100%" stopColor={color.purple} />
14198
</LinearGradient>
14299
<LinearGradient id="openChannelsGrad" x1="0" y1="0" x2="1" y2="1">
143-
<Stop offset="0%" stopColor={color.openChansLightPurple} />
100+
<Stop offset="0%" stopColor={color.lightPurple} />
144101
<Stop offset="50%" stopColor={color.openChansDarkPurple} />
145102
</LinearGradient>
146103
</Defs>

src/component/style.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ export const color = {
1414
loadNetworkLightPurple: '#A95BDC',
1515
loadNetworkMedPurple: '#651399',
1616
loadNetworkMedDarkPurple: '#610F96',
17-
openChansLightPurple: '#A540CD',
1817
openChansDarkPurple: '#6B249C',
1918
orange: '#F66B1C',
2019
blackDark: '#252F4A',

src/computed/loader-msg.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { computed, extendObservable } from 'mobx';
2+
3+
const ComputedLoaderMsg = store => {
4+
extendObservable(store, {
5+
loadingMsg: computed(() => {
6+
const { percentSynced: percent } = store;
7+
return getLoadingMsg(percent);
8+
}),
9+
});
10+
};
11+
12+
export const LOADING_COPY_START = 'Loading network...';
13+
export const LOADING_COPY_MID = 'Almost done...';
14+
export const LOADING_COPY_END = 'Just a few seconds...';
15+
export const LOADING_PERCENT_MID = 50;
16+
export const LOADING_PERCENT_END = 95;
17+
18+
/**
19+
* Retrieve the loading message corresponding to the percent
20+
* @param {number} percent The percentage the network is synced.
21+
* @return {string} The message corresponding to the percent.
22+
*/
23+
// TODO: error handling for network error
24+
export const getLoadingMsg = percent => {
25+
percent = Number(percent);
26+
if (isNaN(percent)) {
27+
percent = 0;
28+
} else if (percent < 0) {
29+
percent = 0;
30+
} else if (percent > 100) {
31+
percent = 100;
32+
}
33+
if (percent < LOADING_PERCENT_MID) {
34+
return LOADING_COPY_START;
35+
} else if (percent < LOADING_PERCENT_END) {
36+
return LOADING_COPY_MID;
37+
} else {
38+
return LOADING_COPY_END;
39+
}
40+
};
41+
42+
export default ComputedLoaderMsg;

src/store.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { extendObservable } from 'mobx';
2+
import ComputedLoaderMsg from './computed/loader-msg';
23
import ComputedWallet from './computed/wallet';
34
import ComputedTransaction from './computed/transaction';
45
import ComputedChannel from './computed/channel';
@@ -17,6 +18,7 @@ export class Store {
1718
walletUnlocked: false, // Is the wallet unlocked
1819
lndReady: false, // Is lnd process running
1920
syncedToChain: false, // Is lnd synced to blockchain
21+
percentSynced: 0, // Expects 0-100 range
2022
route: DEFAULT_ROUTE,
2123
blockHeight: null,
2224
balanceSatoshis: 0,
@@ -72,6 +74,7 @@ export class Store {
7274
}
7375

7476
init() {
77+
ComputedLoaderMsg(this);
7578
ComputedWallet(this);
7679
ComputedTransaction(this);
7780
ComputedChannel(this);

src/view/loader-syncing.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import React from 'react';
2+
import { StyleSheet, View } from 'react-native';
3+
import PropTypes from 'prop-types';
4+
import Background from '../component/background';
5+
import { Text, H1Text, CopyText } from '../component/text';
6+
import MainContent from '../component/main-content';
7+
import { ResizeableSpinner } from '../component/spinner';
8+
import { DownButton } from '../component/button';
9+
import { color, font } from '../component/style';
10+
11+
const styles = StyleSheet.create({
12+
content: {
13+
alignItems: 'center',
14+
},
15+
downBtn: {
16+
margin: 25,
17+
},
18+
});
19+
20+
const LoaderSyncingView = ({ store }) => (
21+
<Background color={color.blackDark}>
22+
<MainContent style={styles.content}>
23+
<LoadNetworkSpinner
24+
percentage={store.percentSynced}
25+
msg={store.loadingMsg}
26+
/>
27+
<CopySection />
28+
<DownButton onPress={() => {}} style={styles.downBtn}>
29+
Learn More
30+
</DownButton>
31+
</MainContent>
32+
</Background>
33+
);
34+
35+
LoaderSyncingView.propTypes = {
36+
store: PropTypes.object.isRequired,
37+
};
38+
39+
//
40+
// Load Network Spinner
41+
//
42+
43+
const size = 80;
44+
const progressWidth = 3;
45+
46+
const loadNetworkStyles = StyleSheet.create({
47+
spinner: {
48+
margin: 20,
49+
},
50+
bolt: {
51+
height: 126 / 4.5,
52+
width: 64 / 4.5,
53+
},
54+
copy: {
55+
fontSize: font.sizeXS,
56+
marginTop: 5,
57+
color: color.white,
58+
textAlign: 'center',
59+
},
60+
});
61+
62+
export const LoadNetworkSpinner = ({ percentage, msg }) => (
63+
<View style={loadNetworkStyles.spinner}>
64+
<ResizeableSpinner
65+
percentage={percentage}
66+
size={size}
67+
progressWidth={progressWidth}
68+
gradient="loadNetworkGrad"
69+
icon="lightning-bolt"
70+
iconStyles={loadNetworkStyles.bolt}
71+
/>
72+
<Text style={loadNetworkStyles.copy}>{msg}</Text>
73+
</View>
74+
);
75+
76+
LoadNetworkSpinner.propTypes = {
77+
percentage: PropTypes.number.isRequired,
78+
msg: PropTypes.string.isRequired,
79+
};
80+
81+
//
82+
// Copy Section
83+
//
84+
85+
const copyStyles = StyleSheet.create({
86+
wrapper: {
87+
flex: 1,
88+
justifyContent: 'center',
89+
alignItems: 'center',
90+
},
91+
title: {
92+
textAlign: 'center',
93+
marginTop: 30,
94+
},
95+
copyTxt: {
96+
textAlign: 'center',
97+
marginTop: 10,
98+
maxWidth: 450,
99+
paddingBottom: 30,
100+
},
101+
});
102+
103+
const CopySection = () => (
104+
<View style={copyStyles.wrapper}>
105+
<H1Text style={copyStyles.title}>Almost there</H1Text>
106+
<CopyText style={copyStyles.copyTxt}>
107+
{
108+
"Why not learn more about what we're doing at Lightning Labs? Or grab a coffee. This could take about 30 minutes."
109+
}
110+
</CopyText>
111+
</View>
112+
);
113+
114+
export default LoaderSyncingView;

stories/component/spinner.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import React from 'react';
22
import { storiesOf } from '@storybook/react';
33
import MainContent from '../../src/component/main-content';
4-
import { LoadNetworkSpinner, SmallSpinner } from '../../src/component/spinner';
4+
import { SmallSpinner } from '../../src/component/spinner';
5+
import { LoadNetworkSpinner } from '../../src/view/loader-syncing';
56
import { color } from '../../src/component/style';
67
import Background from '../../src/component/background';
78

stories/screen.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import PayBitcoinConfirm from '../src/view/pay-bitcoin-confirm';
3737
import PayBitcoinDone from '../src/view/pay-bitcoin-done';
3838
import NoRoute from '../src/view/no-route';
3939
import Loader from '../src/view/loader';
40+
import LoaderSyncing from '../src/view/loader-syncing';
4041
import SeedSuccess from '../src/view/seed-success';
4142
import Seed from '../src/view/seed';
4243
import SeedVerify from '../src/view/seed-verify';
@@ -92,6 +93,7 @@ storiesOf('Screens', module)
9293
<NewAddress store={store} nav={nav} invoice={invoice} />
9394
))
9495
.add('Wait', () => <Wait />)
96+
.add('Loader - Syncing Chain', () => <LoaderSyncing store={store} />)
9597
.add('Home', () => (
9698
<Home
9799
store={store}
@@ -218,6 +220,7 @@ store.pendingChannels = [...Array(6)].map((x, i) => ({
218220
status: i % 2 === 0 ? 'pending-closing' : 'pending-open',
219221
}));
220222
store.selectedChannel = store.computedChannels && store.computedChannels[0];
223+
store.percentSynced = 30;
221224
store.seedMnemonic = [
222225
'empower',
223226
'neglect',
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { observable, useStrict } from 'mobx';
2+
import ComputedLoaderMsg from '../../../src/computed/loader-msg';
3+
import {
4+
LOADING_COPY_START,
5+
LOADING_COPY_MID,
6+
LOADING_COPY_END,
7+
LOADING_PERCENT_MID,
8+
LOADING_PERCENT_END,
9+
} from '../../../src/computed/loader-msg';
10+
11+
describe('Computed Loader Msg Unit Tests', () => {
12+
let store;
13+
14+
beforeEach(() => {
15+
useStrict(false);
16+
store = observable({
17+
percentSynced: 0,
18+
});
19+
});
20+
21+
// TODO: figure out how error handling will work on network error
22+
describe('ComputedLoaderMsg()', () => {
23+
it('should work with non-numerical values', () => {
24+
store.percentSynced = null;
25+
ComputedLoaderMsg(store);
26+
expect(store.loadingMsg, 'to equal', LOADING_COPY_START);
27+
});
28+
29+
it('should work for < 0 and > 100 percentages', () => {
30+
store.percentSynced = -1;
31+
ComputedLoaderMsg(store);
32+
expect(store.loadingMsg, 'to equal', LOADING_COPY_START);
33+
store.percentSynced = 101;
34+
ComputedLoaderMsg(store);
35+
expect(store.loadingMsg, 'to equal', LOADING_COPY_END);
36+
});
37+
38+
it('should work for each milestone percentage', () => {
39+
store.percentSynced = 10;
40+
ComputedLoaderMsg(store);
41+
expect(store.loadingMsg, 'to equal', LOADING_COPY_START);
42+
store.percentSynced = LOADING_PERCENT_MID;
43+
ComputedLoaderMsg(store);
44+
expect(store.loadingMsg, 'to equal', LOADING_COPY_MID);
45+
store.percentSynced = LOADING_PERCENT_END;
46+
ComputedLoaderMsg(store);
47+
expect(store.loadingMsg, 'to equal', LOADING_COPY_END);
48+
});
49+
});
50+
});

0 commit comments

Comments
 (0)