[RN] Add color scheme support to header

This commit is contained in:
Bettenbuk Zoltan 2019-03-05 18:41:39 +01:00 committed by Zoltan Bettenbuk
parent 20c1b1cfae
commit 55a971c0fd
12 changed files with 398 additions and 147 deletions

View File

@ -17,6 +17,13 @@ export default {
icon: ColorPalette.white, icon: ColorPalette.white,
text: ColorPalette.white text: ColorPalette.white
}, },
'Header': {
background: ColorPalette.blue,
icon: ColorPalette.white,
statusBar: ColorPalette.blueHighlight,
statusBarContent: ColorPalette.white,
text: ColorPalette.white
},
'LargeVideo': { 'LargeVideo': {
background: ColorPalette.black background: ColorPalette.black
}, },

View File

@ -2,11 +2,11 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { TouchableOpacity } from 'react-native'; import { TouchableOpacity } from 'react-native';
import { connect } from 'react-redux';
import { ColorSchemeRegistry } from '../../../color-scheme';
import { Icon } from '../../../font-icons'; import { Icon } from '../../../font-icons';
import styles from './styles';
/** /**
* The type of the React {@code Component} props of {@link BackButton} * The type of the React {@code Component} props of {@link BackButton}
*/ */
@ -20,13 +20,18 @@ type Props = {
/** /**
* An external style object passed to the component. * An external style object passed to the component.
*/ */
style?: Object style?: Object,
/**
* The color schemed style of the Header component.
*/
_headerStyles: Object
}; };
/** /**
* A component rendering a back button. * A component rendering a back button.
*/ */
export default class BackButton extends Component<Props> { class BackButton extends Component<Props> {
/** /**
* Implements React's {@link Component#render()}, renders the button. * Implements React's {@link Component#render()}, renders the button.
* *
@ -41,10 +46,26 @@ export default class BackButton extends Component<Props> {
<Icon <Icon
name = { 'arrow_back' } name = { 'arrow_back' }
style = { [ style = { [
styles.headerButtonIcon, this.props._headerStyles.headerButtonIcon,
this.props.style this.props.style
] } /> ] } />
</TouchableOpacity> </TouchableOpacity>
); );
} }
} }
/**
* Maps part of the Redux state to the props of this component.
*
* @param {Object} state - The Redux state.
* @returns {{
* _headerStyles: Object
* }}
*/
function _mapStateToProps(state) {
return {
_headerStyles: ColorSchemeRegistry.get(state, 'Header')
};
}
export default connect(_mapStateToProps)(BackButton);

View File

@ -2,11 +2,11 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Text, TouchableOpacity } from 'react-native'; import { Text, TouchableOpacity } from 'react-native';
import { connect } from 'react-redux';
import { ColorSchemeRegistry } from '../../../color-scheme';
import { translate } from '../../../i18n'; import { translate } from '../../../i18n';
import styles from './styles';
/** /**
* The type of the React {@code Component} props of {@link ForwardButton} * The type of the React {@code Component} props of {@link ForwardButton}
*/ */
@ -35,7 +35,12 @@ type Props = {
/** /**
* The function to be used to translate i18n labels. * The function to be used to translate i18n labels.
*/ */
t: Function t: Function,
/**
* The color schemed style of the Header component.
*/
_headerStyles: Object
}; };
/** /**
@ -49,6 +54,8 @@ class ForwardButton extends Component<Props> {
* @returns {ReactElement} * @returns {ReactElement}
*/ */
render() { render() {
const { _headerStyles } = this.props;
return ( return (
<TouchableOpacity <TouchableOpacity
accessibilityLabel = { 'Forward' } accessibilityLabel = { 'Forward' }
@ -56,8 +63,8 @@ class ForwardButton extends Component<Props> {
onPress = { this.props.onPress } > onPress = { this.props.onPress } >
<Text <Text
style = { [ style = { [
styles.headerButtonText, _headerStyles.headerButtonText,
this.props.disabled && styles.disabledButtonText, this.props.disabled && _headerStyles.disabledButtonText,
this.props.style this.props.style
] }> ] }>
{ this.props.t(this.props.labelKey) } { this.props.t(this.props.labelKey) }
@ -67,4 +74,18 @@ class ForwardButton extends Component<Props> {
} }
} }
export default translate(ForwardButton); /**
* Maps part of the Redux state to the props of the component.
*
* @param {Object} state - The Redux state.
* @returns {{
* _headerStyles: Object
* }}
*/
function _mapStateToProps(state) {
return {
_headerStyles: ColorSchemeRegistry.get(state, 'Header')
};
}
export default translate(connect(_mapStateToProps)(ForwardButton));

View File

@ -2,14 +2,24 @@
import React, { Component, type Node } from 'react'; import React, { Component, type Node } from 'react';
import { Platform, SafeAreaView, StatusBar, View } from 'react-native'; import { Platform, SafeAreaView, StatusBar, View } from 'react-native';
import { connect } from 'react-redux';
import styles, { HEADER_PADDING, STATUSBAR_COLOR } from './styles'; import { ColorSchemeRegistry } from '../../../color-scheme';
import { isDarkColor } from '../../../styles';
import { HEADER_PADDING } from './headerstyles';
/** /**
* Compatibility header padding size for iOS 10 (and older) devices. * Compatibility header padding size for iOS 10 (and older) devices.
*/ */
const IOS10_PADDING = 20; const IOS10_PADDING = 20;
/**
* Constanst for the (currently) supported statusbar colors.
*/
const STATUSBAR_DARK = 'dark-content';
const STATUSBAR_LIGHT = 'light-content';
/** /**
* The type of the React {@code Component} props of {@link Header} * The type of the React {@code Component} props of {@link Header}
*/ */
@ -23,43 +33,18 @@ type Props = {
/** /**
* The component's external style * The component's external style
*/ */
style: Object style: Object,
/**
* The color schemed style of the component.
*/
_styles: Object
} }
/** /**
* A generic screen header component. * A generic screen header component.
*/ */
export default class Header extends Component<Props> { class Header extends Component<Props> {
/**
* The style of button-like React {@code Component}s rendered in
* {@code Header}.
*
* @returns {Object}
*/
static get buttonStyle(): Object {
return styles.headerButtonIcon;
}
/**
* The style of a React {@code Component} rendering a {@code Header} as its
* child.
*
* @returns {Object}
*/
static get pageStyle(): Object {
return styles.page;
}
/**
* The style of text rendered in {@code Header}.
*
* @returns {Object}
*/
static get textStyle(): Object {
return styles.headerText;
}
/** /**
* Initializes a new {@code Header} instance. * Initializes a new {@code Header} instance.
* *
@ -78,20 +63,22 @@ export default class Header extends Component<Props> {
* @inheritdoc * @inheritdoc
*/ */
render() { render() {
const { _styles } = this.props;
return ( return (
<View <View
style = { [ style = { [
styles.headerOverlay, _styles.headerOverlay,
this._getIOS10CompatiblePadding() this._getIOS10CompatiblePadding()
] } > ] } >
<StatusBar <StatusBar
backgroundColor = { STATUSBAR_COLOR } backgroundColor = { _styles.statusBar }
barStyle = 'light-content' barStyle = { this._getStatusBarContentColor() }
translucent = { false } /> translucent = { false } />
<SafeAreaView> <SafeAreaView>
<View <View
style = { [ style = { [
styles.screenHeader, _styles.screenHeader,
this.props.style this.props.style
] }> ] }>
{ {
@ -128,4 +115,54 @@ export default class Header extends Component<Props> {
return null; return null;
} }
/**
* Calculates the color of the statusbar content (light or dark) based on
* certain criterias.
*
* @returns {string}
*/
_getStatusBarContentColor() {
const { _styles } = this.props;
const { statusBarContent } = _styles;
if (statusBarContent) {
// We have the possibility to define the statusbar color in the
// color scheme feature, but since mobile devices (at the moment)
// only support two colors (light and dark) we need to normalize
// the value.
if (isDarkColor(statusBarContent)) {
return STATUSBAR_DARK;
}
return STATUSBAR_LIGHT;
}
// The statusbar color is not defined, so we need to base our choice
// on the header colors
const { statusBar, screenHeader } = _styles;
if (isDarkColor(statusBar || screenHeader.backgroundColor)) {
return STATUSBAR_LIGHT;
}
return STATUSBAR_DARK;
}
} }
/**
* Maps part of the Redux state to the props of the component.
*
* @param {Object} state - The Redux state.
* @returns {{
* _styles: Object
* }}
*/
function _mapStateToProps(state) {
return {
_styles: ColorSchemeRegistry.get(state, 'Header')
};
}
export default connect(_mapStateToProps)(Header);

View File

@ -2,11 +2,11 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Text, View } from 'react-native'; import { Text, View } from 'react-native';
import { connect } from 'react-redux';
import { ColorSchemeRegistry } from '../../../color-scheme';
import { translate } from '../../../i18n'; import { translate } from '../../../i18n';
import styles from './styles';
/** /**
* The type of the React {@code Component} props of {@link HeaderLabel} * The type of the React {@code Component} props of {@link HeaderLabel}
*/ */
@ -20,7 +20,12 @@ type Props = {
/** /**
* The i18n translate function. * The i18n translate function.
*/ */
t: Function t: Function,
/**
* The color schemed style of the Header component.
*/
_headerStyles: Object
}; };
/** /**
@ -34,13 +39,15 @@ class HeaderLabel extends Component<Props> {
* @returns {ReactElement} * @returns {ReactElement}
*/ */
render() { render() {
const { _headerStyles } = this.props;
return ( return (
<View <View
pointerEvents = 'box-none' pointerEvents = 'box-none'
style = { styles.headerTextWrapper }> style = { _headerStyles.headerTextWrapper }>
<Text <Text
style = { [ style = { [
styles.headerText _headerStyles.headerText
] }> ] }>
{ this.props.t(this.props.labelKey) } { this.props.t(this.props.labelKey) }
</Text> </Text>
@ -49,4 +56,18 @@ class HeaderLabel extends Component<Props> {
} }
} }
export default translate(HeaderLabel); /**
* Maps part of the Redux state to the props of this component.
*
* @param {Object} state - The Redux state.
* @returns {{
* _headerStyles: Object
* }}
*/
function _mapStateToProps(state) {
return {
_headerStyles: ColorSchemeRegistry.get(state, 'Header')
};
}
export default translate(connect(_mapStateToProps)(HeaderLabel));

View File

@ -0,0 +1,87 @@
// @flex
import { StyleSheet } from 'react-native';
import { ColorSchemeRegistry, schemeColor } from '../../../color-scheme';
import { BoxModel } from '../../../styles';
const HEADER_HEIGHT = 48;
export const HEADER_PADDING = BoxModel.padding / 2;
ColorSchemeRegistry.register('Header', {
/**
* Style of a disabled button in the header (e.g. Next).
*/
disabledButtonText: {
opacity: 0.6
},
/**
* Platform specific header button (e.g. back, menu, etc).
*/
headerButtonIcon: {
alignSelf: 'center',
color: schemeColor('icon'),
fontSize: 22,
marginRight: 12,
padding: 8
},
headerButtonText: {
color: schemeColor('text'),
fontSize: 20
},
/**
* Style of the header overlay to cover the unsafe areas.
*/
headerOverlay: {
backgroundColor: schemeColor('background')
},
/**
* Generic style for a label placed in the header.
*/
headerText: {
color: schemeColor('text'),
fontSize: 18
},
headerTextWrapper: {
alignItems: 'center',
justifyContent: 'center',
left: 0,
position: 'absolute',
right: 0
},
/**
* The top-level element of a page.
*/
page: {
...StyleSheet.absoluteFillObject,
alignItems: 'stretch',
flex: 1,
flexDirection: 'column',
overflow: 'hidden'
},
/**
* Base style of Header.
*/
screenHeader: {
alignItems: 'center',
backgroundColor: schemeColor('background'),
flexDirection: 'row',
height: HEADER_HEIGHT,
justifyContent: 'space-between',
paddingHorizontal: BoxModel.padding,
paddingVertical: HEADER_PADDING
},
statusBar: schemeColor('statusBar'),
statusBarContent: schemeColor('statusBarContent')
});

View File

@ -5,88 +5,13 @@ import { StyleSheet } from 'react-native';
import { BoxModel, ColorPalette, createStyleSheet } from '../../../styles'; import { BoxModel, ColorPalette, createStyleSheet } from '../../../styles';
const AVATAR_OPACITY = 0.4; const AVATAR_OPACITY = 0.4;
const HEADER_COLOR = ColorPalette.blue;
const HEADER_HEIGHT = 48;
const OVERLAY_FONT_COLOR = 'rgba(255, 255, 255, 0.6)'; const OVERLAY_FONT_COLOR = 'rgba(255, 255, 255, 0.6)';
const SECONDARY_ACTION_BUTTON_SIZE = 30; const SECONDARY_ACTION_BUTTON_SIZE = 30;
export const AVATAR_SIZE = 65; export const AVATAR_SIZE = 65;
export const HEADER_PADDING = BoxModel.padding / 2;
export const STATUSBAR_COLOR = ColorPalette.blueHighlight;
export const SIDEBAR_WIDTH = 250; export const SIDEBAR_WIDTH = 250;
export const UNDERLAY_COLOR = 'rgba(255, 255, 255, 0.2)'; export const UNDERLAY_COLOR = 'rgba(255, 255, 255, 0.2)';
const HEADER_STYLES = {
disabledButtonText: {
opacity: 0.6
},
/**
* Platform specific header button (e.g. back, menu, etc).
*/
headerButtonIcon: {
alignSelf: 'center',
color: ColorPalette.white,
fontSize: 22,
marginRight: 12,
padding: 8
},
headerButtonText: {
color: ColorPalette.white,
fontSize: 20
},
/**
* Style of the header overlay to cover the unsafe areas.
*/
headerOverlay: {
backgroundColor: HEADER_COLOR
},
/**
* Generic style for a label placed in the header.
*/
headerText: {
color: ColorPalette.white,
fontSize: 18
},
headerTextWrapper: {
alignItems: 'center',
justifyContent: 'center',
left: 0,
position: 'absolute',
right: 0
},
/**
* The top-level element of a page.
*/
page: {
...StyleSheet.absoluteFillObject,
alignItems: 'stretch',
flex: 1,
flexDirection: 'column',
overflow: 'hidden'
},
/**
* Base style of Header.
*/
screenHeader: {
alignItems: 'center',
backgroundColor: HEADER_COLOR,
flexDirection: 'row',
height: HEADER_HEIGHT,
justifyContent: 'space-between',
paddingHorizontal: BoxModel.padding,
paddingVertical: HEADER_PADDING
}
};
/** /**
* Style classes of the PagedList-based components. * Style classes of the PagedList-based components.
*/ */
@ -355,7 +280,6 @@ export const TINTED_VIEW_DEFAULT = {
* base/react. * base/react.
*/ */
export default createStyleSheet({ export default createStyleSheet({
...HEADER_STYLES,
...PAGED_LIST_STYLES, ...PAGED_LIST_STYLES,
...SECTION_LIST_STYLES, ...SECTION_LIST_STYLES,
...SIDEBAR_STYLES ...SIDEBAR_STYLES

View File

@ -23,6 +23,12 @@ const HEX_SHORT_COLOR_FORMAT
*/ */
const RGB_COLOR_FORMAT = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/i; const RGB_COLOR_FORMAT = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/i;
/**
* RegExp pattern for RGBA color format.
*/
const RGBA_COLOR_FORMAT
= /^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*([0-9.]+)\)$/i;
/** /**
* The list of the well-known style properties which may not be numbers on Web * The list of the well-known style properties which may not be numbers on Web
* but must be numbers on React Native. * but must be numbers on React Native.
@ -136,6 +142,23 @@ export function getRGBAFormat(color: string, alpha: number): string {
return color; return color;
} }
/**
* Decides if a color is light or dark based on the ITU-R BT.709 and W3C
* recommendations.
*
* NOTE: Please see https://www.w3.org/TR/WCAG20/#relativeluminancedef.
*
* @param {string} color - The color in rgb, rgba or hex format.
* @returns {boolean}
*/
export function isDarkColor(color: string): boolean {
const rgb = _getRGBObjectFormat(color);
return ((_getColorLuminance(rgb.r) * 0.2126)
+ (_getColorLuminance(rgb.g) * 0.7152)
+ (_getColorLuminance(rgb.b) * 0.0722)) <= 0.179;
}
/** /**
* Converts an [0..1] alpha value into HEX. * Converts an [0..1] alpha value into HEX.
* *
@ -147,6 +170,67 @@ function _getAlphaInHex(alpha: number): string {
.padStart(2, '0'); .padStart(2, '0');
} }
/**
* Calculated the color luminance component for an individual color channel.
*
* NOTE: Please see https://www.w3.org/TR/WCAG20/#relativeluminancedef.
*
* @param {number} c - The color which we need the individual luminance
* for.
* @returns {number}
*/
function _getColorLuminance(c: number): number {
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
}
/**
* Parses a color string into an object containing the RGB values as numbers.
*
* NOTE: Object properties are not alpha-sorted for sanity.
*
* @param {string} color - The color to convert.
* @returns {{
* r: number,
* g: number,
* b: number
* }}
*/
function _getRGBObjectFormat(color: string): {r: number, g: number, b: number} {
let match = color.match(HEX_LONG_COLOR_FORMAT);
if (match) {
return {
r: parseInt(match[1], 16) / 255.0,
g: parseInt(match[2], 16) / 255.0,
b: parseInt(match[3], 16) / 255.0
};
}
match = color.match(HEX_SHORT_COLOR_FORMAT);
if (match) {
return {
r: parseInt(`${match[1]}${match[1]}`, 16) / 255.0,
g: parseInt(`${match[2]}${match[2]}`, 16) / 255.0,
b: parseInt(`${match[3]}${match[3]}`, 16) / 255.0
};
}
match = color.match(RGB_COLOR_FORMAT) || color.match(RGBA_COLOR_FORMAT);
if (match) {
return {
r: parseInt(match[1], 10) / 255.0,
g: parseInt(match[2], 10) / 255.0,
b: parseInt(match[3], 10) / 255.0
};
}
return {
r: 0,
g: 0,
b: 0
};
}
/** /**
* Shims style properties to work correctly on native. Allows us to minimize the * Shims style properties to work correctly on native. Allows us to minimize the
* number of style declarations that need to be set or overridden for specific * number of style declarations that need to be set or overridden for specific

View File

@ -9,7 +9,7 @@ import { updateSettings } from '../../base/settings';
* The type of the React {@code Component} props of * The type of the React {@code Component} props of
* {@link AbstractSettingsView}. * {@link AbstractSettingsView}.
*/ */
type Props = { export type Props = {
/** /**
* The default URL for when there is no custom URL set in the settings. * The default URL for when there is no custom URL set in the settings.
@ -47,15 +47,15 @@ type Props = {
* *
* @abstract * @abstract
*/ */
export class AbstractSettingsView extends Component<Props> { export class AbstractSettingsView<P: Props> extends Component<P> {
/** /**
* Initializes a new {@code AbstractSettingsView} instance. * Initializes a new {@code AbstractSettingsView} instance.
* *
* @param {Props} props - The React {@code Component} props to initialize * @param {P} props - The React {@code Component} props to initialize
* the component. * the component.
*/ */
constructor(props: Props) { constructor(props: P) {
super(props); super(props);
// Bind event handlers so they are only bound once per instance. // Bind event handlers so they are only bound once per instance.

View File

@ -11,12 +11,14 @@ import {
} from 'react-native'; } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { ColorSchemeRegistry } from '../../../base/color-scheme';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n';
import { BackButton, Header, Modal } from '../../../base/react'; import { BackButton, Header, Modal } from '../../../base/react';
import { import {
AbstractSettingsView, AbstractSettingsView,
_mapStateToProps _mapStateToProps as _abstractMapStateToProps,
type Props as AbstractProps
} from '../AbstractSettingsView'; } from '../AbstractSettingsView';
import { setSettingsViewVisible } from '../../actions'; import { setSettingsViewVisible } from '../../actions';
import FormRow from './FormRow'; import FormRow from './FormRow';
@ -25,12 +27,20 @@ import { normalizeUserInputURL } from '../../functions';
import styles from './styles'; import styles from './styles';
import { HeaderLabel } from '../../../base/react/components/native'; import { HeaderLabel } from '../../../base/react/components/native';
type Props = AbstractProps & {
/**
* Color schemed style of the header component.
*/
_headerStyles: Object
}
/** /**
* The native container rendering the app settings page. * The native container rendering the app settings page.
* *
* @extends AbstractSettingsView * @extends AbstractSettingsView
*/ */
class SettingsView extends AbstractSettingsView { class SettingsView extends AbstractSettingsView<Props> {
_urlField: Object; _urlField: Object;
/** /**
@ -60,7 +70,7 @@ class SettingsView extends AbstractSettingsView {
onRequestClose = { this._onRequestClose } onRequestClose = { this._onRequestClose }
presentationStyle = 'overFullScreen' presentationStyle = 'overFullScreen'
visible = { this.props._visible }> visible = { this.props._visible }>
<View style = { Header.pageStyle }> <View style = { this.props._headerStyles.page }>
{ this._renderHeader() } { this._renderHeader() }
{ this._renderBody() } { this._renderBody() }
</View> </View>
@ -239,4 +249,19 @@ class SettingsView extends AbstractSettingsView {
} }
} }
/**
* Maps part of the Redux state to the props of this component.
*
* @param {Object} state - The Redux state.
* @returns {{
* _headerStyles: Object
* }}
*/
function _mapStateToProps(state) {
return {
..._abstractMapStateToProps(state),
_headerStyles: ColorSchemeRegistry.get(state, 'Header')
};
}
export default translate(connect(_mapStateToProps)(SettingsView)); export default translate(connect(_mapStateToProps)(SettingsView));

View File

@ -4,8 +4,9 @@ import React, { Component } from 'react';
import { Switch, TouchableWithoutFeedback, View } from 'react-native'; import { Switch, TouchableWithoutFeedback, View } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { ColorSchemeRegistry } from '../../base/color-scheme';
import { translate } from '../../base/i18n'; import { translate } from '../../base/i18n';
import { Header, Text } from '../../base/react'; import { Text } from '../../base/react';
import { updateSettings } from '../../base/settings'; import { updateSettings } from '../../base/settings';
import styles, { SWITCH_THUMB_COLOR, SWITCH_UNDER_COLOR } from './styles'; import styles, { SWITCH_THUMB_COLOR, SWITCH_UNDER_COLOR } from './styles';
@ -25,6 +26,11 @@ type Props = {
*/ */
t: Function, t: Function,
/**
* Color schemed style of the header component.
*/
_headerStyles: Object,
/** /**
* The current settings from redux. * The current settings from redux.
*/ */
@ -55,15 +61,14 @@ class VideoSwitch extends Component<Props> {
* @inheritdoc * @inheritdoc
*/ */
render() { render() {
const { t, _settings } = this.props; const { t, _headerStyles, _settings } = this.props;
const { textStyle } = Header;
return ( return (
<View style = { styles.audioVideoSwitchContainer }> <View style = { styles.audioVideoSwitchContainer }>
<TouchableWithoutFeedback <TouchableWithoutFeedback
onPress = { this._onStartAudioOnlyFalse }> onPress = { this._onStartAudioOnlyFalse }>
<View style = { styles.switchLabel }> <View style = { styles.switchLabel }>
<Text style = { textStyle }> <Text style = { _headerStyles.headerText }>
{ t('welcomepage.audioVideoSwitch.video') } { t('welcomepage.audioVideoSwitch.video') }
</Text> </Text>
</View> </View>
@ -77,7 +82,7 @@ class VideoSwitch extends Component<Props> {
<TouchableWithoutFeedback <TouchableWithoutFeedback
onPress = { this._onStartAudioOnlyTrue }> onPress = { this._onStartAudioOnlyTrue }>
<View style = { styles.switchLabel }> <View style = { styles.switchLabel }>
<Text style = { textStyle }> <Text style = { _headerStyles.headerText }>
{ t('welcomepage.audioVideoSwitch.audio') } { t('welcomepage.audioVideoSwitch.audio') }
</Text> </Text>
</View> </View>
@ -132,6 +137,7 @@ class VideoSwitch extends Component<Props> {
*/ */
export function _mapStateToProps(state: Object) { export function _mapStateToProps(state: Object) {
return { return {
_headerStyles: ColorSchemeRegistry.get(state, 'Header'),
_settings: state['features/base/settings'] _settings: state['features/base/settings']
}; };
} }

View File

@ -10,6 +10,7 @@ import {
} from 'react-native'; } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { ColorSchemeRegistry } from '../../base/color-scheme';
import { translate } from '../../base/i18n'; import { translate } from '../../base/i18n';
import { Icon } from '../../base/font-icons'; import { Icon } from '../../base/font-icons';
import { MEDIA_TYPE } from '../../base/media'; import { MEDIA_TYPE } from '../../base/media';
@ -21,7 +22,10 @@ import {
} from '../../base/tracks'; } from '../../base/tracks';
import { SettingsView } from '../../settings'; import { SettingsView } from '../../settings';
import { AbstractWelcomePage, _mapStateToProps } from './AbstractWelcomePage'; import {
AbstractWelcomePage,
_mapStateToProps as _abstractMapStateToProps
} from './AbstractWelcomePage';
import { setSideBarVisible } from '../actions'; import { setSideBarVisible } from '../actions';
import LocalVideoTrackUnderlay from './LocalVideoTrackUnderlay'; import LocalVideoTrackUnderlay from './LocalVideoTrackUnderlay';
import styles, { PLACEHOLDER_TEXT_COLOR } from './styles'; import styles, { PLACEHOLDER_TEXT_COLOR } from './styles';
@ -90,18 +94,17 @@ class WelcomePage extends AbstractWelcomePage {
* @returns {ReactElement} * @returns {ReactElement}
*/ */
render() { render() {
const { buttonStyle, pageStyle } = Header;
const roomnameAccLabel = 'welcomepage.accessibilityLabel.roomname'; const roomnameAccLabel = 'welcomepage.accessibilityLabel.roomname';
const { t } = this.props; const { _headerStyles, t } = this.props;
return ( return (
<LocalVideoTrackUnderlay style = { styles.welcomePage }> <LocalVideoTrackUnderlay style = { styles.welcomePage }>
<View style = { pageStyle }> <View style = { _headerStyles.page }>
<Header style = { styles.header }> <Header style = { styles.header }>
<TouchableOpacity onPress = { this._onShowSideBar } > <TouchableOpacity onPress = { this._onShowSideBar } >
<Icon <Icon
name = 'menu' name = 'menu'
style = { buttonStyle } /> style = { _headerStyles.headerButtonIcon } />
</TouchableOpacity> </TouchableOpacity>
<VideoSwitch /> <VideoSwitch />
</Header> </Header>
@ -269,4 +272,19 @@ class WelcomePage extends AbstractWelcomePage {
} }
} }
/**
* Maps part of the Redux state to the props of this component.
*
* @param {Object} state - The Redux state.
* @returns {{
* _headerStyles: Object
* }}
*/
function _mapStateToProps(state) {
return {
..._abstractMapStateToProps(state),
_headerStyles: ColorSchemeRegistry.get(state, 'Header')
};
}
export default translate(connect(_mapStateToProps)(WelcomePage)); export default translate(connect(_mapStateToProps)(WelcomePage));