Introduce SafeArea for Settings and Header

This commit is contained in:
zbettenbuk 2018-02-02 15:48:43 +01:00 committed by Lyubo Marinov
parent 9b04a7852a
commit 9a9890f86c
24 changed files with 398 additions and 384 deletions

View File

@ -2,6 +2,5 @@
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. --> <!-- Customize your theme here. -->
<item name="android:windowTranslucentStatus">true</item>
</style> </style>
</resources> </resources>

View File

@ -47,13 +47,15 @@
}, },
"welcomepage":{ "welcomepage":{
"appDescription": "Go ahead, video chat with the whole team. In fact, invite everyone you know. __app__ is a fully encrypted, 100% open source video conferencing solution that you can use all day, every day, for free — with no account needed.", "appDescription": "Go ahead, video chat with the whole team. In fact, invite everyone you know. __app__ is a fully encrypted, 100% open source video conferencing solution that you can use all day, every day, for free — with no account needed.",
"audioOnlyLabel": "Voice",
"go": "GO", "go": "GO",
"join": "JOIN", "join": "JOIN",
"privacy": "Privacy", "privacy": "Privacy",
"roomname": "Enter room name", "roomname": "Enter room name",
"sendFeedback": "Send feedback", "sendFeedback": "Send feedback",
"terms": "Terms", "terms": "Terms",
"title": "More secure, more flexible, and completely free video conferencing" "title": "More secure, more flexible, and completely free video conferencing",
"videoEnabledLabel": "Video"
}, },
"startupoverlay": { "startupoverlay": {
"policyText": " ", "policyText": " ",
@ -500,7 +502,7 @@
"title": "Call info", "title": "Call info",
"tooltip": "Get access info about the meeting" "tooltip": "Get access info about the meeting"
}, },
"profileModal": { "settingsScreen": {
"alertOk": "OK", "alertOk": "OK",
"alertTitle": "Warning", "alertTitle": "Warning",
"alertURLText": "The entered server URL is invalid", "alertURLText": "The entered server URL is invalid",

View File

@ -1,6 +1,6 @@
/** /**
* The type of (redux) action which signals the request * The type of (redux) action which signals the request
* to hide the app settings modal. * to hide the app settings screen.
* *
* { * {
* type: HIDE_APP_SETTINGS * type: HIDE_APP_SETTINGS
@ -10,7 +10,7 @@ export const HIDE_APP_SETTINGS = Symbol('HIDE_APP_SETTINGS');
/** /**
* The type of (redux) action which signals the request * The type of (redux) action which signals the request
* to show the app settings modal where available. * to show the app settings screen where available.
* *
* { * {
* type: SHOW_APP_SETTINGS * type: SHOW_APP_SETTINGS

View File

@ -3,7 +3,7 @@
import { HIDE_APP_SETTINGS, SHOW_APP_SETTINGS } from './actionTypes'; import { HIDE_APP_SETTINGS, SHOW_APP_SETTINGS } from './actionTypes';
/** /**
* Redux-signals the request to hide the app settings modal. * Redux-signals the request to hide the app settings screen.
* *
* @returns {{ * @returns {{
* type: HIDE_APP_SETTINGS * type: HIDE_APP_SETTINGS
@ -16,7 +16,7 @@ export function hideAppSettings() {
} }
/** /**
* Redux-signals the request to open the app settings modal. * Redux-signals the request to open the app settings screen.
* *
* @returns {{ * @returns {{
* type: SHOW_APP_SETTINGS * type: SHOW_APP_SETTINGS

View File

@ -9,11 +9,6 @@ import { getProfile, updateProfile } from '../../base/profile';
*/ */
type Props = { type Props = {
/**
* The current aspect ratio of the screen.
*/
_aspectRatio: Symbol,
/** /**
* The current profile object. * The current profile object.
*/ */
@ -25,7 +20,7 @@ type Props = {
_serverURL: string, _serverURL: string,
/** /**
* The visibility prop of the settings modal. * The visibility prop of the settings screen.
*/ */
_visible: boolean, _visible: boolean,
@ -173,7 +168,6 @@ export function _mapStateToProps(state: Object) {
const _profile = getProfile(state); const _profile = getProfile(state);
return { return {
_aspectRatio: state['features/base/responsive-ui'].aspectRatio,
_profile, _profile,
_serverURL, _serverURL,
_visible: state['features/app-settings'].visible _visible: state['features/app-settings'].visible

View File

@ -4,6 +4,7 @@ import React from 'react';
import { import {
Alert, Alert,
Modal, Modal,
SafeAreaView,
ScrollView, ScrollView,
Switch, Switch,
Text, Text,
@ -13,16 +14,15 @@ import {
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { translate } from '../../base/i18n'; import { translate } from '../../base/i18n';
import { getSafetyOffset, isIPad } from '../../base/react'; import { Header } from '../../base/react';
import { ASPECT_RATIO_NARROW } from '../../base/responsive-ui'; import { PlatformElements } from '../../base/styles';
import { _mapStateToProps, AbstractAppSettings } from './AbstractAppSettings';
import { hideAppSettings } from '../actions'; import { hideAppSettings } from '../actions';
import BackButton from './BackButton.native';
import FormRow from './FormRow.native';
import FormSectionHeader from './FormSectionHeader.native';
import { normalizeUserInputURL } from '../functions'; import { normalizeUserInputURL } from '../functions';
import styles, { HEADER_PADDING } from './styles';
import { BackButton, FormRow, FormSectionHeader } from './_';
import { _mapStateToProps, AbstractAppSettings } from './AbstractAppSettings';
import styles from './styles';
/** /**
* The native container rendering the app settings page. * The native container rendering the app settings page.
@ -40,7 +40,6 @@ class AppSettings extends AbstractAppSettings {
constructor(props) { constructor(props) {
super(props); super(props);
this._getSafetyPadding = this._getSafetyPadding.bind(this);
this._onBlurServerURL = this._onBlurServerURL.bind(this); this._onBlurServerURL = this._onBlurServerURL.bind(this);
this._onRequestClose = this._onRequestClose.bind(this); this._onRequestClose = this._onRequestClose.bind(this);
this._setURLFieldReference = this._setURLFieldReference.bind(this); this._setURLFieldReference = this._setURLFieldReference.bind(this);
@ -56,110 +55,91 @@ class AppSettings extends AbstractAppSettings {
render() { render() {
const { _profile, t } = this.props; const { _profile, t } = this.props;
// FIXME: presentationStyle is added to workaround orientation issue on
// iOS
return ( return (
<Modal <Modal
animationType = 'slide' animationType = 'slide'
onRequestClose = { this._onRequestClose } onRequestClose = { this._onRequestClose }
presentationStyle = 'overFullScreen' presentationStyle = 'fullScreen'
supportedOrientations = { [ supportedOrientations = { [
'landscape', 'landscape',
'portrait' 'portrait'
] } ] }
visible = { this.props._visible }> visible = { this.props._visible }>
<View <View style = { PlatformElements.page }>
style = { [ <Header>
styles.headerContainer, <BackButton
this._getSafetyPadding() onPress = { this._onRequestClose } />
] } > <Text
<BackButton style = { [
onPress = { this._onRequestClose } styles.text,
style = { styles.settingsBackButton } /> PlatformElements.headerText
<Text style = { [ styles.text, styles.headerTitle ] } > ] } >
{ t('profileModal.header') } { t('settingsScreen.header') }
</Text> </Text>
</Header>
<SafeAreaView style = { styles.settingsForm }>
<ScrollView>
<FormSectionHeader
i18nLabel = 'settingsScreen.profileSection' />
<FormRow
fieldSeparator = { true }
i18nLabel = 'settingsScreen.displayName' >
<TextInput
onChangeText = { this._onChangeDisplayName }
placeholder = 'John Doe'
value = { _profile.displayName } />
</FormRow>
<FormRow
i18nLabel = 'settingsScreen.email' >
<TextInput
keyboardType = { 'email-address' }
onChangeText = { this._onChangeEmail }
placeholder = 'email@example.com'
value = { _profile.email } />
</FormRow>
<FormSectionHeader
i18nLabel
= 'settingsScreen.conferenceSection' />
<FormRow
fieldSeparator = { true }
i18nLabel = 'settingsScreen.serverURL' >
<TextInput
autoCapitalize = 'none'
onBlur = { this._onBlurServerURL }
onChangeText = { this._onChangeServerURL }
placeholder = { this.props._serverURL }
value = { _profile.serverURL } />
</FormRow>
<FormRow
fieldSeparator = { true }
i18nLabel
= 'settingsScreen.startWithAudioMuted' >
<Switch
onValueChange = {
this._onStartAudioMutedChange
}
value = {
_profile.startWithAudioMuted
} />
</FormRow>
<FormRow
i18nLabel
= 'settingsScreen.startWithVideoMuted' >
<Switch
onValueChange = {
this._onStartVideoMutedChange
}
value = {
_profile.startWithVideoMuted
} />
</FormRow>
</ScrollView>
</SafeAreaView>
</View> </View>
<ScrollView style = { styles.settingsContainer } >
<FormSectionHeader
i18nLabel = 'profileModal.profileSection' />
<FormRow
fieldSeparator = { true }
i18nLabel = 'profileModal.displayName' >
<TextInput
onChangeText = { this._onChangeDisplayName }
placeholder = 'John Doe'
value = { _profile.displayName } />
</FormRow>
<FormRow
i18nLabel = 'profileModal.email' >
<TextInput
keyboardType = { 'email-address' }
onChangeText = { this._onChangeEmail }
placeholder = 'email@example.com'
value = { _profile.email } />
</FormRow>
<FormSectionHeader
i18nLabel = 'profileModal.conferenceSection' />
<FormRow
fieldSeparator = { true }
i18nLabel = 'profileModal.serverURL' >
<TextInput
autoCapitalize = 'none'
onBlur = { this._onBlurServerURL }
onChangeText = { this._onChangeServerURL }
placeholder = { this.props._serverURL }
ref = { this._setURLFieldReference }
value = { _profile.serverURL } />
</FormRow>
<FormRow
fieldSeparator = { true }
i18nLabel = 'profileModal.startWithAudioMuted' >
<Switch
onValueChange = {
this._onStartAudioMutedChange
}
value = {
_profile.startWithAudioMuted
} />
</FormRow>
<FormRow
i18nLabel = 'profileModal.startWithVideoMuted' >
<Switch
onValueChange = {
this._onStartVideoMutedChange
}
value = {
_profile.startWithVideoMuted
} />
</FormRow>
</ScrollView>
</Modal> </Modal>
); );
} }
_getSafetyPadding: () => Object;
/**
* Calculates header safety padding for mobile devices. See comment in
* functions.js.
*
* @private
* @returns {Object}
*/
_getSafetyPadding() {
if (isIPad() || this.props._aspectRatio === ASPECT_RATIO_NARROW) {
const safeOffset = Math.max(getSafetyOffset(), HEADER_PADDING);
return {
paddingTop: safeOffset
};
}
return undefined;
}
_onBlurServerURL: () => void; _onBlurServerURL: () => void;
/** /**
@ -183,8 +163,6 @@ class AppSettings extends AbstractAppSettings {
_onStartVideoMutedChange: (boolean) => void; _onStartVideoMutedChange: (boolean) => void;
_onRequestClose: () => void;
/** /**
* Processes the server URL. It normalizes it and an error alert is * Processes the server URL. It normalizes it and an error alert is
* displayed in case it's incorrect. * displayed in case it's incorrect.
@ -208,6 +186,8 @@ class AppSettings extends AbstractAppSettings {
} }
} }
_onRequestClose: () => void;
/** /**
* Handles the back button. * Handles the back button.
* Also invokes normalizeUserInputURL to validate the URL entered * Also invokes normalizeUserInputURL to validate the URL entered
@ -243,12 +223,12 @@ class AppSettings extends AbstractAppSettings {
const { t } = this.props; const { t } = this.props;
Alert.alert( Alert.alert(
t('profileModal.alertTitle'), t('settingsScreen.alertTitle'),
t('profileModal.alertURLText'), t('settingsScreen.alertURLText'),
[ [
{ {
onPress: () => this._urlField.focus(), onPress: () => this._urlField.focus(),
text: t('profileModal.alertOk') text: t('settingsScreen.alertOk')
} }
] ]
); );

View File

@ -1,117 +0,0 @@
// @flow
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { connect } from 'react-redux';
import { translate } from '../../base/i18n';
import { getSafetyOffset } from '../../base/react';
import { ASPECT_RATIO_WIDE } from '../../base/responsive-ui';
import styles, { CONTAINER_PADDING } from './styles';
/**
* The type of the React {@code Component} props of {@link FormSectionHeader}
*/
type Props = {
/**
* The current aspect ratio of the screen.
*/
_aspectRatio: Symbol,
/**
* The i18n key of the text label of the section.
*/
i18nLabel: string,
/**
* An external style object passed to the component.
*/
style: Object,
/**
* Invoked to obtain translated strings.
*/
t: Function
}
/**
* Implements a React {@code Component} which renders a section header on a
* form. This calculates the available safe view as well.
*/
class FormSectionHeader extends Component<Props> {
/**
* Initializes a new {@code FormSectionHeader} instance.
*
* @param {Object} props - Component properties.
*/
constructor(props) {
super(props);
this._getSafetyMargin = this._getSafetyMargin.bind(this);
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @override
* @returns {ReactElement}
*/
render() {
const { t } = this.props;
return (
<View
style = { [
styles.formSectionTitle,
this.props.style,
this._getSafetyMargin()
] } >
<Text>
{ t(this.props.i18nLabel) }
</Text>
</View>
);
}
_getSafetyMargin: () => Object;
/**
* Calculates the safety margin for this header. See comment in
* functions.js.
*
* @private
* @returns {Object}
*/
_getSafetyMargin() {
if (this.props._aspectRatio === ASPECT_RATIO_WIDE) {
const safeOffset
= Math.max(getSafetyOffset() - CONTAINER_PADDING, 0);
return {
marginLeft: safeOffset,
marginRight: safeOffset
};
}
return undefined;
}
}
/**
* Maps (parts of) the redux state to the React {@code Component} props of
* {@code FormSectionHeader}.
*
* @param {Object} state - The redux state.
* @protected
* @returns {Object}
*/
export function _mapStateToProps(state: Object) {
return {
_aspectRatio: state['features/base/responsive-ui'].aspectRatio
};
}
export default translate(connect(_mapStateToProps)(FormSectionHeader));

View File

@ -0,0 +1 @@
export * from './native';

View File

@ -3,9 +3,8 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { TouchableOpacity } from 'react-native'; import { TouchableOpacity } from 'react-native';
import { Icon } from '../../base/font-icons'; import { Icon } from '../../../base/font-icons';
import { PlatformElements } from '../../../base/styles';
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,7 +19,7 @@ type Props = {
/** /**
* An external style object passed to the component. * An external style object passed to the component.
*/ */
style: Object style?: Object
}; };
/** /**
@ -41,7 +40,7 @@ export default class BackButton extends Component<Props> {
<Icon <Icon
name = { 'arrow_back' } name = { 'arrow_back' }
style = { [ style = { [
styles.backIcon, PlatformElements.headerButton,
this.props.style this.props.style
] } /> ] } />
</TouchableOpacity> </TouchableOpacity>

View File

@ -2,24 +2,16 @@
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 { translate } from '../../base/i18n'; import { translate } from '../../../base/i18n';
import { getSafetyOffset } from '../../base/react';
import { ASPECT_RATIO_WIDE } from '../../base/responsive-ui';
import styles, { ANDROID_UNDERLINE_COLOR, CONTAINER_PADDING } from './styles'; import styles, { ANDROID_UNDERLINE_COLOR } from './styles';
/** /**
* The type of the React {@code Component} props of {@link FormRow} * The type of the React {@code Component} props of {@link FormRow}
*/ */
type Props = { type Props = {
/**
* The current aspect ratio of the screen.
*/
_aspectRatio: Symbol,
/** /**
* *
*/ */
@ -80,7 +72,10 @@ class FormRow extends Component<Props> {
<View <View
style = { this._getRowStyle() } > style = { this._getRowStyle() } >
<View style = { styles.fieldLabelContainer } > <View style = { styles.fieldLabelContainer } >
<Text style = { styles.text } > <Text
style = { [
styles.text, styles.fieldLabelText
] } >
{ t(this.props.i18nLabel) } { t(this.props.i18nLabel) }
</Text> </Text>
</View> </View>
@ -122,8 +117,7 @@ class FormRow extends Component<Props> {
_getRowStyle: () => Array<Object>; _getRowStyle: () => Array<Object>;
/** /**
* Assembles the row style array based on the row's props. For padding, see * Assembles the row style array based on the row's props.
* comment in functions.js.
* *
* @private * @private
* @returns {Array<Object>} * @returns {Array<Object>}
@ -137,33 +131,8 @@ class FormRow extends Component<Props> {
rowStyle.push(styles.fieldSeparator); rowStyle.push(styles.fieldSeparator);
} }
if (this.props._aspectRatio === ASPECT_RATIO_WIDE) {
const safeOffset = Math.max(
getSafetyOffset() - CONTAINER_PADDING, 0
);
rowStyle.push({
marginLeft: safeOffset,
marginRight: safeOffset
});
}
return rowStyle; return rowStyle;
} }
} }
/** export default translate(FormRow);
* Maps (parts of) the redux state to the React {@code Component} props of
* {@code FormRow}.
*
* @param {Object} state - The redux state.
* @protected
* @returns {Object}
*/
export function _mapStateToProps(state: Object) {
return {
_aspectRatio: state['features/base/responsive-ui'].aspectRatio
};
}
export default translate(connect(_mapStateToProps)(FormRow));

View File

@ -0,0 +1,60 @@
// @flow
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { translate } from '../../../base/i18n';
import styles from './styles';
/**
* The type of the React {@code Component} props of {@link FormSectionHeader}
*/
type Props = {
/**
* The i18n key of the text label of the section.
*/
i18nLabel: string,
/**
* An external style object passed to the component.
*/
style: Object,
/**
* Invoked to obtain translated strings.
*/
t: Function
}
/**
* Implements a React {@code Component} which renders a section header on a
* form.
*/
class FormSectionHeader extends Component<Props> {
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @override
* @returns {ReactElement}
*/
render() {
const { i18nLabel, style, t } = this.props;
return (
<View
style = { [
styles.formSectionTitle,
style
] } >
<Text>
{ t(i18nLabel) }
</Text>
</View>
);
}
}
export default translate(FormSectionHeader);

View File

@ -0,0 +1,3 @@
export { default as BackButton } from './BackButton';
export { default as FormRow } from './FormRow';
export { default as FormSectionHeader } from './FormSectionHeader';

View File

@ -0,0 +1,83 @@
import {
ColorPalette,
createStyleSheet
} from '../../../base/styles';
export const ANDROID_UNDERLINE_COLOR = 'transparent';
const TEXT_SIZE = 17;
/**
* The styles of the native components of the feature
* {@code app-settings}.
*/
export default createStyleSheet({
/**
* Standardized style for a field container {@code View}.
*/
fieldContainer: {
alignItems: 'center',
flexDirection: 'row',
minHeight: 65,
paddingHorizontal: 8
},
/**
* Standard container for a {@code View} containing a field label.
*/
fieldLabelContainer: {
alignItems: 'center',
flexDirection: 'row',
marginRight: 5
},
/**
* Text of the field labels on the form.
*/
fieldLabelText: {
fontSize: TEXT_SIZE
},
/**
* Field container style for all but last row {@code View}.
*/
fieldSeparator: {
borderBottomWidth: 1,
borderColor: 'rgba(0, 0, 0, 0.1)'
},
/**
* Style for the {@code View} containing each
* field values (the actual field).
*/
fieldValueContainer: {
alignItems: 'center',
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end'
},
/**
* Style fo the form section separator titles.
*/
formSectionTitle: {
backgroundColor: 'rgba(0, 0, 0, 0.1)',
marginTop: 5,
padding: 5
},
/**
* Global {@code Text} color for the components.
*/
text: {
color: ColorPalette.black
},
/**
* Standard text input field style.
*/
textInputField: {
flex: 1,
fontSize: TEXT_SIZE,
textAlign: 'right'
}
});

View File

@ -4,90 +4,11 @@ import {
createStyleSheet createStyleSheet
} from '../../base/styles'; } from '../../base/styles';
export const ANDROID_UNDERLINE_COLOR = 'transparent';
export const CONTAINER_PADDING = 2 * BoxModel.padding;
export const HEADER_COLOR = ColorPalette.blue;
export const HEADER_PADDING = BoxModel.padding;
const TEXT_SIZE = 17;
/** /**
* The styles of the React {@code Components} of the feature * The styles of the React {@code Components} of the feature
* {@code app-settings}. * {@code app-settings}.
*/ */
export default createStyleSheet({ export default createStyleSheet({
/**
* The back button style.
*/
backIcon: {
alignSelf: 'center',
fontSize: 26,
padding: 8,
paddingRight: 22
},
/**
* Standardized style for a field container {@code View}.
*/
fieldContainer: {
alignItems: 'center',
flexDirection: 'row',
minHeight: 65
},
/**
* Standard container for a {@code View} containing a field label.
*/
fieldLabelContainer: {
alignItems: 'center',
flexDirection: 'row',
marginRight: 5
},
/**
* Field container style for all but last row {@code View}.
*/
fieldSeparator: {
borderBottomWidth: 1,
borderColor: 'rgba(0, 0, 0, 0.1)'
},
/**
* Style for the {@code View} containing each
* field values (the actual field).
*/
fieldValueContainer: {
alignItems: 'center',
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end'
},
formSectionTitle: {
backgroundColor: 'rgba(0, 0, 0, 0.1)',
marginTop: 5,
padding: 5
},
/**
* Page header {@code View}.
*/
headerContainer: {
alignItems: 'center',
backgroundColor: HEADER_COLOR,
flexDirection: 'row',
justifyContent: 'flex-start',
padding: HEADER_PADDING
},
/**
* The title {@code Text} of the header.
*/
headerTitle: {
color: ColorPalette.white,
fontSize: 22
},
/** /**
* Style of the ScrollView to be able to scroll the content. * Style of the ScrollView to be able to scroll the content.
*/ */
@ -96,38 +17,17 @@ export default createStyleSheet({
}, },
/** /**
* The back button style on the settings screen. * Style of the settings screen content (form).
*/ */
settingsBackButton: { settingsForm: {
color: ColorPalette.white
},
/**
* The top level container {@code View}.
*/
settingsContainer: {
backgroundColor: ColorPalette.white,
flex: 1, flex: 1,
flexDirection: 'column', margin: BoxModel.margin
margin: 0,
padding: CONTAINER_PADDING,
paddingTop: 0
}, },
/** /**
* Global {@code Text} color for the page. * Global {@code Text} color for the page.
*/ */
text: { text: {
color: ColorPalette.black, color: ColorPalette.black
fontSize: TEXT_SIZE
},
/**
* Standard text input field style.
*/
textInputField: {
flex: 1,
fontSize: TEXT_SIZE,
textAlign: 'right'
} }
}); });

View File

@ -0,0 +1,56 @@
// @flow
import React, { Component } from 'react';
import { SafeAreaView, StatusBar, View } from 'react-native';
import styles, { STATUSBAR_COLOR } from './styles';
/**
* The type of the React {@code Component} props of {@link ScreenHeader}
*/
type Props = {
/**
* Children component(s).
*/
children: React$Node,
/**
* The component's external style
*/
style: Object
}
/**
* A generic screen header component.
*/
export default class Header extends Component<Props> {
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
*/
render() {
return (
<View
style = { styles.headerOverlay } >
<StatusBar
backgroundColor = { STATUSBAR_COLOR }
barStyle = 'light-content'
translucent = { false } />
<SafeAreaView>
<View
style = { [
styles.screenHeader,
this.props.style
] }>
{
this.props.children
}
</View>
</SafeAreaView>
</View>
);
}
}

View File

@ -1,5 +1,7 @@
export { default as Container } from './Container'; export { default as Container } from './Container';
export { default as Link } from './Link'; export { default as Link } from './Link';
export { default as LoadingIndicator } from './LoadingIndicator'; export { default as LoadingIndicator } from './LoadingIndicator';
export { default as Header } from './Header';
export * from './styles';
export { default as TintedView } from './TintedView'; export { default as TintedView } from './TintedView';
export { default as Text } from './Text'; export { default as Text } from './Text';

View File

@ -0,0 +1,39 @@
import {
BoxModel,
ColorPalette,
createStyleSheet
} from '../../../styles';
const HEADER_COLOR = ColorPalette.blue;
// Header height is from iOS guidelines. Also, this looks good.
const HEADER_HEIGHT = 44;
const HEADER_PADDING = BoxModel.padding;
export const STATUSBAR_COLOR = ColorPalette.blueHighlight;
/**
* The styles of the React {@code Components} of the generic components
* in the app.
*/
export default createStyleSheet({
/**
* Style of the header overlay to cover the unsafe areas.
*/
headerOverlay: {
backgroundColor: HEADER_COLOR
},
/**
* Base style of Header
*/
screenHeader: {
alignItems: 'center',
backgroundColor: HEADER_COLOR,
flexDirection: 'row',
height: HEADER_HEIGHT,
justifyContent: 'flex-start',
padding: HEADER_PADDING
}
});

View File

@ -1,4 +1,3 @@
export * from './components'; export * from './components';
export * from './functions';
export { default as Platform } from './Platform'; export { default as Platform } from './Platform';
export { default as RouteRegistry } from './RouteRegistry'; export { default as RouteRegistry } from './RouteRegistry';

View File

@ -19,6 +19,7 @@ export const ColorPalette = {
*/ */
black: BLACK, black: BLACK,
blue: '#17A0DB', blue: '#17A0DB',
blueHighlight: '#1081b2',
buttonUnderlay: '#495258', buttonUnderlay: '#495258',
darkGrey: '#555555', darkGrey: '#555555',
red: '#D00000', red: '#D00000',

View File

@ -0,0 +1,42 @@
import { ColorPalette } from './ColorPalette';
import {
createStyleSheet
} from '../../functions';
export const PlatformElements = createStyleSheet({
/**
* Platform specific header button (e.g. back, menu...etc).
*/
headerButton: {
alignSelf: 'center',
color: ColorPalette.white,
fontSize: 26,
paddingRight: 22,
zIndex: 9999
},
/**
* Generic style for a label placed in the header.
*/
headerText: {
color: ColorPalette.white,
fontSize: 20
},
/**
* The topmost level element of a page.
*/
page: {
alignItems: 'stretch',
bottom: 0,
flex: 1,
flexDirection: 'column',
left: 0,
overflow: 'hidden',
position: 'absolute',
right: 0,
top: 0
}
});

View File

@ -1,2 +1,3 @@
export * from './BoxModel'; export * from './BoxModel';
export * from './ColorPalette'; export * from './ColorPalette';
export * from './PlatformElements';

View File

@ -3,7 +3,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
// eslint-disable-next-line react-native/split-platform-components // eslint-disable-next-line react-native/split-platform-components
import { BackAndroid, BackHandler, View } from 'react-native'; import { BackAndroid, BackHandler, StatusBar, View } from 'react-native';
import { connect as reactReduxConnect } from 'react-redux'; import { connect as reactReduxConnect } from 'react-redux';
import { appNavigate } from '../../app'; import { appNavigate } from '../../app';
@ -192,6 +192,7 @@ class Conference extends Component<Props> {
onClick = { this._onClick } onClick = { this._onClick }
style = { styles.conference } style = { styles.conference }
touchFeedback = { false }> touchFeedback = { false }>
<StatusBar translucent = { true } />
{/* {/*
* The LargeVideo is the lowermost stacking layer. * The LargeVideo is the lowermost stacking layer.