From c77e2c8301e521d19fafb2ffd04825e29dbb8739 Mon Sep 17 00:00:00 2001 From: Calinteodor Date: Thu, 1 Sep 2022 15:05:14 +0300 Subject: [PATCH] feat(settings/native): fixes and updates (#12094) feat(settings/native): fixes and updates --- .../components/AbstractSettingsView.js | 200 ----------- .../{SettingsView.js => SettingsView.tsx} | 323 ++++++++++++------ .../settings/components/native/styles.js | 12 - .../toolbox/components/native/OverflowMenu.js | 11 - 4 files changed, 221 insertions(+), 325 deletions(-) delete mode 100644 react/features/settings/components/AbstractSettingsView.js rename react/features/settings/components/native/{SettingsView.js => SettingsView.tsx} (69%) diff --git a/react/features/settings/components/AbstractSettingsView.js b/react/features/settings/components/AbstractSettingsView.js deleted file mode 100644 index 171ef061f3..0000000000 --- a/react/features/settings/components/AbstractSettingsView.js +++ /dev/null @@ -1,200 +0,0 @@ -// @flow - -import { Component } from 'react'; -import type { Dispatch } from 'redux'; - -import { getDefaultURL } from '../../app/functions'; -import { updateSettings } from '../../base/settings'; - -/** - * The type of the React {@code Component} props of - * {@link AbstractSettingsView}. - */ -export type Props = { - - /** - * The default URL for when there is no custom URL set in the settings. - * - * @protected - */ - _serverURL: string, - - /** - * The current settings object. - */ - _settings: Object, - - /** - * Whether {@link AbstractSettingsView} is visible. - * - * @protected - */ - _visible: boolean, - - /** - * Redux store dispatch function. - */ - dispatch: Dispatch, - - /** - * The i18n translate function. - */ - t: Function -}; - -/** - * Base (abstract) class for container component rendering the app settings - * page. - * - * @abstract - */ -export class AbstractSettingsView extends Component { - - /** - * Initializes a new {@code AbstractSettingsView} instance. - * - * @param {P} props - The React {@code Component} props to initialize - * the component. - */ - constructor(props: P) { - 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); - this._onStartAudioMutedChange - = this._onStartAudioMutedChange.bind(this); - this._onStartVideoMutedChange - = this._onStartVideoMutedChange.bind(this); - this._onStartReactionsMutedChange - = this._onStartReactionsMutedChange.bind(this); - } - - _onChangeDisplayName: (string) => void; - - /** - * Handles the display name field value change. - * - * @param {string} text - The value typed in the name field. - * @protected - * @returns {void} - */ - _onChangeDisplayName(text) { - this._updateSettings({ - displayName: text - }); - } - - _onChangeEmail: (string) => void; - - /** - * Handles the email field value change. - * - * @param {string} text - The value typed in the email field. - * @protected - * @returns {void} - */ - _onChangeEmail(text) { - this._updateSettings({ - email: text - }); - } - - _onChangeServerURL: (string) => void; - - /** - * Handles the server name field value change. - * - * @param {string} text - The server URL typed in the server field. - * @protected - * @returns {void} - */ - _onChangeServerURL(text) { - this._updateSettings({ - serverURL: text - }); - } - - _onStartAudioMutedChange: (boolean) => void; - - /** - * Handles the start audio muted change event. - * - * @param {boolean} newValue - The new value for the start audio muted - * option. - * @protected - * @returns {void} - */ - _onStartAudioMutedChange(newValue) { - this._updateSettings({ - startWithAudioMuted: newValue - }); - } - - _onStartVideoMutedChange: (boolean) => void; - - /** - * Handles the start video muted change event. - * - * @param {boolean} newValue - The new value for the start video muted - * option. - * @protected - * @returns {void} - */ - _onStartVideoMutedChange(newValue) { - this._updateSettings({ - startWithVideoMuted: newValue - }); - } - - _onStartReactionsMutedChange: (boolean) => void; - - /** - * Handles the start reactions muted change event. - * - * @param {boolean} newValue - The new value for the start reactions muted - * option. - * @protected - * @returns {void} - */ - _onStartReactionsMutedChange(newValue) { - this._updateSettings({ - startWithReactionsMuted: newValue - }); - } - - _updateSettings: (Object) => void; - - /** - * Updates the persisted settings on any change. - * - * @param {Object} updateObject - The partial update object for the - * settings. - * @private - * @returns {void} - */ - _updateSettings(updateObject: Object) { - this.props.dispatch(updateSettings(updateObject)); - } -} - -/** - * Maps (parts of) the redux state to the React {@code Component} props of - * {@code AbstractSettingsView}. - * - * @param {Object} state - The redux state. - * @protected - * @returns {{ - * _serverURL: string, - * _settings: Object, - * _visible: boolean - * }} - */ -export function _mapStateToProps(state: Object) { - return { - _serverURL: getDefaultURL(state), - _settings: state['features/base/settings'], - _visible: state['features/settings'].visible - }; -} diff --git a/react/features/settings/components/native/SettingsView.js b/react/features/settings/components/native/SettingsView.tsx similarity index 69% rename from react/features/settings/components/native/SettingsView.js rename to react/features/settings/components/native/SettingsView.tsx index 8da245e1b9..8e473e24aa 100644 --- a/react/features/settings/components/native/SettingsView.js +++ b/react/features/settings/components/native/SettingsView.tsx @@ -1,7 +1,9 @@ -// @flow +/* eslint-disable lines-around-comment */ import { Link } from '@react-navigation/native'; -import React from 'react'; +import _ from 'lodash'; +import React, { Component } from 'react'; +import { WithTranslation } from 'react-i18next'; import { Alert, NativeModules, @@ -12,30 +14,34 @@ import { } from 'react-native'; import { Divider, - TextInput, - withTheme + TextInput } from 'react-native-paper'; +// @ts-ignore +import { getDefaultURL } from '../../../app/functions'; +// @ts-ignore import { Avatar } from '../../../base/avatar'; -import { translate } from '../../../base/i18n'; +import { translate } from '../../../base/i18n/functions'; +// @ts-ignore import JitsiScreen from '../../../base/modal/components/JitsiScreen'; -import { - getLocalParticipant, - getParticipantDisplayName -} from '../../../base/participants'; -import { connect } from '../../../base/redux'; +import { getLocalParticipant } from '../../../base/participants/functions'; +import { connect } from '../../../base/redux/functions'; +// @ts-ignore +import { updateSettings } from '../../../base/settings'; +import BaseThemeNative from '../../../base/ui/components/BaseTheme.native'; import Switch from '../../../base/ui/components/native/Switch'; +// @ts-ignore import { screen } from '../../../mobile/navigation/routes'; +// @ts-ignore import { AVATAR_SIZE } from '../../../welcome/components/styles'; +// @ts-ignore import { normalizeUserInputURL, isServerURLChangeEnabled } from '../../functions'; -import { - AbstractSettingsView, - _mapStateToProps as _abstractMapStateToProps, - type Props as AbstractProps -} from '../AbstractSettingsView'; +// @ts-ignore import FormRow from './FormRow'; +// @ts-ignore import FormSectionAccordion from './FormSectionAccordion'; +// @ts-ignore import styles, { PLACEHOLDER_COLOR, PLACEHOLDER_TEXT_COLOR } from './styles'; /** @@ -44,22 +50,27 @@ import styles, { PLACEHOLDER_COLOR, PLACEHOLDER_TEXT_COLOR } from './styles'; const { AppInfo } = NativeModules; -type State = { +interface State { /** * State variable for the disable call integration switch. */ disableCallIntegration: boolean, + /** + * State variable for the disable crash reporting switch. + */ + disableCrashReporting: boolean, + /** * State variable for the disable p2p switch. */ disableP2P: boolean, /** - * State variable for the disable crash reporting switch. + * Whether the self view is disabled or not. */ - disableCrashReporting: boolean, + disableSelfView: boolean, /** * State variable for the display name field. @@ -91,7 +102,19 @@ type State = { * The type of the React {@code Component} props of * {@link SettingsView}. */ -type Props = AbstractProps & { +interface Props extends WithTranslation { + + /** + * The ID of the local participant. + */ + _localParticipantId: string, + + /** + * The default URL for when there is no custom URL set in the settings. + * + * @protected + */ + _serverURL: string, /** * Flag indicating if URL can be changed by user. @@ -101,14 +124,31 @@ type Props = AbstractProps & { _serverURLChangeEnabled: boolean, /** - * Avatar label. + * The current settings object. */ - avatarLabel: string, + _settings: { + disableCallIntegration: boolean; + disableCrashReporting: boolean; + disableP2P: boolean; + disableSelfView: boolean; + displayName: string; + email: string; + serverURL: string; + startWithAudioMuted: boolean; + startWithVideoMuted: boolean; + }, /** - * The ID of the local participant. + * Whether {@link SettingsView} is visible. + * + * @protected */ - localParticipantId: string, + _visible: boolean, + + /** + * Redux store dispatch function. + */ + dispatch: Function, /** * Default prop for navigating between screen components(React Navigation). @@ -118,20 +158,13 @@ type Props = AbstractProps & { /** * Callback to be invoked when settings screen is focused. */ - onSettingsScreenFocused: Function, - - /** - * Theme used for styles. - */ - theme: Object + onSettingsScreenFocused: Function } /** * The native container rendering the app settings page. - * - * @augments AbstractSettingsView */ -class SettingsView extends AbstractSettingsView { +class SettingsView extends Component { _urlField: Object; /** @@ -140,12 +173,14 @@ class SettingsView extends AbstractSettingsView { * * @inheritdoc */ - constructor(props) { + constructor(props: Props) { super(props); + const { disableCallIntegration, disableCrashReporting, disableP2P, + disableSelfView, displayName, email, serverURL, @@ -157,6 +192,7 @@ class SettingsView extends AbstractSettingsView { disableCallIntegration, disableCrashReporting, disableP2P, + disableSelfView, displayName, email, serverURL, @@ -166,14 +202,38 @@ class SettingsView extends AbstractSettingsView { // Bind event handlers so they are only bound once per instance. this._onBlurServerURL = this._onBlurServerURL.bind(this); + this._onChangeDisplayName = this._onChangeDisplayName.bind(this); + this._onChangeEmail = this._onChangeEmail.bind(this); + this._onChangeServerURL = this._onChangeServerURL.bind(this); this._onClose = this._onClose.bind(this); this._onDisableCallIntegration = this._onDisableCallIntegration.bind(this); this._onDisableCrashReporting = this._onDisableCrashReporting.bind(this); this._onDisableP2P = this._onDisableP2P.bind(this); + this._onDisableSelfView = this._onDisableSelfView.bind(this); + this._onStartAudioMutedChange + = this._onStartAudioMutedChange.bind(this); + this._onStartVideoMutedChange + = this._onStartVideoMutedChange.bind(this); this._setURLFieldReference = this._setURLFieldReference.bind(this); this._showURLAlert = this._showURLAlert.bind(this); } + /** + * Updates and syncs settings. + * + * @inheritdoc + * @returns {void} + */ + componentDidUpdate(prevProps: Props) { + const { _settings } = this.props; + + if (!_.isEqual(prevProps._settings, _settings)) { + // @ts-ignore + // eslint-disable-next-line react/no-did-update-set-state + this.setState(_settings); + } + } + /** * Implements React's {@link Component#render()}, renders the settings page. * @@ -185,21 +245,23 @@ class SettingsView extends AbstractSettingsView { disableCallIntegration, disableCrashReporting, disableP2P, + disableSelfView, displayName, email, serverURL, startWithAudioMuted, startWithVideoMuted } = this.state; - const { palette } = this.props.theme; + + const { t } = this.props; const textInputTheme = { colors: { - background: palette.ui01, - placeholder: palette.text01, + background: BaseThemeNative.palette.ui01, + placeholder: BaseThemeNative.palette.text01, primary: PLACEHOLDER_COLOR, underlineColor: 'transparent', - text: palette.text01 + text: BaseThemeNative.palette.text01 } }; @@ -210,20 +272,17 @@ class SettingsView extends AbstractSettingsView { - - { this.props.avatarLabel } - { autoCapitalize = 'none' autoCorrect = { false } keyboardType = { 'email-address' } - label = { this.props.t('settingsView.email') } + label = { t('settingsView.email') } mode = 'outlined' onChangeText = { this._onChangeEmail } placeholder = 'email@example.com' @@ -253,7 +312,7 @@ class SettingsView extends AbstractSettingsView { autoCorrect = { false } editable = { this.props._serverURLChangeEnabled } keyboardType = { 'url' } - label = { this.props.t('settingsView.serverURL') } + label = { t('settingsView.serverURL') } mode = 'outlined' onBlur = { this._onBlurServerURL } onChangeText = { this._onChangeServerURL } @@ -269,33 +328,45 @@ class SettingsView extends AbstractSettingsView { label = 'settingsView.startWithAudioMuted'> + + + + - { this.props.t('settingsView.help') } + { t('settingsView.help') } - { this.props.t('settingsView.terms') } + { t('settingsView.terms') } - { this.props.t('settingsView.privacy') } + { t('settingsView.privacy') } { label = 'settingsView.disableCallIntegration'> @@ -324,6 +396,7 @@ class SettingsView extends AbstractSettingsView { label = 'settingsView.disableP2P'> @@ -333,6 +406,7 @@ class SettingsView extends AbstractSettingsView { label = 'settingsView.disableCrashReporting'> )} @@ -342,8 +416,6 @@ class SettingsView extends AbstractSettingsView { ); } - _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. @@ -356,45 +428,55 @@ class SettingsView extends AbstractSettingsView { } /** - * Callback to update the display name. + * Handles the display name field value change. * - * @param {string} displayName - The new value to set. + * @param {string} displayName - The value typed in the name field. + * @protected * @returns {void} */ - _onChangeDisplayName(displayName) { - super._onChangeDisplayName(displayName); + _onChangeDisplayName(displayName: string) { this.setState({ displayName }); + + this._updateSettings({ + displayName + }); } /** - * Callback to update the email. + * Handles the email field value change. * - * @param {string} email - The new value to set. + * @param {string} email - The value typed in the email field. + * @protected * @returns {void} */ - _onChangeEmail(email) { - super._onChangeEmail(email); + _onChangeEmail(email: string) { this.setState({ email }); + + this._updateSettings({ + email + }); } /** - * Callback to update the server URL. + * Handles the server name field value change. * - * @param {string} serverURL - The new value to set. + * @param {string} serverURL - The server URL typed in the server field. + * @protected * @returns {void} */ - _onChangeServerURL(serverURL) { - super._onChangeServerURL(serverURL); + _onChangeServerURL(serverURL: string) { this.setState({ serverURL }); - } - _onDisableCallIntegration: (boolean) => void; + this._updateSettings({ + serverURL + }); + } /** * Handles the disable call integration change event. @@ -404,16 +486,15 @@ class SettingsView extends AbstractSettingsView { * @private * @returns {void} */ - _onDisableCallIntegration(disableCallIntegration) { - this._updateSettings({ - disableCallIntegration - }); + _onDisableCallIntegration(disableCallIntegration: boolean) { this.setState({ disableCallIntegration }); - } - _onDisableP2P: (boolean) => void; + this._updateSettings({ + disableCallIntegration + }); + } /** * Handles the disable P2P change event. @@ -423,16 +504,32 @@ class SettingsView extends AbstractSettingsView { * @private * @returns {void} */ - _onDisableP2P(disableP2P) { - this._updateSettings({ + _onDisableP2P(disableP2P: boolean) { + this.setState({ disableP2P }); - this.setState({ + + this._updateSettings({ disableP2P }); } - _onDisableCrashReporting: (boolean) => void; + /** . + * Handles the disable self view change event. + * + * @param {boolean} disableSelfView - The new value. + * @private + * @returns {void} + */ + _onDisableSelfView(disableSelfView: boolean) { + this.setState({ + disableSelfView + }); + + this._updateSettings({ + disableSelfView + }); + } /** * Handles the disable crash reporting change event. @@ -442,7 +539,7 @@ class SettingsView extends AbstractSettingsView { * @private * @returns {void} */ - _onDisableCrashReporting(disableCrashReporting) { + _onDisableCrashReporting(disableCrashReporting: boolean) { if (disableCrashReporting) { this._showCrashReportingDisableAlert(); } else { @@ -450,8 +547,6 @@ class SettingsView extends AbstractSettingsView { } } - _onClose: () => void; - /** * Callback to be invoked on closing the modal. Also invokes normalizeUserInputURL to validate * the URL entered by the user. @@ -463,29 +558,39 @@ class SettingsView extends AbstractSettingsView { } /** - * Callback to update the start with audio muted value. + * Handles the start audio muted change event. * - * @param {boolean} startWithAudioMuted - The new value to set. + * @param {boolean} startWithAudioMuted - The new value for the start audio muted + * option. + * @protected * @returns {void} */ - _onStartAudioMutedChange(startWithAudioMuted) { - super._onStartAudioMutedChange(startWithAudioMuted); + _onStartAudioMutedChange(startWithAudioMuted: boolean) { this.setState({ startWithAudioMuted }); + + this._updateSettings({ + startWithAudioMuted + }); } /** - * Callback to update the start with video muted value. + * Handles the start video muted change event. * - * @param {boolean} startWithVideoMuted - The new value to set. + * @param {boolean} startWithVideoMuted - The new value for the start video muted + * option. + * @protected * @returns {void} */ - _onStartVideoMutedChange(startWithVideoMuted) { - super._onStartVideoMutedChange(startWithVideoMuted); + _onStartVideoMutedChange(startWithVideoMuted: boolean) { this.setState({ startWithVideoMuted }); + + this._updateSettings({ + startWithVideoMuted + }); } /** @@ -498,6 +603,7 @@ class SettingsView extends AbstractSettingsView { * @returns {void} */ _processServerURL(hideOnSuccess: boolean) { + // @ts-ignore const { serverURL } = this.props._settings; const normalizedURL = normalizeUserInputURL(serverURL); @@ -512,8 +618,6 @@ class SettingsView extends AbstractSettingsView { return hideOnSuccess; } - _setURLFieldReference: (React$ElementRef<*> | null) => void; - /** * Stores a reference to the URL field for later use. * @@ -521,12 +625,10 @@ class SettingsView extends AbstractSettingsView { * @protected * @returns {void} */ - _setURLFieldReference(component) { + _setURLFieldReference(component: object) { this._urlField = component; } - _showURLAlert: () => void; - /** * Shows an alert telling the user that the URL he/she entered was invalid. * @@ -540,6 +642,7 @@ class SettingsView extends AbstractSettingsView { t('settingsView.alertURLText'), [ { + // @ts-ignore onPress: () => this._urlField.focus(), text: t('settingsView.alertOk') } @@ -570,17 +673,34 @@ class SettingsView extends AbstractSettingsView { ); } - _updateSettings: (Object) => void; - /** * Updates the settings and sets state for disableCrashReporting. * * @param {boolean} disableCrashReporting - Whether crash reporting is disabled or not. * @returns {void} */ - _disableCrashReporting(disableCrashReporting) { - this._updateSettings({ disableCrashReporting }); - this.setState({ disableCrashReporting }); + _disableCrashReporting(disableCrashReporting: boolean) { + this.setState({ + disableCrashReporting + }); + + this._updateSettings({ + disableCrashReporting + }); + } + + /** + * Updates the persisted settings on any change. + * + * @param {Object} updateObject - The partial update object for the + * settings. + * @private + * @returns {void} + */ + _updateSettings(updateObject: Object) { + const { dispatch } = this.props; + + dispatch(updateSettings(updateObject)); } } @@ -590,17 +710,16 @@ class SettingsView extends AbstractSettingsView { * @param {Object} state - The Redux state. * @returns {Props} */ -function _mapStateToProps(state) { +function _mapStateToProps(state: any) { const localParticipant = getLocalParticipant(state); - const localParticipantId = localParticipant?.id; - const avatarLabel = localParticipant && getParticipantDisplayName(state, localParticipantId); return { - ..._abstractMapStateToProps(state), + _localParticipantId: localParticipant?.id, + _serverURL: getDefaultURL(state), _serverURLChangeEnabled: isServerURLChangeEnabled(state), - avatarLabel, - localParticipantId + _settings: state['features/base/settings'], + _visible: state['features/settings'].visible }; } -export default translate(connect(_mapStateToProps)(withTheme(SettingsView))); +export default translate(connect(_mapStateToProps)(SettingsView)); diff --git a/react/features/settings/components/native/styles.js b/react/features/settings/components/native/styles.js index 44ef06e6ba..5b97af13ef 100644 --- a/react/features/settings/components/native/styles.js +++ b/react/features/settings/components/native/styles.js @@ -1,4 +1,3 @@ -import { BoxModel } from '../../../base/styles'; import BaseTheme from '../../../base/ui/components/BaseTheme.native'; export const ANDROID_UNDERLINE_COLOR = 'transparent'; @@ -20,17 +19,6 @@ export default { justifyContent: 'center' }, - /** - * The style of the display name label. - */ - avatarLabel: { - color: BaseTheme.palette.text01, - fontSize: 16, - marginTop: BoxModel.margin, - textAlign: 'center' - }, - - /** * Style for screen container. */ diff --git a/react/features/toolbox/components/native/OverflowMenu.js b/react/features/toolbox/components/native/OverflowMenu.js index b7e47d71de..b404fa1bee 100644 --- a/react/features/toolbox/components/native/OverflowMenu.js +++ b/react/features/toolbox/components/native/OverflowMenu.js @@ -26,7 +26,6 @@ import LinkToSalesforceButton from './LinkToSalesforceButton'; import OpenCarmodeButton from './OpenCarmodeButton'; import RaiseHandButton from './RaiseHandButton'; import ScreenSharingButton from './ScreenSharingButton'; -import ToggleSelfViewButton from './ToggleSelfViewButton'; /** * The type of the React {@code Component} props of {@link OverflowMenu}. @@ -43,11 +42,6 @@ type Props = { */ _recordingEnabled: boolean, - /** - * Whether or not the self view is hidden. - */ - _selfViewHidden: boolean, - /** * The width of the screen. */ @@ -103,7 +97,6 @@ class OverflowMenu extends PureComponent { render() { const { _reactionsEnabled, - _selfViewHidden, _width } = this.props; const toolbarButtons = getMovableButtons(_width); @@ -138,7 +131,6 @@ class OverflowMenu extends PureComponent { {!toolbarButtons.has('participantspane') && } - {_selfViewHidden && } {!_reactionsEnabled && !toolbarButtons.has('raisehand') && } @@ -188,11 +180,8 @@ class OverflowMenu extends PureComponent { * @returns {Props} */ function _mapStateToProps(state) { - const { disableSelfView } = state['features/base/settings']; - return { _reactionsEnabled: isReactionsEnabled(state), - _selfViewHidden: Boolean(disableSelfView), _width: state['features/base/responsive-ui'].clientWidth }; }