Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion sample-apps/react-native/dogfood/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { LiveStream } from './src/navigators/Livestream';
import { StreamTheme, useCalls } from '@stream-io/video-react-native-sdk';
import Toast from 'react-native-toast-message';
import { TestRecording } from './src/navigators/TestRecording';
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';

// only enable warning and error logs from webrtc library
Logger.enable(`${Logger.ROOT_PREFIX}:(WARN|ERROR)`);
Expand Down Expand Up @@ -159,7 +160,9 @@ const StackNavigator = () => {
<VideoWrapper>
<RingingWatcher />
<ChatWrapper>
<Stack.Navigator>{mode}</Stack.Navigator>
<BottomSheetModalProvider>
<Stack.Navigator>{mode}</Stack.Navigator>
</BottomSheetModalProvider>
<Toast />
</ChatWrapper>
</VideoWrapper>
Expand Down
145 changes: 145 additions & 0 deletions sample-apps/react-native/dogfood/src/components/AppSettingsSheet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import { StyleSheet, Switch, Text, View } from 'react-native';
import {
BottomSheetBackdrop,
BottomSheetBackdropProps,
BottomSheetModal,
BottomSheetView,
} from '@gorhom/bottom-sheet';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useTheme } from '@stream-io/video-react-native-sdk';
import {
useAppGlobalStoreSetState,
useAppGlobalStoreValue,
} from '../contexts/AppContext';
import { useAppI18n } from '../hooks/useAppI18n';

type AppSettingsSheetProps = {
visible: boolean;
onClose: () => void;
};

export const AppSettingsSheet = ({
visible,
onClose,
}: AppSettingsSheetProps) => {
const styles = useStyles();
const { t } = useAppI18n();
const insets = useSafeAreaInsets();
const sheetRef = useRef<BottomSheetModal>(null);
const setState = useAppGlobalStoreSetState();
const themeMode = useAppGlobalStoreValue((store) => store.themeMode);
const devMode = useAppGlobalStoreValue((store) => store.devMode);
const showRingStateDebugPane = useAppGlobalStoreValue(
(store) => store.showRingStateDebugPane,
);

useEffect(() => {
if (visible) {
sheetRef.current?.present();
}
}, [visible]);

const renderBackdrop = useCallback(
(props: BottomSheetBackdropProps) => (
<BottomSheetBackdrop
{...props}
appearsOnIndex={0}
disappearsOnIndex={-1}
pressBehavior="close"
/>
),
[],
);

return (
<BottomSheetModal
ref={sheetRef}
onDismiss={onClose}
backdropComponent={renderBackdrop}
backgroundStyle={styles.background}
handleIndicatorStyle={styles.handleIndicator}
>
<BottomSheetView
style={[styles.content, { paddingBottom: insets.bottom + 16 }]}
>
<Text style={styles.title}>
{t('appSettings.title.text', 'Settings')}
</Text>
<SettingRow
label={t('appSettings.darkMode.label', 'Dark mode')}
value={themeMode === 'dark'}
onValueChange={(enabled) =>
setState({ themeMode: enabled ? 'dark' : 'light' })
}
/>
{(__DEV__ || devMode) && (
<SettingRow
label={t('appSettings.ringStatePanel.label', 'Ring state panel')}
value={!!showRingStateDebugPane}
onValueChange={(enabled) =>
setState({ showRingStateDebugPane: enabled })
}
/>
)}
</BottomSheetView>
</BottomSheetModal>
);
};

const SettingRow = ({
label,
value,
onValueChange,
}: {
label: string;
value: boolean;
onValueChange: (value: boolean) => void;
}) => {
const styles = useStyles();
return (
<View style={styles.row}>
<Text style={styles.rowLabel}>{label}</Text>
<Switch value={value} onValueChange={onValueChange} />
</View>
);
};

