stream-chat-react-native icon indicating copy to clipboard operation
stream-chat-react-native copied to clipboard

[🐛] Ghost like view on Android and iOS

Open 2200software opened this issue 4 months ago • 8 comments

🔥

Issue

There is a white ghost like view that probably has something related to keyboardVerticalOffset or your KeyboardCompatibleView (nor sure about this, just a hunch).

The observations are that on android, after the keyboard is dismissed this white view still remains on screen and does not get automatically dismissed. For IOS the bug seems milder, there is this white view that moves when a view on another zIndex changes its height.

Steps to reproduce

Steps to reproduce the behavior:

  1. Make a normal channel component as attached
  2. Change the client theme to dark theme so that you can see these white views

Expected behavior

This white view doesnt exist on Android or automatically gets dismissed, making it transparent on android would probably not help because it will still capture the touch events. This white moving view can be made transparent on iOS.

Project Related Information

Customization

Click To Expand

                    <Channel
                        MessageAvatar={(props) => <CustomMessageAvatar {...props} />}
                        channel={channel}
                        hasCommands={false}
                        keyboardVerticalOffset={iosVerticalOffset}
                        keyboardBehavior='padding'
                        thread={thread} threadList={!!thread}>
                        {thread ? (
                            <Thread />
                        ) : (
                            <>
                                <MessageList onThreadSelect={(thread) => { setThread(thread) }} />
                                <MessageInput />
                            </>
                        )}
                    </Channel>

Offline support

  • [ ] I have enabled offline support.
  • [ ] The feature I'm having does not occur when offline support is disabled. (stripe out if not applicable)

Environment

Click To Expand

package.json:

{
  "name": "",
  "version": "1.0.0",
  "main": "expo-router/entry",
  "scripts": {
    "start": "expo start",
    "reset-project": "node ./scripts/reset-project.js",
    "android": "expo run:android",
    "ios": "expo run:ios",
    "web": "expo start --web",
    "test": "jest --watchAll",
    "lint": "expo lint"
  },
  "jest": {
    "preset": "jest-expo"
  },
  "dependencies": {
    "@expo/vector-icons": "^14.1.0",
    "@notifee/react-native": "^9.1.8",
    "@react-native-async-storage/async-storage": "2.1.2",
    "@react-native-camera-roll/camera-roll": "^7.9.0",
    "@react-native-community/checkbox": "^0.5.17",
    "@react-native-community/cli-platform-android": "^15.1.3",
    "@react-native-community/datetimepicker": "8.4.1",
    "@react-native-community/netinfo": "11.4.1",
    "@react-native-community/slider": "4.5.6",
    "@react-native-firebase/app": "^22.4.0",
    "@react-native-firebase/app-check": "^22.4.0",
    "@react-native-firebase/auth": "^22.4.0",
    "@react-native-firebase/firestore": "^22.4.0",
    "@react-native-firebase/functions": "^22.4.0",
    "@react-native-firebase/messaging": "^22.4.0",
    "@react-native-firebase/storage": "^22.4.0",
    "@react-navigation/drawer": "^7.1.1",
    "@react-navigation/native": "^7.0.14",
    "@stream-io/flat-list-mvcp": "^0.10.3",
    "axios": "^1.11.0",
    "babel-plugin-transform-remove-console": "^6.9.4",
    "expo": "^53.0.20",
    "expo-av": "~15.1.7",
    "expo-build-properties": "~0.14.8",
    "expo-clipboard": "~7.1.5",
    "expo-constants": "~17.1.7",
    "expo-dev-client": "~5.2.4",
    "expo-document-picker": "~13.1.6",
    "expo-file-system": "~18.1.11",
    "expo-font": "~13.3.2",
    "expo-haptics": "~14.1.4",
    "expo-image-manipulator": "~13.1.7",
    "expo-image-picker": "~16.1.4",
    "expo-linking": "~7.1.7",
    "expo-localization": "~16.1.6",
    "expo-location": "~18.1.6",
    "expo-media-library": "~17.1.7",
    "expo-router": "~5.1.4",
    "expo-sharing": "~13.1.5",
    "expo-splash-screen": "~0.30.10",
    "expo-system-ui": "~5.0.10",
    "expo-web-browser": "~14.2.0",
    "fast-xml-parser": "^4.4.0",
    "i18next": "^24.2.3",
    "openai": "^4.47.1",
    "react": "19.0.0",
    "react-dom": "19.0.0",
    "react-i18next": "^15.4.1",
    "react-native": "0.79.5",
    "react-native-currency-input": "^1.1.1",
    "react-native-element-dropdown": "^2.12.0",
    "react-native-geolocation-service": "^5.3.1",
    "react-native-gesture-handler": "~2.24.0",
    "react-native-get-random-values": "~1.11.0",
    "react-native-google-places-textinput": "file:./modules/react-native-google-places-textinput",
    "react-native-image-crop-picker": "^0.41.1",
    "react-native-mmkv": "^3.2.0",
    "react-native-progress-steps": "^1.3.4",
    "react-native-purchases": "^8.5.0",
    "react-native-purchases-ui": "^8.5.0",
    "react-native-reanimated": "~3.17.4",
    "react-native-safe-area-context": "5.4.0",
    "react-native-screens": "~4.11.1",
    "react-native-sha256": "^1.4.10",
    "react-native-star-rating-widget": "^1.9.1",
    "react-native-svg": "15.11.2",
    "react-native-web": "^0.20.0",
    "stream-chat-expo": "^8.3.1"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@react-native-community/cli": "^15.1.3",
    "typescript": "~5.8.3"
  },
  "private": true
}

