Skip to content

Commit

Permalink
fix: call joining, dominant speaker for pip android, spotlight layout…
Browse files Browse the repository at this point in the history
… for tablets (#1603)

### Multiple bug fixes 
- Disables `AcceptCallButton`, `RejectCallButton` and `StartCallButton`
after their initial click to prevent unwanted additional press events
generated.
- dominant speaker is shown in PiP mode in Android
- fixes the spotlight layout for tablet devices
- add new npm dep in the dogfood app for checking if the device is a
tablet (`react-native-device-info`)

<img
src="https://github.com/user-attachments/assets/3a24dbd8-6ddf-4bac-a1f1-e10a4f31abc6"
alt="ios" width="600" height="440"/>
<img
src="https://github.com/user-attachments/assets/9925e55a-1e3e-4b40-85a5-7ff2377b4226"
alt="ios" width="300" height="440"/>
  • Loading branch information
kristian-mkd authored Nov 29, 2024
1 parent db613b3 commit 68ba86b
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 78 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCall } from '@stream-io/video-react-bindings';
import { getLogger } from '@stream-io/video-client';
import React from 'react';
import React, { useState } from 'react';
import { CallControlsButton } from './CallControlsButton';
import { IconWrapper, Phone } from '../../../icons';
import { useTheme } from '../../../contexts/ThemeContext';
Expand Down Expand Up @@ -38,7 +38,10 @@ export const AcceptCallButton = ({
acceptCallButton,
},
} = useTheme();
const [isLoading, setIsLoading] = useState(false);

