feat(deeplinking) Move deeplinking to config.js (#12704)
This commit is contained in:
parent
17b5009e63
commit
32dbdf2e5c
57
config.js
57
config.js
|
@ -1091,10 +1091,67 @@ var config = {
|
|||
// use only.
|
||||
// _desktopSharingSourceDevice: 'sample-id-or-label',
|
||||
|
||||
// DEPRECATED! Use deeplinking.disabled instead.
|
||||
// If true, any checks to handoff to another application will be prevented
|
||||
// and instead the app will continue to display in the current browser.
|
||||
// disableDeepLinking: false,
|
||||
|
||||
// The deeplinking config.
|
||||
// For information about the properties of
|
||||
// deeplinking.[ios/android].dynamicLink check:
|
||||
// https://firebase.google.com/docs/dynamic-links/create-manually
|
||||
// deeplinking: {
|
||||
//
|
||||
// // The desktop deeplinking config.
|
||||
// desktop: {
|
||||
// appName: 'Jitsi Meet'
|
||||
// },
|
||||
// // If true, any checks to handoff to another application will be prevented
|
||||
// // and instead the app will continue to display in the current browser.
|
||||
// disabled: false,
|
||||
|
||||
// // whether to hide the logo on the deep linking pages.
|
||||
// hideLogo: false,
|
||||
|
||||
// // whether to show deeplinking image.
|
||||
// showImage: false,
|
||||
|
||||
// // The ios deeplinking config.
|
||||
// ios: {
|
||||
// appName: 'Jitsi Meet',
|
||||
// // Specify mobile app scheme for opening the app from the mobile browser.
|
||||
// appScheme: 'org.jitsi.meet',
|
||||
// // Custom URL for downloading ios mobile app.
|
||||
// downloadLink: 'https://itunes.apple.com/us/app/jitsi-meet/id1165103905',
|
||||
// dynamicLink: {
|
||||
// apn: 'org.jitsi.meet',
|
||||
// appCode: 'w2atb',
|
||||
// customDomain: undefined,
|
||||
// ibi: 'com.atlassian.JitsiMeet.ios',
|
||||
// isi: '1165103905'
|
||||
// }
|
||||
// },
|
||||
|
||||
// // The android deeplinking config.
|
||||
// android: {
|
||||
// appName: 'Jitsi Meet',
|
||||
// // Specify mobile app scheme for opening the app from the mobile browser.
|
||||
// appScheme: 'org.jitsi.meet',
|
||||
// // Custom URL for downloading android mobile app.
|
||||
// downloadLink: 'https://play.google.com/store/apps/details?id=org.jitsi.meet',
|
||||
// // Android app package name.
|
||||
// appPackage: 'org.jitsi.meet',
|
||||
// fDroidUrl: 'https://f-droid.org/en/packages/org.jitsi.meet/',
|
||||
// dynamicLink: {
|
||||
// apn: 'org.jitsi.meet',
|
||||
// appCode: 'w2atb',
|
||||
// customDomain: undefined,
|
||||
// ibi: 'com.atlassian.JitsiMeet.ios',
|
||||
// isi: '1165103905'
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
|
||||
// A property to disable the right click context menu for localVideo
|
||||
// the menu has option to flip the locally seen video for local presentations
|
||||
// disableLocalVideoFlip: false,
|
||||
|
|
|
@ -76,11 +76,6 @@ var interfaceConfig = {
|
|||
|
||||
GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true,
|
||||
|
||||
/**
|
||||
* Hide the logo on the deep linking pages.
|
||||
*/
|
||||
HIDE_DEEP_LINKING_LOGO: false,
|
||||
|
||||
/**
|
||||
* Hide the invite prompt in the header when alone in the meeting.
|
||||
*/
|
||||
|
@ -108,23 +103,6 @@ var interfaceConfig = {
|
|||
*/
|
||||
MOBILE_APP_PROMO: true,
|
||||
|
||||
/**
|
||||
* Specify custom URL for downloading android mobile app.
|
||||
*/
|
||||
MOBILE_DOWNLOAD_LINK_ANDROID: 'https://play.google.com/store/apps/details?id=org.jitsi.meet',
|
||||
|
||||
/**
|
||||
* Specify custom URL for downloading f droid app.
|
||||
*/
|
||||
MOBILE_DOWNLOAD_LINK_F_DROID: 'https://f-droid.org/en/packages/org.jitsi.meet/',
|
||||
|
||||
/**
|
||||
* Specify URL for downloading ios mobile app.
|
||||
*/
|
||||
MOBILE_DOWNLOAD_LINK_IOS: 'https://itunes.apple.com/us/app/jitsi-meet/id1165103905',
|
||||
|
||||
NATIVE_APP_NAME: 'Jitsi Meet',
|
||||
|
||||
// Names of browsers which should show a warning stating the current browser
|
||||
// has a suboptimal experience. Browsers which are not listed as optimal or
|
||||
// unsupported are considered suboptimal. Valid values are:
|
||||
|
@ -159,7 +137,6 @@ var interfaceConfig = {
|
|||
*/
|
||||
SHOW_CHROME_EXTENSION_BANNER: false,
|
||||
|
||||
SHOW_DEEP_LINKING_IMAGE: false,
|
||||
SHOW_JITSI_WATERMARK: true,
|
||||
SHOW_POWERED_BY: false,
|
||||
SHOW_PROMOTIONAL_CLOSE_PAGE: false,
|
||||
|
@ -200,6 +177,33 @@ var interfaceConfig = {
|
|||
*/
|
||||
// TILE_VIEW_MAX_COLUMNS: 5,
|
||||
|
||||
// List of undocumented settings
|
||||
/**
|
||||
INDICATOR_FONT_SIZES
|
||||
PHONE_NUMBER_REGEX
|
||||
*/
|
||||
|
||||
// -----------------DEPRECATED CONFIGS BELOW THIS LINE-----------------------------
|
||||
|
||||
/**
|
||||
* Specify URL for downloading ios mobile app.
|
||||
*/
|
||||
// MOBILE_DOWNLOAD_LINK_IOS: 'https://itunes.apple.com/us/app/jitsi-meet/id1165103905',
|
||||
|
||||
/**
|
||||
* Specify custom URL for downloading android mobile app.
|
||||
*/
|
||||
// MOBILE_DOWNLOAD_LINK_ANDROID: 'https://play.google.com/store/apps/details?id=org.jitsi.meet',
|
||||
|
||||
// SHOW_DEEP_LINKING_IMAGE: false,
|
||||
|
||||
/**
|
||||
* Specify mobile app scheme for opening the app from the mobile browser.
|
||||
*/
|
||||
// APP_SCHEME: 'org.jitsi.meet',
|
||||
|
||||
// NATIVE_APP_NAME: 'Jitsi Meet',
|
||||
|
||||
/**
|
||||
* Specify Firebase dynamic link properties for the mobile apps.
|
||||
*/
|
||||
|
@ -212,22 +216,19 @@ var interfaceConfig = {
|
|||
// },
|
||||
|
||||
/**
|
||||
* Specify mobile app scheme for opening the app from the mobile browser.
|
||||
* Hide the logo on the deep linking pages.
|
||||
*/
|
||||
// APP_SCHEME: 'org.jitsi.meet',
|
||||
// HIDE_DEEP_LINKING_LOGO: false,
|
||||
|
||||
/**
|
||||
* Specify the Android app package name.
|
||||
*/
|
||||
// ANDROID_APP_PACKAGE: 'org.jitsi.meet',
|
||||
|
||||
// List of undocumented settings
|
||||
/**
|
||||
INDICATOR_FONT_SIZES
|
||||
PHONE_NUMBER_REGEX
|
||||
*/
|
||||
|
||||
// -----------------DEPRECATED CONFIGS BELOW THIS LINE-----------------------------
|
||||
* Specify custom URL for downloading f droid app.
|
||||
*/
|
||||
// MOBILE_DOWNLOAD_LINK_F_DROID: 'https://f-droid.org/en/packages/org.jitsi.meet/',
|
||||
|
||||
// Connection indicators (
|
||||
// CONNECTION_INDICATOR_AUTO_HIDE_ENABLED,
|
||||
|
|
|
@ -88,6 +88,36 @@ export type Sounds = 'ASKED_TO_UNMUTE_SOUND' |
|
|||
'RECORDING_ON_SOUND' |
|
||||
'TALK_WHILE_MUTED_SOUND';
|
||||
|
||||
|
||||
export interface IMobileDynamicLink {
|
||||
apn: string;
|
||||
appCode: string;
|
||||
customDomain?: string;
|
||||
ibi: string;
|
||||
isi: string;
|
||||
}
|
||||
|
||||
export interface IDeeplinkingPlatformConfig {
|
||||
appName: string;
|
||||
}
|
||||
|
||||
export interface IDeeplinkingMobileConfig extends IDeeplinkingPlatformConfig {
|
||||
appPackage?: string;
|
||||
appScheme: string;
|
||||
downloadLink: string;
|
||||
dynamicLink?: IMobileDynamicLink;
|
||||
fDroidUrl?: string;
|
||||
}
|
||||
|
||||
export interface IDeeplinkingConfig {
|
||||
android?: IDeeplinkingMobileConfig;
|
||||
desktop?: IDeeplinkingPlatformConfig;
|
||||
disabled: boolean;
|
||||
hideLogo: boolean;
|
||||
ios?: IDeeplinkingMobileConfig;
|
||||
showImage: boolean;
|
||||
}
|
||||
|
||||
export interface IConfig {
|
||||
_desktopSharingSourceDevice?: string;
|
||||
analytics?: {
|
||||
|
@ -176,6 +206,7 @@ export interface IConfig {
|
|||
};
|
||||
};
|
||||
corsAvatarURLs?: Array<string>;
|
||||
deeplinking?: IDeeplinkingConfig;
|
||||
defaultLanguage?: string;
|
||||
defaultLocalDisplayName?: string;
|
||||
defaultLogoUrl?: string;
|
||||
|
|
|
@ -81,6 +81,8 @@ export default [
|
|||
'brandingRoomAlias',
|
||||
'debug',
|
||||
'debugAudioLevels',
|
||||
'deeplinking.disabled',
|
||||
'deeplinking.showImage',
|
||||
'defaultLocalDisplayName',
|
||||
'defaultRemoteDisplayName',
|
||||
'deploymentUrls',
|
||||
|
|
|
@ -4,7 +4,7 @@ import { IReduxState } from '../../app/types';
|
|||
import { REPLACE_PARTICIPANT } from '../flags/constants';
|
||||
import { getFeatureFlag } from '../flags/functions';
|
||||
|
||||
import { IConfig } from './configType';
|
||||
import { IConfig, IDeeplinkingConfig } from './configType';
|
||||
|
||||
export * from './functions.any';
|
||||
|
||||
|
@ -42,3 +42,14 @@ export function _cleanupConfig(config: IConfig) {
|
|||
export function getReplaceParticipant(state: IReduxState): string {
|
||||
return getFeatureFlag(state, REPLACE_PARTICIPANT, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the defaults for deeplinking.
|
||||
*
|
||||
* @param {IDeeplinkingConfig} _deeplinking - The deeplinking config.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function _setDeeplinkingDefaults(_deeplinking: IDeeplinkingConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { IReduxState } from '../../app/types';
|
||||
|
||||
import { IConfig } from './configType';
|
||||
import { IConfig, IDeeplinkingConfig, IDeeplinkingMobileConfig, IDeeplinkingPlatformConfig } from './configType';
|
||||
import { TOOLBAR_BUTTONS } from './constants';
|
||||
|
||||
export * from './functions.any';
|
||||
|
@ -8,10 +8,11 @@ export * from './functions.any';
|
|||
/**
|
||||
* Removes all analytics related options from the given configuration, in case of a libre build.
|
||||
*
|
||||
* @param {*} config - The configuration which needs to be cleaned up.
|
||||
* @param {*} _config - The configuration which needs to be cleaned up.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function _cleanupConfig(config: IConfig) { // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
export function _cleanupConfig(_config: IConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,3 +61,43 @@ export function areAudioLevelsEnabled(state: IReduxState): boolean {
|
|||
// Default to false for React Native as audio levels are of no interest to the mobile app.
|
||||
return navigator.product !== 'ReactNative' && !state['features/base/config'].disableAudioLevels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the defaults for deeplinking.
|
||||
*
|
||||
* @param {IDeeplinkingConfig} deeplinking - The deeplinking config.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function _setDeeplinkingDefaults(deeplinking: IDeeplinkingConfig) {
|
||||
const {
|
||||
desktop = {} as IDeeplinkingPlatformConfig,
|
||||
android = {} as IDeeplinkingMobileConfig,
|
||||
ios = {} as IDeeplinkingMobileConfig
|
||||
} = deeplinking;
|
||||
|
||||
desktop.appName = desktop.appName || 'Jitsi Meet';
|
||||
|
||||
ios.appName = ios.appName || 'Jitsi Meet';
|
||||
ios.appScheme = ios.appScheme || 'org.jitsi.meet';
|
||||
ios.downloadLink = ios.downloadLink
|
||||
|| 'https://itunes.apple.com/us/app/jitsi-meet/id1165103905';
|
||||
if (ios.dynamicLink) {
|
||||
ios.dynamicLink.apn = ios.dynamicLink.apn || 'org.jitsi.meet';
|
||||
ios.dynamicLink.appCode = ios.dynamicLink.appCode || 'w2atb';
|
||||
ios.dynamicLink.ibi = ios.dynamicLink.ibi || 'com.atlassian.JitsiMeet.ios';
|
||||
ios.dynamicLink.isi = ios.dynamicLink.isi || '1165103905';
|
||||
}
|
||||
|
||||
android.appName = android.appName || 'Jitsi Meet';
|
||||
android.appScheme = android.appScheme || 'org.jitsi.meet';
|
||||
android.downloadLink = android.downloadLink
|
||||
|| 'https://play.google.com/store/apps/details?id=org.jitsi.meet';
|
||||
android.appPackage = android.appPackage || 'org.jitsi.meet';
|
||||
android.fDroidUrl = android.fDroidUrl || 'https://f-droid.org/en/packages/org.jitsi.meet/';
|
||||
if (android.dynamicLink) {
|
||||
android.dynamicLink.apn = android.dynamicLink.apn || 'org.jitsi.meet';
|
||||
android.dynamicLink.appCode = android.dynamicLink.appCode || 'w2atb';
|
||||
android.dynamicLink.ibi = android.dynamicLink.ibi || 'com.atlassian.JitsiMeet.ios';
|
||||
android.dynamicLink.isi = android.dynamicLink.isi || '1165103905';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,14 @@ import {
|
|||
SET_CONFIG,
|
||||
UPDATE_CONFIG
|
||||
} from './actionTypes';
|
||||
import { IConfig } from './configType';
|
||||
import { _cleanupConfig } from './functions';
|
||||
import {
|
||||
IConfig,
|
||||
IDeeplinkingConfig,
|
||||
IDeeplinkingMobileConfig,
|
||||
IDeeplinkingPlatformConfig,
|
||||
IMobileDynamicLink
|
||||
} from './configType';
|
||||
import { _cleanupConfig, _setDeeplinkingDefaults } from './functions';
|
||||
|
||||
/**
|
||||
* The initial state of the feature base/config when executing in a
|
||||
|
@ -292,6 +298,52 @@ function _translateInterfaceConfig(oldValue: IConfig) {
|
|||
}
|
||||
}
|
||||
|
||||
// if we have `deeplinking` defined, ignore deprecated values. Otherwise, compose the config.
|
||||
if (!oldValue.deeplinking) {
|
||||
const disabled = Boolean(oldValue.disableDeepLinking);
|
||||
const deeplinking: IDeeplinkingConfig = {
|
||||
desktop: {} as IDeeplinkingPlatformConfig,
|
||||
hideLogo: false,
|
||||
disabled,
|
||||
showImage: false,
|
||||
android: {} as IDeeplinkingMobileConfig,
|
||||
ios: {} as IDeeplinkingMobileConfig
|
||||
};
|
||||
|
||||
if (typeof interfaceConfig === 'object') {
|
||||
const mobileDynamicLink = interfaceConfig.MOBILE_DYNAMIC_LINK;
|
||||
const dynamicLink: IMobileDynamicLink | undefined = mobileDynamicLink ? {
|
||||
apn: mobileDynamicLink.APN,
|
||||
appCode: mobileDynamicLink.APP_CODE,
|
||||
ibi: mobileDynamicLink.IBI,
|
||||
isi: mobileDynamicLink.ISI,
|
||||
customDomain: mobileDynamicLink.CUSTOM_DOMAIN
|
||||
} : undefined;
|
||||
|
||||
if (deeplinking.desktop) {
|
||||
deeplinking.desktop.appName = interfaceConfig.NATIVE_APP_NAME;
|
||||
}
|
||||
|
||||
deeplinking.hideLogo = Boolean(interfaceConfig.HIDE_DEEP_LINKING_LOGO);
|
||||
deeplinking.showImage = interfaceConfig.SHOW_DEEP_LINKING_IMAGE;
|
||||
deeplinking.android = {
|
||||
appName: interfaceConfig.NATIVE_APP_NAME,
|
||||
appScheme: interfaceConfig.APP_SCHEME,
|
||||
downloadLink: interfaceConfig.MOBILE_DOWNLOAD_LINK_ANDROID,
|
||||
appPackage: interfaceConfig.ANDROID_APP_PACKAGE,
|
||||
fDroidUrl: interfaceConfig.MOBILE_DOWNLOAD_LINK_F_DROID,
|
||||
dynamicLink
|
||||
};
|
||||
deeplinking.ios = {
|
||||
appName: interfaceConfig.NATIVE_APP_NAME,
|
||||
appScheme: interfaceConfig.APP_SCHEME,
|
||||
downloadLink: interfaceConfig.MOBILE_DOWNLOAD_LINK_IOS,
|
||||
dynamicLink
|
||||
};
|
||||
}
|
||||
newValue.deeplinking = deeplinking;
|
||||
}
|
||||
|
||||
return newValue;
|
||||
}
|
||||
|
||||
|
@ -480,6 +532,8 @@ function _translateLegacyConfig(oldValue: IConfig) {
|
|||
};
|
||||
}
|
||||
|
||||
_setDeeplinkingDefaults(newValue.deeplinking as IDeeplinkingConfig);
|
||||
|
||||
return newValue;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import React, { Component } from 'react';
|
|||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { createDeepLinkingPageEvent, sendAnalytics } from '../../analytics';
|
||||
import { IDeeplinkingConfig } from '../../base/config/configType';
|
||||
import { isSupportedBrowser } from '../../base/environment';
|
||||
import { translate } from '../../base/i18n';
|
||||
import { connect } from '../../base/redux';
|
||||
|
@ -16,14 +17,17 @@ import {
|
|||
} from '../actions';
|
||||
import { _TNS } from '../constants';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of
|
||||
* {@link DeepLinkingDesktopPage}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The deeplinking config.
|
||||
*/
|
||||
_deeplinkingCfg: IDeeplinkingConfig,
|
||||
|
||||
/**
|
||||
* Used to dispatch actions from the buttons.
|
||||
*/
|
||||
|
@ -72,10 +76,10 @@ class DeepLinkingDesktopPage<P : Props> extends Component<P> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
const { HIDE_DEEP_LINKING_LOGO, NATIVE_APP_NAME, SHOW_DEEP_LINKING_IMAGE } = interfaceConfig;
|
||||
const { t, _deeplinkingCfg: { desktop = {}, hideLogo, showImage } } = this.props;
|
||||
const { appName } = desktop;
|
||||
const rightColumnStyle
|
||||
= SHOW_DEEP_LINKING_IMAGE ? null : { width: '100%' };
|
||||
= showImage ? null : { width: '100%' };
|
||||
|
||||
return (
|
||||
|
||||
|
@ -84,7 +88,7 @@ class DeepLinkingDesktopPage<P : Props> extends Component<P> {
|
|||
<div className = 'deep-linking-desktop'>
|
||||
<div className = 'header'>
|
||||
{
|
||||
HIDE_DEEP_LINKING_LOGO
|
||||
hideLogo
|
||||
? null
|
||||
: <img
|
||||
alt = { t('welcomepage.logo.logoDeepLinking') }
|
||||
|
@ -94,7 +98,7 @@ class DeepLinkingDesktopPage<P : Props> extends Component<P> {
|
|||
</div>
|
||||
<div className = 'content'>
|
||||
{
|
||||
SHOW_DEEP_LINKING_IMAGE
|
||||
showImage
|
||||
? <div className = 'leftColumn'>
|
||||
<div className = 'leftColumnContent'>
|
||||
<div className = 'image' />
|
||||
|
@ -108,7 +112,7 @@ class DeepLinkingDesktopPage<P : Props> extends Component<P> {
|
|||
<h1 className = 'title'>
|
||||
{
|
||||
t(`${_TNS}.title`,
|
||||
{ app: NATIVE_APP_NAME })
|
||||
{ app: appName })
|
||||
}
|
||||
</h1>
|
||||
<p className = 'description'>
|
||||
|
@ -117,7 +121,7 @@ class DeepLinkingDesktopPage<P : Props> extends Component<P> {
|
|||
`${_TNS}.${isSupportedBrowser()
|
||||
? 'description'
|
||||
: 'descriptionWithoutWeb'}`,
|
||||
{ app: NATIVE_APP_NAME }
|
||||
{ app: appName }
|
||||
)
|
||||
}
|
||||
</p>
|
||||
|
@ -171,4 +175,18 @@ class DeepLinkingDesktopPage<P : Props> extends Component<P> {
|
|||
}
|
||||
}
|
||||
|
||||
export default translate(connect()(DeepLinkingDesktopPage));
|
||||
/**
|
||||
* Maps (parts of) the Redux state to the associated props for the
|
||||
* {@code DeepLinkingDesktopPage} component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @private
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
return {
|
||||
_deeplinkingCfg: state['features/base/config'].deeplinking || {}
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(DeepLinkingDesktopPage));
|
||||
|
|
|
@ -4,6 +4,7 @@ import React, { Component } from 'react';
|
|||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { createDeepLinkingPageEvent, sendAnalytics } from '../../analytics';
|
||||
import { IDeeplinkingConfig, IDeeplinkingMobileConfig } from '../../base/config/configType';
|
||||
import { isSupportedMobileBrowser } from '../../base/environment';
|
||||
import { translate } from '../../base/i18n';
|
||||
import { Platform } from '../../base/react';
|
||||
|
@ -14,8 +15,6 @@ import { _TNS } from '../constants';
|
|||
import { generateDeepLinkingURL } from '../functions';
|
||||
import { renderPromotionalFooter } from '../renderPromotionalFooter';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
/**
|
||||
* The namespace of the CSS styles of DeepLinkingMobilePage.
|
||||
*
|
||||
|
@ -31,9 +30,19 @@ const _SNS = 'deep-linking-mobile';
|
|||
type Props = {
|
||||
|
||||
/**
|
||||
* Application download URL.
|
||||
* The deeplinking config.
|
||||
*/
|
||||
_downloadUrl: ?string,
|
||||
_deeplinkingCfg: IDeeplinkingConfig,
|
||||
|
||||
/**
|
||||
* Application mobile deeplinking config.
|
||||
*/
|
||||
_mobileConfig: IDeeplinkingMobileConfig,
|
||||
|
||||
/**
|
||||
* The deeplinking url.
|
||||
*/
|
||||
_deepLinkingUrl: string,
|
||||
|
||||
/**
|
||||
* The name of the conference attempting to being joined.
|
||||
|
@ -95,13 +104,19 @@ class DeepLinkingMobilePage extends Component<Props> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { _downloadUrl, _room, t, _url } = this.props;
|
||||
const { HIDE_DEEP_LINKING_LOGO, NATIVE_APP_NAME, SHOW_DEEP_LINKING_IMAGE } = interfaceConfig;
|
||||
const {
|
||||
_deeplinkingCfg: { hideLogo, showImage },
|
||||
_mobileConfig: { downloadLink, appName },
|
||||
_room,
|
||||
t,
|
||||
_url,
|
||||
_deepLinkingUrl
|
||||
} = this.props;
|
||||
const downloadButtonClassName
|
||||
= `${_SNS}__button ${_SNS}__button_primary`;
|
||||
|
||||
|
||||
const onOpenLinkProperties = _downloadUrl
|
||||
const onOpenLinkProperties = downloadLink
|
||||
? {
|
||||
// When opening a link to the download page, we want to let the
|
||||
// OS itself handle intercepting and opening the appropriate
|
||||
|
@ -121,7 +136,7 @@ class DeepLinkingMobilePage extends Component<Props> {
|
|||
<div className = { _SNS }>
|
||||
<div className = 'header'>
|
||||
{
|
||||
HIDE_DEEP_LINKING_LOGO
|
||||
hideLogo
|
||||
? null
|
||||
: <img
|
||||
alt = { t('welcomepage.logo.logoDeepLinking') }
|
||||
|
@ -131,7 +146,7 @@ class DeepLinkingMobilePage extends Component<Props> {
|
|||
</div>
|
||||
<div className = { `${_SNS}__body` }>
|
||||
{
|
||||
SHOW_DEEP_LINKING_IMAGE
|
||||
showImage
|
||||
? <img
|
||||
alt = { t('welcomepage.logo.logoDeepLinking') }
|
||||
className = 'image'
|
||||
|
@ -139,7 +154,7 @@ class DeepLinkingMobilePage extends Component<Props> {
|
|||
: null
|
||||
}
|
||||
<p className = { `${_SNS}__text` }>
|
||||
{ t(`${_TNS}.appNotInstalled`, { app: NATIVE_APP_NAME }) }
|
||||
{ t(`${_TNS}.appNotInstalled`, { app: appName }) }
|
||||
</p>
|
||||
<p className = { `${_SNS}__text` }>
|
||||
{ t(`${_TNS}.ifHaveApp`) }
|
||||
|
@ -147,7 +162,7 @@ class DeepLinkingMobilePage extends Component<Props> {
|
|||
<a
|
||||
{ ...onOpenLinkProperties }
|
||||
className = { `${_SNS}__href` }
|
||||
href = { generateDeepLinkingURL() }
|
||||
href = { _deepLinkingUrl }
|
||||
onClick = { this._onOpenApp }
|
||||
target = '_top'>
|
||||
<button className = { `${_SNS}__button ${_SNS}__button_primary` }>
|
||||
|
@ -200,32 +215,28 @@ class DeepLinkingMobilePage extends Component<Props> {
|
|||
* @returns {string} - The URL for downloading the app.
|
||||
*/
|
||||
_generateDownloadURL() {
|
||||
const { _downloadUrl: url } = this.props;
|
||||
const { _mobileConfig: { downloadLink, dynamicLink, appScheme } } = this.props;
|
||||
|
||||
if (url && typeof interfaceConfig.MOBILE_DYNAMIC_LINK === 'undefined') {
|
||||
return url;
|
||||
if (downloadLink && typeof dynamicLink === 'undefined') {
|
||||
return downloadLink;
|
||||
}
|
||||
|
||||
// For information about the properties of
|
||||
// interfaceConfig.MOBILE_DYNAMIC_LINK check:
|
||||
// https://firebase.google.com/docs/dynamic-links/create-manually
|
||||
const {
|
||||
APN = 'org.jitsi.meet',
|
||||
APP_CODE = 'w2atb',
|
||||
CUSTOM_DOMAIN = undefined,
|
||||
IBI = 'com.atlassian.JitsiMeet.ios',
|
||||
ISI = '1165103905'
|
||||
} = interfaceConfig.MOBILE_DYNAMIC_LINK || {};
|
||||
apn,
|
||||
appCode,
|
||||
customDomain,
|
||||
ibi,
|
||||
isi
|
||||
} = dynamicLink || {};
|
||||
|
||||
const domain = CUSTOM_DOMAIN ?? `https://${APP_CODE}.app.goo.gl`;
|
||||
const IUS = interfaceConfig.APP_SCHEME || 'org.jitsi.meet';
|
||||
const domain = customDomain ?? `https://${appCode}.app.goo.gl`;
|
||||
|
||||
return `${domain}/?link=${
|
||||
encodeURIComponent(window.location.href)}&apn=${
|
||||
APN}&ibi=${
|
||||
IBI}&isi=${
|
||||
ISI}&ius=${
|
||||
IUS}&efr=1`;
|
||||
apn}&ibi=${
|
||||
ibi}&isi=${
|
||||
isi}&ius=${
|
||||
appScheme}&efr=1`;
|
||||
}
|
||||
|
||||
_onDownloadApp: () => void;
|
||||
|
@ -281,11 +292,15 @@ class DeepLinkingMobilePage extends Component<Props> {
|
|||
*/
|
||||
function _mapStateToProps(state) {
|
||||
const { locationURL = {} } = state['features/base/connection'];
|
||||
const { deeplinking } = state['features/base/config'];
|
||||
const mobileConfig = deeplinking?.[Platform.OS] || {};
|
||||
|
||||
return {
|
||||
_downloadUrl: interfaceConfig[`MOBILE_DOWNLOAD_LINK_${Platform.OS.toUpperCase()}`],
|
||||
_deeplinkingCfg: deeplinking || {},
|
||||
_mobileConfig: mobileConfig,
|
||||
_room: decodeURIComponent(state['features/base/conference'].room),
|
||||
_url: locationURL
|
||||
_url: locationURL,
|
||||
_deepLinkingUrl: generateDeepLinkingURL(state)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -3,15 +3,28 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
import { createDeepLinkingPageEvent, sendAnalytics } from '../../analytics';
|
||||
import { IDeeplinkingConfig } from '../../base/config/configType';
|
||||
import { connect } from '../../base/redux';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of
|
||||
* {@link NoMobileApp}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The deeplinking config.
|
||||
*/
|
||||
_deeplinkingCfg: IDeeplinkingConfig,
|
||||
};
|
||||
|
||||
/**
|
||||
* React component representing no mobile app page.
|
||||
*
|
||||
* @class NoMobileApp
|
||||
*/
|
||||
export default class NoMobileApp extends Component<*> {
|
||||
class NoMobileApp<P : Props> extends Component<P> {
|
||||
/**
|
||||
* Implements the Component's componentDidMount method.
|
||||
*
|
||||
|
@ -30,6 +43,7 @@ export default class NoMobileApp extends Component<*> {
|
|||
*/
|
||||
render() {
|
||||
const ns = 'no-mobile-app';
|
||||
const { desktop: { appName } } = this.props._deeplinkingCfg;
|
||||
|
||||
return (
|
||||
<div className = { ns }>
|
||||
|
@ -37,10 +51,26 @@ export default class NoMobileApp extends Component<*> {
|
|||
Video chat isn't available on mobile.
|
||||
</h2>
|
||||
<p className = { `${ns}__description` }>
|
||||
Please use { interfaceConfig.NATIVE_APP_NAME } on desktop to
|
||||
Please use { appName } on desktop to
|
||||
join calls.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the Redux state to the associated props for the
|
||||
* {@code NoMobileApp} component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @private
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
return {
|
||||
_deeplinkingCfg: state['features/base/config'].deeplinking || {}
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(NoMobileApp);
|
||||
|
|
|
@ -15,27 +15,31 @@ import { _openDesktopApp } from './openDesktopApp';
|
|||
/**
|
||||
* Generates a deep linking URL based on the current window URL.
|
||||
*
|
||||
* @param {Object} state - Object containing current redux state.
|
||||
*
|
||||
* @returns {string} - The generated URL.
|
||||
*/
|
||||
export function generateDeepLinkingURL() {
|
||||
export function generateDeepLinkingURL(state) {
|
||||
// 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.APP_SCHEME || 'org.jitsi.meet';
|
||||
const { href } = window.location;
|
||||
const regex = new RegExp(URI_PROTOCOL_PATTERN, 'gi');
|
||||
|
||||
const mobileConfig = state['features/base/config'].deeplinking?.[Platform.OS] || {};
|
||||
|
||||
const { appScheme, appPackage } = mobileConfig;
|
||||
|
||||
// Android: use an intent link, custom schemes don't work in all browsers.
|
||||
// https://developer.chrome.com/multidevice/android/intents
|
||||
if (Platform.OS === 'android') {
|
||||
// https://meet.jit.si/foo -> meet.jit.si/foo
|
||||
const url = href.replace(regex, '').substr(2);
|
||||
const pkg = interfaceConfig.ANDROID_APP_PACKAGE || 'org.jitsi.meet';
|
||||
|
||||
return `intent://${url}#Intent;scheme=${appScheme};package=${pkg};end`;
|
||||
return `intent://${url}#Intent;scheme=${appScheme};package=${appPackage};end`;
|
||||
}
|
||||
|
||||
// iOS: Replace the protocol part with the app scheme.
|
||||
|
@ -52,12 +56,13 @@ export function generateDeepLinkingURL() {
|
|||
export function getDeepLinkingPage(state) {
|
||||
const { room } = state['features/base/conference'];
|
||||
const { launchInWeb } = state['features/deep-linking'];
|
||||
const appScheme = typeof interfaceConfig !== 'undefined' && interfaceConfig.APP_SCHEME;
|
||||
const deeplinking = state['features/base/config'].deeplinking || {};
|
||||
const { appScheme } = deeplinking?.[Platform.OS] || {};
|
||||
|
||||
// Show only if we are about to join a conference.
|
||||
if (launchInWeb
|
||||
|| !room
|
||||
|| state['features/base/config'].disableDeepLinking
|
||||
|| state['features/base/config'].deeplinking?.disabled
|
||||
|| (isVpaasMeeting(state) && (!appScheme || appScheme === 'com.8x8.meet'))) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import type { Dispatch } from 'redux';
|
|||
|
||||
import { createWelcomePageEvent, sendAnalytics } from '../../analytics';
|
||||
import { appNavigate } from '../../app/actions';
|
||||
import { IDeeplinkingConfig } from '../../base/config/configType';
|
||||
import isInsecureRoomName from '../../base/util/isInsecureRoomName';
|
||||
import { isCalendarEnabled } from '../../calendar-sync';
|
||||
import { isRecentListEnabled } from '../../recent-list/functions';
|
||||
|
@ -20,6 +21,11 @@ export type Props = {
|
|||
*/
|
||||
_calendarEnabled: boolean,
|
||||
|
||||
/**
|
||||
* The deeplinking config.
|
||||
*/
|
||||
_deeplinkingCfg: IDeeplinkingConfig,
|
||||
|
||||
/**
|
||||
* Whether the insecure room name functionality is enabled or not.
|
||||
*/
|
||||
|
@ -268,6 +274,7 @@ export class AbstractWelcomePage<P: Props> extends Component<P, *> {
|
|||
export function _mapStateToProps(state: Object) {
|
||||
return {
|
||||
_calendarEnabled: isCalendarEnabled(state),
|
||||
_deeplinkingCfg: state['features/base/config'].deeplinking,
|
||||
_enableInsecureRoomNameWarning: state['features/base/config'].enableInsecureRoomNameWarning || false,
|
||||
_moderatedRoomServiceUrl: state['features/base/config'].moderatedRoomServiceUrl,
|
||||
_recentListEnabled: isRecentListEnabled(),
|
||||
|
|
|
@ -343,12 +343,16 @@ class WelcomePage extends AbstractWelcomePage {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderFooter() {
|
||||
const { t } = this.props;
|
||||
const {
|
||||
MOBILE_DOWNLOAD_LINK_ANDROID,
|
||||
MOBILE_DOWNLOAD_LINK_F_DROID,
|
||||
MOBILE_DOWNLOAD_LINK_IOS
|
||||
} = interfaceConfig;
|
||||
t,
|
||||
_deeplinkingCfg: {
|
||||
ios: { downloadLink: iosDownloadLink },
|
||||
android: {
|
||||
fDroidUrl,
|
||||
downloadLink: androidDownloadLink
|
||||
}
|
||||
}
|
||||
} = this.props;
|
||||
|
||||
return (<footer className = 'welcome-footer'>
|
||||
<div className = 'welcome-footer-centered'>
|
||||
|
@ -357,21 +361,21 @@ class WelcomePage extends AbstractWelcomePage {
|
|||
<div className = 'welcome-footer-row-1-text'>{t('welcomepage.jitsiOnMobile')}</div>
|
||||
<a
|
||||
className = 'welcome-badge'
|
||||
href = { MOBILE_DOWNLOAD_LINK_IOS }>
|
||||
href = { iosDownloadLink }>
|
||||
<img
|
||||
alt = { t('welcomepage.mobileDownLoadLinkIos') }
|
||||
src = './images/app-store-badge.png' />
|
||||
</a>
|
||||
<a
|
||||
className = 'welcome-badge'
|
||||
href = { MOBILE_DOWNLOAD_LINK_ANDROID }>
|
||||
href = { androidDownloadLink }>
|
||||
<img
|
||||
alt = { t('welcomepage.mobileDownLoadLinkAndroid') }
|
||||
src = './images/google-play-badge.png' />
|
||||
</a>
|
||||
<a
|
||||
className = 'welcome-badge'
|
||||
href = { MOBILE_DOWNLOAD_LINK_F_DROID }>
|
||||
href = { fDroidUrl }>
|
||||
<img
|
||||
alt = { t('welcomepage.mobileDownLoadLinkFDroid') }
|
||||
src = './images/f-droid-badge.png' />
|
||||
|
|
Loading…
Reference in New Issue