Skip to content

Commit adc43b4

Browse files
authored
Cherry pick hot fix into release branch (#5904)
* rtt * lint fix * change files
1 parent 9c83970 commit adc43b4

7 files changed

Lines changed: 88 additions & 4 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "patch",
3+
"area": "feature",
4+
"workstream": "RTT and Captions",
5+
"comment": "Auto announce completed RTT and caption messages ",
6+
"packageName": "@azure/communication-react",
7+
"email": "96077406+carocao-msft@users.noreply.github.com",
8+
"dependentChangeType": "patch"
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "patch",
3+
"area": "feature",
4+
"workstream": "RTT and Captions",
5+
"comment": "Auto announce completed RTT and caption messages ",
6+
"packageName": "@azure/communication-react",
7+
"email": "96077406+carocao-msft@users.noreply.github.com",
8+
"dependentChangeType": "patch"
9+
}

packages/calling-component-bindings/src/captionsSelector.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ export const captionsBannerSelector: CaptionsBannerSelector = reselect.createSel
158158
displayName: finalDisplayName ?? 'Unnamed Participant',
159159
captionText: c.captionText,
160160
userId,
161-
createdTimeStamp: c.timestamp
161+
createdTimeStamp: c.timestamp,
162+
isFinalized: c.resultType === 'Final'
162163
};
163164
});
164165

@@ -220,17 +221,14 @@ export const captionsBannerSelector: CaptionsBannerSelector = reselect.createSel
220221

221222
return {
222223
captions: captionsInfo ?? [],
223-
224224
realTimeTexts: {
225225
completedMessages: completedRealTimeTexts as RealTimeTextInformation[],
226226
currentInProgress: inProgressRealTimeTexts as RealTimeTextInformation[],
227227
myInProgress: myInProgress as RealTimeTextInformation
228228
},
229229
isCaptionsOn: isCaptionsFeatureActive ?? false,
230230
startCaptionsInProgress: startCaptionsInProgress ?? false,
231-
232231
isRealTimeTextOn: isRealTimeTextActive ?? false,
233-
234232
latestLocalRealTimeText: (myInProgress ?? latestLocalRealTimeText) as RealTimeTextInformation
235233
};
236234
}

packages/communication-react/review/beta/communication-react.api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1973,6 +1973,7 @@ export type CaptionsInformation = {
19731973
captionText: string;
19741974
userId?: string;
19751975
createdTimeStamp?: Date;
1976+
isFinalized?: boolean;
19761977
};
19771978

19781979
// @public

packages/communication-react/review/stable/communication-react.api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,6 +1784,7 @@ export type CaptionsInformation = {
17841784
captionText: string;
17851785
userId?: string;
17861786
createdTimeStamp?: Date;
1787+
isFinalized?: boolean;
17871788
};
17881789

17891790
// @public

packages/react-components/src/components/CaptionsBanner.tsx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
captionsBannerClassName,
1111
captionsBannerFullHeightClassName,
1212
captionsContainerClassName,
13+
hiddenAnnouncementClassName,
1314
loadingBannerFullHeightStyles,
1415
loadingBannerStyles
1516
} from './styles/Captions.style';
@@ -54,6 +55,10 @@ export type CaptionsInformation = {
5455
* If you are using both captions and real time text, please ensure that the createdTimeStamp is populated
5556
*/
5657
createdTimeStamp?: Date;
58+
/**
59+
* If caption is finalized
60+
*/
61+
isFinalized?: boolean;
5762
};
5863

5964
/**
@@ -238,6 +243,10 @@ export const CaptionsBanner = (props: CaptionsBannerProps): JSX.Element => {
238243
const theme = useTheme();
239244

240245
const [expandBannerHeight, setExpandBannerHeight] = useState<boolean>(false);
246+
const [announcedRTT, setAnnouncedRTT] = useState<number[]>([]);
247+
const [announcedCaption, setAnnouncedCaption] = useState<string[]>([]);
248+
const [captionAnnouncementText, setCaptionAnnouncementText] = useState<CaptionsInformation[]>([]);
249+
const [rttAnnouncementText, setRTTAnnouncementText] = useState<RealTimeTextInformation[]>([]);
241250

242251
const getTitle = (): string => {
243252
if (isCaptionsOn && isRealTimeTextOn) {
@@ -305,6 +314,29 @@ export const CaptionsBanner = (props: CaptionsBannerProps): JSX.Element => {
305314
}
306315
}, [latestLocalRealTimeText]);
307316

317+
useEffect(() => {
318+
if (realTimeTexts?.completedMessages) {
319+
//filter out the messages that have already been announced
320+
const rTTMessagesToAnnounce = realTimeTexts.completedMessages.filter(
321+
(message) => !announcedRTT.includes(message.id)
322+
);
323+
if (rTTMessagesToAnnounce.length > 0) {
324+
setRTTAnnouncementText(rTTMessagesToAnnounce);
325+
setAnnouncedRTT((prev) => [...prev, ...rTTMessagesToAnnounce.map((message) => message.id)]);
326+
}
327+
}
328+
if (captions.length > 0) {
329+
// filter out the captions that have already been announced
330+
const captionsToAnnounce = captions.filter(
331+
(caption) => !announcedCaption.includes(caption.id) && caption.isFinalized
332+
);
333+
if (captionsToAnnounce.length > 0) {
334+
setCaptionAnnouncementText(captionsToAnnounce);
335+
setAnnouncedCaption((prev) => [...prev, ...captionsToAnnounce.map((caption) => caption.id)]);
336+
}
337+
}
338+
}, [captions, realTimeTexts?.completedMessages, announcedRTT, announcedCaption]);
339+
308340
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>): void => {
309341
if (event.key === 'Enter') {
310342
event.preventDefault();
@@ -352,6 +384,26 @@ export const CaptionsBanner = (props: CaptionsBannerProps): JSX.Element => {
352384
<>
353385
{(startCaptionsInProgress || isCaptionsOn || isRealTimeTextOn) && (
354386
<FocusZone shouldFocusOnMount className={captionsContainerClassName} data-ui-id="captions-banner">
387+
{/* ARIA live region */}
388+
{(rttAnnouncementText.length > 0 || captionAnnouncementText?.length > 0) && (
389+
<div aria-live="assertive" role="alert" aria-atomic="true" className={hiddenAnnouncementClassName}>
390+
<span>
391+
{rttAnnouncementText.map((text) => (
392+
<span>
393+
{strings.realTimeTextBannerTitle} {text.displayName}: {text.message}
394+
</span>
395+
))}
396+
</span>
397+
<span>
398+
{captionAnnouncementText.map((text) => (
399+
<span>
400+
{strings.captionsOnlyContainerTitle} {text.displayName}: {text.captionText}
401+
</span>
402+
))}
403+
</span>
404+
</div>
405+
)}
406+
355407
{(isCaptionsOn || isRealTimeTextOn) && formFactor === 'compact' && (
356408
<Stack
357409
horizontal

packages/react-components/src/components/styles/Captions.style.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,20 @@ export const captionsContainerClassName = mergeStyles({
114114
overflowX: 'hidden'
115115
});
116116

117+
/**
118+
* @private
119+
*/
120+
export const hiddenAnnouncementClassName = mergeStyles({
121+
position: 'absolute',
122+
width: '1px',
123+
height: '1px',
124+
padding: 0,
125+
overflow: 'hidden',
126+
clip: 'rect(0, 0, 0, 0)',
127+
whiteSpace: 'nowrap',
128+
border: 0
129+
});
130+
117131
/**
118132
* @private
119133
*/

0 commit comments

Comments
 (0)