diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2019-09-16 14:43:58 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2019-09-17 09:51:13 +0200 |
| commit | e901869aee45d171e189bb0cae3af478cb325a4c (patch) | |
| tree | 11fa5bd3920270ec0f390baaf900b409700f00d6 /gui/src | |
| parent | b0e0f72fe364615ffbc51b50e12ef3ce30b1a5c1 (diff) | |
| download | mullvadvpn-e901869aee45d171e189bb0cae3af478cb325a4c.tar.xz mullvadvpn-e901869aee45d171e189bb0cae3af478cb325a4c.zip | |
Remove sticky context and instead put the contents inside of navigation bar
Diffstat (limited to 'gui/src')
| -rw-r--r-- | gui/src/renderer/components/Account.tsx | 12 | ||||
| -rw-r--r-- | gui/src/renderer/components/AdvancedSettings.tsx | 19 | ||||
| -rw-r--r-- | gui/src/renderer/components/NavigationBar.tsx | 176 | ||||
| -rw-r--r-- | gui/src/renderer/components/Preferences.tsx | 19 | ||||
| -rw-r--r-- | gui/src/renderer/components/SelectLocation.tsx | 84 | ||||
| -rw-r--r-- | gui/src/renderer/components/SelectLocationStyles.tsx | 16 | ||||
| -rw-r--r-- | gui/src/renderer/components/Settings.tsx | 13 | ||||
| -rw-r--r-- | gui/src/renderer/components/Support.tsx | 12 | ||||
| -rw-r--r-- | gui/src/renderer/components/WireguardKeys.tsx | 12 |
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> |
