Skip to content

Commit 00a6373

Browse files
authored
feat(design-v2): Call control buttons (#1514)
## 🎯 Goal - Jira Ticket: [PBE-5857](https://stream-io.atlassian.net/browse/PBE-5857) - Add new call control buttons ## 🛠 Implementation details ✅ ParticipantInfo button is moved to the bottom call controls sections ✅ Around half of the call control buttons in the bottom section are moved to bottom drawer and the remaining main buttons are split in left and right sections ✅ Add more button is added that will open bottom drawer with more call controls ✅ New styling and icons is applied on the call controls ## 🎨 UI Changes <!-- Add relevant screenshots --> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <img src="https://github.com/user-attachments/assets/1a28a37e-2484-416e-9d4f-071e14a64731" alt="ios-after" width="200" height="440"/> </td> <td> <img src="https://github.com/user-attachments/assets/39f16ee8-7a9e-4199-9c51-c01d001fa1e4" alt="ios-after" width="200" height="440"/> </td> </tr> </tbody> </table> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> <img src="https://github.com/user-attachments/assets/292b9a06-02dc-4c11-8e87-35003831ea56" alt="ios-after" width="200" height="440"/> </td> <td> <img src="https://github.com/user-attachments/assets/d1d29fbf-8740-410f-aea3-c98085ba482f" alt="ios-after" width="200" height="440"/> </td> </tr> </tbody> </table> </details> [PBE-5857]: https://stream-io.atlassian.net/browse/PBE-5857?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
1 parent 438251d commit 00a6373

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+778
-596
lines changed

packages/react-native-sdk/__tests__/components/CallControls.test.tsx

Lines changed: 2 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ import { mockClientWithUser } from '../mocks/client';
33
import mockParticipant from '../mocks/participant';
44
import { ButtonTestIds, ComponentTestIds } from '../../src/constants/TestIds';
55
import { mockCall } from '../mocks/call';
6-
import { fireEvent, render, screen, waitFor } from '../utils/RNTLTools';
6+
import { fireEvent, render, screen } from '../utils/RNTLTools';
77
import { OwnCapability } from '@stream-io/video-client';
88
import { defaultEmojiReactions } from '../../src/constants';
9-
import { CallControls } from '../../src/components/Call/CallControls/CallControls';
10-
import { ChatButton } from '../../src/components/Call/CallControls/ChatButton';
9+
import { CallControls } from '../../src';
1110
import { HangUpCallButton } from '../../src/components/Call/CallControls/HangupCallButton';
1211
import { ReactionsButton } from '../../src/components/Call/CallControls/ReactionsButton';
1312

@@ -18,48 +17,6 @@ enum P_IDS {
1817
LOCAL_1 = 'local-1',
1918
}
2019

21-
describe('ChatButton', () => {
22-
it('should render an unread badge indicator when the value is defined in the chatButton prop', async () => {
23-
const call = mockCall(mockClientWithUser(), [
24-
mockParticipant({
25-
isLocalParticipant: true,
26-
sessionId: P_IDS.LOCAL_1,
27-
userId: P_IDS.LOCAL_1,
28-
}),
29-
]);
30-
31-
render(<ChatButton onPressHandler={jest.fn()} unreadBadgeCount={1} />, {
32-
call,
33-
});
34-
35-
const indicator = await screen.findByText('1');
36-
37-
expect(indicator).toBeVisible();
38-
});
39-
40-
it('should not render an unread badge indicator when the value is 0 in the chatButton prop', async () => {
41-
const call = mockCall(mockClientWithUser(), [
42-
mockParticipant({
43-
isLocalParticipant: true,
44-
sessionId: P_IDS.LOCAL_1,
45-
userId: P_IDS.LOCAL_1,
46-
}),
47-
]);
48-
49-
render(<ChatButton onPressHandler={jest.fn()} unreadBadgeCount={0} />, {
50-
call,
51-
});
52-
53-
await waitFor(() =>
54-
expect(() =>
55-
screen.getByTestId(ComponentTestIds.CHAT_UNREAD_BADGE_COUNT_INDICATOR)
56-
).toThrow(
57-
/Unable to find an element with testID: chat-unread-badge-count-indicator/i
58-
)
59-
);
60-
});
61-
});
62-
6320
describe('ReactionsButton', () => {
6421
it('render reaction button in call controls component', async () => {
6522
const call = mockCall(

packages/react-native-sdk/__tests__/components/ParticipantView.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ describe('ParticipantView', () => {
4343
expect(
4444
await screen.findByTestId(ComponentTestIds.PARTICIPANT_AVATAR)
4545
).toBeOnTheScreen();
46-
expect(screen.getByTestId(IconTestIds.MUTED_VIDEO)).toBeOnTheScreen();
4746
expect(screen.getByText(testParticipant.name)).toBeOnTheScreen();
4847
// reaction is visible and then disappears after 5500 ms
4948
expect(screen.getByText('🎉')).toBeOnTheScreen();

packages/react-native-sdk/docusaurus/docs/reactnative/04-ui-components/call/call-content.mdx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import CallContentSpotlight from '../../assets/04-ui-components/call/call-conten
1010

1111
import CallTopView from '../../common-content/ui-components/call/call-content/call-top-view.mdx';
1212
import CallControls from '../../common-content/ui-components/call/call-content/call-controls.mdx';
13-
import ParticipantsInfoBadge from '../../common-content/ui-components/call/call-content/participants-info-badge.mdx';
1413
import Landscape from '../../common-content/ui-components/call/call-content/landscape.mdx';
1514
import OnBackPressed from '../../common-content/ui-components/call/call-content/on-back-pressed.mdx';
1615
import OnParticipantInfoPress from '../../common-content/ui-components/call/call-content/on-participant-info-press.mdx';

packages/react-native-sdk/docusaurus/docs/reactnative/04-ui-components/call/call-top-view.mdx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,6 @@ Style to override the container of the `CallTopView`.
6060
| ---------------------------------------------------------- |
6161
| [ViewStyle](https://reactnative.dev/docs/view-style-props) |
6262

63-
### `ParticipantsInfoBadge`
64-
65-
<ParticipantsInfoBadge />
66-
6763
## Customization
6864

6965
You can create your own custom `CallTopView` using the [Call Top View UI Cookbook guide](../../../ui-cookbook/replacing-call-top-view/).

packages/react-native-sdk/docusaurus/docs/reactnative/common-content/ui-components/call/call-content/participants-info-badge.mdx

Lines changed: 0 additions & 5 deletions
This file was deleted.

packages/react-native-sdk/src/components/Call/CallContent/CallContent.tsx

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useEffect, useState } from 'react';
2-
import { StyleSheet, View, ViewStyle } from 'react-native';
2+
import { StyleSheet, View } from 'react-native';
33
import InCallManager from 'react-native-incall-manager';
44

55
import {
@@ -71,10 +71,7 @@ export type CallContentProps = Pick<
7171
HangUpCallButtonProps,
7272
'onHangupCallHandler'
7373
> &
74-
Pick<
75-
CallTopViewProps,
76-
'onBackPressed' | 'onParticipantInfoPress' | 'ParticipantsInfoBadge'
77-
> &
74+
Pick<CallTopViewProps, 'onBackPressed'> &
7875
CallContentComponentProps & {
7976
/**
8077
* This switches the participant's layout between the grid and the spotlight mode.
@@ -101,7 +98,6 @@ export type CallContentProps = Pick<
10198

10299
export const CallContent = ({
103100
onBackPressed,
104-
onParticipantInfoPress,
105101
onHangupCallHandler,
106102
CallParticipantsList,
107103
CallTopView = DefaultCallTopView,
@@ -113,7 +109,6 @@ export const CallContent = ({
113109
ParticipantReaction,
114110
ParticipantVideoFallback,
115111
ParticipantView,
116-
ParticipantsInfoBadge,
117112
VideoRenderer,
118113
layout = 'grid',
119114
landscape = false,
@@ -201,31 +196,23 @@ export const CallContent = ({
201196
supportedReactions,
202197
};
203198

204-
const landscapeStyles: ViewStyle = {
205-
flexDirection: landscape ? 'row' : 'column',
206-
};
207-
208199
return (
209200
<>
210201
{!disablePictureInPicture && (
211202
<RTCViewPipIOS
212203
includeLocalParticipantVideo={iOSPiPIncludeLocalParticipantVideo}
213204
/>
214205
)}
215-
<View style={[styles.container, landscapeStyles, callContent.container]}>
216-
<View style={[styles.container, callContent.callParticipantsContainer]}>
206+
<View style={[styles.container, callContent.container]}>
207+
<View style={[styles.content, callContent.callParticipantsContainer]}>
217208
<View
218209
style={[styles.view, callContent.topContainer]}
219210
// "box-none" disallows the container view to be not take up touches
220211
// and allows only the top and floating view (its child views) to take up the touches
221212
pointerEvents="box-none"
222213
>
223214
{!isInPiPMode && CallTopView && (
224-
<CallTopView
225-
onBackPressed={onBackPressed}
226-
onParticipantInfoPress={onParticipantInfoPress}
227-
ParticipantsInfoBadge={ParticipantsInfoBadge}
228-
/>
215+
<CallTopView onBackPressed={onBackPressed} />
229216
)}
230217
{showFloatingView && FloatingParticipantView && (
231218
<FloatingParticipantView
@@ -260,6 +247,7 @@ export const CallContent = ({
260247

261248
const styles = StyleSheet.create({
262249
container: { flex: 1 },
250+
content: { flex: 1 },
263251
view: {
264252
...StyleSheet.absoluteFillObject,
265253
zIndex: Z_INDEX.IN_FRONT,

packages/react-native-sdk/src/components/Call/CallControls/CallControlsButton.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,26 +57,29 @@ export const CallControlsButton = (
5757

5858
const {
5959
theme: {
60-
variants: { buttonSizes },
6160
colors,
61+
defaults,
62+
variants: { roundButtonSizes },
6263
callControlsButton: { container },
6364
},
6465
} = useTheme();
6566

6667
const pressableStyle: PressableProps['style'] = ({ pressed }) => [
6768
styles.container,
6869
{
69-
backgroundColor: disabled ? colors.disabled : colorProp || colors.base1,
70+
backgroundColor: disabled
71+
? colors.buttonPrimaryDisabled
72+
: colorProp || colors.buttonSecondaryDefault,
7073
opacity: pressed ? 0.2 : 1,
71-
height: size || buttonSizes.sm,
72-
width: size || buttonSizes.sm,
73-
borderRadius: (size || buttonSizes.sm) / 2,
74-
borderColor: colors.background1,
74+
height: size || roundButtonSizes.lg,
75+
width: size || roundButtonSizes.lg,
76+
borderRadius: defaults.borderRadius,
7577
},
7678
styleProp?.container ?? null,
7779
container,
7880
];
7981

82+
const childrenSize = (size || roundButtonSizes.lg) / 2 - 5;
8083
return (
8184
<Pressable
8285
disabled={disabled}
@@ -87,10 +90,7 @@ export const CallControlsButton = (
8790
>
8891
<View
8992
style={[
90-
{
91-
height: (size || buttonSizes.sm) / 2 - 5,
92-
width: (size || buttonSizes.sm) / 2 - 5,
93-
},
93+
{ height: childrenSize, width: childrenSize },
9494
styleProp?.svgContainer ?? null,
9595
]}
9696
>

packages/react-native-sdk/src/components/Call/CallControls/ChatButton.tsx

Lines changed: 0 additions & 90 deletions
This file was deleted.

packages/react-native-sdk/src/components/Call/CallControls/ToggleAudioPreviewButton.tsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useCallStateHooks } from '@stream-io/video-react-bindings';
22
import React from 'react';
33
import { useTheme } from '../../../contexts';
4-
import { Mic, MicOff } from '../../../icons';
4+
import { IconWrapper, Mic, MicOff } from '../../../icons';
55
import { CallControlsButton } from './CallControlsButton';
66

77
/**
@@ -26,6 +26,7 @@ export const ToggleAudioPreviewButton = ({
2626
colors,
2727
toggleAudioPreviewButton,
2828
variants: { buttonSizes },
29+
defaults,
2930
},
3031
} = useTheme();
3132
const { useMicrophoneState } = useCallStateHooks();
@@ -42,21 +43,24 @@ export const ToggleAudioPreviewButton = ({
4243
return (
4344
<CallControlsButton
4445
onPress={onPress}
45-
color={!optimisticIsMute ? colors.base1 : colors.base5}
46+
color={
47+
!optimisticIsMute
48+
? colors.buttonSecondaryDefault
49+
: colors.buttonSecondaryWarningDefault
50+
}
4651
size={buttonSizes.md}
4752
style={{
48-
container: {
49-
shadowColor: !optimisticIsMute ? colors.base1 : colors.base5,
50-
...toggleAudioPreviewButton.container,
51-
},
53+
container: { ...toggleAudioPreviewButton.container },
5254
svgContainer: toggleAudioPreviewButton.svgContainer,
5355
}}
5456
>
55-
{!optimisticIsMute ? (
56-
<Mic color={colors.base5} />
57-
) : (
58-
<MicOff color={colors.base1} />
59-
)}
57+
<IconWrapper>
58+
{!optimisticIsMute ? (
59+
<Mic color={colors.iconPrimaryDefault} size={defaults.iconSize} />
60+
) : (
61+
<MicOff color={colors.iconPrimaryDefault} size={defaults.iconSize} />
62+
)}
63+
</IconWrapper>
6064
</CallControlsButton>
6165
);
6266
};

0 commit comments

Comments
 (0)