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.

LobbyScreen.js 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. // @flow
  2. import React from 'react';
  3. import { Text, View, TouchableOpacity, TextInput } from 'react-native';
  4. import { translate } from '../../../base/i18n';
  5. import JitsiScreen from '../../../base/modal/components/JitsiScreen';
  6. import { LoadingIndicator } from '../../../base/react';
  7. import { connect } from '../../../base/redux';
  8. import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui';
  9. import BaseTheme from '../../../base/ui/components/BaseTheme';
  10. import InviteButton
  11. from '../../../invite/components/add-people-dialog/native/InviteButton';
  12. import { LargeVideo } from '../../../large-video/components';
  13. import HeaderNavigationButton
  14. from '../../../mobile/navigation/components/HeaderNavigationButton';
  15. import { navigate }
  16. from '../../../mobile/navigation/components/lobby/LobbyNavigationContainerRef';
  17. import { screen } from '../../../mobile/navigation/routes';
  18. import AudioMuteButton from '../../../toolbox/components/AudioMuteButton';
  19. import VideoMuteButton from '../../../toolbox/components/VideoMuteButton';
  20. import AbstractLobbyScreen, {
  21. Props as AbstractProps,
  22. _mapStateToProps as abstractMapStateToProps } from '../AbstractLobbyScreen';
  23. import styles from './styles';
  24. type Props = AbstractProps & {
  25. /**
  26. * The current aspect ratio of the screen.
  27. */
  28. _aspectRatio: Symbol
  29. }
  30. /**
  31. * Implements a waiting screen that represents the participant being in the lobby.
  32. */
  33. class LobbyScreen extends AbstractLobbyScreen<Props> {
  34. /**
  35. * Implements React's {@link Component#componentDidMount()}. Invoked
  36. * immediately after this component is mounted.
  37. *
  38. * @inheritdoc
  39. * @returns {void}
  40. */
  41. componentDidMount() {
  42. const { navigation, t } = this.props;
  43. navigation.setOptions({
  44. headerLeft: () => (
  45. <HeaderNavigationButton
  46. label = { t('dialog.Cancel') }
  47. onPress = { this._onCancel } />
  48. )
  49. });
  50. }
  51. /**
  52. * Implements {@code PureComponent#render}.
  53. *
  54. * @inheritdoc
  55. */
  56. render() {
  57. const { _aspectRatio } = this.props;
  58. let contentStyles;
  59. let largeVideoContainerStyles;
  60. let contentContainerStyles;
  61. if (_aspectRatio === ASPECT_RATIO_NARROW) {
  62. largeVideoContainerStyles = styles.largeVideoContainer;
  63. contentContainerStyles = styles.contentContainer;
  64. } else {
  65. contentStyles = styles.contentWide;
  66. largeVideoContainerStyles = styles.largeVideoContainerWide;
  67. contentContainerStyles = styles.contentContainerWide;
  68. }
  69. return (
  70. <JitsiScreen
  71. safeAreaInsets = { [ 'right' ] }
  72. style = { styles.contentWrapper }>
  73. <View style = { contentStyles }>
  74. <View style = { largeVideoContainerStyles }>
  75. <LargeVideo />
  76. </View>
  77. <View style = { contentContainerStyles }>
  78. { this._renderContent() }
  79. { this._renderToolbarButtons() }
  80. </View>
  81. </View>
  82. </JitsiScreen>
  83. );
  84. }
  85. _getScreenTitleKey: () => string;
  86. _onAskToJoin: () => void;
  87. _onCancel: () => boolean;
  88. _onChangeDisplayName: Object => void;
  89. _onChangeEmail: Object => void;
  90. _onChangePassword: Object => void;
  91. _onEnableEdit: () => void;
  92. _onJoinWithPassword: () => void;
  93. _onSwitchToKnockMode: () => void;
  94. _onSwitchToPasswordMode: () => void;
  95. _renderContent: () => React$Element<*>;
  96. _renderToolbarButtons: () => React$Element<*>;
  97. _onNavigateToLobbyChat: () => void;
  98. /**
  99. * Navigates to the lobby chat screen.
  100. *
  101. * @private
  102. * @returns {void}
  103. */
  104. _onNavigateToLobbyChat() {
  105. navigate(screen.lobby.chat);
  106. }
  107. /**
  108. * Renders the joining (waiting) fragment of the screen.
  109. *
  110. * @inheritdoc
  111. */
  112. _renderJoining() {
  113. return (
  114. <View style = { styles.formWrapper }>
  115. <LoadingIndicator
  116. color = { BaseTheme.palette.icon01 }
  117. style = { styles.loadingIndicator } />
  118. <Text style = { styles.joiningMessage }>
  119. { this.props.t('lobby.joiningMessage') }
  120. </Text>
  121. { this._renderStandardButtons() }
  122. </View>
  123. );
  124. }
  125. /**
  126. * Renders the participant form to let the knocking participant enter its details.
  127. *
  128. * @inheritdoc
  129. */
  130. _renderParticipantForm() {
  131. const { t } = this.props;
  132. const { displayName } = this.state;
  133. return (
  134. <View style = { styles.formWrapper }>
  135. <Text style = { styles.fieldLabel }>
  136. { t('lobby.nameField') }
  137. </Text>
  138. <TextInput
  139. onChangeText = { this._onChangeDisplayName }
  140. style = { styles.field }
  141. value = { displayName } />
  142. </View>
  143. );
  144. }
  145. /**
  146. * Renders the participant info fragment when we have all the required details of the user.
  147. *
  148. * @inheritdoc
  149. */
  150. _renderParticipantInfo() {
  151. return this._renderParticipantForm();
  152. }
  153. /**
  154. * Renders the password form to let the participant join by using a password instead of knocking.
  155. *
  156. * @inheritdoc
  157. */
  158. _renderPasswordForm() {
  159. const { _passwordJoinFailed, t } = this.props;
  160. return (
  161. <View style = { styles.formWrapper }>
  162. <Text style = { styles.fieldLabel }>
  163. { this.props.t('lobby.passwordField') }
  164. </Text>
  165. <TextInput
  166. autoCapitalize = 'none'
  167. autoCompleteType = 'off'
  168. onChangeText = { this._onChangePassword }
  169. secureTextEntry = { true }
  170. style = { styles.field }
  171. value = { this.state.password } />
  172. { _passwordJoinFailed && <Text style = { styles.fieldError }>
  173. { t('lobby.invalidPassword') }
  174. </Text> }
  175. </View>
  176. );
  177. }
  178. /**
  179. * Renders the password join button (set).
  180. *
  181. * @inheritdoc
  182. */
  183. _renderPasswordJoinButtons() {
  184. const { t } = this.props;
  185. return (
  186. <View style = { styles.passwordJoinButtonsWrapper }>
  187. <TouchableOpacity
  188. onPress = { this._onSwitchToKnockMode }
  189. style = { [
  190. styles.button,
  191. styles.primaryButton
  192. ] }>
  193. <Text style = { styles.primaryButtonText }>
  194. { t('lobby.backToKnockModeButton') }
  195. </Text>
  196. </TouchableOpacity>
  197. <TouchableOpacity
  198. disabled = { !this.state.password }
  199. onPress = { this._onJoinWithPassword }
  200. style = { [
  201. styles.button,
  202. styles.primaryButton
  203. ] }>
  204. <Text style = { styles.primaryButtonText }>
  205. { t('lobby.passwordJoinButton') }
  206. </Text>
  207. </TouchableOpacity>
  208. </View>
  209. );
  210. }
  211. /**
  212. * Renders the toolbar buttons menu.
  213. *
  214. * @inheritdoc
  215. */
  216. _renderToolbarButtons() {
  217. const { _aspectRatio } = this.props;
  218. let toolboxContainerStyles;
  219. if (_aspectRatio === ASPECT_RATIO_NARROW) {
  220. toolboxContainerStyles = styles.toolboxContainer;
  221. } else {
  222. toolboxContainerStyles = styles.toolboxContainerWide;
  223. }
  224. return (
  225. <View style = { toolboxContainerStyles }>
  226. <AudioMuteButton
  227. styles = { styles.buttonStylesBorderless } />
  228. <VideoMuteButton
  229. styles = { styles.buttonStylesBorderless } />
  230. <InviteButton
  231. styles = { styles.buttonStylesBorderless } />
  232. </View>
  233. );
  234. }
  235. /**
  236. * Renders the standard button set.
  237. *
  238. * @inheritdoc
  239. */
  240. _renderStandardButtons() {
  241. const { _knocking, _renderPassword, _isLobbyChatActive, t } = this.props;
  242. const { displayName } = this.state;
  243. const askToJoinButtonStyles
  244. = displayName ? styles.primaryButton : styles.primaryButtonDisabled;
  245. return (
  246. <View style = { styles.standardButtonWrapper }>
  247. { _knocking && _isLobbyChatActive && <TouchableOpacity
  248. onPress = { this._onNavigateToLobbyChat }
  249. style = { [
  250. styles.button,
  251. styles.primaryButton
  252. ] }>
  253. <Text style = { styles.primaryButtonText }>
  254. { t('toolbar.openChat') }
  255. </Text>
  256. </TouchableOpacity>}
  257. { _knocking || <TouchableOpacity
  258. disabled = { !displayName }
  259. onPress = { this._onAskToJoin }
  260. style = { [
  261. styles.button,
  262. askToJoinButtonStyles
  263. ] }>
  264. <Text style = { styles.primaryButtonText }>
  265. { t('lobby.knockButton') }
  266. </Text>
  267. </TouchableOpacity> }
  268. { _renderPassword && <TouchableOpacity
  269. onPress = { this._onSwitchToPasswordMode }
  270. style = { [
  271. styles.button,
  272. styles.primaryButton
  273. ] }>
  274. <Text style = { styles.primaryButtonText }>
  275. { t('lobby.enterPasswordButton') }
  276. </Text>
  277. </TouchableOpacity> }
  278. </View>
  279. );
  280. }
  281. }
  282. /**
  283. * Maps part of the Redux state to the props of this component.
  284. *
  285. * @param {Object} state - The Redux state.
  286. * @param {Props} ownProps - The own props of the component.
  287. * @returns {{
  288. * _aspectRatio: Symbol
  289. * }}
  290. */
  291. function _mapStateToProps(state: Object, ownProps: Props) {
  292. return {
  293. ...abstractMapStateToProps(state, ownProps),
  294. _aspectRatio: state['features/base/responsive-ui'].aspectRatio
  295. };
  296. }
  297. export default translate(connect(_mapStateToProps)(LobbyScreen));