You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AppSettings.native.js 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // @flow
  2. import React from 'react';
  3. import {
  4. Alert,
  5. Modal,
  6. SafeAreaView,
  7. ScrollView,
  8. Switch,
  9. Text,
  10. TextInput,
  11. View
  12. } from 'react-native';
  13. import { connect } from 'react-redux';
  14. import { translate } from '../../base/i18n';
  15. import { Header } from '../../base/react';
  16. import { PlatformElements } from '../../base/styles';
  17. import { hideAppSettings } from '../actions';
  18. import { normalizeUserInputURL } from '../functions';
  19. import { BackButton, FormRow, FormSectionHeader } from './_';
  20. import { _mapStateToProps, AbstractAppSettings } from './AbstractAppSettings';
  21. import styles from './styles';
  22. /**
  23. * The native container rendering the app settings page.
  24. *
  25. * @extends AbstractAppSettings
  26. */
  27. class AppSettings extends AbstractAppSettings {
  28. _urlField: Object;
  29. /**
  30. * Instantiates a new {@code AppSettings} instance.
  31. *
  32. * @inheritdoc
  33. */
  34. constructor(props) {
  35. super(props);
  36. this._onBlurServerURL = this._onBlurServerURL.bind(this);
  37. this._onRequestClose = this._onRequestClose.bind(this);
  38. this._setURLFieldReference = this._setURLFieldReference.bind(this);
  39. this._showURLAlert = this._showURLAlert.bind(this);
  40. }
  41. /**
  42. * Implements React's {@link Component#render()}, renders the settings page.
  43. *
  44. * @inheritdoc
  45. * @returns {ReactElement}
  46. */
  47. render() {
  48. const { _profile, t } = this.props;
  49. return (
  50. <Modal
  51. animationType = 'slide'
  52. onRequestClose = { this._onRequestClose }
  53. presentationStyle = 'fullScreen'
  54. supportedOrientations = { [
  55. 'landscape',
  56. 'portrait'
  57. ] }
  58. visible = { this.props._visible }>
  59. <View style = { PlatformElements.page }>
  60. <Header>
  61. <BackButton
  62. onPress = { this._onRequestClose } />
  63. <Text
  64. style = { [
  65. styles.text,
  66. PlatformElements.headerText
  67. ] } >
  68. { t('settingsScreen.header') }
  69. </Text>
  70. </Header>
  71. <SafeAreaView style = { styles.settingsForm }>
  72. <ScrollView>
  73. <FormSectionHeader
  74. i18nLabel = 'settingsScreen.profileSection' />
  75. <FormRow
  76. fieldSeparator = { true }
  77. i18nLabel = 'settingsScreen.displayName' >
  78. <TextInput
  79. onChangeText = { this._onChangeDisplayName }
  80. placeholder = 'John Doe'
  81. value = { _profile.displayName } />
  82. </FormRow>
  83. <FormRow
  84. i18nLabel = 'settingsScreen.email' >
  85. <TextInput
  86. keyboardType = { 'email-address' }
  87. onChangeText = { this._onChangeEmail }
  88. placeholder = 'email@example.com'
  89. value = { _profile.email } />
  90. </FormRow>
  91. <FormSectionHeader
  92. i18nLabel
  93. = 'settingsScreen.conferenceSection' />
  94. <FormRow
  95. fieldSeparator = { true }
  96. i18nLabel = 'settingsScreen.serverURL' >
  97. <TextInput
  98. autoCapitalize = 'none'
  99. onBlur = { this._onBlurServerURL }
  100. onChangeText = { this._onChangeServerURL }
  101. placeholder = { this.props._serverURL }
  102. value = { _profile.serverURL } />
  103. </FormRow>
  104. <FormRow
  105. fieldSeparator = { true }
  106. i18nLabel
  107. = 'settingsScreen.startWithAudioMuted' >
  108. <Switch
  109. onValueChange = {
  110. this._onStartAudioMutedChange
  111. }
  112. value = {
  113. _profile.startWithAudioMuted
  114. } />
  115. </FormRow>
  116. <FormRow
  117. i18nLabel
  118. = 'settingsScreen.startWithVideoMuted' >
  119. <Switch
  120. onValueChange = {
  121. this._onStartVideoMutedChange
  122. }
  123. value = {
  124. _profile.startWithVideoMuted
  125. } />
  126. </FormRow>
  127. </ScrollView>
  128. </SafeAreaView>
  129. </View>
  130. </Modal>
  131. );
  132. }
  133. _onBlurServerURL: () => void;
  134. /**
  135. * Handler the server URL lose focus event. Here we validate the server URL
  136. * and update it to the normalized version, or show an error if incorrect.
  137. *
  138. * @private
  139. * @returns {void}
  140. */
  141. _onBlurServerURL() {
  142. this._processServerURL(false /* hideOnSuccess */);
  143. }
  144. _onChangeDisplayName: (string) => void;
  145. _onChangeEmail: (string) => void;
  146. _onChangeServerURL: (string) => void;
  147. _onStartAudioMutedChange: (boolean) => void;
  148. _onStartVideoMutedChange: (boolean) => void;
  149. /**
  150. * Processes the server URL. It normalizes it and an error alert is
  151. * displayed in case it's incorrect.
  152. *
  153. * @param {boolean} hideOnSuccess - True if the dialog should be hidden if
  154. * normalization / validation succeeds, false otherwise.
  155. * @private
  156. * @returns {void}
  157. */
  158. _processServerURL(hideOnSuccess: boolean) {
  159. const { serverURL } = this.props._profile;
  160. const normalizedURL = normalizeUserInputURL(serverURL);
  161. if (normalizedURL === null) {
  162. this._showURLAlert();
  163. } else {
  164. this._onChangeServerURL(normalizedURL);
  165. if (hideOnSuccess) {
  166. this.props.dispatch(hideAppSettings());
  167. }
  168. }
  169. }
  170. _onRequestClose: () => void;
  171. /**
  172. * Handles the back button.
  173. * Also invokes normalizeUserInputURL to validate the URL entered
  174. * by the user.
  175. *
  176. * @returns {void}
  177. */
  178. _onRequestClose() {
  179. this._processServerURL(true /* hideOnSuccess */);
  180. }
  181. _setURLFieldReference: (React$ElementRef<*> | null) => void;
  182. /**
  183. * Stores a reference to the URL field for later use.
  184. *
  185. * @protected
  186. * @param {Object} component - The field component.
  187. * @returns {void}
  188. */
  189. _setURLFieldReference(component) {
  190. this._urlField = component;
  191. }
  192. _showURLAlert: () => void;
  193. /**
  194. * Shows an alert telling the user that the URL he/she entered was invalid.
  195. *
  196. * @returns {void}
  197. */
  198. _showURLAlert() {
  199. const { t } = this.props;
  200. Alert.alert(
  201. t('settingsScreen.alertTitle'),
  202. t('settingsScreen.alertURLText'),
  203. [
  204. {
  205. onPress: () => this._urlField.focus(),
  206. text: t('settingsScreen.alertOk')
  207. }
  208. ]
  209. );
  210. }
  211. }
  212. export default translate(connect(_mapStateToProps)(AppSettings));