react-native info output:

System:
  OS: macOS 15.2
  CPU: (8) arm64 Apple M2
  Memory: 166.34 MB / 8.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 23.10.0
    path: /opt/homebrew/bin/node
  Yarn:
    version: 1.22.22
    path: /opt/homebrew/bin/yarn
  npm:
    version: 10.9.2
    path: /opt/homebrew/bin/npm
  Watchman:
    version: 2025.03.10.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.16.2
    path: /opt/homebrew/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 24.0
      - iOS 18.0
      - macOS 15.0
      - tvOS 18.0
      - visionOS 2.0
      - watchOS 11.0
  Android SDK: Not Found
IDEs:
  Android Studio: 2025.1 AI-251.26094.121.2512.13840223
  Xcode:
    version: 16.0/16A242d
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.11
    path: /usr/bin/javac
  Ruby:
    version: 3.4.1
    path: /opt/homebrew/opt/ruby/bin/ruby
npmPackages:
  "@react-native-community/cli":
    installed: 15.1.3
    wanted: ^15.1.3
  react:
    installed: 19.0.0
    wanted: 19.0.0
  react-native:
    installed: 0.79.5
    wanted: 0.79.5
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: true
iOS:
  hermesEnabled: true
  newArchEnabled: true
  • Platform that you're experiencing the issue on:
    • [ x] iOS
    • [ x] Android
    • [ ] iOS but have not tested behavior on Android
    • [ ] Android but have not tested behavior on iOS
    • [ x] Both
  • stream-chat-react-native version you're using that has this issue:
    • 8.3.1
  • Device/Emulator info:
    • [ x] I am using a physical device
    • OS version: Android 12
    • Device/Emulator: iPhone 16

Additional context

Screenshots

Click To Expand

https://github.com/user-attachments/assets/ef220d4f-e8e0-4efa-90db-476ade9e2946 https://github.com/user-attachments/assets/1f1d76ad-d9a7-456f-b246-251871d18535


2200software avatar Aug 15 '25 18:08 2200software

i am facing same issue

12varun12 avatar Aug 25 '25 07:08 12varun12

@2200software is your issue resolved ?

12varun12 avatar Aug 26 '25 03:08 12varun12

nope, still the same

2200software avatar Aug 29 '25 17:08 2200software

no its a bug in latest version, the bottomsheet attachment picker gets toggled each time keyboard is closed.

I found version 7.2.8 most stable, use that one, 8.x is still in beta I think with so many bugs.

work around

useEffect(() => {
 const didHide = Keyboard.addListener("keyboardDidHide", () => {
   closeAttachmentPicker();
 });
 return () => {
   didHide.remove();
 };
}, []);

you can expect a slight lag when the keyboard hides and the bottomsheet closes, we have to wait until the developers decide to work on it and fix it

https://github.com/user-attachments/assets/f1eb138c-765e-4faa-8fa3-53a0d45dc8c2

iAhtasham avatar Sep 09 '25 23:09 iAhtasham

no its a bug in latest version, the bottomsheet attachment picker gets toggled each time keyboard is closed.

I found version 7.2.8 most stable, use that one, 8.x is still in beta I think with so many bugs.

