Deeplinking (#2760)

* feat(Deeplinking): Implement for web.

* ref(unsupported_browser): Move the mobile version to deeplinking feature

* feat(deeplinking_mobile): Redesign.

* fix(deeplinking): Use interface.NATIVE_APP_NAME.

* feat(dial_in_summary): Add the PIN to the number link.

* fix(deep_linking): Handle use case when there isn't deep linking image.

* fix(deep_linking): css

* fix(deep_linking): deeplink -> "deep linking"

* fix(deeplinking_css): Remove position: fixed

* docs(deeplinking): Add comment for the openWebApp action.
This commit is contained in:
hristoterezov
2018-04-13 17:00:40 -07:00
committed by virtuacoplenny
parent fd44721bac
commit eb19f94598
36 changed files with 571 additions and 204 deletions
@@ -1,16 +0,0 @@
/**
* The type of the Redux action which signals that the React Component
* UnsupportedMobileBrowser which was rendered as a promotion of the mobile app
* on a browser was dismissed by the user. For example, the Web app may possibly
* run in Google Chrome on Android but we choose to promote the mobile app
* anyway claiming the user experience provided by the Web app is inferior to
* that of the mobile app. Eventually, the user may choose to dismiss the
* promotion of the mobile app and take their chances with the Web app instead.
* If unused, then we have chosen to force the mobile app and not allow the Web
* app in mobile browsers.
*
* {
* type: DISMISS_MOBILE_APP_PROMO
* }
*/
export const DISMISS_MOBILE_APP_PROMO = Symbol('DISMISS_MOBILE_APP_PROMO');
@@ -1,21 +0,0 @@
import { DISMISS_MOBILE_APP_PROMO } from './actionTypes';
/**
* Returns a Redux action which signals that the UnsupportedMobileBrowser which
* was rendered as a promotion of the mobile app on a browser was dismissed by
* the user. For example, the Web app may possibly run in Google Chrome
* on Android but we choose to promote the mobile app anyway claiming the user
* experience provided by the Web app is inferior to that of the mobile app.
* Eventually, the user may choose to dismiss the promotion of the mobile app
* and take their chances with the Web app instead. If unused, then we have
* chosen to force the mobile app and not allow the Web app in mobile browsers.
*
* @returns {{
* type: DISMISS_MOBILE_APP_PROMO
* }}
*/
export function dismissMobileAppPromo() {
return {
type: DISMISS_MOBILE_APP_PROMO
};
}
@@ -1,39 +0,0 @@
/* @flow */
import React, { Component } from 'react';
/**
* React component that represents HTML style element with CSS specific to
* unsupported mobile browser components.
*
* @private
* @returns {ReactElement}
*/
export default class HideNotificationBarStyles extends Component<*> {
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
// Temasys provide lib-jitsi-meet/modules/RTC/adapter.screenshare.js
// which detects whether the browser supports WebRTC. If the browser
// does not support WebRTC, it displays an alert in the form of a yellow
// bar at the top of the page. The alert notifies the user that the
// browser does not support WebRTC and, if Temasys provide a plugin for
// the browser, the alert contains a button to initiate installing the
// browser. When Temasys do not provide a plugin for the browser, we do
// not want the alert on the unsupported-browser page because the
// notification about the lack of WebRTC support is the whole point of
// the unsupported-browser page.
return (
<style type = 'text/css'>
{
'iframe[name="adapterjs-alert"] { display: none; }'
}
</style>
);
}
}
@@ -1,37 +0,0 @@
/* @flow */
import React, { Component } from 'react';
import HideNotificationBarStyle from './HideNotificationBarStyle';
declare var interfaceConfig: Object;
/**
* React component representing no mobile app page.
*
* @class NoMobileApp
*/
export default class NoMobileApp extends Component<*> {
/**
* Renders the component.
*
* @returns {ReactElement}
*/
render() {
const ns = 'no-mobile-app';
return (
<div className = { ns }>
<h2 className = { `${ns}__title` }>
Video chat isn't available on mobile.
</h2>
<p className = { `${ns}__description` }>
Please use { interfaceConfig.APP_NAME } on desktop to join
calls.
</p>
<HideNotificationBarStyle />
</div>
);
}
}
@@ -4,10 +4,9 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { translate } from '../../base/i18n';
import { Platform } from '../../base/react';
import { HideNotificationBarStyle, Platform } from '../../base/react';
import { CHROME, FIREFOX, IE, SAFARI } from './browserLinks';
import HideNotificationBarStyle from './HideNotificationBarStyle';
/**
* The namespace of the CSS styles of UnsupportedDesktopBrowser.
@@ -1,165 +0,0 @@
/* @flow */
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { translate, translateToHTML } from '../../base/i18n';
import { Platform } from '../../base/react';
import { URI_PROTOCOL_PATTERN } from '../../base/util';
import { DialInSummary } from '../../invite';
import HideNotificationBarStyle from './HideNotificationBarStyle';
declare var interfaceConfig: Object;
/**
* The namespace of the CSS styles of UnsupportedMobileBrowser.
*
* @private
* @type {string}
*/
const _SNS = 'unsupported-mobile-browser';
/**
* The namespace of the i18n/translation keys of UnsupportedMobileBrowser.
*
* @private
* @type {string}
*/
const _TNS = 'unsupportedBrowser';
/**
* The map of platforms to URLs at which the mobile app for the associated
* platform is available for download.
*
* @private
* @type {Array<string>}
*/
const _URLS = {
android: interfaceConfig.MOBILE_DOWNLOAD_LINK_ANDROID
|| 'https://play.google.com/store/apps/details?id=org.jitsi.meet',
ios: interfaceConfig.MOBILE_DOWNLOAD_LINK_IOS
|| 'https://itunes.apple.com/us/app/jitsi-meet/id1165103905'
};
/**
* React component representing mobile browser page.
*
* @class UnsupportedMobileBrowser
*/
class UnsupportedMobileBrowser extends Component<*, *> {
state: Object;
/**
* UnsupportedMobileBrowser component's property types.
*
* @static
*/
static propTypes = {
/**
* The name of the conference attempting to being joined.
*/
_room: PropTypes.string,
/**
* The function to translate human-readable text.
*
* @public
* @type {Function}
*/
t: PropTypes.func
};
/**
* Initializes the text and URL of the `Start a conference` / `Join the
* conversation` button which takes the user to the mobile app.
*
* @inheritdoc
*/
componentWillMount() {
// If the user installed the app while this Component was displayed
// (e.g. the user clicked the Download the App button), then we would
// like to open the current URL in the mobile app. The only way to do it
// appears to be a link with an app-specific scheme, not a Universal
// Link.
const appScheme = interfaceConfig.MOBILE_APP_SCHEME || 'org.jitsi.meet';
// Replace the protocol part with the app scheme.
const joinURL
= window.location.href.replace(
new RegExp(`^${URI_PROTOCOL_PATTERN}`), `${appScheme}:`);
this.setState({
joinURL
});
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const { _room, t } = this.props;
const openAppButtonClassName
= `${_SNS}__button ${_SNS}__button_primary`;
const appName
= interfaceConfig.ADD_PEOPLE_APP_NAME || interfaceConfig.APP_NAME;
return (
<div className = { _SNS }>
<div className = { `${_SNS}__body` }>
<img
className = { `${_SNS}__logo` }
src = 'images/logo-blue.svg' />
<p className = { `${_SNS}__text` }>
{
translateToHTML(
t,
`${_TNS}.appNotInstalled`,
{ app: appName })
}
</p>
<a href = { this.state.joinURL }>
<button className = { openAppButtonClassName }>
{ t(`${_TNS}.openApp`,
{ app: appName }) }
</button>
</a>
<a href = { _URLS[Platform.OS] }>
<button className = { `${_SNS}__button` }>
{ t(`${_TNS}.downloadApp`) }
</button>
</a>
{ _room
? <DialInSummary
className = 'unsupported-dial-in'
clickableNumbers = { true }
room = { _room } />
: null }
</div>
<HideNotificationBarStyle />
</div>
);
}
}
/**
* Maps (parts of) the Redux state to the associated props for the
* {@code UnsupportedMobileBrowser} component.
*
* @param {Object} state - The Redux state.
* @private
* @returns {{
* _room: string
* }}
*/
function _mapStateToProps(state) {
return {
_room: state['features/base/conference'].room
};
}
export default translate(connect(_mapStateToProps)(UnsupportedMobileBrowser));
@@ -1,8 +1,3 @@
export { default as HideNotificationBarStyle }
from './HideNotificationBarStyle';
export { default as NoMobileApp } from './NoMobileApp';
export { default as PluginRequiredBrowser } from './PluginRequiredBrowser';
export { default as UnsupportedDesktopBrowser }
from './UnsupportedDesktopBrowser';
export { default as UnsupportedMobileBrowser }
from './UnsupportedMobileBrowser';
@@ -1,5 +1,3 @@
export * from './actions';
export * from './components';
import './middleware';
import './reducer';
@@ -1,27 +0,0 @@
import { ReducerRegistry } from '../base/redux';
import { DISMISS_MOBILE_APP_PROMO } from './actionTypes';
ReducerRegistry.register(
'features/unsupported-browser',
(state = {}, action) => {
switch (action.type) {
case DISMISS_MOBILE_APP_PROMO:
return {
...state,
/**
* The indicator which determines whether the React
* Component UnsupportedMobileBrowser which was rendered as
* a promotion of the mobile app on a browser was dismissed
* by the user. If unused, then we have chosen to force the
* mobile app and not allow the Web app in mobile browsers.
*
* @type {boolean}
*/
mobileAppPromoDismissed: true
};
}
return state;
});