Fix settings screen layout on iOS and add soft back button

This commit is contained in:
Lyubo Marinov 2018-01-18 15:28:25 -06:00
parent 410dc132e1
commit 112c856850
17 changed files with 292 additions and 304 deletions

View File

@ -27,12 +27,12 @@
.icon-arrow_back:before {
content: "\e5c4";
}
.icon-navigate_before:before {
content: "\e408";
}
.icon-event_note:before {
content: "\e616";
}
.icon-navigate_before:before {
content: "\e408";
}
.icon-public:before {
content: "\e80b";
}

View File

@ -1,29 +1,29 @@
/* @flow */
// @flow
import { HIDE_APP_SETTINGS, SHOW_APP_SETTINGS } from './actionTypes';
/**
* Redux-signals the request to open the app settings modal.
*
* @returns {{
* type: SHOW_APP_SETTINGS
* }}
*/
export function showAppSettings() {
return {
type: SHOW_APP_SETTINGS
};
}
/**
* Redux-signals the request to hide the app settings modal.
*
* @returns {{
* type: HIDE_APP_SETTINGS
* }}
*/
* Redux-signals the request to hide the app settings modal.
*
* @returns {{
* type: HIDE_APP_SETTINGS
* }}
*/
export function hideAppSettings() {
return {
type: HIDE_APP_SETTINGS
};
}
/**
* Redux-signals the request to open the app settings modal.
*
* @returns {{
* type: SHOW_APP_SETTINGS
* }}
*/
export function showAppSettings() {
return {
type: SHOW_APP_SETTINGS
};
}

View File

