зеркало из
1
0
Форкнуть 0

adding a local preview example (#212)

* adding a local preview example

* prettier and lint fixes

* PR comments and visual upgrade

* Removing control bar from video tile examples

* using new local preview in composite

* some small nit fixes

* storybook fixes

* Change files

* updating snapshots
This commit is contained in:
alkwa-msft 2021-05-06 17:09:47 -07:00 коммит произвёл GitHub
Родитель d7b62e0ea8
Коммит 20cd0cc3c3
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
19 изменённых файлов: 331 добавлений и 216 удалений

Просмотреть файл

@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Removing references to static media.svg and styles",
"packageName": "react-components",
"email": "alkwa@microsoft.com",
"dependentChangeType": "patch"
}

Просмотреть файл

@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Using new local preview in calling composite",
"packageName": "react-composites",
"email": "alkwa@microsoft.com",
"dependentChangeType": "patch"
}

Просмотреть файл

@ -22,9 +22,3 @@ export const videoHint = mergeStyles({
maxWidth: '40%',
borderRadius: 4
});
export const staticMediaContainer = mergeStyles({
position: 'relative',
height: '100%',
width: '100%'
});

Просмотреть файл

@ -1,15 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { CallVideoIcon, MicIcon } from '@fluentui/react-icons-northstar';
import { Stack, Toggle, Image, ImageFit, IImageStyles } from '@fluentui/react';
import { CallVideoOffIcon } from '@fluentui/react-icons-northstar';
import { Stack, Text } from '@fluentui/react';
import React from 'react';
import {
localPreviewContainerStyle,
toggleButtonsBarStyle,
toggleButtonsBarToken,
toggleStyle
} from './styles/LocalPreview.styles';
import { localPreviewContainerStyle, cameraOffLabelStyle, localPreviewTileStyle } from './styles/LocalPreview.styles';
import { MapToMediaControlsProps, MediaControlsContainerProps } from './consumers/MapToMediaControlsProps';
import {
connectFuncsToContext,
@ -18,24 +13,19 @@ import {
MapToErrorBarProps,
MapToLocalVideoProps
} from '../../consumers';
import { StreamMedia, VideoTile, ErrorBar as ErrorBarComponent } from 'react-components';
import staticMediaSVG from './assets/staticmedia.svg';
import {
StreamMedia,
VideoTile,
ErrorBar as ErrorBarComponent,
MicrophoneButton,
ControlBar,
CameraButton
} from 'react-components';
import { useCallContext } from '../../providers';
import { ErrorHandlingProps } from '../../providers/ErrorProvider';
import { WithErrorHandling } from '../../utils/WithErrorHandling';
import { CommunicationUiErrorFromError } from '../../types/CommunicationUiError';
const staticAvatarStyle: Partial<IImageStyles> = {
image: { maxWidth: '10rem', maxHeight: '10rem', width: '100%', height: '100%' },
root: { flexGrow: 1 }
};
const imageProps = {
src: staticMediaSVG.toString(),
imageFit: ImageFit.contain,
maximizeFrame: true
};
const LocalPreviewComponentBase = (
props: MediaControlsContainerProps & LocalDeviceSettingsContainerProps & ErrorHandlingProps
): JSX.Element => {
@ -52,53 +42,56 @@ const LocalPreviewComponentBase = (
});
const ErrorBar = connectFuncsToContext(ErrorBarComponent, MapToErrorBarProps);
const { localVideoEnabled, isMicrophoneActive } = props;
return (
<Stack className={localPreviewContainerStyle}>
<VideoTile
styles={localPreviewTileStyle}
isVideoReady={isVideoReady}
videoProvider={<StreamMedia videoStreamElement={videoStreamElement} />}
placeholderProvider={
<Image styles={staticAvatarStyle} aria-label="Local video preview image" {...imageProps} />
<Stack style={{ width: '100%', height: '100%' }} verticalAlign="center">
<Stack.Item align="center">
<CallVideoOffIcon />
</Stack.Item>
<Stack.Item align="center">
<Text className={cameraOffLabelStyle}>Your camera is turned off</Text>
</Stack.Item>
</Stack>
}
/>
<Stack
horizontal
horizontalAlign="center"
verticalAlign="center"
tokens={toggleButtonsBarToken}
className={toggleButtonsBarStyle}
>
<CallVideoIcon size="medium" />
<Toggle
styles={toggleStyle}
disabled={isVideoDisabled}
onChange={() => {
props.toggleLocalVideo().catch((error) => {
if (props.onErrorCallback) {
props.onErrorCallback(CommunicationUiErrorFromError(error));
} else {
throw error;
}
});
}}
ariaLabel="Video Icon"
/>
<MicIcon size="medium" />
<Toggle
styles={toggleStyle}
disabled={isAudioDisabled}
onChange={() => {
props.toggleMicrophone().catch((error) => {
if (props.onErrorCallback) {
props.onErrorCallback(CommunicationUiErrorFromError(error));
} else {
throw error;
}
});
}}
ariaLabel="Microphone Icon"
/>
</Stack>
<ControlBar layout="floatingBottom">
<CameraButton
checked={localVideoEnabled}
ariaLabel="Video Icon"
disabled={isVideoDisabled}
onClick={() => {
props.toggleLocalVideo().catch((error) => {
if (props.onErrorCallback) {
props.onErrorCallback(CommunicationUiErrorFromError(error));
} else {
throw error;
}
});
}}
/>
<MicrophoneButton
ariaLabel="Microphone Icon"
disabled={isAudioDisabled}
checked={isMicrophoneActive}
onClick={() => {
props.toggleMicrophone().catch((error) => {
if (props.onErrorCallback) {
props.onErrorCallback(CommunicationUiErrorFromError(error));
} else {
throw error;
}
});
}}
/>
</ControlBar>
</VideoTile>
<ErrorBar />
</Stack>
);

Просмотреть файл

@ -39,3 +39,15 @@ export const toggleButtonsBarStyle = mergeStyles({
width: '100%',
backgroundColor: palette.neutralQuaternaryAlt
});
export const cameraOffLabelStyle = mergeStyles({
fontFamily: 'Segoe UI Regular',
fontSize: '0.625rem', // 10px
color: palette.neutralTertiary
});
export const localPreviewTileStyle = {
root: {
minHeight: '14rem'
}
};

Просмотреть файл

@ -29,13 +29,13 @@ module.exports = {
// Note: This triggers babel to retranspile all package dependency files during webpack's compilation step.
config.resolve.alias = {
...(config.resolve.alias || {}),
"@azure/communication-react": path.resolve(__dirname, "../../communication-react/src"),
"react-composites": path.resolve(__dirname, "../../react-composites/src"),
"@azure/acs-chat-declarative": path.resolve(__dirname, "../../acs-chat-declarative/src"),
"@azure/acs-chat-selector": path.resolve(__dirname, "../../acs-chat-selector/src"),
"@azure/acs-calling-declarative": path.resolve(__dirname, "../../acs-calling-declarative/src"),
"@azure/acs-calling-selector": path.resolve(__dirname, "../../acs-calling-selector/src")
}
'@azure/communication-react': path.resolve(__dirname, '../../communication-react/src'),
'react-composites': path.resolve(__dirname, '../../react-composites/src'),
'@azure/acs-chat-declarative': path.resolve(__dirname, '../../acs-chat-declarative/src'),
'@azure/acs-chat-selector': path.resolve(__dirname, '../../acs-chat-selector/src'),
'@azure/acs-calling-declarative': path.resolve(__dirname, '../../acs-calling-declarative/src'),
'@azure/acs-calling-selector': path.resolve(__dirname, '../../acs-calling-selector/src')
};
return config;
}

