rn: add DialInSummary

This commit is contained in:
Bettenbuk Zoltan 2019-05-07 16:50:57 +02:00 committed by Zoltan Bettenbuk
parent 7e9df74e60
commit 86d0d4fc22
31 changed files with 351 additions and 53 deletions

View File

@ -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'
}

View File

@ -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() {

View File

@ -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')

View File

@ -185,6 +185,7 @@
font-size: 12px;
max-height: 100%;
overflow: auto;
padding: 15pt;
position: absolute;
transform: translateY(-50%);
top: 50%;

View File

@ -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|

View File

@ -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

View File

@ -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",

19
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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<Props> {
return lines && lines.length ? lines.map(this._renderItemLine) : null;
}
/**
* Renders the secondary action label.
*
* @private
* @returns {React$Node}
*/
_renderSecondaryAction() {
const { secondaryAction } = this.props;
return (
<Container
onClick = { secondaryAction }
style = { styles.secondaryActionContainer }>
<Text style = { styles.secondaryActionLabel }>+</Text>
</Container>
);
}
/**
* Renders the content of this component.
*
@ -138,14 +119,12 @@ export default class NavigateSectionListItem extends Component<Props> {
return (
<Swipeout
autoClose = { true }
backgroundColor = { ColorPalette.transparent }
right = { right }>
<AvatarListItem
item = { item }
onPress = { this.props.onPress }>
{ this.props.secondaryAction
&& this._renderSecondaryAction() }
</AvatarListItem>
onPress = { this.props.onPress } />
</Swipeout>
);
}

View File

@ -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'
}

View File

@ -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.
*

View File

@ -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
};
}

View File

@ -0,0 +1,3 @@
// @flow
export * from './native';

View File

@ -0,0 +1,3 @@
// @flow
export * from './web';

View File

@ -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<any>
};
/**
* Implements a React native component that displays the dial in info page for a specific room.
*/
class DialInSummary extends Component<Props> {
/**
* 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 (
<SlidingView
position = 'bottom'
show = { Boolean(_summaryUrl) } >
<View style = { styles.webViewWrapper }>
<HeaderWithNavigation
headerLabelKey = 'info.label'
onPressBack = { this._onCloseView } />
<WebView
onError = { this._onError }
onShouldStartLoadWithRequest = { this._onNavigate }
renderLoading = { this._renderLoading }
source = {{ uri: getDialInfoPageURLForURIString(_summaryUrl) }}
startInLoadingState = { true }
style = { styles.webView } />
</View>
</SlidingView>
);
}
_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<any>;
/**
* Renders the loading indicator.
*
* @returns {React$Component<any>}
*/
_renderLoading() {
return (
<View style = { styles.indicatorWrapper }>
<LoadingIndicator
color = { INDICATOR_COLOR }
size = 'large' />
</View>
);
}
}
/**
* 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));

View File

@ -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 (
<AlertDialog
contentKey = 'info.dialInSummaryError' />
);
}
_onSubmit: () => boolean;
}
export default translate(connect()(DialInSummaryErrorDialog));

View File

@ -1 +1,3 @@
// @flow
export { default as DialInSummary } from './DialInSummary';

View File

@ -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'
}
};

View File

@ -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}.

View File

@ -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';

View File

@ -1,8 +1,8 @@
/* @flow */
// @flow
import React, { Component } from 'react';
import { translate } from '../../../base/i18n';
import { translate } from '../../../../base/i18n';
type Props = {

View File

@ -0,0 +1,3 @@
// @flow
export { default as DialInSummary } from './DialInSummary';

View File

@ -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';

View File

@ -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.
*

View File

@ -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,

View File

@ -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<Props> {
super(props);
this._onDelete = this._onDelete.bind(this);
this._onShowDialInInfo = this._onShowDialInInfo.bind(this);
}
/**
@ -79,6 +82,10 @@ class RecentList extends AbstractRecentList<Props> {
} = 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<Props> {
_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));
}
}
/**

View File

@ -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 {
</SafeAreaView>
<WelcomePageLists disabled = { this.state._fieldFocused } />
<SettingsView />
<DialInSummary />
</View>
<WelcomePageSideBar />
</LocalVideoTrackUnderlay>