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.

AudioRoutePickerDialog.js 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // @flow
  2. import _ from 'lodash';
  3. import React, { Component } from 'react';
  4. import { NativeModules } from 'react-native';
  5. import { connect } from 'react-redux';
  6. import { hideDialog, SimpleBottomSheet } from '../../../base/dialog';
  7. import { translate } from '../../../base/i18n';
  8. /**
  9. * {@code PasswordRequiredPrompt}'s React {@code Component} prop types.
  10. */
  11. type Props = {
  12. /**
  13. * Used for hiding the dialog when the selection was completed.
  14. */
  15. dispatch: Function,
  16. /**
  17. * Invoked to obtain translated strings.
  18. */
  19. t: Function
  20. };
  21. type State = {
  22. /**
  23. * Array of available devices.
  24. */
  25. devices: Array<string>
  26. };
  27. const { AudioMode } = NativeModules;
  28. /**
  29. * Maps each device type to a display name and icon.
  30. */
  31. const deviceInfoMap = {
  32. BLUETOOTH: {
  33. iconName: 'bluetooth',
  34. text: 'audioDevices.bluetooth',
  35. type: 'BLUETOOTH'
  36. },
  37. EARPIECE: {
  38. iconName: 'phone-talk',
  39. text: 'audioDevices.phone',
  40. type: 'EARPIECE'
  41. },
  42. HEADPHONES: {
  43. iconName: 'headset',
  44. text: 'audioDevices.headphones',
  45. type: 'HEADPHONES'
  46. },
  47. SPEAKER: {
  48. iconName: 'volume',
  49. text: 'audioDevices.speaker',
  50. type: 'SPEAKER'
  51. }
  52. };
  53. /**
  54. * The exported React {@code Component}. {@code AudioRoutePickerDialog} is
  55. * exported only if the {@code AudioMode} module has the capability to get / set
  56. * audio devices.
  57. */
  58. let AudioRoutePickerDialog_;
  59. /**
  60. * Implements a React {@code Component} which prompts the user when a password
  61. * is required to join a conference.
  62. */
  63. class AudioRoutePickerDialog extends Component<Props, State> {
  64. state = {
  65. /**
  66. * Available audio devices, it will be set in
  67. * {@link #componentWillMount()}.
  68. */
  69. devices: []
  70. };
  71. /**
  72. * Initializes a new {@code PasswordRequiredPrompt} instance.
  73. *
  74. * @param {Props} props - The read-only React {@code Component} props with
  75. * which the new instance is to be initialized.
  76. */
  77. constructor(props) {
  78. super(props);
  79. // Bind event handlers so they are only bound once per instance.
  80. this._onCancel = this._onCancel.bind(this);
  81. this._onSubmit = this._onSubmit.bind(this);
  82. }
  83. /**
  84. * Initializes the device list by querying {@code AudioMode}.
  85. *
  86. * @inheritdoc
  87. */
  88. componentWillMount() {
  89. AudioMode.getAudioDevices().then(({ devices, selected }) => {
  90. const audioDevices = [];
  91. if (devices) {
  92. for (const device of devices) {
  93. if (deviceInfoMap[device]) {
  94. const info = Object.assign({}, deviceInfoMap[device]);
  95. info.selected = device === selected;
  96. info.text = this.props.t(info.text);
  97. audioDevices.push(info);
  98. }
  99. }
  100. }
  101. if (audioDevices) {
  102. // Make sure devices is alphabetically sorted.
  103. this.setState({
  104. devices: _.sortBy(audioDevices, 'text')
  105. });
  106. }
  107. });
  108. }
  109. /**
  110. * Dispatches a redux action to hide this sheet.
  111. *
  112. * @returns {void}
  113. */
  114. _hide() {
  115. this.props.dispatch(hideDialog(AudioRoutePickerDialog_));
  116. }
  117. _onCancel: () => void;
  118. /**
  119. * Cancels the dialog by hiding it.
  120. *
  121. * @private
  122. * @returns {void}
  123. */
  124. _onCancel() {
  125. this._hide();
  126. }
  127. _onSubmit: (?Object) => void;
  128. /**
  129. * Handles the selection of a device on the sheet. The selected device will
  130. * be used by {@code AudioMode}.
  131. *
  132. * @param {Object} device - Object representing the selected device.
  133. * @private
  134. * @returns {void}
  135. */
  136. _onSubmit(device) {
  137. this._hide();
  138. AudioMode.setAudioDevice(device.type);
  139. }
  140. /**
  141. * Implements React's {@link Component#render()}.
  142. *
  143. * @inheritdoc
  144. * @returns {ReactElement}
  145. */
  146. render() {
  147. const { devices } = this.state;
  148. if (!devices.length) {
  149. return null;
  150. }
  151. return (
  152. <SimpleBottomSheet
  153. onCancel = { this._onCancel }
  154. onSubmit = { this._onSubmit }
  155. options = { devices } />
  156. );
  157. }
  158. }
  159. // Only export the dialog if we have support for getting / setting audio devices
  160. // in AudioMode.
  161. if (AudioMode.getAudioDevices && AudioMode.setAudioDevice) {
  162. AudioRoutePickerDialog_ = translate(connect()(AudioRoutePickerDialog));
  163. }
  164. export default AudioRoutePickerDialog_;