Просмотреть файл

@ -1,18 +1,16 @@
import { analyticsCookieConsentObtained } from "./telemetry";
import { analyticsCookieConsentObtained } from './telemetry';
describe('storybook telemetry util tests', () => {
beforeEach(() => {
// reset cookie consent window variables
(window as any).siteConsent = undefined;
})
describe ('test analyticsCookieConsentObtained', () => {
});
describe('test analyticsCookieConsentObtained', () => {
test('analyticsCookieConsentObtained returns false if telemetry library is not initialized', () => {
// set cookie consent library to uninitialized
(window as any).siteConsent = undefined;
const result = analyticsCookieConsentObtained();
expect(result).toEqual(false);
@ -27,7 +25,7 @@ describe('storybook telemetry util tests', () => {
Analytics: false
})
};
const result = analyticsCookieConsentObtained();
expect(result).toEqual(false);
@ -42,7 +40,7 @@ describe('storybook telemetry util tests', () => {
Analytics: true
})
};
const result = analyticsCookieConsentObtained();
expect(result).toEqual(true);
@ -57,11 +55,10 @@ describe('storybook telemetry util tests', () => {
Analytics: false
})
};
const result = analyticsCookieConsentObtained();
expect(result).toEqual(true);
});
})
});
});
});

Просмотреть файл

