diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2018-08-03 15:36:03 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2018-08-08 16:25:34 +0200 |
| commit | 9f01cc07d2d6da86d43a002e52a189f60b63eb5d (patch) | |
| tree | 8f5f13a221aefba51d485b7e6e77d5228269cca3 /app | |
| parent | 7cb837912df646992f63ad5ff61c26871f5c24b8 (diff) | |
| download | mullvadvpn-9f01cc07d2d6da86d43a002e52a189f60b63eb5d.tar.xz mullvadvpn-9f01cc07d2d6da86d43a002e52a189f60b63eb5d.zip | |
Add launch screen
Diffstat (limited to 'app')
| -rw-r--r-- | app/app.js | 16 | ||||
| -rw-r--r-- | app/components/Launch.js | 58 | ||||
| -rw-r--r-- | app/containers/LaunchPage.js | 23 | ||||
| -rw-r--r-- | app/routes.js | 26 |
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} /> |
