summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2019-09-16 14:43:58 +0200
committerAndrej Mihajlov <and@mullvad.net>2019-09-17 09:51:13 +0200
commite901869aee45d171e189bb0cae3af478cb325a4c (patch)
tree11fa5bd3920270ec0f390baaf900b409700f00d6
parentb0e0f72fe364615ffbc51b50e12ef3ce30b1a5c1 (diff)
downloadmullvadvpn-e901869aee45d171e189bb0cae3af478cb325a4c.tar.xz
mullvadvpn-e901869aee45d171e189bb0cae3af478cb325a4c.zip
Remove sticky context and instead put the contents inside of navigation bar
-rw-r--r--gui/src/renderer/components/Account.tsx12
-rw-r--r--gui/src/renderer/components/AdvancedSettings.tsx19
-rw-r--r--gui/src/renderer/components/NavigationBar.tsx176
-rw-r--r--gui/src/renderer/components/Preferences.tsx19
-rw-r--r--gui/src/renderer/components/SelectLocation.tsx84
-rw-r--r--gui/src/renderer/components/SelectLocationStyles.tsx16
-rw-r--r--gui/src/renderer/components/Settings.tsx13
-rw-r--r--gui/src/renderer/components/Support.tsx12
-rw-r--r--gui/src/renderer/components/WireguardKeys.tsx12
9 files changed, 108 insertions, 255 deletions
diff --git a/gui/src/renderer/components/Account.tsx b/gui/src/renderer/components/Account.tsx
index efe8ff2d13..fb4eb6bf35 100644
--- a/gui/src/renderer/components/Account.tsx
+++ b/gui/src/renderer/components/Account.tsx
@@ -6,7 +6,7 @@ import styles from './AccountStyles';
import * as AppButton from './AppButton';
import ClipboardLabel from './ClipboardLabel';
import { Container, Layout } from './Layout';
-import { BackBarItem, NavigationBar } from './NavigationBar';
+import { BackBarItem, NavigationBar, NavigationItems } from './NavigationBar';
import SettingsHeader, { HeaderTitle } from './SettingsHeader';
import { AccountToken } from '../../shared/daemon-rpc-types';
@@ -28,10 +28,12 @@ export default class Account extends Component<IProps> {
<Container>
<View style={styles.account}>
<NavigationBar>
- <BackBarItem action={this.props.onClose}>
- {// TRANSLATORS: Back button in navigation bar
- messages.pgettext('account-nav', 'Settings')}
- </BackBarItem>
+ <NavigationItems>
+ <BackBarItem action={this.props.onClose}>
+ {// TRANSLATORS: Back button in navigation bar
+ messages.pgettext('account-nav', 'Settings')}
+ </BackBarItem>
+ </NavigationItems>
</NavigationBar>
<View style={styles.account__container}>
diff --git a/gui/src/renderer/components/AdvancedSettings.tsx b/gui/src/renderer/components/AdvancedSettings.tsx
index 6abf4c4958..c9a985789b 100644
--- a/gui/src/renderer/components/AdvancedSettings.tsx
+++ b/gui/src/renderer/components/AdvancedSettings.tsx
@@ -11,6 +11,7 @@ import {
BackBarItem,
NavigationBar,
NavigationContainer,
+ NavigationItems,
NavigationScrollbars,
TitleBarItem,
} from './NavigationBar';
@@ -162,14 +163,16 @@ export default class AdvancedSettings extends Component<IProps, IState> {
<View style={styles.advanced_settings}>
<NavigationContainer>
<NavigationBar>
- <BackBarItem action={this.props.onClose}>
- {// TRANSLATORS: Back button in navigation bar
- messages.pgettext('advanced-settings-nav', 'Settings')}
- </BackBarItem>
- <TitleBarItem>
- {// TRANSLATORS: Title label in navigation bar
- messages.pgettext('advanced-settings-nav', 'Advanced')}
- </TitleBarItem>
+ <NavigationItems>
+ <BackBarItem action={this.props.onClose}>
+ {// TRANSLATORS: Back button in navigation bar
+ messages.pgettext('advanced-settings-nav', 'Settings')}
+ </BackBarItem>
+ <TitleBarItem>
+ {// TRANSLATORS: Title label in navigation bar
+ messages.pgettext('advanced-settings-nav', 'Advanced')}
+ </TitleBarItem>
+ </NavigationItems>
</NavigationBar>
<View style={styles.advanced_settings__container}>
diff --git a/gui/src/renderer/components/NavigationBar.tsx b/gui/src/renderer/components/NavigationBar.tsx
index 097422aa10..cba9df0786 100644
--- a/gui/src/renderer/components/NavigationBar.tsx
+++ b/gui/src/renderer/components/NavigationBar.tsx
@@ -1,5 +1,4 @@
import * as React from 'react';
-import * as ReactDOM from 'react-dom';
import { Animated, Button, Component, Styles, Text, Types, UserInterface, View } from 'reactxp';
import { colors } from '../../config.json';
import CustomScrollbars, { IScrollEvent } from './CustomScrollbars';
@@ -12,9 +11,9 @@ const styles = {
paddingHorizontal: 12,
paddingBottom: 12,
}),
- content: Styles.createViewStyle({
+ wrapper: Styles.createViewStyle({
flex: 1,
- flexDirection: 'row',
+ flexDirection: 'column',
}),
separator: Styles.createViewStyle({
backgroundColor: 'rgba(0, 0, 0, 0.2)',
@@ -34,6 +33,10 @@ const styles = {
paddingTop: 12,
}),
},
+ navigationItems: Styles.createViewStyle({
+ flex: 1,
+ flexDirection: 'row',
+ }),
navigationBarTitle: {
container: Styles.createViewStyle({
flex: 1,
@@ -113,13 +116,6 @@ const styles = {
}),
},
},
- stickyContentHolder: Styles.createViewStyle({
- position: 'absolute',
- top: 0,
- left: 0,
- right: 0,
- backgroundColor: colors.darkBlue,
- }),
};
interface INavigationScrollContextValue {
@@ -178,15 +174,8 @@ export class NavigationContainer extends Component {
}
private updateBarAppearance(event: IScrollEvent) {
- // detect if any of child elements provide a sticky context
- // in that case the navigation bar does not draw the separator line
- // since the sticky content is expected to include it.
- const hasSticky = React.Children.toArray(this.props.children).some((child) => {
- return React.isValidElement(child) && child.type === StickyContentContainer;
- });
-
// that's where SettingsHeader.HeaderTitle intersects the navigation bar
- const showsBarSeparator = event.scrollTop > 11 && !hasSticky;
+ const showsBarSeparator = event.scrollTop > 11;
// that's when SettingsHeader.HeaderTitle goes behind the navigation bar
const showsBarTitle = event.scrollTop > 20;
@@ -344,87 +333,6 @@ class PrivateBarItemAnimationContainer extends Component<IPrivateBarItemAnimatio
}
}
-interface IStickyContentContext {
- container: HTMLDivElement | null;
- holder: React.Ref<View>;
- isSticky: boolean;
-}
-
-const StickyContentContext = React.createContext<IStickyContentContext>({
- container: null,
- holder: React.createRef<View>(),
- isSticky: false,
-});
-
-export class StickyContentContainer extends Component<{
- style: Types.StyleRuleSet<Types.ViewStyle>;
-}> {
- public static contextType = NavigationScrollContext;
- public context!: React.ContextType<typeof NavigationScrollContext>;
-
- public state = {
- container: null,
- holder: React.createRef<View>(),
- isSticky: false,
- };
-
- public componentDidMount() {
- if (this.context.navigationContainer) {
- this.context.navigationContainer.addScrollEventListener(this.onScroll);
- }
- }
-
- public componentWillUnmount() {
- if (this.context.navigationContainer) {
- this.context.navigationContainer.removeScrollEventListener(this.onScroll);
- }
- }
-
- public render() {
- return (
- <div
- ref={this.onRef}
- style={{
- position: 'relative',
- display: 'flex',
- flexDirection: 'column',
- overflow: 'hidden',
- }}>
- <View style={this.props.style}>
- <StickyContentContext.Provider value={this.state}>
- {this.props.children}
- </StickyContentContext.Provider>
- </View>
- </div>
- );
- }
-
- private onScroll = async (_scrollEvent: IScrollEvent) => {
- const holder = this.state.holder.current;
-
- if (holder) {
- let layout: Types.LayoutInfo;
-
- try {
- layout = await UserInterface.measureLayoutRelativeToAncestor(holder, this);
- } catch {
- // TODO: handle error
- return;
- }
-
- const isSticky = layout.y <= 0;
-
- if (this.state.isSticky !== isSticky) {
- this.setState({ isSticky });
- }
- }
- };
-
- private onRef = (ref: HTMLDivElement | null) => {
- this.setState({ container: ref });
- };
-}
-
interface IScopeBarProps {
defaultSelectedIndex: number;
onChange?: (selectedIndex: number) => void;
@@ -493,67 +401,6 @@ export class ScopeBar extends Component<IScopeBarProps, IScopeBarState> {
}
}
-interface IStickyContentHolderProps {
- style?: Types.ViewStyleRuleSet;
-}
-
-interface IStickyContentHolderState {
- contentHeight: number;
-}
-
-export class StickyContentHolder extends Component<
- IStickyContentHolderProps,
- IStickyContentHolderState
-> {
- public state = {
- contentHeight: 0,
- };
-
- public render() {
- return (
- <StickyContentContext.Consumer>
- {(stickyContext) => {
- const contentStyle = stickyContext.isSticky ? styles.stickyContentHolder : undefined;
- const contentPlaceholderStyle = stickyContext.isSticky
- ? Styles.createViewStyle(
- {
- height: this.state.contentHeight,
- },
- false,
- )
- : undefined;
-
- const children = (
- <View style={contentStyle} onLayout={this.onLayout}>
- {this.props.children}
- {stickyContext.isSticky ? <NavigationBarSeparator /> : undefined}
- </View>
- );
-
- return (
- <View style={this.props.style} ref={stickyContext.holder}>
- {stickyContext.isSticky && stickyContext.container ? (
- <React.Fragment>
- <View style={contentPlaceholderStyle} />
- {ReactDOM.createPortal(children, stickyContext.container)}
- </React.Fragment>
- ) : (
- children
- )}
- </View>
- );
- }}
- </StickyContentContext.Consumer>
- );
- }
-
- private onLayout = async (layout: Types.LayoutInfo) => {
- if (this.state.contentHeight !== layout.height) {
- this.setState({ contentHeight: layout.height });
- }
- };
-}
-
interface IScopeBarItemProps {
children?: React.ReactText;
selected?: boolean;
@@ -598,6 +445,7 @@ function NavigationBarSeparator() {
interface INavigationBarProps {
children?: React.ReactNode;
+ alwaysDisplayBarTitle?: boolean;
}
export const NavigationBar = React.forwardRef(function NavigationBarT(
@@ -609,7 +457,7 @@ export const NavigationBar = React.forwardRef(function NavigationBarT(
{(context) => (
<PrivateNavigationBar
ref={ref}
- showsBarTitle={context.showsBarTitle}
+ showsBarTitle={props.alwaysDisplayBarTitle || context.showsBarTitle}
showsBarSeparator={context.showsBarSeparator}>
{props.children}
</PrivateNavigationBar>
@@ -635,6 +483,10 @@ const PrivateTitleBarItemContext = React.createContext({
measuringTextRef: React.createRef<Text>(),
});
+export function NavigationItems(props: { children: React.ReactNode }) {
+ return <View style={styles.navigationItems}>{props.children}</View>;
+}
+
class PrivateNavigationBar extends Component<
IPrivateNavigationBarProps,
IPrivateNavigationBarState
@@ -661,7 +513,7 @@ class PrivateNavigationBar extends Component<
public render() {
return (
<View style={[styles.navigationBar.default, this.getPlatformStyle()]}>
- <View style={styles.navigationBar.content} onLayout={this.onLayout}>
+ <View style={styles.navigationBar.wrapper} onLayout={this.onLayout}>
<PrivateTitleBarItemContext.Provider
value={{
titleAdjustment: this.state.titleAdjustment,
diff --git a/gui/src/renderer/components/Preferences.tsx b/gui/src/renderer/components/Preferences.tsx
index 2c6df58a99..b295c68308 100644
--- a/gui/src/renderer/components/Preferences.tsx
+++ b/gui/src/renderer/components/Preferences.tsx
@@ -7,6 +7,7 @@ import {
BackBarItem,
NavigationBar,
NavigationContainer,
+ NavigationItems,
NavigationScrollbars,
TitleBarItem,
} from './NavigationBar';
@@ -39,14 +40,16 @@ export default class Preferences extends Component<IProps> {
<View style={styles.preferences}>
<NavigationContainer>
<NavigationBar>
- <BackBarItem action={this.props.onClose}>
- {// TRANSLATORS: Back button in navigation bar
- messages.pgettext('preferences-nav', 'Settings')}
- </BackBarItem>
- <TitleBarItem>
- {// TRANSLATORS: Title label in navigation bar
- messages.pgettext('preferences-nav', 'Preferences')}
- </TitleBarItem>
+ <NavigationItems>
+ <BackBarItem action={this.props.onClose}>
+ {// TRANSLATORS: Back button in navigation bar
+ messages.pgettext('preferences-nav', 'Settings')}
+ </BackBarItem>
+ <TitleBarItem>
+ {// TRANSLATORS: Title label in navigation bar
+ messages.pgettext('preferences-nav', 'Preferences')}
+ </TitleBarItem>
+ </NavigationItems>
</NavigationBar>
<View style={styles.preferences__container}>
diff --git a/gui/src/renderer/components/SelectLocation.tsx b/gui/src/renderer/components/SelectLocation.tsx
index 3753e3312a..0018446291 100644
--- a/gui/src/renderer/components/SelectLocation.tsx
+++ b/gui/src/renderer/components/SelectLocation.tsx
@@ -14,15 +14,14 @@ import {
CloseBarItem,
NavigationBar,
NavigationContainer,
+ NavigationItems,
NavigationScrollbars,
ScopeBar,
ScopeBarItem,
- StickyContentContainer,
- StickyContentHolder,
TitleBarItem,
} from './NavigationBar';
import styles from './SelectLocationStyles';
-import SettingsHeader, { HeaderSubTitle, HeaderTitle } from './SettingsHeader';
+import { HeaderSubTitle } from './SettingsHeader';
interface IProps {
locationScope: LocationScope;
@@ -75,51 +74,44 @@ export default class SelectLocation extends Component<IProps> {
<Container>
<View style={styles.select_location}>
<NavigationContainer>
- <NavigationBar>
- <CloseBarItem action={this.props.onClose} />
- <TitleBarItem>
- {// TRANSLATORS: Title label in navigation bar
- messages.pgettext('select-location-nav', 'Select location')}
- </TitleBarItem>
+ <NavigationBar alwaysDisplayBarTitle={true}>
+ <NavigationItems>
+ <CloseBarItem action={this.props.onClose} />
+ <TitleBarItem>
+ {// TRANSLATORS: Title label in navigation bar
+ messages.pgettext('select-location-nav', 'Select location')}
+ </TitleBarItem>
+ </NavigationItems>
+ <View style={styles.navigationBarAttachment}>
+ <HeaderSubTitle>
+ {this.props.allowBridgeSelection
+ ? messages.pgettext(
+ 'select-location-view',
+ 'While connected, your traffic will be routed through two secure locations, the entry point (a bridge server) and the exit point (a VPN server).',
+ )
+ : messages.pgettext(
+ 'select-location-view',
+ 'While connected, your real location is masked with a private and secure location in the selected region.',
+ )}
+ </HeaderSubTitle>
+ {this.props.allowBridgeSelection && (
+ <ScopeBar
+ style={styles.scopeBar}
+ defaultSelectedIndex={this.props.locationScope}
+ onChange={this.props.onChangeLocationScope}>
+ <ScopeBarItem>
+ {messages.pgettext('select-location-nav', 'Entry')}
+ </ScopeBarItem>
+ <ScopeBarItem>
+ {messages.pgettext('select-location-nav', 'Exit')}
+ </ScopeBarItem>
+ </ScopeBar>
+ )}
+ </View>
</NavigationBar>
- <StickyContentContainer style={styles.container}>
+ <View style={styles.container}>
<NavigationScrollbars ref={this.scrollView}>
<View style={styles.content}>
- <SettingsHeader
- style={this.props.allowBridgeSelection ? styles.headerWithScope : undefined}>
- <HeaderTitle>
- {messages.pgettext('select-location-view', 'Select location')}
- </HeaderTitle>
- <HeaderSubTitle>
- {this.props.allowBridgeSelection
- ? messages.pgettext(
- 'select-location-view',
- 'While connected, your traffic will be routed through two secure locations, the entry point (a bridge server) and the exit point (a VPN server).',
- )
- : messages.pgettext(
- 'select-location-view',
- 'While connected, your real location is masked with a private and secure location in the selected region.',
- )}
- </HeaderSubTitle>
- </SettingsHeader>
-
- {this.props.allowBridgeSelection && (
- <StickyContentHolder style={styles.stickyHolder}>
- <View style={styles.stickyContent}>
- <ScopeBar
- defaultSelectedIndex={this.props.locationScope}
- onChange={this.props.onChangeLocationScope}>
- <ScopeBarItem>
- {messages.pgettext('select-location-nav', 'Entry')}
- </ScopeBarItem>
- <ScopeBarItem>
- {messages.pgettext('select-location-nav', 'Exit')}
- </ScopeBarItem>
- </ScopeBar>
- </View>
- </StickyContentHolder>
- )}
-
{this.props.locationScope === LocationScope.relay ? (
<LocationList
key={'exit-locations'}
@@ -151,7 +143,7 @@ export default class SelectLocation extends Component<IProps> {
)}
</View>
</NavigationScrollbars>
- </StickyContentContainer>
+ </View>
</NavigationContainer>
</View>
</Container>
diff --git a/gui/src/renderer/components/SelectLocationStyles.tsx b/gui/src/renderer/components/SelectLocationStyles.tsx
index bfda9c1055..ad6c116436 100644
--- a/gui/src/renderer/components/SelectLocationStyles.tsx
+++ b/gui/src/renderer/components/SelectLocationStyles.tsx
@@ -13,18 +13,12 @@ export default {
content: Styles.createViewStyle({
overflow: 'visible',
}),
- headerWithScope: Styles.createViewStyle({
- paddingBottom: 4,
+ navigationBarAttachment: Styles.createTextStyle({
+ marginTop: 8,
+ paddingHorizontal: 4,
}),
- stickyHolder: Styles.createViewStyle({
- marginTop: 4,
- }),
- stickyContent: Styles.createViewStyle({
- paddingHorizontal: 12,
- paddingBottom: 8,
-
- // NavigationBar already adds some spacing
- paddingTop: 0,
+ scopeBar: Styles.createViewStyle({
+ marginTop: 8,
}),
selectedCell: Styles.createViewStyle({
backgroundColor: colors.green,
diff --git a/gui/src/renderer/components/Settings.tsx b/gui/src/renderer/components/Settings.tsx
index bf0e812a89..6c04d9a8e5 100644
--- a/gui/src/renderer/components/Settings.tsx
+++ b/gui/src/renderer/components/Settings.tsx
@@ -11,6 +11,7 @@ import {
CloseBarItem,
NavigationBar,
NavigationContainer,
+ NavigationItems,
NavigationScrollbars,
TitleBarItem,
} from './NavigationBar';
@@ -44,11 +45,13 @@ export default class Settings extends Component<IProps> {
<View style={styles.settings}>
<NavigationContainer>
<NavigationBar>
- <CloseBarItem action={this.props.onClose} />
- <TitleBarItem>
- {// TRANSLATORS: Title label in navigation bar
- messages.pgettext('settings-view-nav', 'Settings')}
- </TitleBarItem>
+ <NavigationItems>
+ <CloseBarItem action={this.props.onClose} />
+ <TitleBarItem>
+ {// TRANSLATORS: Title label in navigation bar
+ messages.pgettext('settings-view-nav', 'Settings')}
+ </TitleBarItem>
+ </NavigationItems>
</NavigationBar>
<View style={styles.settings__container}>
diff --git a/gui/src/renderer/components/Support.tsx b/gui/src/renderer/components/Support.tsx
index c3b7d42993..02f374737d 100644
--- a/gui/src/renderer/components/Support.tsx
+++ b/gui/src/renderer/components/Support.tsx
@@ -5,7 +5,7 @@ import * as AppButton from './AppButton';
import ImageView from './ImageView';
import { Container, Layout } from './Layout';
import { ModalAlert, ModalContainer, ModalContent } from './Modal';
-import { BackBarItem, NavigationBar } from './NavigationBar';
+import { BackBarItem, NavigationBar, NavigationItems } from './NavigationBar';
import SettingsHeader, { HeaderSubTitle, HeaderTitle } from './SettingsHeader';
import styles from './SupportStyles';
@@ -139,10 +139,12 @@ export default class Support extends Component<ISupportProps, ISupportState> {
<ModalContent>
<View style={styles.support}>
<NavigationBar>
- <BackBarItem action={this.props.onClose}>
- {// TRANSLATORS: Back button in navigation bar
- messages.pgettext('support-nav', 'Settings')}
- </BackBarItem>
+ <NavigationItems>
+ <BackBarItem action={this.props.onClose}>
+ {// TRANSLATORS: Back button in navigation bar
+ messages.pgettext('support-nav', 'Settings')}
+ </BackBarItem>
+ </NavigationItems>
</NavigationBar>
<View style={styles.support__container}>
{header}
diff --git a/gui/src/renderer/components/WireguardKeys.tsx b/gui/src/renderer/components/WireguardKeys.tsx
index 9ea386ec91..053b8567c7 100644
--- a/gui/src/renderer/components/WireguardKeys.tsx
+++ b/gui/src/renderer/components/WireguardKeys.tsx
@@ -8,7 +8,7 @@ import { IWgKey, WgKeyState } from '../redux/settings/reducers';
import * as AppButton from './AppButton';
import ImageView from './ImageView';
import { Container, Layout } from './Layout';
-import { BackBarItem, NavigationBar, NavigationContainer } from './NavigationBar';
+import { BackBarItem, NavigationBar, NavigationContainer, NavigationItems } from './NavigationBar';
import SettingsHeader, { HeaderTitle } from './SettingsHeader';
import styles from './WireguardKeysStyles';
@@ -32,10 +32,12 @@ export default class WireguardKeys extends Component<IProps> {
<View style={styles.wgkeys}>
<NavigationContainer>
<NavigationBar>
- <BackBarItem action={this.props.onClose}>
- {// TRANSLATORS: Back button in navigation bar
- messages.pgettext('wireguard-keys-nav', 'Advanced')}
- </BackBarItem>
+ <NavigationItems>
+ <BackBarItem action={this.props.onClose}>
+ {// TRANSLATORS: Back button in navigation bar
+ messages.pgettext('wireguard-keys-nav', 'Advanced')}
+ </BackBarItem>
+ </NavigationItems>
</NavigationBar>
</NavigationContainer>