@ -1,13 +1,15 @@
import { ApplicationInsights } from '@microsoft/applicationinsights-web'
import { ApplicationInsights } from '@microsoft/applicationinsights-web';
/**
* Check if we have the necessary cookie consent to allow the app insights library to make use of cookies
*/
export const analyticsCookieConsentObtained = (): boolean => {
return !!(window as any).siteConsent && // has telemetry library been initialized
return (
!!(window as any).siteConsent && // has telemetry library been initialized
(!(window as any).siteConsent.isConsentRequired || // check if we need collect consent in this region
(window as any).siteConsent.getConsent().Analytics); // check if we have consent to collect analytics telemetry
}
(window as any).siteConsent.getConsent().Analytics)
); // check if we have consent to collect analytics telemetry
};
/**
* Start telemetry collection and watch for cookie consent changes.
@ -18,7 +20,7 @@ export const initTelemetry = () => {
if (appInsightsInstance) {
createCookieChangedCallback(appInsightsInstance);
}
}
};
/**
* Setup the window.cookieConsentChanged that is called when the cookie banner's onConsentChanged is called.
@ -28,8 +30,8 @@ const createCookieChangedCallback = (applicationInsightsInstance: ApplicationIns
(window as any).cookieConsentChanged = () => {
const analyticsCookieConsent = analyticsCookieConsentObtained();
applicationInsightsInstance.getCookieMgr().setEnabled(analyticsCookieConsent);
}
}
};
};
/**
* Start app insights tracking telemetry
@ -39,11 +41,10 @@ const createCookieChangedCallback = (applicationInsightsInstance: ApplicationIns
const startTelemetry = (cookieConsent: boolean): ApplicationInsights | undefined => {
const instrumentationKey = process.env.TELEMETRY_INSTRUMENTATION_KEY;
if (!instrumentationKey) {
console.warn('No telemetry instrumentationKey provided. Telemetry collection is disabled.')
console.warn('No telemetry instrumentationKey provided. Telemetry collection is disabled.');
return;
}
// Initialize and start collecting telemetry
const appInsights = new ApplicationInsights({
config: {
@ -55,4 +56,4 @@ const startTelemetry = (cookieConsent: boolean): ApplicationInsights | undefined
appInsights.loadAppInsights();
return appInsights;
}
};

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 1.2 KiB

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Просмотреть файл

@ -1,5 +1,3 @@
// LobbyControlBar.example.tsx
import { CameraButton, ControlBar, EndCallButton, MicrophoneButton, OptionsButton } from '@azure/communication-react';
import { useTheme } from '@fluentui/react-theme-provider';
import React from 'react';

Просмотреть файл

@ -0,0 +1,30 @@
import { boolean } from '@storybook/addon-knobs';
import { Meta } from '@storybook/react/types-6-0';
import React from 'react';
import { EXAMPLES_FOLDER_PREFIX } from '../../constants';
import { getDocs } from './LocalPreviewDocs';
import { LocalPreviewExample } from './snippets/LocalPreviewExample.snippet';
export const LocalPreview: () => JSX.Element = () => {
const isVideoAvailable = boolean('Is video available', true);
const isCameraEnabled = boolean('Is camera available', true);
const isMicrophoneEnabled = boolean('Is microphone available', true);
return (
<LocalPreviewExample
isVideoAvailable={isVideoAvailable}
isCameraEnabled={isCameraEnabled}
isMicrophoneEnabled={isMicrophoneEnabled}
/>
);
};
export default {
title: `${EXAMPLES_FOLDER_PREFIX}/Local Preview`,
component: LocalPreview,
parameters: {
docs: {
page: () => getDocs()
}
}
} as Meta;

Просмотреть файл

@ -0,0 +1,29 @@
import { Title, Heading, Description, Canvas, Source } from '@storybook/addon-docs/blocks';
import React from 'react';
import { LocalPreviewExample } from './snippets/LocalPreviewExample.snippet';
const LocalPreviewExampleText = require('!!raw-loader!./snippets/LocalPreviewExample.snippet.tsx').default;
export const getDocs: () => JSX.Element = () => {
return (
<>
<Title>Local Preview</Title>
<Heading>Basic example</Heading>
<Description>
To build a local preview, we recommend using the Fluent UI
[Stack](https://developer.microsoft.com/en-us/fluentui#/controls/web/stack) as a container as shown in the code
below. For enabling and disabling the camera or microphone we suggest using the
[Toggle](https://developer.microsoft.com/en-us/fluentui#/controls/web/toggle) component. The area for showing
your local preview is a [VideoTile](./?path=/docs/ui-components-videotile--video-tile-component) which can also
be used in our video grid layouts.
</Description>
<Source code={LocalPreviewExampleText} />
<Canvas withSource="none">
<div style={{ height: '17.188rem' }}>
<LocalPreviewExample isVideoAvailable={true} isCameraEnabled={true} isMicrophoneEnabled={true} />
</div>
</Canvas>
</>
);
};

Просмотреть файл

@ -0,0 +1,90 @@
import { Stack, mergeStyles, Text } from '@fluentui/react';
import { CallVideoOffIcon } from '@fluentui/react-northstar';
import { useTheme } from '@fluentui/react-theme-provider';
import React, { useState } from 'react';
import {
StreamMedia,
VideoTile,
ControlBar,
CameraButton,
MicrophoneButton,
FluentThemeProvider
} from 'react-components';
import { renderVideoStream } from '../../../utils';
export interface LocalPreviewProps {
isVideoAvailable: boolean;
isCameraEnabled: boolean;
isMicrophoneEnabled: boolean;
}
export const LocalPreviewExample = ({
isVideoAvailable,
isCameraEnabled,
isMicrophoneEnabled
}: LocalPreviewProps): JSX.Element => {
const [microphone, setMicrophone] = useState(false);
const [camera, setCamera] = useState(false);
const theme = useTheme();
const palette = theme.palette;
const localPreviewContainerStyle = mergeStyles({
minWidth: '25rem',
width: '100%',
height: '100%',
maxHeight: '18.75rem',
minHeight: '16.875rem',
margin: '0 auto',
background: palette.neutralLighter,
color: palette.neutralTertiary
});
const videoTileStyle = {
root: {
minHeight: '14rem'
}
};
const cameraOffLabelStyle = mergeStyles({
fontFamily: 'Segoe UI Regular',
fontSize: '0.625rem', // 10px
color: palette.neutralTertiary
});
return (
<FluentThemeProvider fluentTheme={theme}>
<Stack style={{ width: '100%', height: '100%' }} verticalAlign="center">
<Stack.Item align="center">
<Stack className={localPreviewContainerStyle}>
<VideoTile
styles={videoTileStyle}
isVideoReady={isVideoAvailable}
// Here this storybook example isn't connected with Azure Communication Services
// We would suggest you replace this videoStreamElement below with a rendered video stream from the calling SDK
videoProvider={<StreamMedia videoStreamElement={renderVideoStream()} />}
placeholderProvider={
<Stack style={{ width: '100%', height: '100%' }} verticalAlign="center">
<Stack.Item align="center">
<CallVideoOffIcon />
</Stack.Item>
<Stack.Item align="center">
<Text className={cameraOffLabelStyle}>Your camera is turned off</Text>
</Stack.Item>
</Stack>
}
>
<ControlBar layout="floatingBottom">
<CameraButton disabled={!isCameraEnabled} checked={camera} onClick={() => setCamera(!camera)} />
<MicrophoneButton
disabled={!isMicrophoneEnabled}
checked={microphone}
onClick={() => setMicrophone(!microphone)}
/>
</ControlBar>
</VideoTile>
</Stack>
</Stack.Item>
</Stack>
</FluentThemeProvider>
);
};

Просмотреть файл

@ -1,13 +1,5 @@
import {
CameraButton,
ControlBar,
EndCallButton,
FluentThemeProvider,
MicrophoneButton,
StreamMedia,
VideoTile
} from '@azure/communication-react';
import React from 'react';
import { FluentThemeProvider, StreamMedia, VideoTile } from 'react-components';
import { renderVideoStream } from '../../utils';
export const VideoTileExample: () => JSX.Element = () => {
@ -16,7 +8,7 @@ export const VideoTileExample: () => JSX.Element = () => {
videoContainer: { border: '5px solid firebrick' },
overlayContainer: { background: 'rgba(165, 13, 13, 0.5)' }
};
const controlBarStyles = { root: { background: 'white' } };
return (
<FluentThemeProvider>
<VideoTile
@ -28,13 +20,7 @@ export const VideoTileExample: () => JSX.Element = () => {
avatarName={'Jack Reacher'}
invertVideo={true}
styles={customStyles}
>
<ControlBar layout="floatingBottom" styles={controlBarStyles}>
<CameraButton />
<MicrophoneButton />
<EndCallButton />
</ControlBar>
</VideoTile>
></VideoTile>
</FluentThemeProvider>
);
};

Просмотреть файл

@ -1,15 +1,6 @@
// © Microsoft Corporation. All rights reserved.
import {
CameraButton,
ControlBar,
EndCallButton,
MicrophoneButton,
OptionsButton,
StreamMedia,
VideoTile as VideoTileComponent
} from '@azure/communication-react';
import { Stack } from '@fluentui/react';
import { StreamMedia, VideoTile as VideoTileComponent } from '@azure/communication-react';
import { text, boolean, number } from '@storybook/addon-knobs';
import { Meta } from '@storybook/react/types-6-0';
import React from 'react';
@ -22,7 +13,6 @@ import { getDocs } from './VideoTileDocs';
export const VideoTile: () => JSX.Element = () => {
const avatarName = text('Avatar Name', 'John Krasinski');
const isVideoReady = boolean('Is Video Ready', false);
const showControlBarComponent = boolean('Show Control Bar (Not a part of this component)', false);
const invertVideo = boolean('Invert Video', false);
const width = number('Width', 400, {
range: true,
@ -46,18 +36,7 @@ export const VideoTile: () => JSX.Element = () => {
styles={{
root: { height: height, width: width }
}}
>
{showControlBarComponent && (
<Stack style={{ position: 'absolute', left: '50%', bottom: '1rem' }}>
<ControlBar styles={{ root: { position: 'relative', left: '-50%' } }}>
<CameraButton />
<MicrophoneButton />
<OptionsButton />
<EndCallButton />
</ControlBar>
</Stack>
)}
</VideoTileComponent>
/>
);
};

Просмотреть файл

@ -381,7 +381,7 @@ exports[`storybook snapshot tests Storyshots Examples/IncomingCallAlerts Incomin
</div>
</div>
<div
className="ms-Stack css-118 css-48"
className="ms-Stack css-119 css-48"
>
<div
className="ms-Stack css-51"
@ -580,10 +580,10 @@ exports[`storybook snapshot tests Storyshots Examples/IncomingCallAlerts Incomin
className="ms-Stack css-2"
>
<div
className="ms-Stack css-114 css-3"
className="ms-Stack css-115 css-3"
>
<div
className="ms-Stack css-115 css-4"
className="ms-Stack css-116 css-4"
>
<div
aria-label="John Doe"
@ -647,7 +647,7 @@ exports[`storybook snapshot tests Storyshots Examples/IncomingCallAlerts Incomin
className="ms-Stack css-21"
>
<button
className="ms-Button ms-Button--default css-117 root-22"
className="ms-Button ms-Button--default css-118 root-22"
data-is-focusable={true}
onClick={[Function]}
onKeyDown={[Function]}
@ -685,7 +685,7 @@ exports[`storybook snapshot tests Storyshots Examples/IncomingCallAlerts Incomin
</span>
</button>
<button
className="ms-Button ms-Button--default css-116 root-22"
className="ms-Button ms-Button--default css-117 root-22"
data-is-focusable={true}
onClick={[Function]}
onKeyDown={[Function]}

Просмотреть файл

@ -1,17 +1,19 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { CallVideoIcon, MicIcon } from '@fluentui/react-icons-northstar';
import { Stack, Toggle, Image, ImageFit, IImageStyles, mergeStyles } from '@fluentui/react';
import { CallVideoOffIcon } from '@fluentui/react-icons-northstar';
import { Stack, Text } from '@fluentui/react';
import { localPreviewContainerStyle, cameraOffLabelStyle, localPreviewTileStyle } from './styles/LocalPreview.styles';
import React from 'react';
import {
localPreviewContainerStyle,
toggleButtonsBarStyle,
toggleButtonsBarToken,
toggleStyle
} from './styles/LocalPreview.styles';
import { MapToMediaControlsProps, MediaControlsContainerProps } from './consumers/MapToMediaControlsProps';
import { ErrorBar as ErrorBarComponent, StreamMedia, VideoTile } from 'react-components';
import {
CameraButton,
ControlBar,
ErrorBar as ErrorBarComponent,
MicrophoneButton,
StreamMedia,
VideoTile
} from 'react-components';
import {
connectFuncsToContext,
MapToLocalVideoProps,
@ -24,20 +26,6 @@ import {
LocalDeviceSettingsContainerProps
} from 'react-composites';
import { useTheme } from '@fluentui/react-theme-provider';
import staticMediaSVG from '../assets/staticmedia.svg';
const staticAvatarStyle: Partial<IImageStyles> = {
image: { maxWidth: '10rem', maxHeight: '10rem', width: '100%', height: '100%' },
root: { flexGrow: 1 }
};
const imageProps = {
src: staticMediaSVG.toString(),
imageFit: ImageFit.contain,
maximizeFrame: true
};
const LocalPreviewComponentBase = (
props: MediaControlsContainerProps & LocalDeviceSettingsContainerProps & ErrorHandlingProps
): JSX.Element => {
@ -47,7 +35,6 @@ const LocalPreviewComponentBase = (
// we haven't properly properly exported this component to make it re-usable
// we should create a MapToLocalPreviewProps, instead of using MapToMediaControlsProps and MapToLocalDeviceSettingsProps
const { localVideoStream } = useCallContext();
const theme = useTheme();
const { isVideoReady, videoStreamElement } = MapToLocalVideoProps({
stream: localVideoStream,
@ -55,53 +42,56 @@ const LocalPreviewComponentBase = (
});
const ErrorBar = connectFuncsToContext(ErrorBarComponent, MapToErrorBarProps);
const { localVideoEnabled, isMicrophoneActive } = props;
return (
<Stack className={localPreviewContainerStyle}>
<VideoTile
styles={localPreviewTileStyle}
isVideoReady={isVideoReady}
videoProvider={<StreamMedia videoStreamElement={videoStreamElement} />}
placeholderProvider={
<Image styles={staticAvatarStyle} aria-label="Local video preview image" {...imageProps} />
<Stack style={{ width: '100%', height: '100%' }} verticalAlign="center">
<Stack.Item align="center">
<CallVideoOffIcon />
</Stack.Item>
<Stack.Item align="center">
<Text className={cameraOffLabelStyle}>Your camera is turned off</Text>
</Stack.Item>
</Stack>
}
/>
<Stack
horizontal
horizontalAlign="center"
verticalAlign="center"
tokens={toggleButtonsBarToken}
className={mergeStyles(toggleButtonsBarStyle, { background: theme.palette.neutralLight })}
>
<CallVideoIcon size="medium" style={{ color: theme.palette.black }} />
<Toggle
styles={toggleStyle}
disabled={isVideoDisabled}
onChange={() => {
props.toggleLocalVideo().catch((error) => {
if (props.onErrorCallback) {
props.onErrorCallback(CommunicationUiErrorFromError(error));
} else {
throw error;
}
});
}}
ariaLabel="Video Icon"
/>
<MicIcon size="medium" style={{ color: theme.palette.black }} />
<Toggle
styles={toggleStyle}
disabled={isAudioDisabled}
onChange={() => {
props.toggleMicrophone().catch((error) => {
if (props.onErrorCallback) {
props.onErrorCallback(CommunicationUiErrorFromError(error));
} else {
throw error;
}
});
}}
ariaLabel="Microphone Icon"
/>
</Stack>
<ControlBar layout="floatingBottom">
<CameraButton
checked={localVideoEnabled}
ariaLabel="Video Icon"
disabled={isVideoDisabled}
onClick={() => {
props.toggleLocalVideo().catch((error) => {
if (props.onErrorCallback) {
props.onErrorCallback(CommunicationUiErrorFromError(error));
} else {
throw error;
}
});
}}
/>
<MicrophoneButton
ariaLabel="Microphone Icon"
disabled={isAudioDisabled}
checked={isMicrophoneActive}
onClick={() => {
props.toggleMicrophone().catch((error) => {
if (props.onErrorCallback) {
props.onErrorCallback(CommunicationUiErrorFromError(error));
} else {
throw error;
}
});
}}
/>
</ControlBar>
</VideoTile>
<ErrorBar />
</Stack>
);

Просмотреть файл

@ -31,10 +31,22 @@ export const localPreviewContainerStyle = mergeStyles({
maxHeight: '18.75rem',
minHeight: '16.875rem',
background: palette.neutralLighter,
color: palette.neutralPrimaryAlt
color: palette.neutralTertiary
});
export const cameraOffLabelStyle = mergeStyles({
fontFamily: 'Segoe UI Regular',
fontSize: '0.625rem', // 10px
color: palette.neutralTertiary
});
export const toggleButtonsBarStyle = mergeStyles({
height: '2.8125rem',
width: '100%'
});
export const localPreviewTileStyle = {
root: {
minHeight: '14rem'
}
};

Просмотреть файл

@ -1,10 +0,0 @@
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24">
<!-- Generator: Sketch 59.1 (86144) - https://sketch.com -->
<title>ic_fluent_person_24_filled</title>
<desc>Created with Sketch.</desc>
<g id="🔍-Product-Icons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="ic_fluent_person_24_filled" fill="#D7D7D7" fill-rule="nonzero">
<path d="M17.7541747,13.999921 C18.9961948,13.999921 20.0030511,15.0067773 20.0030511,16.2487975 L20.0030511,17.1672553 C20.0030511,17.7406209 19.8238304,18.2996465 19.4904678,18.7661395 C17.9445793,20.9293884 15.4202806,22.0010712 12,22.0010712 C8.57903185,22.0010712 6.05606966,20.9289147 4.51390935,18.7645697 C4.18194679,18.2986691 4.00354153,17.7408416 4.00354153,17.1687745 L4.00354153,16.2487975 C4.00354153,15.0067773 5.0103978,13.999921 6.25241795,13.999921 L17.7541747,13.999921 Z M12,2.0046246 C14.7614237,2.0046246 17,4.24320085 17,7.0046246 C17,9.76604835 14.7614237,12.0046246 12,12.0046246 C9.23857625,12.0046246 7,9.76604835 7,7.0046246 C7,4.24320085 9.23857625,2.0046246 12,2.0046246 Z" id="🎨-Color"></path>
</g>
</g>
</svg>

До

Ширина:  |  Высота:  |  Размер: 1.2 KiB