GetStream / stream-chat-react-native

💬 React-Native Chat SDK ➜ Stream Chat. Includes a tutorial on building your own chat app experience using React-Native, React-Navigation and Stream
https://getstream.io/chat/sdk/react-native/
Other
976 stars 326 forks source link

[🐛] Overlap Bottom Navigation Menu #2502

Closed david-shiko closed 6 months ago

david-shiko commented 6 months ago

Hello Stream Team, I have an issue related to the React Native (RN) SDK, specifically with the GetStream chat screens (Chat, Channel List, Channel) which overlap my bottom menu from the React Native Navigation library. I'm not very experienced with layout design, but I think it's related to the OverlayProvider. According to the documentation, it should be positioned outside of the navigation components (stack screen). However, instead of wrapping the screens as usual, my bottom menu is now inside the GetStream Chat wrapper and is being overlapped by it. I could manually add padding to make my bottom menu visible, but the real problem, in my opinion, is that wrapping the navigation is breaking the design architecture. 123

P.S. it's the only screen with a such issue, other screens works fine with my bottom navigation menu.

// MessengerScreen.tsx
import React from 'react';
import { ChannelList } from 'stream-chat-expo';
import { useNavigation } from '@react-navigation/native';

export default function Messenger(): React.ReactElement {

    const navigation = useNavigation();

    return (
        <ChannelList 
        filters={{ members: { $in: ['steve'] } }}
        onSelect={(channel) => {
            navigation.navigate('Channel')
        }}
    );
}

// ChannelScreen.tsx
import { useChannelContext } from 'stream-chat-expo';

const ChannelScreen = () => {
    const { channel } = useChannelContext(); // Not works. useGetStreamChatContext does works

    return (
        <Channel channel={channel}>
            <MessageList />
            <MessageInput />
        </Channel>
    );
};

export default ChannelScreen;

// Navigation.ts
import { Chat, OverlayProvider } from 'stream-chat-expo';
import {createStackNavigator} from '@react-navigation/stack';
import { useUserContext } from 'app/src/contexts/User';
import { MessengerScreen, ChannelScreen } from 'app/screens';

export type GetStreamStackParamList = {
    Messenger: any; // TODO Need types
    Channel: any; // TODO Need types
};

const GetStreamStack = createStackNavigator<GetStreamStackParamList>();

export function GetStreamStackScreen(): React.ReactElement {

    const { user } = useUserContext();
    user.messenger.connectUser() // TODO use hook
    return (
        <OverlayProvider>
            <Chat client={user.messenger.provider.client}>
                <GetStreamStack.Navigator initialRouteName='Messenger'>
                    <GetStreamStack.Screen name='Messenger' component={MessengerScreen}/>
                    <GetStreamStack.Screen name='Channel' component={ChannelScreen}/>
                </GetStreamStack.Navigator>
            </Chat>
        </OverlayProvider>
    );
}

// App.tsx
import React from 'react';
import registerRootComponent from 'expo/build/launch/registerRootComponent';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import AppNavigator from 'app/src/navigation/AppNavigator';

export default function App() {
    return (
        <GestureHandlerRootView style={{ flex: 1 }}>
            <GetStreamChatProvider>
                <AppNavigator />
            </GetStreamChatProvider>
        </GestureHandlerRootView>
    );
}

registerRootComponent(App);

// Bottom menu declaration

// Built-in modules
import React from 'react';
// Third-party modules
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
// Internal modules
import Colors from 'app/src/styles/colors';
import MockScreen from 'app/src/screens/Mock/Mock';
import SwipeScreen from 'app/src/screens/Swipes/Swipe';
import MapScreen from 'app/src/screens/Map/Map';
import { StackScreen as DailyInterestsNavigator } from 'app/src/navigation/Interests';
import { 
    GetStreamStackScreen as GetStreamMessengerNavigator,
    // StackScreen as MessengerNavigator
 } from 'app/src/navigation/Messenger';
import { StackScreen as ProfileNavigator } from 'app/src/navigation/Profile';
// SVG
import {
    ChatActive,
    ChatInactive,
    HomeActive,
    HomeInactive,
    LocationActive,
    LocationInactive,
    ProfileActive,
    ProfileInactive,
    SwipeActive,
    SwipeInactive,
} from 'app/assets/images/bottomMenu';

export type BottomMenuParamList = {
    /**
     * Type with params of screens and their props in Tabs
     */
    BottomMenuFeed: undefined;
    BottomMenuSwipes: undefined;
    BottomMenuDailyInterests: undefined;
    BottomMenuMessenger: undefined;
    BottomMenuProfile: undefined;
    BottomMenuMap: undefined;
};
const BottomTab = createBottomTabNavigator<BottomMenuParamList>();