const useStyles = () => {
const {
theme: { semantics, primitives },
} = useTheme();
return useMemo(
() =>
StyleSheet.create({
background: {
backgroundColor: semantics.backgroundCoreElevation2,
borderTopLeftRadius: primitives.radiusXl,
borderTopRightRadius: primitives.radiusXl,
},
handleIndicator: {
backgroundColor: semantics.borderCoreDefault,
},
content: {
paddingHorizontal: primitives.spacingLg,
},
title: {
fontSize: primitives.typographyFontSizeLg,
fontWeight: primitives.typographyFontWeightSemiBold,
color: semantics.textPrimary,
marginBottom: primitives.spacingSm,
},
row: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingVertical: primitives.spacingMd,
},
rowLabel: {
fontSize: primitives.typographyFontSizeMd,
color: semantics.textPrimary,
},
}),
[semantics, primitives],
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ import {
import { BottomControlsDrawer, DrawerOption } from './BottomControlsDrawer';
import Feedback from '../../../assets/Feedback';
import FeedbackModal from '../../FeedbackModal';
import {
ThemeMode,
useAppGlobalStoreSetState,
useAppGlobalStoreValue,
} from '../../../contexts/AppContext';
import LightDark from '../../../assets/LightDark';
import Stats from '../../../assets/Stats';
import ClosedCaptions from '../../../assets/ClosedCaptions';
import Screenshot from '../../../assets/Screenshot';
Expand Down Expand Up @@ -77,8 +71,6 @@ export const MoreActionsButton = ({
const [feedbackModalVisible, setFeedbackModalVisible] = useState(false);
const [screenshotModalVisible, setScreenshotModalVisible] = useState(false);
const [screenshotImage, setScreenshotImage] = useState<string | null>(null);
const setState = useAppGlobalStoreSetState();
const themeMode = useAppGlobalStoreValue((store) => store.themeMode);
const call = useCall();
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const {
Expand Down Expand Up @@ -115,13 +107,6 @@ export const MoreActionsButton = ({
setFeedbackModalVisible(false);
};

const getName = (theme: ThemeMode) => {
if (theme === 'light') {
return 'Dark mode';
}
return 'Light mode';
};

const getCaptionsLabel = () =>
isCaptioningInProgress
? 'Disable closed captions'
Expand Down Expand Up @@ -199,26 +184,6 @@ export const MoreActionsButton = ({
setIsDrawerVisible(true);
},
},
{
id: '3',
label: getName(themeMode),
icon: (
<IconWrapper>
<LightDark
color={semantics.accentNeutral}
size={components.iconSizeMd}
/>
</IconWrapper>
),
onPress: () => {
if (themeMode === 'light') {
setState({ themeMode: 'dark' });
} else {
setState({ themeMode: 'light' });
}
setIsDrawerVisible(false);
},
},
{
id: '4',
label: 'Take Screenshot',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
useTheme,
} from '@stream-io/video-react-native-sdk';
import { useAppI18n } from '../hooks/useAppI18n';
import React, { useMemo } from 'react';
import React, { useMemo, useState } from 'react';
import { Alert, Pressable, StyleSheet, Text } from 'react-native';
import {
useAppGlobalStoreSetState,
Expand All @@ -18,6 +18,7 @@ import { AVATAR_SIZE } from '../constants';
import { ButtonTestIds } from '../constants/TestIds';
import Close from '../assets/Close';
import { Leave } from '../assets/Leave';
import { AppSettingsSheet } from './AppSettingsSheet';

export const NavigationHeader = ({ route }: NativeStackHeaderProps) => {
const videoClient = useStreamVideoClient();
Expand All @@ -27,6 +28,7 @@ export const NavigationHeader = ({ route }: NativeStackHeaderProps) => {
const userName = useAppGlobalStoreValue((store) => store.userName);
const environment = useAppGlobalStoreValue((store) => store.appEnvironment);
const appStoreSetState = useAppGlobalStoreSetState();
const [settingsVisible, setSettingsVisible] = useState(false);

const logoutHandler = () => {
Alert.alert(
Expand Down Expand Up @@ -70,7 +72,14 @@ export const NavigationHeader = ({ route }: NativeStackHeaderProps) => {

return (
<SafeAreaView style={styles.header} edges={['top', 'left', 'right']}>
{user && <Avatar user={user} size="lg" />}
{user && (
<Pressable
testID={ButtonTestIds.APP_SETTINGS}
onPress={() => setSettingsVisible(true)}
>
<Avatar user={user} size="lg" />
</Pressable>
)}
<Text style={styles.userNameText}>{userName}</Text>

{!showChooseModeButton ? (
Expand All @@ -92,6 +101,10 @@ export const NavigationHeader = ({ route }: NativeStackHeaderProps) => {
<Close color={styles.icon.color} size={24} />
</Pressable>
)}
<AppSettingsSheet
visible={settingsVisible}
onClose={() => setSettingsVisible(false)}
/>
</SafeAreaView>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,17 +118,21 @@ const formatMap = (map?: Record<string, number>) => {

const useStyles = () => {
const {
theme: { semantics, primitives },
theme: { semantics, primitives, callAppBar, callControlsButton },
} = useTheme();
const insets = useSafeAreaInsets();
const callAppBarHeight =
Number(callAppBar.container.padding) * 2 +
Number(callControlsButton.container.height) +
Number(callControlsButton.container.margin) * 2;

return useMemo(() => {
return StyleSheet.create({
container: {
position: 'absolute',
left: primitives.spacingMd,
right: primitives.spacingMd,
top: insets.top + primitives.spacingMd,
top: insets.top + callAppBarHeight + primitives.spacingMd,
zIndex: Z_INDEX.IN_FRONT,
backgroundColor: semantics.backgroundCoreOverlayLight,
borderRadius: 8,
Expand All @@ -139,7 +143,7 @@ const useStyles = () => {
paddingHorizontal: primitives.spacingMd,
},
headerText: {
color: semantics.textOnAccent,
color: semantics.textPrimary,
fontSize: 14,
fontWeight: 'bold',
},
Expand All @@ -159,7 +163,7 @@ const useStyles = () => {
marginRight: primitives.spacingSm,
},
rowValue: {
color: semantics.textOnAccent,
color: semantics.textPrimary,
fontSize: 12,
flexShrink: 1,
},
Expand Down Expand Up @@ -194,5 +198,5 @@ const useStyles = () => {
fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace',
},
});
}, [semantics, primitives, insets]);
}, [semantics, primitives, insets, callAppBarHeight]);
};
1 change: 1 addition & 0 deletions sample-apps/react-native/dogfood/src/constants/TestIds.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export enum ButtonTestIds {
LOG_OUT = 'log-out',
CHOOSE_MODE = 'choose-mode',
APP_SETTINGS = 'app-settings',
EXIT_PARTICIPANTS_INFO = 'exit-participants-info',
}

Expand Down
3 changes: 3 additions & 0 deletions sample-apps/react-native/dogfood/src/contexts/AppContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type AppGlobalStore = {
e2eeKeyInput: string;
coordinatorBaseUrl?: string;
disableRingStatePolling?: boolean;
showRingStateDebugPane?: boolean;
};

export const {
Expand All @@ -44,6 +45,7 @@ export const {
e2eeKeyInput: '',
coordinatorBaseUrl: '',
disableRingStatePolling: false,
showRingStateDebugPane: true,
},
[
'apiKey',
Expand All @@ -58,5 +60,6 @@ export const {
'e2eeKeyInput',
'coordinatorBaseUrl',
'disableRingStatePolling',
'showRingStateDebugPane',
],
);
9 changes: 6 additions & 3 deletions sample-apps/react-native/dogfood/src/navigators/Call.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ import { RingStateDebugPane } from '../components/Ringing/RingStateDebugPane';
import { useAppGlobalStoreValue } from '../contexts/AppContext';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

const ENABLE_RING_STATE_DEBUG = __DEV__;

const CallStack = createNativeStackNavigator<CallStackParamList>();

const Calls = () => {
const calls = useCalls().filter((c) => c.ringing);
const orientation = useOrientation();
const insets = useSafeAreaInsets();
const devMode = useAppGlobalStoreValue((store) => store.devMode);
const showRingStateDebugPane = useAppGlobalStoreValue(
(store) => store.showRingStateDebugPane,
);

const firstCall = calls.at(-1);

Expand Down Expand Up @@ -55,7 +56,9 @@ const Calls = () => {
CallContent={customCallContent}
insets={insets}
/>
{(ENABLE_RING_STATE_DEBUG || devMode) && <RingStateDebugPane />}
{(__DEV__ || devMode) && showRingStateDebugPane && (
<RingStateDebugPane />
)}
</View>
</StreamCall>
);
Expand Down
Loading