work around

useEffect(() => { const didHide = Keyboard.addListener("keyboardDidHide", () => { closeAttachmentPicker(); }); return () => { didHide.remove(); }; }, []); you can expect a slight lag when the keyboard hides and the bottomsheet closes, we have to wait until the developers decide to work on it and fix it

Record_2025-09-10-04-13-04_00ed75b494686ed80a675e715cb7f4c4.mp4

I’m using that version but still experiencing the issue. I have wrapped all of my screens inside the Chat component, and that seems to be causing the problem across every screen. When I commented out the wrapper and ran the code, it worked fine.

Vijay-Magadum avatar Sep 18 '25 10:09 Vijay-Magadum

I’ve patched the package locally and it resolves the ghost issue on both Android and iOS. "stream-chat-react-native": "8.5.2", "react-native": "0.80.2",

What was fixed:

  • Gallery thumbnails: Removed the -1 offset on height/width and simplified container styles. This prevents the ghost overlay effect on images.
  • Thumbnail building: Always using cover mode for resize, so thumbnails consistently fill their container instead of leaving gaps.
  • Attachment picker & keyboard: Removed the keyboard event listener that was closing/reopening the picker whenever the keyboard appeared. Now, the picker only responds to user interaction (tapping the attachment button), which resolves the annoying picker/keyboard conflict.

Here is the full patch: patches/stream-chat-react-native-core+8.5.2.patch

