diff --git a/android/sdk/build.gradle b/android/sdk/build.gradle index bca24d819..0e4ea2fab 100644 --- a/android/sdk/build.gradle +++ b/android/sdk/build.gradle @@ -62,6 +62,7 @@ dependencies { implementation project(':react-native-sound') implementation project(':react-native-vector-icons') implementation project(':react-native-webrtc') + implementation project(':react-native-webview') testImplementation 'junit:junit:4.12' } diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java index 4e3228e34..aa4944095 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java @@ -147,6 +147,7 @@ class ReactInstanceManagerHolder { new com.oblador.vectoricons.VectorIconsPackage(), new com.ocetnik.timer.BackgroundTimerPackage(), new com.oney.WebRTCModule.WebRTCModulePackage(), + new com.reactnativecommunity.webview.RNCWebViewPackage(), new com.rnimmersive.RNImmersivePackage(), new com.zmxv.RNSound.RNSoundPackage(), new ReactPackageAdapter() { diff --git a/android/settings.gradle b/android/settings.gradle index a9cd5743e..4d6b5af64 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -3,6 +3,8 @@ rootProject.name = 'jitsi-meet' include ':app', ':sdk' include ':react-native-background-timer' project(':react-native-background-timer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-background-timer/android') +include ':react-native-calendar-events' +project(':react-native-calendar-events').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-calendar-events/android') include ':react-native-fast-image' project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fast-image/android') include ':react-native-google-signin' @@ -19,5 +21,5 @@ include ':react-native-vector-icons' project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') include ':react-native-webrtc' project(':react-native-webrtc').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webrtc/android') -include ':react-native-calendar-events' -project(':react-native-calendar-events').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-calendar-events/android') +include ':react-native-webview' +project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android') diff --git a/css/modals/invite/_info.scss b/css/modals/invite/_info.scss index a9c9be91e..bc8aa5bb1 100644 --- a/css/modals/invite/_info.scss +++ b/css/modals/invite/_info.scss @@ -185,6 +185,7 @@ font-size: 12px; max-height: 100%; overflow: auto; + padding: 15pt; position: absolute; transform: translateY(-50%); top: 50%; diff --git a/ios/Podfile b/ios/Podfile index 4fc009470..f5b5b6620 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -40,10 +40,14 @@ target 'JitsiMeet' do pod 'react-native-background-timer', :path => '../node_modules/react-native-background-timer' + pod 'react-native-calendar-events', + :path => '../node_modules/react-native-calendar-events' pod 'react-native-fast-image', :path => '../node_modules/react-native-fast-image' pod 'react-native-keep-awake', :path => '../node_modules/react-native-keep-awake' + pod 'react-native-webview', + :path => '../node_modules/react-native-webview' pod 'BVLinearGradient', :path => '../node_modules/react-native-linear-gradient' pod 'react-native-webrtc', :path => '../node_modules/react-native-webrtc' @@ -52,8 +56,6 @@ target 'JitsiMeet' do pod 'RNSound', :path => '../node_modules/react-native-sound' pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons' pod 'RNWatch', :path => '../node_modules/react-native-watch-connectivity' - pod 'react-native-calendar-events', - :path => '../node_modules/react-native-calendar-events' end post_install do |installer| diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 3dcf5a9c5..71c6c773a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -99,6 +99,8 @@ PODS: - React - react-native-webrtc (1.69.1): - React + - react-native-webview (5.8.1): + - React - React/Core (0.59.5): - yoga (= 0.59.5.React) - React/CxxBridge (0.59.5): @@ -180,6 +182,7 @@ DEPENDENCIES: - react-native-fast-image (from `../node_modules/react-native-fast-image`) - react-native-keep-awake (from `../node_modules/react-native-keep-awake`) - react-native-webrtc (from `../node_modules/react-native-webrtc`) + - react-native-webview (from `../node_modules/react-native-webview`) - React/Core (from `../node_modules/react-native`) - React/CxxBridge (from `../node_modules/react-native`) - React/DevSupport (from `../node_modules/react-native`) @@ -239,6 +242,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-keep-awake" react-native-webrtc: :path: "../node_modules/react-native-webrtc" + react-native-webview: + :path: "../node_modules/react-native-webview" RNGoogleSignin: :path: "../node_modules/react-native-google-signin" RNSound: @@ -279,6 +284,7 @@ SPEC CHECKSUMS: react-native-fast-image: 47487b71169aea34868e7b38bf870b6b3f2157c5 react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae react-native-webrtc: 90a847d19deb2d7323fef8cc89ca12b8995fbc90 + react-native-webview: a95842e3f351a6d2c8bc8bcc9eab689c7e7e5ad4 RNGoogleSignin: 361174d9a3090d295b06257162b560d8efc8a6ed RNSound: e157320f503bdd4f4ee6d8542e948d54f90c3c3a RNVectorIcons: d819334932bcda3332deb3d2c8ea4d069e0b98f9 @@ -286,6 +292,6 @@ SPEC CHECKSUMS: SDWebImage: 3f3f0c02f09798048c47a5ed0a13f17b063572d8 yoga: 2e571f113e8cbeb0eb752aeebc86c1bfe7a8200c -PODFILE CHECKSUM: 9e6bc935ea7d2974604572cc68938281a88cf35c +PODFILE CHECKSUM: 0efc5cf3d69bf87368dc776a4e9a3c21935a16cf COCOAPODS: 1.6.1 diff --git a/lang/main.json b/lang/main.json index b68a5de6a..88e115a9b 100644 --- a/lang/main.json +++ b/lang/main.json @@ -351,6 +351,7 @@ "dialInConferenceID": "PIN:", "dialInNotSupported": "Sorry, dialing in is currently not supported.", "dialInNumber": "Dial-in:", + "dialInSummaryError": "Error fetching dial-in info now. Please try again later.", "dialInTollFree": "Toll Free", "genericError": "Whoops, something went wrong.", "inviteLiveStream": "To view the live stream of this meeting, click this link: __url__", @@ -773,6 +774,7 @@ "enterRoomTitle": "Start a new meeting", "go": "GO", "join": "JOIN", + "info": "Info", "privacy": "Privacy", "recentList": "Recent", "recentListDelete": "Delete", diff --git a/package-lock.json b/package-lock.json index d43a3e892..1666f5e05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12274,6 +12274,25 @@ "prop-types": "^15.5.10" } }, + "react-native-webview": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-5.8.1.tgz", + "integrity": "sha512-b6pSvmjoiWtcz6YspggW02X+BRXJWuquHwkh37BRx1NMW1iwMZA31SnFQvTpPzWYYIb9WF/mRsy2nGtt9C6NIg==", + "requires": { + "escape-string-regexp": "1.0.5", + "invariant": "2.2.4" + }, + "dependencies": { + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + } + } + }, "react-node-resolver": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/react-node-resolver/-/react-node-resolver-1.0.1.tgz", diff --git a/package.json b/package.json index f9ededacc..0a51dcb2f 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "react-native-vector-icons": "6.0.2", "react-native-watch-connectivity": "0.2.0", "react-native-webrtc": "github:jitsi/react-native-webrtc#4064c6f2db4f8b961daaaa8dafc6a896d7cfbc43", + "react-native-webview": "5.8.1", "react-redux": "5.0.7", "react-transition-group": "2.4.0", "redux": "4.0.0", diff --git a/react/features/base/react/components/native/NavigateSectionListItem.js b/react/features/base/react/components/native/NavigateSectionListItem.js index 7b3037ed4..7dc6d0be2 100644 --- a/react/features/base/react/components/native/NavigateSectionListItem.js +++ b/react/features/base/react/components/native/NavigateSectionListItem.js @@ -5,12 +5,11 @@ import Swipeout from 'react-native-swipeout'; import { ColorPalette } from '../../../styles'; -import Container from './Container'; -import Text from './Text'; -import styles from './styles'; import type { Item } from '../../Types'; import AvatarListItem from './AvatarListItem'; +import Text from './Text'; +import styles from './styles'; type Props = { @@ -93,24 +92,6 @@ export default class NavigateSectionListItem extends Component { return lines && lines.length ? lines.map(this._renderItemLine) : null; } - /** - * Renders the secondary action label. - * - * @private - * @returns {React$Node} - */ - _renderSecondaryAction() { - const { secondaryAction } = this.props; - - return ( - - + - - ); - } - /** * Renders the content of this component. * @@ -138,14 +119,12 @@ export default class NavigateSectionListItem extends Component { return ( - { this.props.secondaryAction - && this._renderSecondaryAction() } - + onPress = { this.props.onPress } /> ); } diff --git a/react/features/base/react/components/native/styles.js b/react/features/base/react/components/native/styles.js index 63a702aaf..c77dcc73e 100644 --- a/react/features/base/react/components/native/styles.js +++ b/react/features/base/react/components/native/styles.js @@ -4,7 +4,6 @@ import { BoxModel, ColorPalette, createStyleSheet } from '../../../styles'; const AVATAR_OPACITY = 0.4; const OVERLAY_FONT_COLOR = 'rgba(255, 255, 255, 0.6)'; -const SECONDARY_ACTION_BUTTON_SIZE = 30; export const AVATAR_SIZE = 65; export const UNDERLAY_COLOR = 'rgba(255, 255, 255, 0.2)'; @@ -218,21 +217,6 @@ const SECTION_LIST_STYLES = { color: OVERLAY_FONT_COLOR }, - secondaryActionContainer: { - alignItems: 'center', - backgroundColor: ColorPalette.blue, - borderRadius: 3, - height: SECONDARY_ACTION_BUTTON_SIZE, - justifyContent: 'center', - margin: BoxModel.margin * 0.5, - marginRight: BoxModel.margin, - width: SECONDARY_ACTION_BUTTON_SIZE - }, - - secondaryActionLabel: { - color: ColorPalette.white - }, - touchableView: { flexDirection: 'row' } diff --git a/react/features/invite/actionTypes.js b/react/features/invite/actionTypes.js index c58c63db9..7481da176 100644 --- a/react/features/invite/actionTypes.js +++ b/react/features/invite/actionTypes.js @@ -41,6 +41,16 @@ export const REMOVE_PENDING_INVITE_REQUESTS */ export const SET_CALLEE_INFO_VISIBLE = 'SET_CALLEE_INFO_VISIBLE'; +/** + * The type of Redux action to set the visibility of the dial in summary. + * + * { + * type: SET_DIAL_IN_SUMMARY_VISIBLE, + * visible: boolean + * } + */ +export const SET_DIAL_IN_SUMMARY_VISIBLE = 'SET_DIAL_IN_SUMMARY_VISIBLE'; + /** * The type of redux action which sets the invite dialog visible or invisible. * diff --git a/react/features/invite/actions.js b/react/features/invite/actions.js index 9361645a6..964d4e514 100644 --- a/react/features/invite/actions.js +++ b/react/features/invite/actions.js @@ -11,6 +11,7 @@ import { BEGIN_ADD_PEOPLE, REMOVE_PENDING_INVITE_REQUESTS, SET_CALLEE_INFO_VISIBLE, + SET_DIAL_IN_SUMMARY_VISIBLE, SET_INVITE_DIALOG_VISIBLE, UPDATE_DIAL_IN_NUMBERS_FAILED, UPDATE_DIAL_IN_NUMBERS_SUCCESS @@ -256,6 +257,15 @@ export function addPendingInviteRequest( }; } +/** + * Action to hide the dial in summary. + * + * @returns {showDialInSummary} + */ +export function hideDialInSummary() { + return showDialInSummary(undefined); +} + /** * Removes all pending invite requests. * @@ -268,3 +278,19 @@ export function removePendingInviteRequests() { type: REMOVE_PENDING_INVITE_REQUESTS }; } + +/** + * Action to set the dial in summary url (and show it). + * + * @param {?string} locationUrl - The location URL to show the dial in summary for. + * @returns {{ + * type: SET_DIAL_IN_SUMMARY_VISIBLE, + * summaryUrl: ?string + * }} + */ +export function showDialInSummary(locationUrl: ?string) { + return { + type: SET_DIAL_IN_SUMMARY_VISIBLE, + summaryUrl: locationUrl + }; +} diff --git a/react/features/invite/components/dial-in-summary/ConferenceID.native.js b/react/features/invite/components/dial-in-summary/ConferenceID.native.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/react/features/invite/components/dial-in-summary/DialInSummary.native.js b/react/features/invite/components/dial-in-summary/DialInSummary.native.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/react/features/invite/components/dial-in-summary/NumbersList.native.js b/react/features/invite/components/dial-in-summary/NumbersList.native.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/react/features/invite/components/dial-in-summary/index.native.js b/react/features/invite/components/dial-in-summary/index.native.js new file mode 100644 index 000000000..a32ec6061 --- /dev/null +++ b/react/features/invite/components/dial-in-summary/index.native.js @@ -0,0 +1,3 @@ +// @flow + +export * from './native'; diff --git a/react/features/invite/components/dial-in-summary/index.web.js b/react/features/invite/components/dial-in-summary/index.web.js new file mode 100644 index 000000000..40d5f4652 --- /dev/null +++ b/react/features/invite/components/dial-in-summary/index.web.js @@ -0,0 +1,3 @@ +// @flow + +export * from './web'; diff --git a/react/features/invite/components/dial-in-summary/native/DialInSummary.js b/react/features/invite/components/dial-in-summary/native/DialInSummary.js new file mode 100644 index 000000000..0eb0d7707 --- /dev/null +++ b/react/features/invite/components/dial-in-summary/native/DialInSummary.js @@ -0,0 +1,156 @@ +// @flow + +import React, { Component } from 'react'; +import { Linking, View } from 'react-native'; +import { WebView } from 'react-native-webview'; +import { type Dispatch } from 'redux'; + +import { openDialog } from '../../../../base/dialog'; +import { translate } from '../../../../base/i18n'; +import { + HeaderWithNavigation, + LoadingIndicator, + SlidingView +} from '../../../../base/react'; +import { connect } from '../../../../base/redux'; + +import { hideDialInSummary } from '../../../actions'; +import { getDialInfoPageURLForURIString } from '../../../functions'; + +import DialInSummaryErrorDialog from './DialInSummaryErrorDialog'; +import styles, { INDICATOR_COLOR } from './styles'; + +type Props = { + + /** + * The URL to display the summary for. + */ + _summaryUrl: ?string, + + dispatch: Dispatch +}; + +/** + * Implements a React native component that displays the dial in info page for a specific room. + */ +class DialInSummary extends Component { + + /** + * Initializes a new instance. + * + * @inheritdoc + */ + constructor(props: Props) { + super(props); + + this._onCloseView = this._onCloseView.bind(this); + this._onError = this._onError.bind(this); + this._onNavigate = this._onNavigate.bind(this); + this._renderLoading = this._renderLoading.bind(this); + } + + /** + * Implements React's {@link Component#render()}. + * + * @inheritdoc + */ + render() { + const { _summaryUrl } = this.props; + + return ( + + + + + + + ); + } + + _onCloseView: () => void; + + /** + * Closes the view. + * + * @returns {void} + */ + _onCloseView() { + this.props.dispatch(hideDialInSummary()); + } + + _onError: () => void; + + /** + * Callback to handle the error if the page fails to load. + * + * @returns {void} + */ + _onError() { + this.props.dispatch(hideDialInSummary()); + this.props.dispatch(openDialog(DialInSummaryErrorDialog)); + } + + _onNavigate: Object => Boolean; + + /** + * Callback to intercept navigation inside the webview and make the native app handle the dial requests. + * + * NOTE: We don't navigate to anywhere else form that view. + * + * @param {any} request - The request object. + * @returns {boolean} + */ + _onNavigate(request) { + const { url } = request; + + if (url.startsWith('tel:')) { + Linking.openURL(url); + this.props.dispatch(hideDialInSummary()); + } + + return url === getDialInfoPageURLForURIString(this.props._summaryUrl); + } + + _renderLoading: () => React$Component; + + /** + * Renders the loading indicator. + * + * @returns {React$Component} + */ + _renderLoading() { + return ( + + + + ); + } +} + +/** + * Maps part of the Redux state to the props of this component. + * + * @param {Object} state - The Redux state. + * @returns {{ + * _summaryUrl: ?string + * }} + */ +function _mapStateToProps(state) { + return { + _summaryUrl: state['features/invite'].summaryUrl + }; +} + +export default translate(connect(_mapStateToProps)(DialInSummary)); diff --git a/react/features/invite/components/dial-in-summary/native/DialInSummaryErrorDialog.js b/react/features/invite/components/dial-in-summary/native/DialInSummaryErrorDialog.js new file mode 100644 index 000000000..b0b318fe8 --- /dev/null +++ b/react/features/invite/components/dial-in-summary/native/DialInSummaryErrorDialog.js @@ -0,0 +1,29 @@ +// @flow + +import React, { Component } from 'react'; + +import { AlertDialog } from '../../../../base/dialog'; +import { translate } from '../../../../base/i18n'; +import { connect } from '../../../../base/redux'; + +/** + * Dialog to inform the user that we could't fetch the dial-in info page. + */ +class DialInSummaryErrorDialog extends Component<{}> { + /** + * Implements React's {@link Component#render()}. + * + * @inheritdoc + * @returns {ReactElement} + */ + render() { + return ( + + ); + } + + _onSubmit: () => boolean; +} + +export default translate(connect()(DialInSummaryErrorDialog)); diff --git a/react/features/invite/components/dial-in-summary/index.js b/react/features/invite/components/dial-in-summary/native/index.js similarity index 85% rename from react/features/invite/components/dial-in-summary/index.js rename to react/features/invite/components/dial-in-summary/native/index.js index b4a57eeb9..60396a03f 100644 --- a/react/features/invite/components/dial-in-summary/index.js +++ b/react/features/invite/components/dial-in-summary/native/index.js @@ -1 +1,3 @@ +// @flow + export { default as DialInSummary } from './DialInSummary'; diff --git a/react/features/invite/components/dial-in-summary/native/styles.js b/react/features/invite/components/dial-in-summary/native/styles.js new file mode 100644 index 000000000..f472e1bbd --- /dev/null +++ b/react/features/invite/components/dial-in-summary/native/styles.js @@ -0,0 +1,24 @@ +// @flow + +import { ColorPalette } from '../../../../base/styles'; + +export const INDICATOR_COLOR = ColorPalette.lightGrey; + +export default { + + indicatorWrapper: { + alignItems: 'center', + backgroundColor: ColorPalette.white, + flex: 1, + justifyContent: 'center' + }, + + webView: { + flex: 1 + }, + + webViewWrapper: { + flex: 1, + flexDirection: 'column' + } +}; diff --git a/react/features/invite/components/dial-in-summary/ConferenceID.web.js b/react/features/invite/components/dial-in-summary/web/ConferenceID.js similarity index 95% rename from react/features/invite/components/dial-in-summary/ConferenceID.web.js rename to react/features/invite/components/dial-in-summary/web/ConferenceID.js index 9c2c30c04..4227cc0ba 100644 --- a/react/features/invite/components/dial-in-summary/ConferenceID.web.js +++ b/react/features/invite/components/dial-in-summary/web/ConferenceID.js @@ -1,8 +1,8 @@ -/* @flow */ +// @flow import React, { Component } from 'react'; -import { translate } from '../../../base/i18n'; +import { translate } from '../../../../base/i18n'; /** * The type of the React {@code Component} props of {@link ConferenceID}. diff --git a/react/features/invite/components/dial-in-summary/DialInSummary.web.js b/react/features/invite/components/dial-in-summary/web/DialInSummary.js similarity index 99% rename from react/features/invite/components/dial-in-summary/DialInSummary.web.js rename to react/features/invite/components/dial-in-summary/web/DialInSummary.js index eab869f28..6da706d54 100644 --- a/react/features/invite/components/dial-in-summary/DialInSummary.web.js +++ b/react/features/invite/components/dial-in-summary/web/DialInSummary.js @@ -1,8 +1,8 @@ -/* @flow */ +// @flow import React, { Component } from 'react'; -import { translate } from '../../../base/i18n'; +import { translate } from '../../../../base/i18n'; import ConferenceID from './ConferenceID'; import NumbersList from './NumbersList'; diff --git a/react/features/invite/components/dial-in-summary/NumbersList.web.js b/react/features/invite/components/dial-in-summary/web/NumbersList.js similarity index 99% rename from react/features/invite/components/dial-in-summary/NumbersList.web.js rename to react/features/invite/components/dial-in-summary/web/NumbersList.js index 3ff9b22fa..3558e59fe 100644 --- a/react/features/invite/components/dial-in-summary/NumbersList.web.js +++ b/react/features/invite/components/dial-in-summary/web/NumbersList.js @@ -1,8 +1,8 @@ -/* @flow */ +// @flow import React, { Component } from 'react'; -import { translate } from '../../../base/i18n'; +import { translate } from '../../../../base/i18n'; type Props = { diff --git a/react/features/invite/components/dial-in-summary/web/index.js b/react/features/invite/components/dial-in-summary/web/index.js new file mode 100644 index 000000000..60396a03f --- /dev/null +++ b/react/features/invite/components/dial-in-summary/web/index.js @@ -0,0 +1,3 @@ +// @flow + +export { default as DialInSummary } from './DialInSummary'; diff --git a/react/features/invite/components/index.js b/react/features/invite/components/index.js index 791759e8e..132e7a3e7 100644 --- a/react/features/invite/components/index.js +++ b/react/features/invite/components/index.js @@ -1,6 +1,6 @@ // @flow export * from './add-people-dialog'; -export { DialInSummary } from './dial-in-summary'; +export * from './dial-in-summary'; export * from './info-dialog'; export * from './callee-info'; diff --git a/react/features/invite/functions.js b/react/features/invite/functions.js index bdb313de0..98771e285 100644 --- a/react/features/invite/functions.js +++ b/react/features/invite/functions.js @@ -508,6 +508,22 @@ export function getDialInfoPageURL( return `${origin}${newPath}/static/dialInInfo.html?room=${conferenceName}`; } +/** + * Generates the URL for the static dial in info page. + * + * @param {string} uri - The conference URI string. + * @returns {string} + */ +export function getDialInfoPageURLForURIString( + uri: ?string) { + if (!uri) { + return undefined; + } + const { protocol, host, contextRoot, room } = parseURIString(uri); + + return `${protocol}//${host}${contextRoot}static/dialInInfo.html?room=${room}`; +} + /** * Sets the internal state of which dial-in number to display. * diff --git a/react/features/invite/reducer.js b/react/features/invite/reducer.js index 35dbe8329..b151fd262 100644 --- a/react/features/invite/reducer.js +++ b/react/features/invite/reducer.js @@ -6,6 +6,7 @@ import { ADD_PENDING_INVITE_REQUEST, REMOVE_PENDING_INVITE_REQUESTS, SET_CALLEE_INFO_VISIBLE, + SET_DIAL_IN_SUMMARY_VISIBLE, SET_INVITE_DIALOG_VISIBLE, UPDATE_DIAL_IN_NUMBERS_FAILED, UPDATE_DIAL_IN_NUMBERS_SUCCESS @@ -50,6 +51,12 @@ ReducerRegistry.register('features/invite', (state = DEFAULT_STATE, action) => { initialCalleeInfo: action.initialCalleeInfo }; + case SET_DIAL_IN_SUMMARY_VISIBLE: + return { + ...state, + summaryUrl: action.summaryUrl + }; + case SET_INVITE_DIALOG_VISIBLE: return { ...state, diff --git a/react/features/recent-list/components/RecentList.native.js b/react/features/recent-list/components/RecentList.native.js index 60ce39f14..5d5416115 100644 --- a/react/features/recent-list/components/RecentList.native.js +++ b/react/features/recent-list/components/RecentList.native.js @@ -7,6 +7,8 @@ import { getDefaultURL } from '../../app'; import { translate } from '../../base/i18n'; import { NavigateSectionList, type Section } from '../../base/react'; import { connect } from '../../base/redux'; +import { ColorPalette } from '../../base/styles'; +import { showDialInSummary } from '../../invite'; import { deleteRecentListEntry } from '../actions'; import { isRecentListEnabled, toDisplayableList } from '../functions'; @@ -60,6 +62,7 @@ class RecentList extends AbstractRecentList { super(props); this._onDelete = this._onDelete.bind(this); + this._onShowDialInInfo = this._onShowDialInInfo.bind(this); } /** @@ -79,6 +82,10 @@ class RecentList extends AbstractRecentList { } = this.props; const recentList = toDisplayableList(_recentList, t, _defaultServerURL); const slideActions = [ { + backgroundColor: ColorPalette.blue, + onPress: this._onShowDialInInfo, + text: t('welcomepage.info') + }, { backgroundColor: 'red', onPress: this._onDelete, text: t('welcomepage.recentListDelete') @@ -107,6 +114,18 @@ class RecentList extends AbstractRecentList { _onDelete(itemId) { this.props.dispatch(deleteRecentListEntry(itemId)); } + + _onShowDialInInfo: Object => void + + /** + * Callback for the dial-in info action of the list. + * + * @param {Object} itemId - The ID of the entry for which we'd like to show the dial in numbers. + * @returns {void} + */ + _onShowDialInInfo(itemId) { + this.props.dispatch(showDialInSummary(itemId.url)); + } } /** diff --git a/react/features/welcome/components/WelcomePage.native.js b/react/features/welcome/components/WelcomePage.native.js index c0fe92433..23a6db293 100644 --- a/react/features/welcome/components/WelcomePage.native.js +++ b/react/features/welcome/components/WelcomePage.native.js @@ -20,6 +20,7 @@ import { createDesiredLocalTracks, destroyLocalTracks } from '../../base/tracks'; +import { DialInSummary } from '../../invite'; import { SettingsView } from '../../settings'; import { @@ -135,6 +136,7 @@ class WelcomePage extends AbstractWelcomePage { +