feat(dynamic-branding) add initial mobile SDK customization
* feat(dynamic-branding) sdk customization * feat(dynamic-branding) unsetDynamicBranding when we disconnect * feat(dynamic-branding) added branding colors to conference * feat(dynamic-branding) extracted logger to its own file * feat(dynamic-branding) reverted style change * feat(dynamic-branding) unset branding if connection failed * feat(dynamic-branding) removed index.js, updated imports, added ImageBackground component * feat(dynamic-branding) created logger feature object * feat(dynamic-branding) moved brandingStyles to mapStateToProps, used SvGUri * feat(dynamic-branding) created BrandingImageBackground component, fixed styles * feat(dynamic-branding) moved BrandingImageBackground to dynamic-branding feature * feat(dynamic-branding) fixed linter * feat(dynamic-branding) added style comment
This commit is contained in:
parent
543f273792
commit
f3f9cd3d05
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
|
||||
import '../authentication/middleware';
|
||||
import '../dynamic-branding/middleware';
|
||||
import '../gifs/middleware';
|
||||
import '../mobile/audio-mode/middleware';
|
||||
import '../mobile/background/middleware';
|
||||
|
|
|
@ -13,6 +13,7 @@ import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
|
|||
import { TestConnectionInfo } from '../../../base/testing';
|
||||
import { ConferenceNotification, isCalendarEnabled } from '../../../calendar-sync';
|
||||
import { DisplayNameLabel } from '../../../display-name';
|
||||
import { BrandingImageBackground } from '../../../dynamic-branding';
|
||||
import {
|
||||
FILMSTRIP_SIZE,
|
||||
Filmstrip,
|
||||
|
@ -55,6 +56,16 @@ type Props = AbstractProps & {
|
|||
*/
|
||||
_aspectRatio: Symbol,
|
||||
|
||||
/**
|
||||
* Branding styles for conference.
|
||||
*/
|
||||
_brandingStyles: Object,
|
||||
|
||||
/**
|
||||
* Branding image background.
|
||||
*/
|
||||
_brandingImageBackgroundUrl: string,
|
||||
|
||||
/**
|
||||
* Wherther the calendar feature is enabled or not.
|
||||
*/
|
||||
|
@ -214,10 +225,20 @@ class Conference extends AbstractConference<Props, State> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { _fullscreenEnabled } = this.props;
|
||||
const {
|
||||
_brandingImageBackgroundUrl,
|
||||
_brandingStyles,
|
||||
_fullscreenEnabled
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Container style = { styles.conference }>
|
||||
<Container
|
||||
style = { [
|
||||
styles.conference,
|
||||
_brandingStyles
|
||||
] }>
|
||||
<BrandingImageBackground
|
||||
uri = { _brandingImageBackgroundUrl } />
|
||||
<StatusBar
|
||||
barStyle = 'light-content'
|
||||
hidden = { _fullscreenEnabled }
|
||||
|
@ -499,11 +520,17 @@ class Conference extends AbstractConference<Props, State> {
|
|||
function _mapStateToProps(state) {
|
||||
const { isOpen } = state['features/participants-pane'];
|
||||
const { aspectRatio, reducedUI } = state['features/base/responsive-ui'];
|
||||
const { backgroundColor, backgroundImageUrl } = state['features/dynamic-branding'];
|
||||
const participantCount = getParticipantCount(state);
|
||||
const brandingStyles = backgroundColor ? {
|
||||
backgroundColor
|
||||
} : undefined;
|
||||
|
||||
return {
|
||||
...abstractMapStateToProps(state),
|
||||
_aspectRatio: aspectRatio,
|
||||
_brandingStyles: brandingStyles,
|
||||
_brandingImageBackgroundUrl: backgroundImageUrl,
|
||||
_calendarEnabled: isCalendarEnabled(state),
|
||||
_connecting: isConnecting(state),
|
||||
_filmstripVisible: isFilmstripVisible(state),
|
||||
|
|
|
@ -12,3 +12,8 @@ export const SET_DYNAMIC_BRANDING_FAILED = 'SET_DYNAMIC_BRANDING_FAILED';
|
|||
* Action used to signal the branding elements are ready to be displayed
|
||||
*/
|
||||
export const SET_DYNAMIC_BRANDING_READY = 'SET_DYNAMIC_BRANDING_READY';
|
||||
|
||||
/**
|
||||
* Action used to unset branding elements
|
||||
*/
|
||||
export const UNSET_DYNAMIC_BRANDING = 'UNSET_DYNAMIC_BRANDING';
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
// @flow
|
||||
|
||||
import { getLogger } from '@jitsi/logger';
|
||||
|
||||
import { doGetJSON } from '../base/util';
|
||||
|
||||
import {
|
||||
|
@ -10,8 +6,7 @@ import {
|
|||
SET_DYNAMIC_BRANDING_READY
|
||||
} from './actionTypes';
|
||||
import { getDynamicBrandingUrl } from './functions.any';
|
||||
|
||||
const logger = getLogger(__filename);
|
||||
import logger from './logger';
|
||||
|
||||
|
||||
/**
|
||||
|
@ -52,7 +47,7 @@ export function fetchCustomBrandingData() {
|
|||
* @param {Object} value - The custom data to be set.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function setDynamicBrandingData(value) {
|
||||
export function setDynamicBrandingData(value) {
|
||||
return {
|
||||
type: SET_DYNAMIC_BRANDING_DATA,
|
||||
value
|
||||
|
@ -64,7 +59,7 @@ function setDynamicBrandingData(value) {
|
|||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
function setDynamicBrandingReady() {
|
||||
export function setDynamicBrandingReady() {
|
||||
return {
|
||||
type: SET_DYNAMIC_BRANDING_READY
|
||||
};
|
||||
|
@ -75,7 +70,7 @@ function setDynamicBrandingReady() {
|
|||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
function setDynamicBrandingFailed() {
|
||||
export function setDynamicBrandingFailed() {
|
||||
return {
|
||||
type: SET_DYNAMIC_BRANDING_FAILED
|
||||
};
|
|
@ -0,0 +1,54 @@
|
|||
import { doGetJSON } from '../base/util';
|
||||
|
||||
import { UNSET_DYNAMIC_BRANDING } from './actionTypes';
|
||||
import {
|
||||
setDynamicBrandingData,
|
||||
setDynamicBrandingFailed,
|
||||
setDynamicBrandingReady
|
||||
} from './actions.any';
|
||||
import logger from './logger';
|
||||
|
||||
|
||||
/**
|
||||
* Fetches custom branding data.
|
||||
* If there is no data or the request fails, sets the `customizationReady` flag
|
||||
* so the defaults can be displayed.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function fetchCustomBrandingData() {
|
||||
return async function(dispatch: Function, getState: Function) {
|
||||
const state = getState();
|
||||
const { dynamicBrandingUrl } = state['features/base/config'];
|
||||
|
||||
if (dynamicBrandingUrl) {
|
||||
try {
|
||||
return dispatch(
|
||||
setDynamicBrandingData(
|
||||
await doGetJSON(dynamicBrandingUrl))
|
||||
);
|
||||
} catch (err) {
|
||||
logger.error('Error fetching branding data', err);
|
||||
|
||||
return dispatch(
|
||||
setDynamicBrandingFailed()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
dispatch(unsetDynamicBranding());
|
||||
}
|
||||
|
||||
dispatch(setDynamicBrandingReady());
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Action used to unset branding elements.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function unsetDynamicBranding() {
|
||||
return {
|
||||
type: UNSET_DYNAMIC_BRANDING
|
||||
};
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from './native/index';
|
|
@ -0,0 +1,45 @@
|
|||
import React from 'react';
|
||||
import { Image } from 'react-native';
|
||||
import { SvgUri } from 'react-native-svg';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
interface Props {
|
||||
uri: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component that displays a branding background image.
|
||||
*
|
||||
* @param {Props} props - The props of the component.
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
const BrandingImageBackground: React.FC<Props> = ({ uri }:Props) => {
|
||||
const imageType = uri?.substr(uri.lastIndexOf('/') + 1);
|
||||
const imgSrc = uri ? uri : undefined;
|
||||
|
||||
let backgroundImage;
|
||||
|
||||
if (imageType?.includes('.svg')) {
|
||||
backgroundImage
|
||||
= (
|
||||
<SvgUri
|
||||
height = '100%'
|
||||
style = { styles.brandingImageBackgroundSvg }
|
||||
uri = { imgSrc }
|
||||
width = '100%' />
|
||||
);
|
||||
} else {
|
||||
backgroundImage
|
||||
= (
|
||||
<Image
|
||||
source = {{ uri: imgSrc }}
|
||||
style = { styles.brandingImageBackground } />
|
||||
);
|
||||
}
|
||||
|
||||
return backgroundImage;
|
||||
};
|
||||
|
||||
export default BrandingImageBackground;
|
|
@ -0,0 +1 @@
|
|||
export { default as BrandingImageBackground } from './BrandingImageBackground';
|
|
@ -0,0 +1,15 @@
|
|||
export default {
|
||||
|
||||
/**
|
||||
* {@code BrandingImageBackground} Style.
|
||||
*/
|
||||
brandingImageBackgroundSvg: {
|
||||
position: 'absolute' as 'absolute'
|
||||
},
|
||||
|
||||
brandingImageBackground: {
|
||||
height: '100%',
|
||||
position: 'absolute' as 'absolute',
|
||||
width: '100%'
|
||||
}
|
||||
};
|
|
@ -1,2 +0,0 @@
|
|||
export * from './actions';
|
||||
export * from './functions.any';
|
|
@ -0,0 +1 @@
|
|||
export * from './components/index.native';
|
|
@ -0,0 +1,5 @@
|
|||
// @flow
|
||||
|
||||
import { getLogger } from '../base/logging/functions';
|
||||
|
||||
export default getLogger('features/dynamic-branding');
|
|
@ -0,0 +1,36 @@
|
|||
import { SET_CONFIG } from '../base/config';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
|
||||
import { SET_DYNAMIC_BRANDING_DATA } from './actionTypes';
|
||||
import { fetchCustomBrandingData } from './actions.native';
|
||||
|
||||
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
case SET_CONFIG: {
|
||||
const result = next(action);
|
||||
|
||||
store.dispatch(fetchCustomBrandingData());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
case SET_DYNAMIC_BRANDING_DATA: {
|
||||
const {
|
||||
avatarBackgrounds,
|
||||
backgroundColor,
|
||||
backgroundImageUrl
|
||||
} = action.value;
|
||||
|
||||
action.value = {
|
||||
...action.value,
|
||||
avatarBackgrounds,
|
||||
backgroundColor,
|
||||
backgroundImageUrl
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
});
|
|
@ -1,12 +1,11 @@
|
|||
// @flow
|
||||
|
||||
import { APP_WILL_MOUNT } from '../base/app';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
|
||||
import { SET_DYNAMIC_BRANDING_DATA } from './actionTypes';
|
||||
import { fetchCustomBrandingData } from './actions';
|
||||
import { fetchCustomBrandingData } from './actions.any';
|
||||
import { createMuiBrandingTheme } from './functions.web';
|
||||
|
||||
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
case APP_WILL_MOUNT: {
|
||||
|
|
|
@ -6,9 +6,11 @@ import { type Image } from '../virtual-background/constants';
|
|||
import {
|
||||
SET_DYNAMIC_BRANDING_DATA,
|
||||
SET_DYNAMIC_BRANDING_FAILED,
|
||||
SET_DYNAMIC_BRANDING_READY
|
||||
SET_DYNAMIC_BRANDING_READY,
|
||||
UNSET_DYNAMIC_BRANDING
|
||||
} from './actionTypes';
|
||||
|
||||
|
||||
/**
|
||||
* The name of the redux store/state property which is the root of the redux
|
||||
* state of the feature {@code dynamic-branding}.
|
||||
|
@ -194,6 +196,9 @@ ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
|||
...state,
|
||||
customizationReady: true
|
||||
};
|
||||
|
||||
case UNSET_DYNAMIC_BRANDING:
|
||||
return DEFAULT_STATE;
|
||||
}
|
||||
|
||||
return state;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
import { getLocalParticipant } from '../base/participants';
|
||||
import { extractFqnFromPath } from '../dynamic-branding';
|
||||
import { extractFqnFromPath } from '../dynamic-branding/functions.any';
|
||||
|
||||
import { DETECT_FACE, FACE_BOX_EVENT_TYPE, SEND_IMAGE_INTERVAL_MS } from './constants';
|
||||
import logger from './logger';
|
||||
|
|
|
@ -4,7 +4,7 @@ import type { Dispatch } from 'redux';
|
|||
|
||||
import { FEEDBACK_REQUEST_IN_PROGRESS } from '../../../modules/UI/UIErrors';
|
||||
import { openDialog } from '../base/dialog';
|
||||
import { extractFqnFromPath } from '../dynamic-branding';
|
||||
import { extractFqnFromPath } from '../dynamic-branding/functions.any';
|
||||
import { isVpaasMeeting } from '../jaas/functions';
|
||||
|
||||
import {
|
||||
|
|
|
@ -8,7 +8,7 @@ import { Dialog } from '../../../../base/dialog';
|
|||
import { translate } from '../../../../base/i18n';
|
||||
import { JitsiRecordingConstants } from '../../../../base/lib-jitsi-meet';
|
||||
import { connect } from '../../../../base/redux';
|
||||
import { isDynamicBrandingDataLoaded } from '../../../../dynamic-branding';
|
||||
import { isDynamicBrandingDataLoaded } from '../../../../dynamic-branding/functions.any';
|
||||
import EmbedMeetingTrigger from '../../../../embed-meeting/components/EmbedMeetingTrigger';
|
||||
import { isVpaasMeeting } from '../../../../jaas/functions';
|
||||
import { getActiveSession } from '../../../../recording';
|
||||
|
|
|
@ -2,14 +2,13 @@
|
|||
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../base/color-scheme';
|
||||
import { ParticipantView, getParticipantById } from '../../base/participants';
|
||||
import { connect } from '../../base/redux';
|
||||
import { StyleType } from '../../base/styles';
|
||||
import { isLocalVideoTrackDesktop } from '../../base/tracks/functions';
|
||||
|
||||
import { AVATAR_SIZE } from './styles';
|
||||
|
||||
|
||||
/**
|
||||
* The type of the React {@link Component} props of {@link LargeVideo}.
|
||||
*/
|
||||
|
@ -32,11 +31,6 @@ type Props = {
|
|||
*/
|
||||
_participantId: string,
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of the feature.
|
||||
*/
|
||||
_styles: StyleType,
|
||||
|
||||
/**
|
||||
* Application's viewport height.
|
||||
*/
|
||||
|
@ -120,7 +114,6 @@ class LargeVideo extends PureComponent<Props, State> {
|
|||
const {
|
||||
_disableVideo,
|
||||
_participantId,
|
||||
_styles,
|
||||
onClick
|
||||
} = this.props;
|
||||
|
||||
|
@ -130,7 +123,6 @@ class LargeVideo extends PureComponent<Props, State> {
|
|||
disableVideo = { _disableVideo }
|
||||
onPress = { onClick }
|
||||
participantId = { _participantId }
|
||||
style = { _styles.largeVideo }
|
||||
testHintId = 'org.jitsi.meet.LargeVideo'
|
||||
useConnectivityInfoLabel = { useConnectivityInfoLabel }
|
||||
zOrder = { 0 }
|
||||
|
@ -160,7 +152,6 @@ function _mapStateToProps(state) {
|
|||
_disableVideo: disableVideo,
|
||||
_height: height,
|
||||
_participantId: participantId,
|
||||
_styles: ColorSchemeRegistry.get(state, 'LargeVideo'),
|
||||
_width: width
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,25 +1,4 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
import { ColorSchemeRegistry, schemeColor } from '../../base/color-scheme';
|
||||
|
||||
/**
|
||||
* Size for the Avatar.
|
||||
*/
|
||||
export const AVATAR_SIZE = 200;
|
||||
|
||||
/**
|
||||
* Color schemed styles for the @{LargeVideo} component.
|
||||
*/
|
||||
ColorSchemeRegistry.register('LargeVideo', {
|
||||
|
||||
/**
|
||||
* Large video container style.
|
||||
*/
|
||||
largeVideo: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
alignItems: 'stretch',
|
||||
backgroundColor: schemeColor('background'),
|
||||
flex: 1,
|
||||
justifyContent: 'center'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@ import { v4 as uuidv4 } from 'uuid';
|
|||
|
||||
import { getFeatureFlag, REACTIONS_ENABLED } from '../base/flags';
|
||||
import { getLocalParticipant } from '../base/participants';
|
||||
import { extractFqnFromPath } from '../dynamic-branding';
|
||||
import { extractFqnFromPath } from '../dynamic-branding/functions.any';
|
||||
|
||||
import { REACTIONS, SOUNDS_THRESHOLDS } from './constants';
|
||||
import logger from './logger';
|
||||
|
|
|
@ -4,7 +4,7 @@ import { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
|
|||
import { getLocalParticipant, isLocalParticipantModerator } from '../base/participants';
|
||||
import { isInBreakoutRoom } from '../breakout-rooms/functions';
|
||||
import { isEnabled as isDropboxEnabled } from '../dropbox';
|
||||
import { extractFqnFromPath } from '../dynamic-branding';
|
||||
import { extractFqnFromPath } from '../dynamic-branding/functions.any';
|
||||
|
||||
import { RECORDING_STATUS_PRIORITIES, RECORDING_TYPES } from './constants';
|
||||
import logger from './logger';
|
||||
|
|
|
@ -7,7 +7,7 @@ import './createImageBitmap';
|
|||
import { createScreensharingCaptureTakenEvent, sendAnalytics } from '../analytics';
|
||||
import { getCurrentConference } from '../base/conference';
|
||||
import { getLocalParticipant, getRemoteParticipants } from '../base/participants';
|
||||
import { extractFqnFromPath } from '../dynamic-branding';
|
||||
import { extractFqnFromPath } from '../dynamic-branding/functions.any';
|
||||
|
||||
import {
|
||||
CLEAR_INTERVAL,
|
||||
|
|
Loading…
Reference in New Issue