export function BottomMenu(): React.ReactElement {
    const insets = useSafeAreaInsets();
    const TabBarOwmHeight = 48;
    const TabBarFullHeight = insets.bottom + TabBarOwmHeight;

    return (
        <BottomTab.Navigator
            initialRouteName={'BottomMenuDailyInterests'}
            screenOptions={{
                headerShown: false,
                title: 'qwerty',
                tabBarStyle: {
                    position: 'absolute',
                    height: TabBarFullHeight,
                    borderRadius: 25,
                    shadowColor: Colors.Black,
                    shadowOffset: {
                        width: 0,
                        height: -1,
                    },
                    shadowOpacity: 0.50,
                    shadowRadius: 5,
                    borderTopWidth: 0,
                    elevation: 15,
                },
                tabBarShowLabel: false,
                tabBarItemStyle: {
                    height: TabBarOwmHeight,
                },
            }}
        >
            <BottomTab.Screen name='BottomMenuFeed' component={MockScreen} options={{
                tabBarIcon: ({ focused }): React.ReactElement => focused ? <LocationActive /> : <LocationInactive />,
            }} />
            <BottomTab.Screen name='BottomMenuMap' component={MapScreen} options={{
                tabBarIcon: ({ focused }): React.ReactElement => focused ? <LocationActive /> : <LocationInactive />,
            }} />
            <BottomTab.Screen name='BottomMenuSwipes' component={SwipeScreen} options={{
                tabBarIcon: ({ focused }): React.ReactElement => focused ? <SwipeActive /> : <SwipeInactive />,
            }} />
            <BottomTab.Screen name='BottomMenuDailyInterests' component={DailyInterestsNavigator} options={{
                tabBarIcon: ({ focused }): React.ReactElement => focused ? <HomeActive /> : <HomeInactive />,
            }} />
            <BottomTab.Screen name='BottomMenuMessenger' component={GetStreamMessengerNavigator} options={{
                tabBarIcon: ({ focused }): React.ReactElement => focused ? <ChatActive /> : <ChatInactive />,
            }} />
            <BottomTab.Screen name='BottomMenuProfile' component={ProfileNavigator} options={{
                tabBarIcon: ({ focused }): React.ReactElement => focused ? <ProfileActive /> : <ProfileInactive />,
            }} />
        </BottomTab.Navigator>
    );
}

Enviroment:

{
  "name": "rubiklovemobile",
  "version": "1.0.0",
  "main": "app/src/App.tsx",
  "scripts": {
    "start": "expo start",
    "android": "expo run:android",
    "ios": "expo run:ios",
    "web": "expo start --web",
    "lint": "eslint . --ext .js,.jsx,.ts,.tsx",
    "lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix"
  },
  "dependencies": {
    "@expo/metro-config": "~0.17.1",
    "@expo/webpack-config": "~19.0.1",
    "@ptomasroos/react-native-multi-slider": "^2.2.2",
    "@react-native-community/netinfo": "11.1.0",
    "@react-native-google-signin/google-signin": "^11.0.0",
    "@react-native-picker/picker": "2.6.1",
    "@react-navigation/bottom-tabs": "^6.5.7",
    "@react-navigation/native": "^6.1.6",
    "@react-navigation/stack": "^6.3.16",
    "@stream-io/flat-list-mvcp": "^0.10.3",
    "axios": "^1.3.4",
    "expo": "~50.0.17",
    "expo-auth-session": "~5.4.0",
    "expo-crypto": "~12.8.1",
    "expo-file-system": "~16.0.9",
    "expo-image-manipulator": "~11.8.0",
    "expo-image-picker": "~14.7.1",
    "expo-linear-gradient": "~12.7.2",
    "expo-location": "~16.5.5",
    "expo-media-library": "~15.9.2",
    "expo-splash-screen": "~0.26.4",
    "expo-status-bar": "~1.11.1",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-native": "0.73.6",
    "react-native-auth0": "^3.1.0",
    "react-native-gesture-handler": "~2.14.0",
    "react-native-image-picker": "^7.1.0",
    "react-native-maps": "1.10.0",
    "react-native-pager-view": "6.2.3",
    "react-native-reanimated": "~3.6.2",
    "react-native-safe-area-context": "4.8.2",
    "react-native-svg": "14.1.0",
    "react-native-tab-view": "^3.5.1",
    "react-native-textinput-effects": "^0.6.3",
    "react-native-walkthrough-tooltip": "^1.5.0",
    "react-native-web": "~0.19.6",
    "stream-chat-expo": "^5.27.1"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@types/react": "~18.2.45",
    "@types/react-native": "^0.73.0",
    "@typescript-eslint/eslint-plugin": ">=5.43.0",
    "@typescript-eslint/parser": ">=5.43.0",
    "babel-plugin-module-resolver": "^5.0.0",
    "dependency-cruiser": "^16.2.0",
    "eslint": "8",
    "eslint-config-standard-with-typescript": "^43.0.1",
    "eslint-config-xo": "^0.44.0",
    "eslint-config-xo-typescript": "^2.0.0",
    "eslint-plugin-import": "^2.25.2",
    "eslint-plugin-n": "^16.6.2",
    "eslint-plugin-promise": "^6.0.0",
    "eslint-plugin-react": "^7.32.2",
    "madge": "^6.0.0",
    "react-native-screens": "~3.29.0",
    "react-native-svg-transformer": "^1.0.0",
    "typescript": "^5.3.0"
  },
  "private": true
}

Device:

adb -s emulator-5554 shell getprop ro.build.version.sdk
31
adb -s emulator-5554 shell getprop ro.product.brand
google
adb -s emulator-5554 shell getprop ro.product.model
sdk_gphone64_x86_64
adb -s emulator-5554 shell getprop ro.build.version.release
12

Running:

npx expo start -c -> a

khushal87 commented 6 months ago

Hey @david-shiko, we have this sample app where we use bottom tabs, and it works well. Your issue doesn't give me any clarity on what you might be facing. Please follow the sample app, and this should work fine for you. I don't think it's a fault of our components like OverlayProvider.

https://github.com/GetStream/stream-chat-react-native/tree/develop/examples/SampleApp

david-shiko commented 6 months ago

Hey @david-shiko, we have this sample app where we use bottom tabs, and it works well. Your issue doesn't give me any clarity on what you might be facing. Please follow the sample app, and this should work fine for you. I don't think it's a fault of our components like OverlayProvider.

https://github.com/GetStream/stream-chat-react-native/tree/develop/examples/SampleApp

I have already reviewed the sample app before posing my question, but found it not very informative due to its extensive use of styles. Maybe the sample app have encountered the same issue and resorted to using "position: absolute" as a workaround. BTW I believe that the styles in the demo are excessive and not necessary for addressing the fundamental problem.