@ -2,43 +2,44 @@
import { Component } from 'react';
import { hideAppSettings } from '../actions';
import { getProfile, updateProfile } from '../../base/profile';
import { hideAppSettings } from '../actions';
/**
* The type of the React {@code Component} props of {@link AbstractAppSettings}
*/
* The type of the React {@code Component} props of {@link AbstractAppSettings}
*/
type Props = {
/**
* The current aspect ratio of the screen.
*/
* The current aspect ratio of the screen.
*/
_aspectRatio: Symbol,
/**
* The default URL for when there is no custom URL set in the profile.
*/
_serverURL: string,
/**
* The current profile object.
*/
* The current profile object.
*/
_profile: Object,
/**
* The visibility prop of the settings modal.
*/
* The default URL for when there is no custom URL set in the profile.
*/
_serverURL: string,
/**
* The visibility prop of the settings modal.
*/
_visible: boolean,
/**
* Redux store dispatch function.
*/
* Redux store dispatch function.
*/
dispatch: Dispatch<*>
};
/**
* Base (abstract) class for container component rendering
* the app settings page.
* Base (abstract) class for container component rendering the app settings
* page.
*
* @abstract
*/
@ -65,12 +66,12 @@ export class AbstractAppSettings extends Component<Props> {
_onChangeDisplayName: (string) => void;
/**
* Handles the display name field value change.
*
* @protected
* @param {string} text - The value typed in the name field.
* @returns {void}
*/
* Handles the display name field value change.
*
* @protected
* @param {string} text - The value typed in the name field.
* @returns {void}
*/
_onChangeDisplayName(text) {
this._updateProfile({
displayName: text
@ -80,12 +81,12 @@ export class AbstractAppSettings extends Component<Props> {
_onChangeEmail: (string) => void;
/**
* Handles the email field value change.
*
* @protected
* @param {string} text - The value typed in the email field.
* @returns {void}
*/
* Handles the email field value change.
*
* @protected
* @param {string} text - The value typed in the email field.
* @returns {void}
*/
_onChangeEmail(text) {
this._updateProfile({
email: text
@ -95,12 +96,12 @@ export class AbstractAppSettings extends Component<Props> {
_onChangeServerURL: (string) => void;
/**
* Handles the server name field value change.
*
* @protected
* @param {string} text - The server URL typed in the server field.
* @returns {void}
*/
* Handles the server name field value change.
*
* @protected
* @param {string} text - The server URL typed in the server field.
* @returns {void}
*/
_onChangeServerURL(text) {
this._updateProfile({
serverURL: text
@ -110,10 +111,10 @@ export class AbstractAppSettings extends Component<Props> {
_onRequestClose: () => void;
/**
* Handles the back button.
*
* @returns {void}
*/
* Handles the back button.
*
* @returns {void}
*/
_onRequestClose() {
this.props.dispatch(hideAppSettings());
}
@ -121,13 +122,13 @@ export class AbstractAppSettings extends Component<Props> {
_onStartAudioMutedChange: (boolean) => void;
/**
* Handles the start audio muted change event.
*
* @protected
* @param {boolean} newValue - The new value for the
* start audio muted option.
* @returns {void}
*/
* Handles the start audio muted change event.
*
* @protected
* @param {boolean} newValue - The new value for the
* start audio muted option.
* @returns {void}
*/
_onStartAudioMutedChange(newValue) {
this._updateProfile({
startWithAudioMuted: newValue
@ -137,13 +138,13 @@ export class AbstractAppSettings extends Component<Props> {
_onStartVideoMutedChange: (boolean) => void;
/**
* Handles the start video muted change event.
*
* @protected
* @param {boolean} newValue - The new value for the
* start video muted option.
* @returns {void}
*/
* Handles the start video muted change event.
*
* @protected
* @param {boolean} newValue - The new value for the
* start video muted option.
* @returns {void}
*/
_onStartVideoMutedChange(newValue) {
this._updateProfile({
startWithVideoMuted: newValue
@ -153,12 +154,12 @@ export class AbstractAppSettings extends Component<Props> {
_updateProfile: (Object) => void;
/**
* Updates the persisted profile on any change.
*
* @private
* @param {Object} updateObject - The partial update object for the profile.
* @returns {void}
*/
* Updates the persisted profile on any change.
*
* @private
* @param {Object} updateObject - The partial update object for the profile.
* @returns {void}
*/
_updateProfile(updateObject: Object) {
this.props.dispatch(updateProfile({
...this.props._profile,
@ -181,8 +182,8 @@ export function _mapStateToProps(state: Object) {
return {
_aspectRatio: state['features/base/aspect-ratio'].aspectRatio,
_serverURL,
_profile,
_serverURL,
_visible: state['features/app-settings'].visible
};
}

View File

@ -5,24 +5,21 @@ import {
Switch,
Text,
TextInput,
View } from 'react-native';
View
} from 'react-native';
import { connect } from 'react-redux';
import {
_mapStateToProps,
AbstractAppSettings
} from './AbstractAppSettings';
import BackButton from './BackButton';
import FormRow from './FormRow';
import FormSectionHeader from './FormSectionHeader';
import styles, { HEADER_PADDING } from './styles';
import { getSafetyOffset } from '../functions.native';
import { ASPECT_RATIO_NARROW } from '../../base/aspect-ratio';
import { translate } from '../../base/i18n';
import { isIPad } from '../../base/react';
import { _mapStateToProps, AbstractAppSettings } from './AbstractAppSettings';
import BackButton from './BackButton';
import FormRow from './FormRow';
import FormSectionHeader from './FormSectionHeader';
import { getSafetyOffset } from '../functions';
import styles, { HEADER_PADDING } from './styles';
/**
* The native container rendering the app settings page.
*
@ -30,10 +27,10 @@ import { isIPad } from '../../base/react';
*/
class AppSettings extends AbstractAppSettings {
/**
* Instantiates a new {@code AppSettings} instance.
*
* @inheritdoc
*/
* Instantiates a new {@code AppSettings} instance.
*
* @inheritdoc
*/
constructor(props) {
super(props);
@ -49,8 +46,8 @@ class AppSettings extends AbstractAppSettings {
render() {
const { _profile, t } = this.props;
// FIXME: presentationStyle is added to workaround
// orientation issue on iOS
// FIXME: presentationStyle is added to workaround orientation issue on
// iOS
return (
<Modal
@ -131,12 +128,12 @@ class AppSettings extends AbstractAppSettings {
}
/**
* Calculates header safety padding for mobile devices.
* See comment in functions.js.
*
* @private
* @returns {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);

View File

@ -3,29 +3,29 @@
import React, { Component } from 'react';
import { TouchableOpacity } from 'react-native';
import styles from './styles';
import { Icon } from '../../base/font-icons';
import { Platform } from '../../base/react';
import styles from './styles';
/**
* The icon glyph to be used on a specific platform.
*/
* The icon glyph to be used on a specific platform.
*/
const BACK_ICON = Platform.OS === 'android' ? 'arrow_back' : 'navigate_before';
/**
* The type of the React {@code Component} props of {@link BackButton}
*/
* The type of the React {@code Component} props of {@link BackButton}
*/
type Props = {
/**
* The action to be performed when the button is pressed.
*/
* The action to be performed when the button is pressed.
*/
onPress: Function,
/**
* An external style object passed to the component.
*/
* An external style object passed to the component.
*/
style: Object
};

View File

@ -1,40 +1,38 @@
/* @flow */
// @flow
import React, { Component } from 'react';
import {
Text,
View } from 'react-native';
import { Text, View } from 'react-native';
import { connect } from 'react-redux';
import styles, { ANDROID_UNDERLINE_COLOR, CONTAINER_PADDING } from './styles';
import { getSafetyOffset } from '../functions';
import { ASPECT_RATIO_WIDE } from '../../base/aspect-ratio';
import { translate } from '../../base/i18n';
import { getSafetyOffset } from '../functions';
import styles, { ANDROID_UNDERLINE_COLOR, CONTAINER_PADDING } 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 = {
/**
* The current aspect ratio of the screen.
*/
* The current aspect ratio of the screen.
*/
_aspectRatio: Symbol,
/**
*/
*
*/
children: Object,
/**
* Prop to decide if a row separator is to be rendered.
*/
* Prop to decide if a row separator is to be rendered.
*/
fieldSeparator: boolean,
/**
* The i18n key of the text label of the form field.
*/
* The i18n key of the text label of the form field.
*/
i18nLabel: string,
/**
@ -44,8 +42,8 @@ type Props = {
}
/**
* Implements a React {@code Component} which renders a standardized row
* on a form. The component should have exactly one child component.
* Implements a React {@code Component} which renders a standardized row on a
* form. The component should have exactly one child component.
*/
class FormRow extends Component<Props> {
/**
@ -96,17 +94,17 @@ class FormRow extends Component<Props> {
_getDefaultFieldProps: (field: Component<*, *>) => Object;
/**
* Assembles the default props to the field child component of
* this form row.
*
* Currently tested/supported field types:
* - TextInput
* - Switch (needs no addition props ATM).
*
* @private
* @param {Object} field - The field (child) component.
* @returns {Object}
*/
* Assembles the default props to the field child component of this form
* row.
*
* Currently tested/supported field types:
* - TextInput
* - Switch (needs no addition props ATM).
*
* @private
* @param {Object} field - The field (child) component.
* @returns {Object}
*/
_getDefaultFieldProps(field: Object) {
if (field && field.type) {
switch (field.type.displayName) {
@ -124,12 +122,12 @@ class FormRow extends Component<Props> {
_getRowStyle: () => Array<Object>;
/**
* Assembles the row style array based on the row's props.
* For padding, see comment in functions.js.
*
* @private
* @returns {Array<Object>}
*/
* Assembles the row style array based on the row's props. For padding, see
* comment in functions.js.
*
* @private
* @returns {Array<Object>}
*/
_getRowStyle() {
const rowStyle = [
styles.fieldContainer

View File

@ -1,34 +1,33 @@
/* @flow */
// @flow
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { connect } from 'react-redux';
import styles, { CONTAINER_PADDING } from './styles';
import { getSafetyOffset } from '../functions';
import { ASPECT_RATIO_WIDE } from '../../base/aspect-ratio';
import { translate } from '../../base/i18n';
import { getSafetyOffset } from '../functions';
import styles, { CONTAINER_PADDING } from './styles';
/**
* The type of the React {@code Component} props of {@link FormSectionHeader}
*/
* The type of the React {@code Component} props of {@link FormSectionHeader}
*/
type Props = {
/**
* The current aspect ratio of the screen.
*/
* The current aspect ratio of the screen.
*/
_aspectRatio: Symbol,
/**
* The i18n key of the text label of the section.
*/
* The i18n key of the text label of the section.
*/
i18nLabel: string,
/**
* An external style object passed to the component.
*/
* An external style object passed to the component.
*/
style: Object,
/**
@ -38,8 +37,8 @@ type Props = {
}
/**
* Implements a React {@code Component} which renders
* a section header on a form. This calculates the available safe view as well.
* 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> {
/**
@ -80,17 +79,16 @@ class FormSectionHeader extends Component<Props> {
_getSafetyMargin: () => Object;
/**
* Calculates the safety margin for this header.
* See comment in functions.js.
*
* @private
* @returns {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
);
const safeOffset
= Math.max(getSafetyOffset() - CONTAINER_PADDING, 0);
return {
marginLeft: safeOffset,

View File

@ -1,4 +1,5 @@
import { Platform } from 'react-native';
import {
BoxModel,
ColorPalette,
@ -13,30 +14,29 @@ const TEXT_SIZE = 17;
/**
* The styles of the React {@code Components} of the feature
* {@code AppSettings}.
* {@code app-settings}.
*/
export default createStyleSheet({
/**
*The platform specific back button style.
*/
* The platform specific back button style.
*/
backIcon: {
alignSelf: 'center',
...Platform.select({
ios: {
alignSelf: 'center',
fontSize: 30
},
android: {
fontSize: 24,
padding: 8
},
ios: {
fontSize: 30
}
})
},
/**
* Standardized style for a field container {@code View}.
*/
* Standardized style for a field container {@code View}.
*/
fieldContainer: {
alignItems: 'center',
flexDirection: 'row',
@ -44,25 +44,25 @@ export default createStyleSheet({
},
/**
* Standard container for a {@code View} containing a field label.
*/
* Standard container for a {@code View} containing a field label.
*/
fieldLabelContainer: {
alignItems: 'center',
flexDirection: 'row'
},
/**
* Field container style for all but last row {@code View}.
*/
* 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).
*/
* Style for the {@code View} containing each
* field values (the actual field).
*/
fieldValueContainer: {
alignItems: 'center',
flex: 1,
@ -77,8 +77,8 @@ export default createStyleSheet({
},
/**
* Page header {@code View}.
*/
* Page header {@code View}.
*/
headerContainer: {
alignItems: 'center',
backgroundColor: HEADER_COLOR,
@ -88,31 +88,31 @@ export default createStyleSheet({
},
/**
* The title {@code Text} of the header.
*/
* The title {@code Text} of the header.
*/
headerTitle: {
color: ColorPalette.white,
fontSize: 24
},
/**
* Style of the scrollview to be able to scroll the content.
*/
* Style of the ScrollView to be able to scroll the content.
*/
scrollView: {
flex: 1
},
/**
* The back button style on the settings screen.
*/
* The back button style on the settings screen.
*/
settingsBackButton: {
color: ColorPalette.white,
fontSize: 25
},
/**
* The top level container {@code View}.
*/
* The top level container {@code View}.
*/
settingsContainer: {
backgroundColor: ColorPalette.white,
flex: 1,
@ -123,16 +123,16 @@ export default createStyleSheet({
},
/**
* Global {@code Text} color for the page.
*/
* Global {@code Text} color for the page.
*/
text: {
color: ColorPalette.black,
fontSize: TEXT_SIZE
},
/**
* Standard text input field style.
*/
* Standard text input field style.
*/
textInputField: {
flex: 1,
fontSize: TEXT_SIZE,

View File

@ -6,23 +6,17 @@ const IPHONE_OFFSET = 20;
const IPHONEX_OFFSET = 44;
/**
* Determines the offset to be used for the device.
* This uses a custom implementation to minimize empty area around screen,
* especially on iPhone X.
*
* @returns {number}
*/
* Determines the offset to be used for the device. This uses a custom
* implementation to minimize empty area around screen, especially on iPhone X.
*
* @returns {number}
*/
export function getSafetyOffset() {
if (Platform.OS === 'android') {
/* Android doesn't need offset, except the Essential phone. Should be
* addressed later with a generic solution.
*/
// Android doesn't need offset, except the Essential phone. Should be
// addressed later with a generic solution.
return 0;
}
if (isIPhoneX()) {
return IPHONEX_OFFSET;
}
return IPHONE_OFFSET;
return isIPhoneX() ? IPHONEX_OFFSET : IPHONE_OFFSET;
}

View File

@ -1,10 +1,10 @@
/* @flow */
import { hideAppSettings } from './actions';
// @flow
import { SET_ROOM } from '../base/conference';
import { MiddlewareRegistry } from '../base/redux';
import { hideAppSettings } from './actions';
/**
* The Redux middleware to trigger settings screen show or hide
* when necessary.
@ -30,8 +30,8 @@ MiddlewareRegistry.register(store => next => action => {
* @private
* @returns {Object} The new state.
*/
function _closeAppSettings(store, next, action) {
store.dispatch(hideAppSettings());
function _closeAppSettings({ dispatch }, next, action) {
dispatch(hideAppSettings());
return next(action);
}

View File

@ -179,7 +179,7 @@ export class AbstractApp extends Component {
* @returns {void}
*/
componentWillReceiveProps(nextProps) {
const currentProps = this.props;
const { props } = this;
this.init.then(() => {
// The consumer of this AbstractApp did not provide a redux store.
@ -191,7 +191,7 @@ export class AbstractApp extends Component {
// its own internal redux store. If the consumer did not
// provide a redux store before, then this instance is
// using its own internal redux store already.
&& typeof currentProps.store !== 'undefined') {
&& typeof props.store !== 'undefined') {
this.setState({
store: this._maybeCreateStore(nextProps)
});
@ -201,11 +201,11 @@ export class AbstractApp extends Component {
let { url } = nextProps;
url = toURLString(url);
if (toURLString(currentProps.url) !== url
if (toURLString(props.url) !== url
// XXX Refer to the implementation of loadURLObject: in
// ios/sdk/src/JitsiMeetView.m for further information.
|| currentProps.timestamp !== nextProps.timestamp) {
|| props.timestamp !== nextProps.timestamp) {
this._openURL(url || this._getDefaultURL());
}
});
@ -375,11 +375,10 @@ export class AbstractApp extends Component {
}
}
const profileServerURL = getProfile(
this._getStore().getState()
).serverURL;
return this.props.defaultURL || profileServerURL || DEFAULT_URL;
return (
this.props.defaultURL
|| getProfile(this._getStore().getState()).serverURL
|| DEFAULT_URL);
}
/**

View File

@ -214,6 +214,7 @@ function _visitNode(node, callback) {
if (console) {
const loggerLevels = require('jitsi-meet-logger').levels;
console.disableYellowBox = true;
Object.keys(loggerLevels).forEach(key => {
const level = loggerLevels[key];
const consoleLog = console[level];

View File

@ -1,17 +1,13 @@
/* @flow */
import { PROFILE_UPDATED } from './actionTypes';
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
// @flow
import {
getLocalParticipant,
participantUpdated
} from '../participants';
import { getLocalParticipant, participantUpdated } from '../participants';
import { getProfile } from '../profile';
import { toState } from '../redux';
import { MiddlewareRegistry, toState } from '../redux';
import { PROFILE_UPDATED } from './actionTypes';
/**
* A MiddleWare to update the local participant when the profile
* is updated.
* A middleWare to update the local participant when the profile is updated.
*
* @param {Store} store - The redux store.
* @returns {Function}
@ -34,11 +30,17 @@ MiddlewareRegistry.register(store => next => action => {
* @returns {void}
*/
function _updateLocalParticipant(store) {
const localParticipant = getLocalParticipant(toState(store));
const profile = getProfile(toState(store));
const state = toState(store);
const localParticipant = getLocalParticipant(state);
const profile = getProfile(state);
localParticipant.email = profile.email;
localParticipant.name = profile.displayName;
store.dispatch(participantUpdated({
// Identify that the participant to update i.e. the local participant:
id: localParticipant && localParticipant.id,
local: true,
store.dispatch(participantUpdated(localParticipant));
// Specify the updates to be applied to the identified participant:
email: profile.email,
name: profile.displayName
}));
}

View File

@ -1,37 +1,35 @@
// @flow
import { Dimensions } from 'react-native';
import Platform from './Platform';
const IPHONEX_HEIGHT = 812;
const IPHONEX_WIDTH = 375;
/**
* Determines if the device is an iPad or not.
*
* @returns {boolean}
*/
* Determines if the device is an iPad or not.
*
* @returns {boolean}
*/
export function isIPad() {
const { height, width } = Dimensions.get('window');
return Platform.OS === 'ios' && (
Math.max(height, width)
/ Math.min(height, width)) < 1.6;
return (
Platform.OS === 'ios'
&& (Math.max(height, width) / Math.min(height, width)) < 1.6);
}
/**
* Determines if it's an iPhone X or not.
*
* @returns {boolean}
*/
* Determines if it's an iPhone X or not.
*
* @returns {boolean}
*/
export function isIPhoneX() {
const { height, width } = Dimensions.get('window');
return (
Platform.OS === 'ios'
&& ((height === IPHONEX_HEIGHT
&& width === IPHONEX_WIDTH)
|| (height === IPHONEX_WIDTH
&& width === IPHONEX_HEIGHT))
);
&& ((height === IPHONEX_HEIGHT && width === IPHONEX_WIDTH)
|| (height === IPHONEX_WIDTH && width === IPHONEX_HEIGHT)));
}

View File

@ -26,18 +26,18 @@ MiddlewareRegistry.register(store => next => action => {
});
/**
* Stores the recently joined room into {@code window.localStorage}.
*
* @param {Store} store - The redux store in which the specified action is being
* dispatched.
* @param {Dispatch} next - The redux {@code dispatch} function to dispatch the
* specified action to the specified store.
* @param {Action} action - The redux action {@code SET_ROOM} which is being
* dispatched in the specified store.
* @private
* @returns {Object} The new state that is the result of the reduction of the
* specified action.
*/
* Stores the recently joined room into {@code window.localStorage}.
*
* @param {Store} store - The redux store in which the specified action is being
* dispatched.
* @param {Dispatch} next - The redux {@code dispatch} function to dispatch the
* specified action to the specified store.
* @param {Action} action - The redux action {@code SET_ROOM} which is being
* dispatched in the specified store.
* @private
* @returns {Object} The new state that is the result of the reduction of the
* specified action.
*/
function _storeJoinedRoom(store, next, action) {
const result = next(action);
@ -70,18 +70,18 @@ function _storeJoinedRoom(store, next, action) {
}
/**
* Updates the conference length when left.
*
* @param {Store} store - The redux store in which the specified action is being
* dispatched.
* @param {Dispatch} next - The redux {@code dispatch} function to dispatch the
* specified action to the specified store.
* @param {Action} action - The redux action {@code CONFERENCE_WILL_LEAVE} which
* is being dispatched in the specified store.
* @private
* @returns {Object} The new state that is the result of the reduction of the
* specified action.
*/
* Updates the conference length when left.
*
* @param {Store} store - The redux store in which the specified action is being
* dispatched.
* @param {Dispatch} next - The redux {@code dispatch} function to dispatch the
* specified action to the specified store.
* @param {Action} action - The redux action {@code CONFERENCE_WILL_LEAVE} which
* is being dispatched in the specified store.
* @private
* @returns {Object} The new state that is the result of the reduction of the
* specified action.
*/
function _updateConferenceDuration({ getState }, next, action) {
const result = next(action);

View File

@ -201,11 +201,11 @@ export class AbstractWelcomePage extends Component<*, *> {
_onSettingsOpen: () => void;
/**
* Sets the app settings modal visible.
*
* @protected
* @returns {void}
*/
* Sets the app settings modal visible.
*
* @protected
* @returns {void}
*/
_onSettingsOpen() {
this.props.dispatch(showAppSettings());
}

View File

@ -38,8 +38,8 @@ export default createStyleSheet({
},
/**
* Layout of the button container.
*/
* Layout of the button container.
*/
buttonRow: {
flexDirection: 'row'
},
@ -54,8 +54,8 @@ export default createStyleSheet({
},
/**
* Style of the join button.
*/
* Style of the join button.
*/
joinButton: {
flex: 1
},
@ -126,16 +126,16 @@ export default createStyleSheet({
},
/**
* Style of the settings button.
*/
* Style of the settings button.
*/
settingsButton: {
width: 65,
marginRight: BoxModel.margin
},
/**
* Style of the settings icon on the settings button.
*/
* Style of the settings icon on the settings button.
*/
settingsIcon: {
fontSize: 24,
alignSelf: 'center'