diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java
index ded19071b..96dba56d3 100644
--- a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java
+++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java
@@ -33,14 +33,14 @@ import java.net.URL;
/**
* Base Activity for applications integrating Jitsi Meet at a higher level. It
- * contains all the required wiring between the {@code JKConferenceView} and
+ * contains all the required wiring between the {@code JitsiMeetView} and
* the Activity lifecycle methods already implemented.
*
- * In this activity we use a single {@code JKConferenceView} instance. This
+ * In this activity we use a single {@code JitsiMeetView} instance. This
* instance gives us access to a view which displays the welcome page and the
* conference itself. All lifetime methods associated with this Activity are
* hooked to the React Native subsystem via proxy calls through the
- * {@code JKConferenceView} static methods.
+ * {@code JitsiMeetView} static methods.
*/
public class JitsiMeetActivity extends AppCompatActivity {
/**
diff --git a/lang/main.json b/lang/main.json
index 2b884abed..0f10649e2 100644
--- a/lang/main.json
+++ b/lang/main.json
@@ -47,16 +47,18 @@
},
"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.",
- "audioOnlyLabel": "Voice",
+ "audioVideoSwitch": {
+ "audio": "Voice",
+ "video": "Video"
+ },
"go": "GO",
- "hintText": "Enter a room name you want to join to, or simply create a new room name, eg. MeetingWithJohn",
"join": "JOIN",
"privacy": "Privacy",
"roomname": "Enter room name",
+ "roomnameHint": "Enter the name or URL of the room you want to join. You may make a name up, just let the people you are meeting know it so that they enter the same name.",
"sendFeedback": "Send feedback",
"terms": "Terms",
- "title": "More secure, more flexible, and completely free video conferencing",
- "videoEnabledLabel": "Video"
+ "title": "More secure, more flexible, and completely free video conferencing"
},
"startupoverlay": {
"policyText": " ",
@@ -503,7 +505,7 @@
"title": "Call info",
"tooltip": "Get access info about the meeting"
},
- "settingsScreen": {
+ "settingsView": {
"alertOk": "OK",
"alertTitle": "Warning",
"alertURLText": "The entered server URL is invalid",
@@ -515,8 +517,5 @@
"serverURL": "Server URL",
"startWithAudioMuted": "Start with audio muted",
"startWithVideoMuted": "Start with video muted"
- },
- "sideBar": {
- "settings": "Settings"
}
}
diff --git a/modules/UI/side_pannels/settings/SettingsMenu.js b/modules/UI/side_pannels/settings/SettingsMenu.js
index 35d2106c7..fbf7ff372 100644
--- a/modules/UI/side_pannels/settings/SettingsMenu.js
+++ b/modules/UI/side_pannels/settings/SettingsMenu.js
@@ -1,17 +1,18 @@
/* global $, APP, interfaceConfig */
/* eslint-disable no-unused-vars */
+
import React from 'react';
import ReactDOM from 'react-dom';
import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux';
import { i18next } from '../../../../react/features/base/i18n';
-import { SettingsMenu } from '../../../../react/features/settings-menu';
-/* eslint-enable no-unused-vars */
-
+import { SettingsMenu } from '../../../../react/features/settings';
import UIUtil from '../../util/UIUtil';
+/* eslint-enable no-unused-vars */
+
export default {
init() {
const settingsMenuContainer = document.createElement('div');
@@ -31,8 +32,7 @@ export default {
ReactDOM.render(
-
+
,
settingsMenuContainer
diff --git a/react/features/analytics/AnalyticsEvents.js b/react/features/analytics/AnalyticsEvents.js
index afb11f246..049bffe83 100644
--- a/react/features/analytics/AnalyticsEvents.js
+++ b/react/features/analytics/AnalyticsEvents.js
@@ -76,13 +76,13 @@ export const VIDEO_MUTE = 'video.mute';
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createApiEvent = function(action, attributes = {}) {
+export function createApiEvent(action, attributes = {}) {
return {
action,
attributes,
source: 'jitsi-meet-api'
};
-};
+}
/**
* Creates an event which indicates that the audio-only mode has been changed.
@@ -91,11 +91,11 @@ export const createApiEvent = function(action, attributes = {}) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createAudioOnlyChangedEvent = function(enabled) {
+export function createAudioOnlyChangedEvent(enabled) {
return {
action: `audio.only.${enabled ? 'enabled' : 'disabled'}`
};
-};
+}
/**
* Creates an event which indicates that a device was changed.
@@ -106,7 +106,7 @@ export const createAudioOnlyChangedEvent = function(enabled) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createDeviceChangedEvent = function(mediaType, deviceType) {
+export function createDeviceChangedEvent(mediaType, deviceType) {
return {
action: 'device.changed',
attributes: {
@@ -114,7 +114,7 @@ export const createDeviceChangedEvent = function(mediaType, deviceType) {
'media_type': mediaType
}
};
-};
+}
/**
* Creates an event which specifies that the feedback dialog has been opened.
@@ -122,11 +122,11 @@ export const createDeviceChangedEvent = function(mediaType, deviceType) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createFeedbackOpenEvent = function() {
+export function createFeedbackOpenEvent() {
return {
action: 'feedback.opened'
};
-};
+}
/**
* Creates an event which indicates that the invite dialog was closed. This is
@@ -136,11 +136,11 @@ export const createFeedbackOpenEvent = function() {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createInviteDialogClosedEvent = function() {
+export function createInviteDialogClosedEvent() {
return {
action: 'invite.dialog.closed'
};
-};
+}
/**
* Creates a "page reload" event.
@@ -152,17 +152,16 @@ export const createInviteDialogClosedEvent = function() {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createPageReloadScheduledEvent
- = function(reason, timeout, details) {
- return {
- action: 'page.reload.scheduled',
- attributes: {
- reason,
- timeout,
- ...details
- }
- };
+export function createPageReloadScheduledEvent(reason, timeout, details) {
+ return {
+ action: 'page.reload.scheduled',
+ attributes: {
+ reason,
+ timeout,
+ ...details
+ }
};
+}
/**
* Creates a "pinned" or "unpinned" event.
@@ -173,17 +172,16 @@ export const createPageReloadScheduledEvent
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createPinnedEvent
- = function(action, participantId, attributes) {
- return {
- type: TYPE_TRACK,
- action,
- actionSubject: 'participant',
- objectType: 'participant',
- objectId: participantId,
- attributes
- };
- };
+export function createPinnedEvent(action, participantId, attributes) {
+ return {
+ type: TYPE_TRACK,
+ action,
+ actionSubject: 'participant',
+ objectType: 'participant',
+ objectId: participantId,
+ attributes
+ };
+}
/**
* Creates an event which indicates that a button in the profile panel was
@@ -194,16 +192,15 @@ export const createPinnedEvent
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createProfilePanelButtonEvent
- = function(buttonName, attributes = {}) {
- return {
- action: 'clicked',
- actionSubject: buttonName,
- attributes,
- source: 'profile.panel',
- type: TYPE_UI
- };
+export function createProfilePanelButtonEvent(buttonName, attributes = {}) {
+ return {
+ action: 'clicked',
+ actionSubject: buttonName,
+ attributes,
+ source: 'profile.panel',
+ type: TYPE_UI
};
+}
/**
* Creates an event which indicates that a specific button on one of the
@@ -215,14 +212,14 @@ export const createProfilePanelButtonEvent
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createRecordingDialogEvent = function(dialogName, buttonName) {
+export function createRecordingDialogEvent(dialogName, buttonName) {
return {
action: 'clicked',
actionSubject: buttonName,
source: `${dialogName}.recording.dialog`,
type: TYPE_UI
};
-};
+}
/**
* Creates an event which specifies that the "confirm" button on the remote
@@ -233,7 +230,7 @@ export const createRecordingDialogEvent = function(dialogName, buttonName) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createRemoteMuteConfirmedEvent = function(participantId) {
+export function createRemoteMuteConfirmedEvent(participantId) {
return {
action: 'clicked',
actionSubject: 'remote.mute.dialog.confirm.button',
@@ -243,7 +240,7 @@ export const createRemoteMuteConfirmedEvent = function(participantId) {
source: 'remote.mute.dialog',
type: TYPE_UI
};
-};
+}
/**
* Creates an event which indicates that one of the buttons in the "remote
@@ -254,16 +251,15 @@ export const createRemoteMuteConfirmedEvent = function(participantId) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createRemoteVideoMenuButtonEvent
- = function(buttonName, attributes) {
- return {
- action: 'clicked',
- actionSubject: buttonName,
- attributes,
- source: 'remote.video.menu',
- type: TYPE_UI
- };
+export function createRemoteVideoMenuButtonEvent(buttonName, attributes) {
+ return {
+ action: 'clicked',
+ actionSubject: buttonName,
+ attributes,
+ source: 'remote.video.menu',
+ type: TYPE_UI
};
+}
/**
* Creates an event indicating that an action related to screen sharing
@@ -273,12 +269,12 @@ export const createRemoteVideoMenuButtonEvent
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createScreenSharingEvent = function(action) {
+export function createScreenSharingEvent(action) {
return {
action,
actionSubject: 'screen.sharing'
};
-};
+}
/**
* The local participant failed to send a "selected endpoint" message to the
@@ -288,7 +284,7 @@ export const createScreenSharingEvent = function(action) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createSelectParticipantFailedEvent = function(error) {
+export function createSelectParticipantFailedEvent(error) {
const event = {
action: 'select.participant.failed'
};
@@ -298,7 +294,7 @@ export const createSelectParticipantFailedEvent = function(error) {
}
return event;
-};
+}
/**
* Creates an event associated with the "shared video" feature.
@@ -308,13 +304,13 @@ export const createSelectParticipantFailedEvent = function(error) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createSharedVideoEvent = function(action, attributes = {}) {
+export function createSharedVideoEvent(action, attributes = {}) {
return {
action,
attributes,
actionSubject: 'shared.video'
};
-};
+}
/**
* Creates an event associated with a shortcut being pressed, released or
@@ -331,17 +327,19 @@ export const createSharedVideoEvent = function(action, attributes = {}) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createShortcutEvent
- = function(shortcut, action = ACTION_SHORTCUT_TRIGGERED, attributes = {}) {
- return {
- action,
- actionSubject: 'keyboard.shortcut',
- actionSubjectId: shortcut,
- attributes,
- source: 'keyboard.shortcut',
- type: TYPE_UI
- };
+export function createShortcutEvent(
+ shortcut,
+ action = ACTION_SHORTCUT_TRIGGERED,
+ attributes = {}) {
+ return {
+ action,
+ actionSubject: 'keyboard.shortcut',
+ actionSubjectId: shortcut,
+ attributes,
+ source: 'keyboard.shortcut',
+ type: TYPE_UI
};
+}
/**
* Creates an event which indicates the "start audio only" configuration.
@@ -350,14 +348,14 @@ export const createShortcutEvent
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createStartAudioOnlyEvent = function(audioOnly) {
+export function createStartAudioOnlyEvent(audioOnly) {
return {
action: 'start.audio.only',
attributes: {
enabled: audioOnly
}
};
-};
+}
/**
* Creates an event which indicates the "start muted" configuration.
@@ -372,17 +370,19 @@ export const createStartAudioOnlyEvent = function(audioOnly) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createStartMutedConfigurationEvent
- = function(source, audioMute, videoMute) {
- return {
- action: 'start.muted.configuration',
- attributes: {
- source,
- 'audio_mute': audioMute,
- 'video_mute': videoMute
- }
- };
+export function createStartMutedConfigurationEvent(
+ source,
+ audioMute,
+ videoMute) {
+ return {
+ action: 'start.muted.configuration',
+ attributes: {
+ source,
+ 'audio_mute': audioMute,
+ 'video_mute': videoMute
+ }
};
+}
/**
* Creates an event which indicates the delay for switching between simulcast
@@ -392,12 +392,12 @@ export const createStartMutedConfigurationEvent
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createStreamSwitchDelayEvent = function(attributes) {
+export function createStreamSwitchDelayEvent(attributes) {
return {
action: 'stream.switch.delay',
attributes
};
-};
+}
/**
* Automatically changing the mute state of a media track in order to match
@@ -409,7 +409,7 @@ export const createStreamSwitchDelayEvent = function(attributes) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createSyncTrackStateEvent = function(mediaType, muted) {
+export function createSyncTrackStateEvent(mediaType, muted) {
return {
action: 'sync.track.state',
attributes: {
@@ -417,7 +417,7 @@ export const createSyncTrackStateEvent = function(mediaType, muted) {
muted
}
};
-};
+}
/**
* Creates an event associated with a toolbar button being clicked/pressed. By
@@ -431,7 +431,7 @@ export const createSyncTrackStateEvent = function(mediaType, muted) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createToolbarEvent = function(buttonName, attributes = {}) {
+export function createToolbarEvent(buttonName, attributes = {}) {
return {
action: 'clicked',
actionSubject: buttonName,
@@ -439,7 +439,7 @@ export const createToolbarEvent = function(buttonName, attributes = {}) {
source: 'toolbar.button',
type: TYPE_UI
};
-};
+}
/**
* Creates an event which indicates that a local track was muted.
@@ -452,7 +452,7 @@ export const createToolbarEvent = function(buttonName, attributes = {}) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createTrackMutedEvent = function(mediaType, reason, muted = true) {
+export function createTrackMutedEvent(mediaType, reason, muted = true) {
return {
action: 'track.muted',
attributes: {
@@ -461,7 +461,7 @@ export const createTrackMutedEvent = function(mediaType, reason, muted = true) {
reason
}
};
-};
+}
/**
* Creates an event for an action on the welcome page.
@@ -472,12 +472,11 @@ export const createTrackMutedEvent = function(mediaType, reason, muted = true) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
-export const createWelcomePageEvent
- = function(action, actionSubject, attributes = {}) {
- return {
- action,
- actionSubject,
- attributes,
- source: 'welcomePage'
- };
+export function createWelcomePageEvent(action, actionSubject, attributes = {}) {
+ return {
+ action,
+ actionSubject,
+ attributes,
+ source: 'welcomePage'
};
+}
diff --git a/react/features/app-settings/actionTypes.js b/react/features/app-settings/actionTypes.js
deleted file mode 100644
index 36c7e0b12..000000000
--- a/react/features/app-settings/actionTypes.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * The type of (redux) action which signals the request
- * to hide the app settings screen.
- *
- * {
- * type: HIDE_APP_SETTINGS
- * }
- */
-export const HIDE_APP_SETTINGS = Symbol('HIDE_APP_SETTINGS');
-
-/**
- * The type of (redux) action which signals the request
- * to show the app settings screen where available.
- *
- * {
- * type: SHOW_APP_SETTINGS
- * }
- */
-export const SHOW_APP_SETTINGS = Symbol('SHOW_APP_SETTINGS');
diff --git a/react/features/app-settings/actions.js b/react/features/app-settings/actions.js
deleted file mode 100644
index f446570ec..000000000
--- a/react/features/app-settings/actions.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// @flow
-
-import { HIDE_APP_SETTINGS, SHOW_APP_SETTINGS } from './actionTypes';
-
-/**
- * Redux-signals the request to hide the app settings screen.
- *
- * @returns {{
- * type: HIDE_APP_SETTINGS
- * }}
- */
-export function hideAppSettings() {
- return {
- type: HIDE_APP_SETTINGS
- };
-}
-
-/**
- * Redux-signals the request to open the app settings screen.
- *
- * @returns {{
- * type: SHOW_APP_SETTINGS
- * }}
- */
-export function showAppSettings() {
- return {
- type: SHOW_APP_SETTINGS
- };
-}
diff --git a/react/features/app-settings/components/AppSettings.native.js b/react/features/app-settings/components/AppSettings.native.js
deleted file mode 100644
index 86040846a..000000000
--- a/react/features/app-settings/components/AppSettings.native.js
+++ /dev/null
@@ -1,238 +0,0 @@
-// @flow
-
-import React from 'react';
-import {
- Alert,
- Modal,
- SafeAreaView,
- ScrollView,
- Switch,
- Text,
- TextInput,
- View
-} from 'react-native';
-import { connect } from 'react-redux';
-
-import { translate } from '../../base/i18n';
-import { Header } from '../../base/react';
-import { PlatformElements } from '../../base/styles';
-
-import { hideAppSettings } from '../actions';
-import { normalizeUserInputURL } from '../functions';
-
-import { BackButton, FormRow, FormSectionHeader } from './_';
-import { _mapStateToProps, AbstractAppSettings } from './AbstractAppSettings';
-import styles from './styles';
-
-/**
- * The native container rendering the app settings page.
- *
- * @extends AbstractAppSettings
- */
-class AppSettings extends AbstractAppSettings {
- _urlField: Object;
-
- /**
- * Instantiates a new {@code AppSettings} instance.
- *
- * @inheritdoc
- */
- constructor(props) {
- super(props);
-
- this._onBlurServerURL = this._onBlurServerURL.bind(this);
- this._onRequestClose = this._onRequestClose.bind(this);
- this._setURLFieldReference = this._setURLFieldReference.bind(this);
- this._showURLAlert = this._showURLAlert.bind(this);
- }
-
- /**
- * Implements React's {@link Component#render()}, renders the settings page.
- *
- * @inheritdoc
- * @returns {ReactElement}
- */
- render() {
- const { _profile, t } = this.props;
-
- return (
-
-
-
-
-
- { t('settingsScreen.header') }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }
-
- _onBlurServerURL: () => void;
-
- /**
- * Handler the server URL lose focus event. Here we validate the server URL
- * and update it to the normalized version, or show an error if incorrect.
- *
- * @private
- * @returns {void}
- */
- _onBlurServerURL() {
- this._processServerURL(false /* hideOnSuccess */);
- }
-
- _onChangeDisplayName: (string) => void;
-
- _onChangeEmail: (string) => void;
-
- _onChangeServerURL: (string) => void;
-
- _onStartAudioMutedChange: (boolean) => void;
-
- _onStartVideoMutedChange: (boolean) => void;
-
- /**
- * Processes the server URL. It normalizes it and an error alert is
- * displayed in case it's incorrect.
- *
- * @param {boolean} hideOnSuccess - True if the dialog should be hidden if
- * normalization / validation succeeds, false otherwise.
- * @private
- * @returns {void}
- */
- _processServerURL(hideOnSuccess: boolean) {
- const { serverURL } = this.props._profile;
- const normalizedURL = normalizeUserInputURL(serverURL);
-
- if (normalizedURL === null) {
- this._showURLAlert();
- } else {
- this._onChangeServerURL(normalizedURL);
- if (hideOnSuccess) {
- this.props.dispatch(hideAppSettings());
- }
- }
- }
-
- _onRequestClose: () => void;
-
- /**
- * Handles the back button.
- * Also invokes normalizeUserInputURL to validate the URL entered
- * by the user.
- *
- * @returns {void}
- */
- _onRequestClose() {
- this._processServerURL(true /* hideOnSuccess */);
- }
-
- _setURLFieldReference: (React$ElementRef<*> | null) => void;
-
- /**
- * Stores a reference to the URL field for later use.
- *
- * @protected
- * @param {Object} component - The field component.
- * @returns {void}
- */
- _setURLFieldReference(component) {
- this._urlField = component;
- }
-
- _showURLAlert: () => void;
-
- /**
- * Shows an alert telling the user that the URL he/she entered was invalid.
- *
- * @returns {void}
- */
- _showURLAlert() {
- const { t } = this.props;
-
- Alert.alert(
- t('settingsScreen.alertTitle'),
- t('settingsScreen.alertURLText'),
- [
- {
- onPress: () => this._urlField.focus(),
- text: t('settingsScreen.alertOk')
- }
- ]
- );
- }
-}
-
-export default translate(connect(_mapStateToProps)(AppSettings));
diff --git a/react/features/app-settings/components/AppSettings.web.js b/react/features/app-settings/components/AppSettings.web.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/react/features/app-settings/components/_.web.js b/react/features/app-settings/components/_.web.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/react/features/app-settings/components/index.js b/react/features/app-settings/components/index.js
deleted file mode 100644
index 3be0dae45..000000000
--- a/react/features/app-settings/components/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default as AppSettings } from './AppSettings';
diff --git a/react/features/app-settings/components/native/index.js b/react/features/app-settings/components/native/index.js
deleted file mode 100644
index 4a8909939..000000000
--- a/react/features/app-settings/components/native/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-export { default as BackButton } from './BackButton';
-export { default as FormRow } from './FormRow';
-export { default as FormSectionHeader } from './FormSectionHeader';
diff --git a/react/features/app-settings/components/styles.js b/react/features/app-settings/components/styles.js
deleted file mode 100644
index 166bf299b..000000000
--- a/react/features/app-settings/components/styles.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import {
- BoxModel,
- ColorPalette,
- createStyleSheet
-} from '../../base/styles';
-
-/**
- * The styles of the React {@code Components} of the feature
- * {@code app-settings}.
- */
-export default createStyleSheet({
- /**
- * Style of the ScrollView to be able to scroll the content.
- */
- scrollView: {
- flex: 1
- },
-
- /**
- * Style of the settings screen content (form).
- */
- settingsForm: {
- flex: 1,
- margin: BoxModel.margin
- },
-
- /**
- * Global {@code Text} color for the page.
- */
- text: {
- color: ColorPalette.black
- }
-});
diff --git a/react/features/app-settings/reducer.js b/react/features/app-settings/reducer.js
deleted file mode 100644
index 62115d19c..000000000
--- a/react/features/app-settings/reducer.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// @flow
-
-import {
- HIDE_APP_SETTINGS,
- SHOW_APP_SETTINGS
-} from './actionTypes';
-
-import { ReducerRegistry } from '../base/redux';
-
-const DEFAULT_STATE = {
- visible: false
-};
-
-ReducerRegistry.register(
- 'features/app-settings', (state = DEFAULT_STATE, action) => {
- switch (action.type) {
- case HIDE_APP_SETTINGS:
- return {
- ...state,
- visible: false
- };
-
- case SHOW_APP_SETTINGS:
- return {
- ...state,
- visible: true
- };
- }
-
- return state;
- });
diff --git a/react/features/base/conference/middleware.js b/react/features/base/conference/middleware.js
index 8a421bff3..e4fa97662 100644
--- a/react/features/base/conference/middleware.js
+++ b/react/features/base/conference/middleware.js
@@ -125,17 +125,20 @@ function _connectionEstablished({ dispatch }, next, action) {
*/
function _conferenceFailedOrLeft({ dispatch, getState }, next, action) {
const result = next(action);
+
const state = getState();
const { audioOnly } = state['features/base/conference'];
const { startAudioOnly } = state['features/base/profile'].profile;
- // FIXME: Consider implementing a standalone audio-only feature
- // that handles all these state changes.
- if (audioOnly && !startAudioOnly) {
- sendAnalytics(createAudioOnlyChangedEvent(false));
- logger.log('Audio only disabled');
- dispatch(setAudioOnly(false));
- } else if (!audioOnly && startAudioOnly) {
+ // FIXME: Consider implementing a standalone audio-only feature that handles
+ // all these state changes.
+ if (audioOnly) {
+ if (!startAudioOnly) {
+ sendAnalytics(createAudioOnlyChangedEvent(false));
+ logger.log('Audio only disabled');
+ dispatch(setAudioOnly(false));
+ }
+ } else if (startAudioOnly) {
sendAnalytics(createAudioOnlyChangedEvent(true));
logger.log('Audio only enabled');
dispatch(setAudioOnly(true));
diff --git a/react/features/base/react/components/native/Header.js b/react/features/base/react/components/native/Header.js
index 420fc56d1..98d1c5e71 100644
--- a/react/features/base/react/components/native/Header.js
+++ b/react/features/base/react/components/native/Header.js
@@ -32,7 +32,36 @@ type Props = {
export default class Header extends Component {
/**
- * Constructor of the Header component.
+ * The style of button-like React {@code Component}s rendered in
+ * {@code Header}.
+ *
+ * @returns {Object}
+ */
+ static get buttonStyle() {
+ return styles.headerButton;
+ }
+
+ /**
+ * The style of a React {@code Component} rendering a {@code Header} as its
+ * child.
+ *
+ * @returns {Object}
+ */
+ static get pageStyle() {
+ return styles.page;
+ }
+
+ /**
+ * The style of text rendered in {@code Header}.
+ *
+ * @returns {Object}
+ */
+ static get textStyle() {
+ return styles.headerText;
+ }
+
+ /**
+ * Initializes a new {@code Header} instance.
*
* @inheritdoc
*/
@@ -77,8 +106,8 @@ export default class Header extends Component {
_getIOS10CompatiblePadding: () => Object;
/**
- * Adds a padding for iOS 10 (and older) devices to avoid clipping
- * with the status bar.
+ * Adds a padding for iOS 10 (and older) devices to avoid clipping with the
+ * status bar.
* Note: This is a workaround for iOS 10 (and older) devices only to fix
* usability, but it doesn't take orientation into account, so unnecessary
* padding is rendered in some cases.
@@ -99,5 +128,4 @@ export default class Header extends Component {
return null;
}
-
}
diff --git a/react/features/base/react/components/native/SideBar.js b/react/features/base/react/components/native/SideBar.js
index d266de1ea..9f2656ff4 100644
--- a/react/features/base/react/components/native/SideBar.js
+++ b/react/features/base/react/components/native/SideBar.js
@@ -1,4 +1,4 @@
-/* @flow */
+// @flow
import React, { Component } from 'react';
import {
@@ -10,9 +10,8 @@ import {
import styles, { SIDEBAR_WIDTH } from './styles';
-
/**
- * The type of the React {@code Component} props of {@link SideBar}
+ * The type of the React {@code Component} props of {@link SideBar}.
*/
type Props = {
@@ -38,18 +37,21 @@ type Props = {
show: boolean
}
+/**
+ * The type of the React {@code Component} state of {@link SideBar}.
+ */
type State = {
- /**
- * Indicates whether the side bar is visible or not.
- */
- showSideBar: boolean,
-
/**
* Indicates whether the side overlay should be rendered or not.
*/
showOverlay: boolean,
+ /**
+ * Indicates whether the side bar is visible or not.
+ */
+ showSideBar: boolean,
+
/**
* The native animation object.
*/
@@ -63,7 +65,7 @@ export default class SideBar extends Component {
_mounted: boolean;
/**
- * Component's contructor.
+ * Initializes a new {@code SideBar} instance.
*
* @inheritdoc
*/
@@ -71,15 +73,15 @@ export default class SideBar extends Component {
super(props);
this.state = {
- showSideBar: false,
showOverlay: false,
+ showSideBar: false,
sliderAnimation: new Animated.Value(-SIDEBAR_WIDTH)
};
- this._setShow = this._setShow.bind(this);
-
this._getContainerStyle = this._getContainerStyle.bind(this);
this._onHideMenu = this._onHideMenu.bind(this);
+ this._setShow = this._setShow.bind(this);
+
this._setShow(props.show);
}
@@ -171,8 +173,8 @@ export default class SideBar extends Component {
/**
* Sets the side menu visible or hidden.
*
- * @private
* @param {boolean} show - The new expected visibility value.
+ * @private
* @returns {void}
*/
_setShow(show) {
@@ -183,15 +185,17 @@ export default class SideBar extends Component {
});
}
- Animated.timing(this.state.sliderAnimation, {
- toValue: show ? 0 : -SIDEBAR_WIDTH
- }).start(animationState => {
- if (animationState.finished && !show) {
- this.setState({
- showOverlay: false
- });
- }
- });
+ Animated
+ .timing(
+ this.state.sliderAnimation,
+ { toValue: show ? 0 : -SIDEBAR_WIDTH })
+ .start(animationState => {
+ if (animationState.finished && !show) {
+ this.setState({
+ showOverlay: false
+ });
+ }
+ });
}
if (this._mounted) {
@@ -200,5 +204,4 @@ export default class SideBar extends Component {
});
}
}
-
}
diff --git a/react/features/base/react/components/native/index.js b/react/features/base/react/components/native/index.js
index 63bcce6f9..aed450682 100644
--- a/react/features/base/react/components/native/index.js
+++ b/react/features/base/react/components/native/index.js
@@ -1,8 +1,7 @@
export { default as Container } from './Container';
+export { default as Header } from './Header';
export { default as Link } from './Link';
export { default as LoadingIndicator } from './LoadingIndicator';
-export { default as Header } from './Header';
export { default as SideBar } from './SideBar';
-export * from './styles';
-export { default as TintedView } from './TintedView';
export { default as Text } from './Text';
+export { default as TintedView } from './TintedView';
diff --git a/react/features/base/react/components/native/styles.js b/react/features/base/react/components/native/styles.js
index 6b177c9d7..aa4aa550e 100644
--- a/react/features/base/react/components/native/styles.js
+++ b/react/features/base/react/components/native/styles.js
@@ -14,11 +14,20 @@ export const STATUSBAR_COLOR = ColorPalette.blueHighlight;
export const SIDEBAR_WIDTH = 250;
/**
- * The styles of the React {@code Components} of the generic components
- * in the app.
+ * The styles of the generic React {@code Components} of the app.
*/
export default createStyleSheet({
+ /**
+ * Platform specific header button (e.g. back, menu...etc).
+ */
+ headerButton: {
+ alignSelf: 'center',
+ color: ColorPalette.white,
+ fontSize: 26,
+ paddingRight: 22
+ },
+
/**
* Style of the header overlay to cover the unsafe areas.
*/
@@ -26,6 +35,29 @@ export default createStyleSheet({
backgroundColor: HEADER_COLOR
},
+ /**
+ * Generic style for a label placed in the header.
+ */
+ headerText: {
+ color: ColorPalette.white,
+ fontSize: 20
+ },
+
+ /**
+ * The top-level element of a page.
+ */
+ page: {
+ alignItems: 'stretch',
+ bottom: 0,
+ flex: 1,
+ flexDirection: 'column',
+ left: 0,
+ overflow: 'hidden',
+ position: 'absolute',
+ right: 0,
+ top: 0
+ },
+
/**
* Base style of Header
*/
diff --git a/react/features/base/styles/components/styles/PlatformElements.native.js b/react/features/base/styles/components/styles/PlatformElements.native.js
deleted file mode 100644
index b25b3557b..000000000
--- a/react/features/base/styles/components/styles/PlatformElements.native.js
+++ /dev/null
@@ -1,41 +0,0 @@
-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
- },
-
- /**
- * 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
- }
-});
diff --git a/react/features/base/styles/components/styles/PlatformElements.web.js b/react/features/base/styles/components/styles/PlatformElements.web.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/react/features/base/styles/components/styles/index.js b/react/features/base/styles/components/styles/index.js
index f6673b7c1..5b08709f4 100644
--- a/react/features/base/styles/components/styles/index.js
+++ b/react/features/base/styles/components/styles/index.js
@@ -1,3 +1,2 @@
export * from './BoxModel';
export * from './ColorPalette';
-export * from './PlatformElements';
diff --git a/react/features/settings-menu/components/DeviceSelectionButton.native.js b/react/features/settings-menu/components/DeviceSelectionButton.native.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/react/features/settings-menu/components/LanguageSelectDropdown.native.js b/react/features/settings-menu/components/LanguageSelectDropdown.native.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/react/features/settings-menu/components/ModeratorCheckboxes.native.js b/react/features/settings-menu/components/ModeratorCheckboxes.native.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/react/features/settings-menu/components/SettingsMenu.native.js b/react/features/settings-menu/components/SettingsMenu.native.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/react/features/settings-menu/index.js b/react/features/settings-menu/index.js
deleted file mode 100644
index 07635cbbc..000000000
--- a/react/features/settings-menu/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export * from './components';
diff --git a/react/features/settings/actionTypes.js b/react/features/settings/actionTypes.js
new file mode 100644
index 000000000..e37aefdde
--- /dev/null
+++ b/react/features/settings/actionTypes.js
@@ -0,0 +1,10 @@
+/**
+ * The type of (redux) action which sets the visibility of the view/UI rendering
+ * the app's settings.
+ *
+ * {
+ * type: SET_SETTINGS_VIEW_VISIBLE
+ * visible: boolean
+ * }
+ */
+export const SET_SETTINGS_VIEW_VISIBLE = Symbol('SET_SETTINGS_VIEW_VISIBLE');
diff --git a/react/features/settings/actions.js b/react/features/settings/actions.js
new file mode 100644
index 000000000..3b61bc2d6
--- /dev/null
+++ b/react/features/settings/actions.js
@@ -0,0 +1,20 @@
+// @flow
+
+import { SET_SETTINGS_VIEW_VISIBLE } from './actionTypes';
+
+/**
+ * Sets the visibility of the view/UI which renders the app's settings.
+ *
+ * @param {boolean} visible - If the view/UI which renders the app's settings is
+ * to be made visible, {@code true}; otherwise, {@code false}.
+ * @returns {{
+ * type: SET_SETTINGS_VIEW_VISIBLE,
+ * visible: boolean
+ * }}
+ */
+export function setSettingsViewVisible(visible: boolean) {
+ return {
+ type: SET_SETTINGS_VIEW_VISIBLE,
+ visible
+ };
+}
diff --git a/react/features/app-settings/components/AbstractAppSettings.js b/react/features/settings/components/AbstractSettingsView.js
similarity index 80%
rename from react/features/app-settings/components/AbstractAppSettings.js
rename to react/features/settings/components/AbstractSettingsView.js
index 70e0147ee..8bfdabd89 100644
--- a/react/features/app-settings/components/AbstractAppSettings.js
+++ b/react/features/settings/components/AbstractSettingsView.js
@@ -5,7 +5,8 @@ import { Component } from 'react';
import { getProfile, updateProfile } from '../../base/profile';
/**
- * The type of the React {@code Component} props of {@link AbstractAppSettings}
+ * The type of the React {@code Component} props of
+ * {@link AbstractSettingsView}.
*/
type Props = {
@@ -20,7 +21,7 @@ type Props = {
_serverURL: string,
/**
- * The visibility prop of the settings screen.
+ * Whether {@link AbstractSettingsView} is visible.
*/
_visible: boolean,
@@ -41,10 +42,10 @@ type Props = {
*
* @abstract
*/
-export class AbstractAppSettings extends Component {
+export class AbstractSettingsView extends Component {
/**
- * Initializes a new {@code AbstractAppSettings} instance.
+ * Initializes a new {@code AbstractSettingsView} instance.
*
* @param {Props} props - The React {@code Component} props to initialize
* the component.
@@ -52,6 +53,7 @@ export class AbstractAppSettings extends Component {
constructor(props: Props) {
super(props);
+ // Bind event handlers so they are only bound once per instance.
this._onChangeDisplayName = this._onChangeDisplayName.bind(this);
this._onChangeEmail = this._onChangeEmail.bind(this);
this._onChangeServerURL = this._onChangeServerURL.bind(this);
@@ -66,8 +68,8 @@ export class AbstractAppSettings extends Component {
/**
* Handles the display name field value change.
*
- * @protected
* @param {string} text - The value typed in the name field.
+ * @protected
* @returns {void}
*/
_onChangeDisplayName(text) {
@@ -81,8 +83,8 @@ export class AbstractAppSettings extends Component {
/**
* Handles the email field value change.
*
- * @protected
* @param {string} text - The value typed in the email field.
+ * @protected
* @returns {void}
*/
_onChangeEmail(text) {
@@ -96,8 +98,8 @@ export class AbstractAppSettings extends Component {
/**
* Handles the server name field value change.
*
- * @protected
* @param {string} text - The server URL typed in the server field.
+ * @protected
* @returns {void}
*/
_onChangeServerURL(text) {
@@ -111,9 +113,9 @@ export class AbstractAppSettings extends Component {
/**
* Handles the start audio muted change event.
*
+ * @param {boolean} newValue - The new value for the start audio muted
+ * option.
* @protected
- * @param {boolean} newValue - The new value for the
- * start audio muted option.
* @returns {void}
*/
_onStartAudioMutedChange(newValue) {
@@ -127,9 +129,9 @@ export class AbstractAppSettings extends Component {
/**
* Handles the start video muted change event.
*
+ * @param {boolean} newValue - The new value for the start video muted
+ * option.
* @protected
- * @param {boolean} newValue - The new value for the
- * start video muted option.
* @returns {void}
*/
_onStartVideoMutedChange(newValue) {
@@ -143,8 +145,8 @@ export class AbstractAppSettings extends Component {
/**
* Updates the persisted profile on any change.
*
- * @private
* @param {Object} updateObject - The partial update object for the profile.
+ * @private
* @returns {void}
*/
_updateProfile(updateObject: Object) {
@@ -157,19 +159,20 @@ export class AbstractAppSettings extends Component {
/**
* Maps (parts of) the redux state to the React {@code Component} props of
- * {@code AbstractAppSettings}.
+ * {@code AbstractSettingsView}.
*
* @param {Object} state - The redux state.
* @protected
- * @returns {Object}
+ * @returns {{
+ * _profile: Object,
+ * _serverURL: string,
+ * _visible: boolean
+ * }}
*/
export function _mapStateToProps(state: Object) {
- const _serverURL = state['features/app'].app._getDefaultURL();
- const _profile = getProfile(state);
-
return {
- _profile,
- _serverURL,
- _visible: state['features/app-settings'].visible
+ _profile: getProfile(state),
+ _serverURL: state['features/app'].app._getDefaultURL(),
+ _visible: state['features/settings'].visible
};
}
diff --git a/react/features/app-settings/components/_.native.js b/react/features/settings/components/_.native.js
similarity index 100%
rename from react/features/app-settings/components/_.native.js
rename to react/features/settings/components/_.native.js
diff --git a/react/features/settings/components/_.web.js b/react/features/settings/components/_.web.js
new file mode 100644
index 000000000..b80c83af3
--- /dev/null
+++ b/react/features/settings/components/_.web.js
@@ -0,0 +1 @@
+export * from './web';
diff --git a/react/features/settings/components/index.js b/react/features/settings/components/index.js
new file mode 100644
index 000000000..cda61441e
--- /dev/null
+++ b/react/features/settings/components/index.js
@@ -0,0 +1 @@
+export * from './_';
diff --git a/react/features/app-settings/components/native/BackButton.js b/react/features/settings/components/native/BackButton.js
similarity index 90%
rename from react/features/app-settings/components/native/BackButton.js
rename to react/features/settings/components/native/BackButton.js
index e1889a45a..02be052d4 100644
--- a/react/features/app-settings/components/native/BackButton.js
+++ b/react/features/settings/components/native/BackButton.js
@@ -4,7 +4,7 @@ import React, { Component } from 'react';
import { TouchableOpacity } from 'react-native';
import { Icon } from '../../../base/font-icons';
-import { PlatformElements } from '../../../base/styles';
+import { Header } from '../../../base/react';
/**
* The type of the React {@code Component} props of {@link BackButton}
@@ -40,7 +40,7 @@ export default class BackButton extends Component {
diff --git a/react/features/app-settings/components/native/FormRow.js b/react/features/settings/components/native/FormRow.js
similarity index 92%
rename from react/features/app-settings/components/native/FormRow.js
rename to react/features/settings/components/native/FormRow.js
index 461a71647..f51beee49 100644
--- a/react/features/app-settings/components/native/FormRow.js
+++ b/react/features/settings/components/native/FormRow.js
@@ -47,6 +47,7 @@ class FormRow extends Component {
super(props);
React.Children.only(this.props.children);
+
this._getDefaultFieldProps = this._getDefaultFieldProps.bind(this);
this._getRowStyle = this._getRowStyle.bind(this);
}
@@ -63,10 +64,10 @@ class FormRow extends Component {
// Some field types need additional props to look good and standardized
// on a form.
- const newChild = React.cloneElement(
- this.props.children,
- this._getDefaultFieldProps(this.props.children)
- );
+ const newChild
+ = React.cloneElement(
+ this.props.children,
+ this._getDefaultFieldProps(this.props.children));
return (
{
{ t(this.props.i18nLabel) }
@@ -96,8 +98,8 @@ class FormRow extends Component {
* - TextInput
* - Switch (needs no addition props ATM).
*
- * @private
* @param {Object} field - The field (child) component.
+ * @private
* @returns {Object}
*/
_getDefaultFieldProps(field: Object) {
diff --git a/react/features/app-settings/components/native/FormSectionHeader.js b/react/features/settings/components/native/FormSectionHeader.js
similarity index 100%
rename from react/features/app-settings/components/native/FormSectionHeader.js
rename to react/features/settings/components/native/FormSectionHeader.js
diff --git a/react/features/settings/components/native/SettingsView.js b/react/features/settings/components/native/SettingsView.js
new file mode 100644
index 000000000..8c2f4da19
--- /dev/null
+++ b/react/features/settings/components/native/SettingsView.js
@@ -0,0 +1,251 @@
+// @flow
+
+import React from 'react';
+import {
+ Alert,
+ Modal,
+ SafeAreaView,
+ ScrollView,
+ Switch,
+ Text,
+ TextInput,
+ View
+} from 'react-native';
+import { connect } from 'react-redux';
+
+import { translate } from '../../../base/i18n';
+import { Header } from '../../../base/react';
+
+import {
+ AbstractSettingsView,
+ _mapStateToProps
+} from '../AbstractSettingsView';
+import { setSettingsViewVisible } from '../../actions';
+import BackButton from './BackButton';
+import FormRow from './FormRow';
+import FormSectionHeader from './FormSectionHeader';
+import { normalizeUserInputURL } from '../../functions';
+import styles from './styles';
+
+/**
+ * The native container rendering the app settings page.
+ *
+ * @extends AbstractSettingsView
+ */
+class SettingsView extends AbstractSettingsView {
+ _urlField: Object;
+
+ /**
+ * Initializes a new {@code SettingsView} instance.
+ *
+ * @inheritdoc
+ */
+ constructor(props) {
+ super(props);
+
+ // Bind event handlers so they are only bound once per instance.
+ this._onBlurServerURL = this._onBlurServerURL.bind(this);
+ this._onRequestClose = this._onRequestClose.bind(this);
+ this._setURLFieldReference = this._setURLFieldReference.bind(this);
+ this._showURLAlert = this._showURLAlert.bind(this);
+ }
+
+ /**
+ * Implements React's {@link Component#render()}, renders the settings page.
+ *
+ * @inheritdoc
+ * @returns {ReactElement}
+ */
+ render() {
+ return (
+
+
+ { this._renderHeader() }
+ { this._renderBody() }
+
+
+ );
+ }
+
+ _onBlurServerURL: () => void;
+
+ /**
+ * Handler the server URL lose focus event. Here we validate the server URL
+ * and update it to the normalized version, or show an error if incorrect.
+ *
+ * @private
+ * @returns {void}
+ */
+ _onBlurServerURL() {
+ this._processServerURL(false /* hideOnSuccess */);
+ }
+
+ _onChangeDisplayName: (string) => void;
+
+ _onChangeEmail: (string) => void;
+
+ _onChangeServerURL: (string) => void;
+
+ _onRequestClose: () => void;
+
+ /**
+ * Handles the back button. Also invokes normalizeUserInputURL to validate
+ * the URL entered by the user.
+ *
+ * @returns {void}
+ */
+ _onRequestClose() {
+ this._processServerURL(true /* hideOnSuccess */);
+ }
+
+ _onStartAudioMutedChange: (boolean) => void;
+
+ _onStartVideoMutedChange: (boolean) => void;
+
+ /**
+ * Processes the server URL. It normalizes it and an error alert is
+ * displayed in case it's incorrect.
+ *
+ * @param {boolean} hideOnSuccess - True if the dialog should be hidden if
+ * normalization / validation succeeds, false otherwise.
+ * @private
+ * @returns {void}
+ */
+ _processServerURL(hideOnSuccess: boolean) {
+ const { serverURL } = this.props._profile;
+ const normalizedURL = normalizeUserInputURL(serverURL);
+
+ if (normalizedURL === null) {
+ this._showURLAlert();
+ } else {
+ this._onChangeServerURL(normalizedURL);
+ if (hideOnSuccess) {
+ this.props.dispatch(setSettingsViewVisible(false));
+ }
+ }
+ }
+
+ /**
+ * Renders the body (under the header) of {@code SettingsView}.
+ *
+ * @private
+ * @returns {React$Element}
+ */
+ _renderBody() {
+ const { _profile } = this.props;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+
+ /**
+ * Renders the header of {@code SettingsView}.
+ *
+ * @private
+ * @returns {React$Element}
+ */
+ _renderHeader() {
+ return (
+
+
+
+ { this.props.t('settingsView.header') }
+
+
+ );
+ }
+
+ _setURLFieldReference: (React$ElementRef<*> | null) => void;
+
+ /**
+ * Stores a reference to the URL field for later use.
+ *
+ * @param {Object} component - The field component.
+ * @protected
+ * @returns {void}
+ */
+ _setURLFieldReference(component) {
+ this._urlField = component;
+ }
+
+ _showURLAlert: () => void;
+
+ /**
+ * Shows an alert telling the user that the URL he/she entered was invalid.
+ *
+ * @returns {void}
+ */
+ _showURLAlert() {
+ const { t } = this.props;
+
+ Alert.alert(
+ t('settingsView.alertTitle'),
+ t('settingsView.alertURLText'),
+ [
+ {
+ onPress: () => this._urlField.focus(),
+ text: t('settingsView.alertOk')
+ }
+ ]
+ );
+ }
+}
+
+export default translate(connect(_mapStateToProps)(SettingsView));
diff --git a/react/features/settings/components/native/index.js b/react/features/settings/components/native/index.js
new file mode 100644
index 000000000..1320e1ba9
--- /dev/null
+++ b/react/features/settings/components/native/index.js
@@ -0,0 +1 @@
+export { default as SettingsView } from './SettingsView';
diff --git a/react/features/app-settings/components/native/styles.js b/react/features/settings/components/native/styles.js
similarity index 95%
rename from react/features/app-settings/components/native/styles.js
rename to react/features/settings/components/native/styles.js
index f82f9b445..d202d3cb8 100644
--- a/react/features/app-settings/components/native/styles.js
+++ b/react/features/settings/components/native/styles.js
@@ -7,8 +7,7 @@ export const ANDROID_UNDERLINE_COLOR = 'transparent';
const TEXT_SIZE = 17;
/**
- * The styles of the native components of the feature
- * {@code app-settings}.
+ * The styles of the native components of the feature {@code settings}.
*/
export default createStyleSheet({
/**
diff --git a/react/features/settings-menu/components/DeviceSelectionButton.web.js b/react/features/settings/components/web/DeviceSelectionButton.js
similarity index 94%
rename from react/features/settings-menu/components/DeviceSelectionButton.web.js
rename to react/features/settings/components/web/DeviceSelectionButton.js
index 0ba5c230e..63faec81e 100644
--- a/react/features/settings-menu/components/DeviceSelectionButton.web.js
+++ b/react/features/settings/components/web/DeviceSelectionButton.js
@@ -3,8 +3,8 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
-import { translate } from '../../base/i18n';
-import { openDeviceSelectionDialog } from '../../device-selection';
+import { translate } from '../../../base/i18n';
+import { openDeviceSelectionDialog } from '../../../device-selection';
/**
* Implements a React {@link Component} which displays a button for opening the
diff --git a/react/features/settings-menu/components/LanguageSelectDropdown.web.js b/react/features/settings/components/web/LanguageSelectDropdown.js
similarity index 98%
rename from react/features/settings-menu/components/LanguageSelectDropdown.web.js
rename to react/features/settings/components/web/LanguageSelectDropdown.js
index 5118b6c06..8a5827faf 100644
--- a/react/features/settings-menu/components/LanguageSelectDropdown.web.js
+++ b/react/features/settings/components/web/LanguageSelectDropdown.js
@@ -5,7 +5,7 @@ import DropdownMenu, {
import PropTypes from 'prop-types';
import React, { Component } from 'react';
-import { DEFAULT_LANGUAGE, LANGUAGES, translate } from '../../base/i18n';
+import { DEFAULT_LANGUAGE, LANGUAGES, translate } from '../../../base/i18n';
/**
* Implements a React {@link Component} which displays a dropdown for changing
diff --git a/react/features/settings-menu/components/ModeratorCheckboxes.web.js b/react/features/settings/components/web/ModeratorCheckboxes.js
similarity index 98%
rename from react/features/settings-menu/components/ModeratorCheckboxes.web.js
rename to react/features/settings/components/web/ModeratorCheckboxes.js
index e3db3c0f6..6fb698f1d 100644
--- a/react/features/settings-menu/components/ModeratorCheckboxes.web.js
+++ b/react/features/settings/components/web/ModeratorCheckboxes.js
@@ -2,8 +2,8 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
-import { setFollowMe, setStartMutedPolicy } from '../../base/conference';
-import { translate } from '../../base/i18n';
+import { setFollowMe, setStartMutedPolicy } from '../../../base/conference';
+import { translate } from '../../../base/i18n';
/**
* Implements a React {@link Component} which displays checkboxes for enabling
diff --git a/react/features/settings-menu/components/SettingsMenu.web.js b/react/features/settings/components/web/SettingsMenu.js
similarity index 95%
rename from react/features/settings-menu/components/SettingsMenu.web.js
rename to react/features/settings/components/web/SettingsMenu.js
index 4b4888e3d..c4def41c0 100644
--- a/react/features/settings-menu/components/SettingsMenu.web.js
+++ b/react/features/settings/components/web/SettingsMenu.js
@@ -2,8 +2,11 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
-import { translate } from '../../base/i18n';
-import { getLocalParticipant, PARTICIPANT_ROLE } from '../../base/participants';
+import { translate } from '../../../base/i18n';
+import {
+ getLocalParticipant,
+ PARTICIPANT_ROLE
+} from '../../../base/participants';
import DeviceSelectionButton from './DeviceSelectionButton';
import LanguageSelectDropdown from './LanguageSelectDropdown';
diff --git a/react/features/settings-menu/components/index.js b/react/features/settings/components/web/index.js
similarity index 100%
rename from react/features/settings-menu/components/index.js
rename to react/features/settings/components/web/index.js
diff --git a/react/features/app-settings/functions.js b/react/features/settings/functions.js
similarity index 92%
rename from react/features/app-settings/functions.js
rename to react/features/settings/functions.js
index bd0191dcd..9ca8fcf27 100644
--- a/react/features/app-settings/functions.js
+++ b/react/features/settings/functions.js
@@ -14,6 +14,7 @@ export function normalizeUserInputURL(url: string) {
if (url) {
url = url.replace(/\s/g, '').toLowerCase();
+
const urlRegExp = new RegExp('^(\\w+://)?(.+)$');
const urlComponents = urlRegExp.exec(url);
@@ -21,8 +22,7 @@ export function normalizeUserInputURL(url: string) {
url = `https://${urlComponents[2]}`;
}
- const parsedURI
- = parseStandardURIString(url);
+ const parsedURI = parseStandardURIString(url);
if (!parsedURI.host) {
return null;
diff --git a/react/features/app-settings/index.js b/react/features/settings/index.js
similarity index 59%
rename from react/features/app-settings/index.js
rename to react/features/settings/index.js
index 582e1f9dd..a29aa08e0 100644
--- a/react/features/app-settings/index.js
+++ b/react/features/settings/index.js
@@ -1,4 +1,6 @@
export * from './actions';
+export * from './actionTypes';
export * from './components';
+import './middleware';
import './reducer';
diff --git a/react/features/app-settings/middleware.js b/react/features/settings/middleware.js
similarity index 52%
rename from react/features/app-settings/middleware.js
rename to react/features/settings/middleware.js
index 513189bba..e24b4cc7c 100644
--- a/react/features/app-settings/middleware.js
+++ b/react/features/settings/middleware.js
@@ -3,35 +3,34 @@
import { SET_ROOM } from '../base/conference';
import { MiddlewareRegistry } from '../base/redux';
-import { hideAppSettings } from './actions';
+import { setSettingsViewVisible } from './actions';
/**
- * The Redux middleware to trigger settings screen show or hide
- * when necessary.
+ * The redux middleware to set the visibility of {@link SettingsView}.
*
- * @param {Store} store - The Redux store.
+ * @param {Store} store - The redux store.
* @returns {Function}
*/
MiddlewareRegistry.register(store => next => action => {
switch (action.type) {
case SET_ROOM:
- return _closeAppSettings(store, next, action);
+ return _hideSettingsView(store, next, action);
}
return next(action);
});
/**
- * Hides the settings screen.
+ * Hides {@link SettingsView}.
*
* @param {Store} store - The redux store.
- * @param {Dispatch} next - The redux dispatch function.
+ * @param {Dispatch} next - The redux {@code dispatch} function.
* @param {Action} action - The redux action.
* @private
* @returns {Object} The new state.
*/
-function _closeAppSettings({ dispatch }, next, action) {
- dispatch(hideAppSettings());
+function _hideSettingsView({ dispatch }, next, action) {
+ dispatch(setSettingsViewVisible(false));
return next(action);
}
diff --git a/react/features/settings/reducer.js b/react/features/settings/reducer.js
new file mode 100644
index 000000000..cc790b3e2
--- /dev/null
+++ b/react/features/settings/reducer.js
@@ -0,0 +1,17 @@
+// @flow
+
+import { ReducerRegistry } from '../base/redux';
+
+import { SET_SETTINGS_VIEW_VISIBLE } from './actionTypes';
+
+ReducerRegistry.register('features/settings', (state = {}, action) => {
+ switch (action.type) {
+ case SET_SETTINGS_VIEW_VISIBLE:
+ return {
+ ...state,
+ visible: action.visible
+ };
+ }
+
+ return state;
+});
diff --git a/react/features/welcome/actionTypes.js b/react/features/welcome/actionTypes.js
index 6e666c714..be0ea0b6c 100644
--- a/react/features/welcome/actionTypes.js
+++ b/react/features/welcome/actionTypes.js
@@ -1,4 +1,10 @@
/**
- * Action type to signal the need to hide or show the side bar.
+ * The type of the (redux) action which sets the visibility of
+ * {@link WelcomePageSideBar}.
+ *
+ * {
+ * type: SET_SIDEBAR_VISIBLE,
+ * visible: boolean
+ * }
*/
-export const SET_SIDEBAR_VISIBILITY = Symbol('SET_SIDEBAR_VISIBILITY');
+export const SET_SIDEBAR_VISIBLE = Symbol('SET_SIDEBAR_VISIBLE');
diff --git a/react/features/welcome/actions.js b/react/features/welcome/actions.js
index aa20a4c50..f6983d8b3 100644
--- a/react/features/welcome/actions.js
+++ b/react/features/welcome/actions.js
@@ -1,19 +1,20 @@
// @flow
-import { SET_SIDEBAR_VISIBILITY } from './actionTypes';
+import { SET_SIDEBAR_VISIBLE } from './actionTypes';
/**
- * Redux action to hide or show the status bar.
+ * Sets the visibility of {@link WelcomePageSideBar}.
*
- * @param {boolean} visible - The new value of the visibility.
+ * @param {boolean} visible - If the {@code WelcomePageSideBar} is to be made
+ * visible, {@code true}; otherwise, {@code false}.
* @returns {{
- * type: SET_SIDEBAR_VISIBILITY,
- * sideBarVisible: boolean
+ * type: SET_SIDEBAR_VISIBLE,
+ * visible: boolean
* }}
*/
-export function setSideBarVisibility(visible: boolean) {
+export function setSideBarVisible(visible: boolean) {
return {
- type: SET_SIDEBAR_VISIBILITY,
- sideBarVisible: visible
+ type: SET_SIDEBAR_VISIBLE,
+ visible
};
}
diff --git a/react/features/welcome/components/SideBarItem.js b/react/features/welcome/components/SideBarItem.js
index b13fc1f0d..bafefb03b 100644
--- a/react/features/welcome/components/SideBarItem.js
+++ b/react/features/welcome/components/SideBarItem.js
@@ -3,11 +3,11 @@
import React, { Component } from 'react';
import { Linking, Text, TouchableOpacity, View } from 'react-native';
-import styles from './styles';
-
import { Icon } from '../../base/font-icons';
import { translate } from '../../base/i18n';
+import styles from './styles';
+
type Props = {
/**
@@ -43,13 +43,14 @@ type Props = {
class SideBarItem extends Component {
/**
- * Contructor of the SideBarItem Component.
+ * Initializes a new {@code SideBarItem} instance.
*
* @inheritdoc
*/
constructor(props: Props) {
super(props);
+ // Bind event handlers so they are only bound once per instance.
this._onOpenURL = this._onOpenURL.bind(this);
}
diff --git a/react/features/welcome/components/WelcomePage.native.js b/react/features/welcome/components/WelcomePage.native.js
index 8a7023420..ab27add2c 100644
--- a/react/features/welcome/components/WelcomePage.native.js
+++ b/react/features/welcome/components/WelcomePage.native.js
@@ -11,26 +11,21 @@ import {
} from 'react-native';
import { connect } from 'react-redux';
-import { AppSettings } from '../../app-settings';
import { translate } from '../../base/i18n';
import { Icon } from '../../base/font-icons';
import { MEDIA_TYPE } from '../../base/media';
import { updateProfile } from '../../base/profile';
-import {
- LoadingIndicator,
- Header,
- Text
-} from '../../base/react';
-import { ColorPalette, PlatformElements } from '../../base/styles';
+import { LoadingIndicator, Header, Text } from '../../base/react';
+import { ColorPalette } from '../../base/styles';
import {
createDesiredLocalTracks,
destroyLocalTracks
} from '../../base/tracks';
import { RecentList } from '../../recent-list';
-
-import { setSideBarVisibility } from '../actions';
+import { SettingsView } from '../../settings';
import { AbstractWelcomePage, _mapStateToProps } from './AbstractWelcomePage';
+import { setSideBarVisible } from '../actions';
import LocalVideoTrackUnderlay from './LocalVideoTrackUnderlay';
import styles, {
PLACEHOLDER_TEXT_COLOR,
@@ -62,6 +57,7 @@ class WelcomePage extends AbstractWelcomePage {
this.state.hintBoxAnimation = new Animated.Value(0);
+ // Bind event handlers so they are only bound once per instance.
this._getHintBoxStyle = this._getHintBoxStyle.bind(this);
this._onFieldFocusChange = this._onFieldFocusChange.bind(this);
this._onShowSideBar = this._onShowSideBar.bind(this);
@@ -97,20 +93,21 @@ class WelcomePage extends AbstractWelcomePage {
* @returns {ReactElement}
*/
render() {
+ const { buttonStyle, pageStyle, textStyle } = Header;
const { t, _profile } = this.props;
return (
-
+
+ style = { buttonStyle } />
-
- { t('welcomepage.videoEnabledLabel') }
+
+ { t('welcomepage.audioVideoSwitch.video') }
-
- { t('welcomepage.audioOnlyLabel') }
+
+ { t('welcomepage.audioVideoSwitch.audio') }
@@ -145,7 +142,7 @@ class WelcomePage extends AbstractWelcomePage {
}
-
+
@@ -204,7 +201,7 @@ class WelcomePage extends AbstractWelcomePage {
*/
_onShowSideBar() {
Keyboard.dismiss();
- this.props.dispatch(setSideBarVisibility(true));
+ this.props.dispatch(setSideBarVisible(true));
}
/**
@@ -234,17 +231,14 @@ class WelcomePage extends AbstractWelcomePage {
const { t } = this.props;
return (
-
+
- { t('welcomepage.hintText') }
+ { t('welcomepage.roomnameHint') }
- {
- this._renderJoinButton()
- }
+ { this._renderJoinButton() }
);
diff --git a/react/features/welcome/components/WelcomePageSideBar.native.js b/react/features/welcome/components/WelcomePageSideBar.native.js
index 684f51080..7b31e3e09 100644
--- a/react/features/welcome/components/WelcomePageSideBar.native.js
+++ b/react/features/welcome/components/WelcomePageSideBar.native.js
@@ -4,12 +4,6 @@ import React, { Component } from 'react';
import { SafeAreaView, ScrollView, Text } from 'react-native';
import { connect } from 'react-redux';
-import SideBarItem from './SideBarItem';
-import styles from './styles';
-
-import { setSideBarVisibility } from '../actions';
-
-import { showAppSettings } from '../../app-settings';
import {
Avatar,
getAvatarURL,
@@ -20,6 +14,11 @@ import {
Header,
SideBar
} from '../../base/react';
+import { setSettingsViewVisible } from '../../settings';
+
+import { setSideBarVisible } from '../actions';
+import SideBarItem from './SideBarItem';
+import styles from './styles';
/**
* The URL at which the privacy policy is available to the user.
@@ -71,6 +70,7 @@ class WelcomePageSideBar extends Component {
constructor(props) {
super(props);
+ // Bind event handlers so they are only bound once per instance.
this._onHideSideBar = this._onHideSideBar.bind(this);
this._onOpenSettings = this._onOpenSettings.bind(this);
}
@@ -122,19 +122,19 @@ class WelcomePageSideBar extends Component {
_onHideSideBar: () => void;
/**
- * Invoked when the sidebar has closed itslef (e.g. overlay pressed).
+ * Invoked when the sidebar has closed itself (e.g. overlay pressed).
*
* @private
* @returns {void}
*/
_onHideSideBar() {
- this.props.dispatch(setSideBarVisibility(false));
+ this.props.dispatch(setSideBarVisible(false));
}
_onOpenSettings: () => void;
/**
- * Opens the settings screen.
+ * Shows the {@link SettingsView}.
*
* @private
* @returns {void}
@@ -142,8 +142,8 @@ class WelcomePageSideBar extends Component {
_onOpenSettings() {
const { dispatch } = this.props;
- dispatch(setSideBarVisibility(false));
- dispatch(showAppSettings());
+ dispatch(setSideBarVisible(false));
+ dispatch(setSettingsViewVisible(true));
}
}
diff --git a/react/features/welcome/components/styles.js b/react/features/welcome/components/styles.js
index c6f2c78dd..c483c613c 100644
--- a/react/features/welcome/components/styles.js
+++ b/react/features/welcome/components/styles.js
@@ -98,14 +98,7 @@ export default createStyleSheet({
*/
hintButtonContainer: {
flexDirection: 'row',
- justifyContent: 'flex-end'
- },
-
- /**
- * Container for the text on the hint box.
- */
- hintTextContainer: {
- marginBottom: 2 * BoxModel.margin
+ justifyContent: 'center'
},
/**
@@ -123,6 +116,13 @@ export default createStyleSheet({
paddingVertical: 2 * BoxModel.padding
},
+ /**
+ * Container for the text on the hint box.
+ */
+ hintTextContainer: {
+ marginBottom: 2 * BoxModel.margin
+ },
+
/**
* Container for the items in the side bar.
*/
@@ -142,7 +142,7 @@ export default createStyleSheet({
},
/**
- * Top level screen style
+ * Top-level screen style.
*/
page: {
flex: 1,
diff --git a/react/features/welcome/index.js b/react/features/welcome/index.js
index ee08e02fd..f77620716 100644
--- a/react/features/welcome/index.js
+++ b/react/features/welcome/index.js
@@ -1,5 +1,5 @@
-import './reducer';
-import './route';
-
export * from './components';
export * from './functions';
+
+import './reducer';
+import './route';
diff --git a/react/features/welcome/reducer.js b/react/features/welcome/reducer.js
index bf56bd98d..87f4c50a2 100644
--- a/react/features/welcome/reducer.js
+++ b/react/features/welcome/reducer.js
@@ -1,23 +1,20 @@
-import { ReducerRegistry } from '../base/redux';
-import { SET_SIDEBAR_VISIBILITY } from './actionTypes';
+// @flow
-const DEFAULT_STATE = {
- sideBarVisible: false
-};
+import { ReducerRegistry } from '../base/redux';
+import { SET_SIDEBAR_VISIBLE } from './actionTypes';
/**
- * Reduces the Redux actions of the feature features/recording.
+ * Reduces redux actions for the purposes of {@code features/welcome}.
*/
-ReducerRegistry.register('features/welcome',
- (state = DEFAULT_STATE, action) => {
- switch (action.type) {
- case SET_SIDEBAR_VISIBILITY:
- return {
- ...state,
- sideBarVisible: action.sideBarVisible
- };
+ReducerRegistry.register('features/welcome', (state = {}, action) => {
+ switch (action.type) {
+ case SET_SIDEBAR_VISIBLE:
+ return {
+ ...state,
+ sideBarVisible: action.visible
+ };
- default:
- return state;
- }
- });
+ default:
+ return state;
+ }
+});