const acceptCallHandler = async () => {
setIsLoading(true);
if (onPressHandler) {
onPressHandler();
return;
Expand All @@ -51,6 +54,8 @@ export const AcceptCallButton = ({
} catch (error) {
const logger = getLogger(['AcceptCallButton']);
logger('error', 'Error joining Call', error);
} finally {
setIsLoading(false);
}
};

Expand All @@ -60,6 +65,7 @@ export const AcceptCallButton = ({
color={colors.buttonSuccess}
size={buttonSizes.md}
style={acceptCallButton}
disabled={isLoading}
>
<IconWrapper>
<Phone color={colors.iconPrimary} size={iconSizes.lg} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
import React from 'react';
import React, { useState } from 'react';
import { CallControlsButton } from './CallControlsButton';
import { IconWrapper, PhoneDown } from '../../../icons';
import { CallingState, getLogger } from '@stream-io/video-client';
Expand Down Expand Up @@ -57,7 +57,10 @@ export const RejectCallButton = ({
variants: { buttonSizes, iconSizes },
},
} = useTheme();
const [isLoading, setIsLoading] = useState(false);

const rejectCallHandler = async () => {
setIsLoading(true);
if (onPressHandler) {
onPressHandler();
return;
Expand All @@ -73,6 +76,8 @@ export const RejectCallButton = ({
} catch (error) {
const logger = getLogger(['RejectCallButton']);
logger('error', 'Error rejecting Call', error);
} finally {
setIsLoading(false);
}
};

Expand All @@ -84,6 +89,7 @@ export const RejectCallButton = ({
// TODO: check what to do about this random style prop
// svgContainerStyle={theme.icon.lg}
style={rejectCallButton}
disabled={isLoading}
>
<IconWrapper>
<PhoneDown color={colors.iconPrimary} size={iconSizes.lg} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,16 @@ export const CallParticipantsGrid = ({
const {
theme: { colors, callParticipantsGrid },
} = useTheme();
const { useRemoteParticipants, useParticipants, useLocalParticipant } =
useCallStateHooks();
const {
useRemoteParticipants,
useParticipants,
useLocalParticipant,
useDominantSpeaker,
} = useCallStateHooks();
const _remoteParticipants = useRemoteParticipants();
const localParticipant = useLocalParticipant();
const _allParticipants = useParticipants();
const dominantSpeaker = useDominantSpeaker();
// we debounce the participants arrays to avoid unnecessary rerenders that happen when participant tracks are all subscribed simultaneously
const remoteParticipants = useDebouncedValue(_remoteParticipants, 300);
const allParticipants = useDebouncedValue(_allParticipants, 300);
Expand All @@ -80,7 +85,7 @@ export const CallParticipantsGrid = ({
if (isInPiPMode) {
participants =
remoteParticipants.length > 0
? [remoteParticipants[0] as StreamVideoParticipant]
? [dominantSpeaker || (remoteParticipants[0] as StreamVideoParticipant)]
: localParticipant
? [localParticipant]
: [];
Expand Down
142 changes: 74 additions & 68 deletions sample-apps/react-native/dogfood/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1728,6 +1728,8 @@ PODS:
- React-Core
- RNCPushNotificationIOS (1.11.0):
- React-Core
- RNDeviceInfo (14.0.1):
- React-Core
- RNGestureHandler (2.21.2):
- DoubleConversion
- glog
Expand Down Expand Up @@ -2010,7 +2012,7 @@ PODS:
- stream-react-native-webrtc (125.0.0-rc.2):
- React-Core
- WebRTC-SDK (~> 125.6422.05)
- stream-video-react-native (1.4.0):
- stream-video-react-native (1.4.2):
- DoubleConversion
- glog
- hermes-engine
Expand Down Expand Up @@ -2110,6 +2112,7 @@ DEPENDENCIES:
- RNCallKeep (from `../node_modules/react-native-callkeep`)
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
- "RNCPushNotificationIOS (from `../node_modules/@react-native-community/push-notification-ios`)"
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- "RNGoogleSignin (from `../node_modules/@react-native-google-signin/google-signin`)"
- "RNNotifee (from `../node_modules/@notifee/react-native`)"
Expand Down Expand Up @@ -2281,6 +2284,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-clipboard/clipboard"
RNCPushNotificationIOS:
:path: "../node_modules/@react-native-community/push-notification-ios"
RNDeviceInfo:
:path: "../node_modules/react-native-device-info"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNGoogleSignin:
Expand Down Expand Up @@ -2321,90 +2326,91 @@ SPEC CHECKSUMS:
GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
hermes-engine: 3852e37f6158a2fcfad23e31215ed495da3a6a40
RCT-Folly: 84578c8756030547307e4572ab1947de1685c599
RCT-Folly: bf5c0376ffe4dd2cf438dcf86db385df9fdce648
RCTDeprecation: d575d28132f93e5deef4849d5afffb4ac4e63226
RCTRequired: e2e5df1df76aac8685aabfebca389e6bec64792b
RCTTypeSafety: 30e36ceafa26979860e13fb3f234fb61692924c2
React: 10ad41b51f981992714011b6a4e081234c28dc2e
React-callinvoker: 58b51494f8b2cca07a27fc6f69273239c30a1e70
React-Codegen: 4b8b4817cea7a54b83851d4c1f91f79aa73de30a
React-Core: 7a5e9897daf0189c0233b25243d6704e5b9025d8
React-CoreModules: 09d4f4ddd85ce9301c4b06dfe68750a82ee4b4f5
React-cxxreact: 29bfe097a993c73a314f569998fe863eb6fb8a18
React-Core: 54860c16fb5873a6f00dd44d8979bbb648b34c7c
React-CoreModules: 443101f113a7b5d51b93e061574dcadf7850f8cc
React-cxxreact: 5407ecb854a755de34c0e6b03965d3a51c28c933
React-debug: a01fc4f077430d1a73f333ee2838f4d766e2d58b
React-defaultsnativemodule: 421fc755e08d5ad7726a252cc38f6925cd2bf919
React-domnativemodule: 64a00466588556262f7a238f0600d201a5d27b86
React-Fabric: 22f4287daa4187e2a10f9742dc74f3af9d9b2254
React-FabricComponents: 9295f2fabf5495c87621cea38cbd4dc445f43650
React-FabricImage: 5caf84d721e28747c53823825a551528c20ff875
React-defaultsnativemodule: fad7dd0129357e9012b734d641bdd7c7d8b95c8c
React-domnativemodule: b026c1578ffaada6c62ed8453a44ba263743830c
React-Fabric: 5ffd7ec9e7bf3d9e98358cbfbb1ef1b26954b6f5
React-FabricComponents: 6306fe9587c4a460017595749f6bfd7979817f43
React-FabricImage: 189f860814c8d2581ddc784d08addcb2e86ba5be
React-featureflags: 0845d47c3314ba87f2f6315bd33d6be8d23d2be8
React-featureflagsnativemodule: 6220f08c9c51a407375e5025421b06b7aa696ca0
React-graphics: d9f0317c34579ce4f14d9933b8033fe9ef61c72b
React-hermes: ab8705477c497a5839966bd57471ee3611f864f8
React-idlecallbacksnativemodule: 28c85b4c689eccc6d3fffe6fb5d010a18f48f629
React-ImageManager: 9005e783cfae8c521d59c33b8a4df2b78d3a6345
React-jserrorhandler: a14500014e8cd4d2f960cf16b69d2edbd32547ff
React-jsi: de2c6119671b281671fabf9e96eb11110207fe9d
React-jsiexecutor: 936132921f4d991af7b4faa7424fc54e67791dd0
React-jsinspector: 12d33a2f643ea2fd08ff4443f3b6c8b9fc5c4976
React-jsitracing: 1724696aadc78fca5c66ec8d2ce3b8f04d2799bc
React-logger: addd140841248966c2547eb94836399cc1061f4d
React-Mapbuffer: 1bc8e611871f4965dac0bc47a4561421a6e20f69
React-microtasksnativemodule: cff02bc87f8a1d5b9985c1c92ea8e84e854229d9
react-native-blob-util: 4f935148b217389fff952096c0f1a6ff67f4bdea
react-native-image-picker: 5c4cfe25630a6ec9105c16693abe8373a6f36d9a
react-native-mmkv: 36d57903d6b78677f6b7ec90c900df6e43d7d3e4
react-native-netinfo: a65f803f0e7dfa2fd70d093546161357d9326581
react-native-safe-area-context: ee4151c59dc010b5211fe68eca73b0f98d17b224
react-native-video: 6d495634696a5580559828544e3454c6ac27fbd7
React-featureflagsnativemodule: 5dfb68d7678e0fa395deac55f2a1b241a7a9dbd5
React-graphics: e8288c4a68627349c834eaf2fcc92108f2dbefb6
React-hermes: 8f31f252aff98a4cb711ccf6644cccfe35d8edd1
React-idlecallbacksnativemodule: a6780c405376fa6db47619deb44ff3f8dec6c3c9
React-ImageManager: 0b553a8e762b75d4cf9176474629f2d39cdb2aad
React-jserrorhandler: 2c47610e18594ed6b9c52995308afdbec0f59b71
React-jsi: b96853ac12c1dab5fe3ea131f959fda0bbaf1151
React-jsiexecutor: e38748a0e9d899f63dec562f93ac06c7acbc813d
React-jsinspector: b707427ae4772f34dab943a7343feddb155e8add
React-jsitracing: f4028bf2f09cd8707ad8befb35a8b78221d1673d
React-logger: 81d58ca6f1d93fca9a770bda6cc1c4fbfcc99c9c
React-Mapbuffer: b9bfad03a24c3ff440557e9011a6a09864849eae
React-microtasksnativemodule: 853dae5be1372b3ab52b21e29f86f2e1a0c61f37
react-native-blob-util: 356047c561b3506396852bc0d7988243f74dd77d
react-native-image-picker: df6597d4b1878a443796be11eb2b7286ed10ece6
react-native-mmkv: fb501d25ce65d16a1fad3296f7fc69150a1f0788
react-native-netinfo: 299dad906cdbf3b67bcc6f693c807f98bdd127cc
react-native-safe-area-context: f826417dadd1c1042c59355fb050682a9839f990
react-native-video: e5e752b62458690667276df947aee93b394d3e20
React-nativeconfig: 7f8cd6cae21f8bb18c53b746c495e72795fc5cb0
React-NativeModulesApple: 3210b7177c11145bb8e0d6f24aae102a221c4ddc
React-perflogger: c8860eaab4fe60d628b27bf0086a372c429fc74f
React-performancetimeline: 6b072ee07b20f71ca7aa443d7c78b9cb2a934ead
React-NativeModulesApple: 4fb24980fec9a94c9e9c1de3cdfd38ff3b87361c
React-perflogger: f2c94413cfad44817c96cab33753831e73f0d0dd
React-performancetimeline: c3ad160557d7406ceb5bb4dbc62834b1e61ee797
React-RCTActionSheet: 2eb26cbf384f3d3b2cb2e23be850a956d83f77ab
React-RCTAnimation: aa0a663829963ca72f4c722e71bd5debbecc1348
React-RCTAppDelegate: 12688b64e1e28e0eb1c628690678ae5d3ab356b4
React-RCTBlob: bef788ef3433170f9748d0e00d1afc7be64bc51d
React-RCTFabric: 5f335f0643a84dd888bf7ba70d6d60484c981d87
React-RCTImage: a9de66d305fa02008759a2aa5a723b68d18907e5
React-RCTLinking: 15fe8ccad84a4a5274d55b9d43e223896718772d
React-RCTNetwork: 7635ab6b7617648e5b5e35cdb3a4edab6fa309a6
React-RCTSettings: 18e666705ea62aac59f2a8d50ced87b9b8902c7b
React-RCTText: 5cf76f649b4781362d23f9ee3d52e8d12a74dd18
React-RCTVibration: bd72dc267866c8cd524c9a61d15060949ff24cf9
React-RCTAnimation: 59463699a92edc6705ce5306bb789d6a0ca4df0b
React-RCTAppDelegate: 4d9efca7caa477b106e3d55af339d0e071441536
React-RCTBlob: 0883f5363069ad30f628c970fcb413a619e42804
React-RCTFabric: 8cd047489627f322e491cf21d91ea242c8068fe3
React-RCTImage: 78884b7ea6ef4f7bb9655614bf09a40054f282ce
React-RCTLinking: b9beba7465fd9a1ed7a88a4e7fc403d26e17ab95
React-RCTNetwork: 701d9c050077596b15a11b6b573ed95c309d2315
React-RCTSettings: e700a82e3e923c10060b8f65297f9d321b93d8eb
React-RCTText: e782ce1c3f9d915daf50d97157f8c226e8f3d206
React-RCTVibration: 2a19c56be78cb7afce9f4f3471aacfb063f32a00
React-rendererconsistency: bbb7bafd25f3a41f4ea604be846dc2da8180e840
React-rendererdebug: 7c262ecec4bcddf7c9b8782f836fa68864d3d5f7
React-rendererdebug: 5cd463cfe5c4c174a8aa6abd67f190ad07a03e24
React-rncore: f2e8940f20f97f900f359861adf3a96f30dc82a3
React-RuntimeApple: e98509dfdc3c1da7560ac10637e077a05fc438d0
React-RuntimeCore: 89bd1ffca294f5fb437466e32b394f17bae28b31
React-RuntimeApple: 4ce7c4cc1ee24608b40a22667250e32e4171eef0
React-RuntimeCore: c3e89760391557d91b72bba1078d3e2ce26e963d
React-runtimeexecutor: 69e27948ee2127400297c7de50b809a7cd127a15
React-RuntimeHermes: 52f1738a3864f40445b0a5362e232eba29dcbcb1
React-runtimescheduler: 98d80589939956811f3ff51cb1ab720e6b3b1290
React-RuntimeHermes: 446adf8034db4b8f9d53b0140fdab832e475e7c9
React-runtimescheduler: 18e831b141db320f5ee13e0a6ecfd486a0e3de0c
React-timing: 5627775f1ccecc1d56bfc1247f942eec82069d1f
React-utils: 7ce63e32e4ca425cc73cfb84e656bfb9e02e58b3
ReactCodegen: 76542015d808938c67640540879b99413001fe42
ReactCommon: a1c914f7575011239a63603a95fb341d0331953c
ReactNativeIncallManager: ef7b845e166f04cf8ddf433d8a23227b01cef87a
RNCallKeep: 516281f03461e6be68f21a4634dbeee85d3fb730
RNCClipboard: efe1b27ad1ea378c60c8c8aabfd130961bbeb474
RNCPushNotificationIOS: 6c4ca3388c7434e4a662b92e4dfeeee858e6f440
RNGestureHandler: 932e0f07ccf470940afa9d0a8b6d8221e7e19cff
RNGoogleSignin: 9b083b6a575e7c2401aac339c93f8292d0542d29
RNNotifee: 52b319634ba89a2eacdfbadc01e059fd18505f04
RNPermissions: a9ea34e4f88ced1f9664d6589f57b4931b23e3aa
RNReactNativeHapticFeedback: d557285118551f215efe4b8fbbd24d2c4ae6c1b9
RNReanimated: 9ebacf9fbe1b8aeb2fc19de93d4a6779b89d0b89
RNScreens: d6b3735a362dab6a8cef14d032bdbdaf6e1b8dfa
RNSVG: b24f7dfe496d5463a79b330713226587e4b13956
RNVoipPushNotification: e5edde96849c0133ebc7e900dc30c8c221cfb690
React-utils: 2431220eeebc884010eb8df65335cb16c5849a55
ReactCodegen: 7ffe695604dd4aa69ac6d1baa4e51d2f1a9c610f
ReactCommon: 555c6f17f322bf4e7b9ce48990b252723170d158
ReactNativeIncallManager: bfc9c67358cd524882a7c4116dcb311ac2293d4b
RNCallKeep: 7bfa8f502067be6650eeca5ec0ebbf795314c5c3
RNCClipboard: 3f0451a8100393908bea5c5c5b16f96d45f30bfc
RNCPushNotificationIOS: 64218f3c776c03d7408284a819b2abfda1834bc8
RNDeviceInfo: 825f0d2f4381327317f12d1522720a8f76e6a19e
RNGestureHandler: 15ee1ab573a954c92641877ca946e2680f2e58da
RNGoogleSignin: fc408799f1990a12497a32f64280c0fe353ffcc1
RNNotifee: bc20a5e3d581f629db988075944fdd944d363dfe
RNPermissions: 13cf580b8ac0f6e36ff8f61eb3a955dcffdbd9ab
RNReactNativeHapticFeedback: 70dd302f264d06d1a2e0632a717d0b3ed10a0f35
RNReanimated: 7f11fff1964b5d073961b54167c22ebf3bd5aaff
RNScreens: 61099dac2e3cd356d2f7818ef15e9b6ad2769408
RNSVG: feeb4eb546e718d6c6fb70d10fd31e0c5c2d0d90
RNVoipPushNotification: 543e18f83089134a35e7f1d2eba4c8b1f7776b08
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
stream-chat-react-native: 470c37e2bed295da2ed9148f398694995d98f5af
stream-io-video-filters-react-native: 8e3d06506767c1a58576bb9d0229cbfc51a709d6
stream-react-native-webrtc: 2930ee2acccc0ba9f52d320055e4b0287a7cbbbc
stream-video-react-native: 0c883e0958749d3175397b121f3176b0aae6cf86
stream-chat-react-native: e515fc7d0951a32627f75ccca0699c139ba34579
stream-io-video-filters-react-native: 4153f006b31f805f6a4e42556d8e4ae768231900
stream-react-native-webrtc: c6e8ce6f886d1c4eb8bf048639176d46cfb681d6
stream-video-react-native: 7ce50d983d650bba27a5aa9eb834d7cd9823fdba
WebRTC-SDK: 1990a1a595bd0b59c17485ce13ff17f575732c12
Yoga: 513b871d622689bd53b51481bbcfb6b8f1a3de5b

PODFILE CHECKSUM: 22e502ced1a8b5a5e637f60837d3de140b3387b8

COCOAPODS: 1.15.2
COCOAPODS: 1.16.2
1 change: 1 addition & 0 deletions sample-apps/react-native/dogfood/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"react-native": "0.76.2",
"react-native-blob-util": "^0.19.11",
"react-native-callkeep": "4.3.11",
"react-native-device-info": "^14.0.1",
"react-native-dotenv": "^3.4.11",
"react-native-gesture-handler": "^2.21",
"react-native-haptic-feedback": "^2.0.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { TopControls } from './CallControlls/TopControls';
import { useLayout } from '../contexts/LayoutContext';
import { useToggleCallRecording } from '@stream-io/video-react-bindings';
import { useAppGlobalStoreValue } from '../contexts/AppContext';
import DeviceInfo from 'react-native-device-info';

type ActiveCallProps = {
onHangupCallHandler?: () => void;
Expand All @@ -31,11 +32,13 @@ export const ActiveCall = ({
const [isCallParticipantsVisible, setIsCallParticipantsVisible] =
useState<boolean>(false);
const call = useCall();
const currentOrientation = useOrientation();
const styles = useStyles();
const { selectedLayout } = useLayout();
const themeMode = useAppGlobalStoreValue((store) => store.themeMode);
const isInPiPMode = useIsInPiPMode(false);
const currentOrientation = useOrientation();
const isTablet = DeviceInfo.isTablet();
const isLandscape = !isTablet && currentOrientation === 'landscape';

const onOpenCallParticipantsInfo = useCallback(() => {
setIsCallParticipantsVisible(true);
Expand Down Expand Up @@ -93,7 +96,7 @@ export const ActiveCall = ({
<CallContent
onHangupCallHandler={onHangupCallHandler}
CallControls={CustomBottomControls}
landscape={currentOrientation === 'landscape'}
landscape={isLandscape}
layout={selectedLayout}
/>
<ParticipantsInfoList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ const JoinCallScreen = () => {
const { t } = useI18n();
const orientation = useOrientation();
const styles = useStyles();
const [isLoading, setIsLoading] = useState(false);

const startCallHandler = useCallback(async () => {
setIsLoading(true);
let ringingUserIds = !ringingUserIdsText
? ringingUsers
: ringingUserIdsText.split(',');
Expand Down Expand Up @@ -65,6 +67,8 @@ const JoinCallScreen = () => {
Alert.alert('Error calling users', error.message);
}
console.log('Failed to createCall', error);
} finally {
setIsLoading(false);
}
}, [ringingUserIdsText, ringingUsers, videoClient, userId]);

Expand All @@ -85,6 +89,9 @@ const JoinCallScreen = () => {
flexDirection: orientation === 'landscape' ? 'row' : 'column',
};

const startCallDisabled =
(ringingUserIdsText === '' && ringingUsers.length === 0) || isLoading;

return (
<KeyboardAvoidingView
style={[styles.container, landscapeStyles]}
Expand Down Expand Up @@ -127,8 +134,8 @@ const JoinCallScreen = () => {
style={styles.textInputStyle}
/>
<Button
title={t('Start a New Call')}
disabled={ringingUserIdsText === '' && ringingUsers.length === 0}
title={isLoading ? t('Calling...') : t('Start a New Call')}
disabled={startCallDisabled}
onPress={startCallHandler}
/>
</View>
Expand Down
3 changes: 2 additions & 1 deletion sample-apps/react-native/dogfood/src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"Login": "Login",
"Google Sign In": "Google Sign In",
"Start a New Call": "Start a New Call",
"Calling...": "Calling...",
"Join As Guest": "Join As Guest",
"Continue Anonymously": "Continue Anonymously",
"Join Call": "Join Call",
Expand All @@ -65,4 +66,4 @@
"You are about to join a call with id {{ callId }}.": "You are about to join a call with id {{ callId }}.",
"{{ user }} requested to {{ permissions }}": "{{ user }} requested to {{ permissions }}",
"Pronto": "Pronto"
}
}
Loading

0 comments on commit 68ba86b

Please sign in to comment.