summaryrefslogtreecommitdiffhomepage
path: root/app
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2018-08-03 15:36:03 +0200
committerAndrej Mihajlov <and@mullvad.net>2018-08-08 16:25:34 +0200
commit9f01cc07d2d6da86d43a002e52a189f60b63eb5d (patch)
tree8f5f13a221aefba51d485b7e6e77d5228269cca3 /app
parent7cb837912df646992f63ad5ff61c26871f5c24b8 (diff)
downloadmullvadvpn-9f01cc07d2d6da86d43a002e52a189f60b63eb5d.tar.xz
mullvadvpn-9f01cc07d2d6da86d43a002e52a189f60b63eb5d.zip
Add launch screen
Diffstat (limited to 'app')
-rw-r--r--app/app.js16
-rw-r--r--app/components/Launch.js58
-rw-r--r--app/containers/LaunchPage.js23
-rw-r--r--app/routes.js26
4 files changed, 117 insertions, 6 deletions
diff --git a/app/app.js b/app/app.js
index 6a465e0867..4ccf992b03 100644
--- a/app/app.js
+++ b/app/app.js
@@ -137,7 +137,7 @@ export default class AppRenderer {
// Redirect the user after some time to allow for
// the 'Login Successful' screen to be visible
setTimeout(async () => {
- if (history.location.pathname === '/') {
+ if (history.location.pathname === '/login') {
actions.history.replace('/connect');
}
@@ -168,15 +168,19 @@ export default class AppRenderer {
actions.account.updateAccountToken(accountToken);
actions.account.loginSuccessful();
+ // take user to main view if user is still at launch screen `/`
if (history.location.pathname === '/') {
actions.history.replace('/connect');
}
} else {
log.debug('No account set, showing login view.');
+
+ // show window when account is not set
ipcRenderer.send('show-window');
- if (history.location.pathname !== '/') {
- actions.history.replace('/');
+ // take user to `/login` screen if user is at launch screen `/`
+ if (history.location.pathname === '/') {
+ actions.history.replace('/login');
}
}
}
@@ -191,7 +195,7 @@ export default class AppRenderer {
this._fetchAccountHistory(),
]);
actions.account.loggedOut();
- actions.history.replace('/');
+ actions.history.replace('/login');
} catch (e) {
log.info('Failed to logout: ', e.message);
}
@@ -385,6 +389,7 @@ export default class AppRenderer {
// save to redux that the app connected to daemon
this._reduxActions.daemon.connected();
+ // reset the reconnect backoff when connection established.
this._reconnectBackoff.reset();
// authenticate once connected
@@ -452,6 +457,9 @@ export default class AppRenderer {
this._reconnectBackoff.attempt(() => {
recover();
});
+
+ // take user back to the launch screen `/`.
+ actions.history.replace('/');
}
}
diff --git a/app/components/Launch.js b/app/components/Launch.js
new file mode 100644
index 0000000000..bab877dd53
--- /dev/null
+++ b/app/components/Launch.js
@@ -0,0 +1,58 @@
+// @flow
+import * as React from 'react';
+import { Component, Styles, View, Text } from 'reactxp';
+import { Layout, Container, Header } from './Layout';
+import { SettingsBarButton } from './HeaderBar';
+import Img from './Img';
+import { colors } from '../config';
+
+const styles = {
+ container: Styles.createViewStyle({
+ flex: 1,
+ flexDirection: 'column',
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginTop: -150,
+ }),
+ logo: Styles.createViewStyle({
+ marginBottom: 4,
+ }),
+ title: Styles.createTextStyle({
+ fontFamily: 'DINPro',
+ fontSize: 24,
+ fontWeight: '900',
+ lineHeight: 30,
+ letterSpacing: -0.5,
+ color: colors.white60,
+ marginBottom: 4,
+ }),
+ subtitle: Styles.createTextStyle({
+ fontFamily: 'Open Sans',
+ fontSize: 14,
+ lineHeight: 20,
+ color: colors.white40,
+ }),
+};
+
+type Props = {
+ openSettings: () => void,
+};
+
+export default class Launch extends Component<Props> {
+ render() {
+ return (
+ <Layout>
+ <Header>
+ <SettingsBarButton onPress={this.props.openSettings} />
+ </Header>
+ <Container>
+ <View style={styles.container} testName="headerbar__container">
+ <Img height={120} width={120} source="logo-icon" style={styles.logo} />
+ <Text style={styles.title}>{'MULLVAD VPN'}</Text>
+ <Text style={styles.subtitle}>{'Connecting to daemon...'}</Text>
+ </View>
+ </Container>
+ </Layout>
+ );
+ }
+}
diff --git a/app/containers/LaunchPage.js b/app/containers/LaunchPage.js
new file mode 100644
index 0000000000..1b265dd030
--- /dev/null
+++ b/app/containers/LaunchPage.js
@@ -0,0 +1,23 @@
+// @flow
+import { bindActionCreators } from 'redux';
+import { connect } from 'react-redux';
+import { push } from 'connected-react-router';
+import Launch from '../components/Launch';
+
+import type { ReduxState, ReduxDispatch } from '../redux/store';
+import type { SharedRouteProps } from '../routes';
+
+const mapStateToProps = (_state: ReduxState) => ({});
+const mapDispatchToProps = (dispatch: ReduxDispatch, _props: SharedRouteProps) => {
+ const history = bindActionCreators({ push }, dispatch);
+ return {
+ openSettings: () => {
+ history.push('/settings');
+ },
+ };
+};
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps,
+)(Launch);
diff --git a/app/routes.js b/app/routes.js
index 95ad24e876..37c6398cac 100644
--- a/app/routes.js
+++ b/app/routes.js
@@ -4,6 +4,7 @@ import * as React from 'react';
import { Switch, Route, Redirect } from 'react-router';
import TransitionContainer from './components/TransitionContainer';
import PlatformWindow from './components/PlatformWindow';
+import LaunchPage from './containers/LaunchPage';
import LoginPage from './containers/LoginPage';
import ConnectPage from './containers/ConnectPage';
import SettingsPage from './containers/SettingsPage';
@@ -62,7 +63,7 @@ export default function makeRoutes(
if (isLoggedIn) {
return renderMergedProps(component, routeProps, otherProps);
} else {
- return <Redirect to={'/'} />;
+ return <Redirect to={'/login'} />;
}
}}
/>
@@ -91,6 +92,26 @@ export default function makeRoutes(
);
};
+ // Renders launch route that is only available when daemon is not connected.
+ // Otherwise this route redirects user to /login.
+ // example: <LaunchRoute path="/" component={ MyComponent } />
+ const LaunchRoute = ({ component, ...otherProps }) => {
+ return (
+ // $FlowFixMe: This has been fixed in Flow 0.71
+ <Route
+ {...otherProps}
+ render={(routeProps) => {
+ const { daemon } = getState();
+ if (daemon.isConnected) {
+ return <Redirect to={'/login'} />;
+ } else {
+ return renderMergedProps(component, routeProps, otherProps);
+ }
+ }}
+ />
+ );
+ };
+
// store previous route
let previousRoute: ?string;
@@ -107,7 +128,8 @@ export default function makeRoutes(
<PlatformWindow>
<TransitionContainer {...transitionProps}>
<Switch key={location.key} location={location}>
- <LoginRoute exact path="/" component={LoginPage} />
+ <LaunchRoute exact path="/" component={LaunchPage} />
+ <LoginRoute exact path="/login" component={LoginPage} />
<PrivateRoute exact path="/connect" component={ConnectPage} />
<PublicRoute exact path="/settings" component={SettingsPage} />
<PrivateRoute exact path="/settings/account" component={AccountPage} />