index 7da851d..884ea42 100644
--- a/node_modules/stream-chat-react-native-core/src/components/Attachment/Gallery.tsx
+++ b/node_modules/stream-chat-react-native-core/src/components/Attachment/Gallery.tsx
@@ -448,8 +448,8 @@ const GalleryImageThumbnail = ({
     <View
       style={[
         {
-          height: thumbnail.height - 1,
-          width: thumbnail.width - 1,
+          height: thumbnail.height,
+          width: thumbnail.width,
         },
         gallery.thumbnail,
       ]}
@@ -476,8 +476,8 @@ const GalleryImageThumbnail = ({
             style={[
               borderRadius,
               {
-                height: thumbnail.height - 1,
-                width: thumbnail.width - 1,
+                height: thumbnail.height,
+                width: thumbnail.width,
               },
               gallery.image,
             ]}
@@ -685,9 +685,8 @@ const styles = StyleSheet.create({
     display: 'flex',
     flexDirection: 'row',
     justifyContent: 'center',
-    padding: 1,
   },
-  imageContainerStyle: { alignItems: 'center', flex: 1, justifyContent: 'center' },
+  imageContainerStyle: { alignItems: 'center', justifyContent: 'center' },
   imageLoadingErrorIndicatorStyle: {
     bottom: 4,
     left: 4,
diff --git a/node_modules/stream-chat-react-native-core/src/components/Attachment/utils/buildGallery/buildThumbnail.ts b/node_modules/stream-chat-react-native-core/src/components/Attachment/utils/buildGallery/buildThumbnail.ts
index 3132979..c4bb64f 100644
--- a/node_modules/stream-chat-react-native-core/src/components/Attachment/utils/buildGallery/buildThumbnail.ts
+++ b/node_modules/stream-chat-react-native-core/src/components/Attachment/utils/buildGallery/buildThumbnail.ts
@@ -36,7 +36,7 @@ export function buildThumbnail({
     height,
     resizeMode: resizeMode
       ? resizeMode
-      : ((image.original_height && image.original_width ? 'contain' : 'cover') as ImageResizeMode),
+      : ('cover' as ImageResizeMode), // Always use 'cover' to fill the container completely
     thumb_url: image.thumb_url,
     type: image.type,
     url: shouldResize
diff --git a/node_modules/stream-chat-react-native-core/src/components/AttachmentPicker/AttachmentPicker.tsx b/node_modules/stream-chat-react-native-core/src/components/AttachmentPicker/AttachmentPicker.tsx
index 18ff1f1..7327ba2 100644
--- a/node_modules/stream-chat-react-native-core/src/components/AttachmentPicker/AttachmentPicker.tsx
+++ b/node_modules/stream-chat-react-native-core/src/components/AttachmentPicker/AttachmentPicker.tsx
@@ -178,29 +178,11 @@ export const AttachmentPicker = React.forwardRef(
       return () => backHandler.remove();
     }, [selectedPicker, closePicker, setSelectedPicker]);
 
-    useEffect(() => {
-      const onKeyboardOpenHandler = () => {
-        if (selectedPicker) {
-          setSelectedPicker(undefined);
-        }
-        closePicker();
-      };
-      const keyboardShowEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
-      const keyboardSubscription = Keyboard.addListener(keyboardShowEvent, onKeyboardOpenHandler);
-
-      return () => {
-        // Following if-else condition to avoid deprecated warning coming RN 0.65
-        if (keyboardSubscription?.remove) {
-          keyboardSubscription.remove();
-          return;
-        }
-        // @ts-ignore
-        else if (Keyboard.removeListener) {
-          // @ts-ignore
-          Keyboard.removeListener(keyboardShowEvent, onKeyboardOpenHandler);
-        }
-      };
-    }, [closePicker, selectedPicker, setSelectedPicker]);
+    // Removed keyboard event listener that was causing the attachment picker
+    // to close when keyboard opens. The picker should only be controlled by
+    // user interaction (clicking the attachment button), not by keyboard events.
+    // This prevents the unwanted behavior where the picker becomes visible
+    // when the keyboard opens.
 
     useEffect(() => {
       if (currentIndex < 0) {

mudassir-iqbal avatar Oct 06 '25 11:10 mudassir-iqbal

This change has fixed my issue — possibly BottomSheetFlatList renders an empty scroll container even when the data array is empty. This empty container still takes layout space inside the BottomSheet, causing the sheet to open or expand unexpectedly.

node_modules/stream-chat-react-native-core/src/components/AttachmentPicker/AttachmentPicker.tsx

{selectedPhotos?.length > 0 && (
  <BottomSheetFlatList
    ...
  />
)}
// Fix: FlatList takes full space even with empty data, causing BottomSheet to open.
// So render FlatList only when photos are available.
{selectedPhotos?.length > 0 && (
  <BottomSheetFlatList
    contentContainerStyle={[
      styles.container,
      { backgroundColor: white },
      bottomSheetContentContainer,
      { opacity: photoError ? 0 : 1 },
    ]}
    data={selectedPhotos}
    keyExtractor={(item) => item.asset.uri}
    numColumns={numberOfAttachmentPickerImageColumns ?? 3}
    onEndReached={photoError ? undefined : getMorePhotos}
    renderItem={renderAttachmentPickerItem}
    testID={'attachment-picker-list'}
  />
)}

parth-brilworks avatar Nov 20 '25 10:11 parth-brilworks

An alternative workaround that appears to be effective is forcing the resolution of @gorhom/bottom-sheet to version 5.1.4. Versions above 5.1.4 seem to result in this issue.

The override object is placed in package.json:

  "overrides": {
    "stream-chat-react-native-core": {
      "@gorhom/bottom-sheet": "5.1.4"
    }
  }

See also https://github.com/GetStream/stream-chat-react-native/issues/1741

For our project we are still on Stream 7.3.0 so unsure if this workaround would be effective on version 8 or higher, but may be a simpler approach versus patching.

chrisknepper-ef avatar Nov 20 '25 20:11 chrisknepper-ef

This change has fixed my issue — possibly BottomSheetFlatList renders an empty scroll container even when the data array is empty. This empty container still takes layout space inside the BottomSheet, causing the sheet to open or expand unexpectedly.

node_modules/stream-chat-react-native-core/src/components/AttachmentPicker/AttachmentPicker.tsx

{selectedPhotos?.length > 0 && (
  <BottomSheetFlatList
    ...
  />
)}
// Fix: FlatList takes full space even with empty data, causing BottomSheet to open.
// So render FlatList only when photos are available.
{selectedPhotos?.length > 0 && (
  <BottomSheetFlatList
    contentContainerStyle={[
      styles.container,
      { backgroundColor: white },
      bottomSheetContentContainer,
      { opacity: photoError ? 0 : 1 },
    ]}
    data={selectedPhotos}
    keyExtractor={(item) => item.asset.uri}
    numColumns={numberOfAttachmentPickerImageColumns ?? 3}
    onEndReached={photoError ? undefined : getMorePhotos}
    renderItem={renderAttachmentPickerItem}
    testID={'attachment-picker-list'}
  />
)}

This will "fix" the issue but then you won't see any recent images in the tray when you go to add a photo.

programthis avatar Dec 16 '25 15:12 programthis