Skip to content

Commit b4a13cc

Browse files
authored
Merge pull request #1367 from GetStream/develop
Next Release - v4.5.0
2 parents 04e44c5 + 50a5e1e commit b4a13cc

Some content is hidden

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

50 files changed

+1285
-7275
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ NEXT_RELEASE_CHANGELOG.md
33
artifacts
44
e2e/.env
55
*.log
6+
.DS_STORE

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,17 @@ For complete pricing details visit our [Chat Pricing Page](https://getstream.io/
4242

4343
## 🔮 Example Apps
4444

45-
This repo includes 4 example apps. One made with Expo, one Native JavaScript code, and two in TypeScript. One TypeScript app is a simple implementation for reference, the other is a more full featured app example.
45+
This repo includes 3 example apps. One made with Expo, two in TypeScript. One TypeScript app is a simple implementation for reference, the other is a more full featured app example.
4646

4747
- [Expo example](./examples/ExpoMessaging)
48-
- [Native example](./examples/NativeMessaging)
4948
- [Typescript example](./examples/TypeScriptMessaging)
5049
- [Fully featured messaging application](./examples/SampleApp)
5150

5251
Besides, our team maintains a dedicated repository for fully-fledged sample applications and demos at [GetStream/react-native-samples](https://github.com/GetStream/react-native-samples). Please consider checking following sample applications:
5352

5453
- [Slack Clone](https://github.com/GetStream/react-native-samples/tree/main/projects/SlackClone#slack-clone-using-react-native-and-stream-chat)
5554
- [iMessage Clone](https://github.com/GetStream/react-native-samples/tree/main/projects/iMessageClone#imessage-clone)
55+
- [WhatsApp Clone](https://github.com/GetStream/react-native-samples/tree/main/projects/WhatsAppClone#whatsapp-clone-using-react-native-and-stream-chat)
5656

5757
## 💬 Keep in mind
5858

docusaurus/docs/reactnative/basics/getting_started.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ To be able to use the Stream Chat React Native SDK, a few dependencies must meet
9292

9393
| react-native | stream-chat-react-native (min required) | react-native-reanimated (min required) |
9494
| ------------ | --------------------------------------- | -------------------------------------- |
95+
| 0.67 | 4.2.0 | 2.4.0 |
9596
| 0.66 | 3.9.0 | 2.2.3 |
9697
| 0.65 | 3.9.0 | 2.2.1 |
9798
| 0.64 | 3.6.2 | 2.2.0 |

docusaurus/docs/reactnative/common-content/core-components/channel/props/on_press_message.mdx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,27 @@ You will have to handle these cases when overriding this function.
1111
| -------- |
1212
| function |
1313

14-
| Parameter | Description |
15-
| --------- | ----------------------------- |
16-
| payload | `{ actionHandlers, message }` |
14+
| Parameter | Description |
15+
| --------- | --------------------------------------------- |
16+
| payload | `{ additionalInfo, actionHandlers, message }` |
17+
18+
The `additionalInfo` prop is handy for getting information from certain click events.
19+
A good example of this is getting the user details when a textMention (for example @Enigma-I-am) is clicked.
20+
21+
For example:
22+
23+
```tsx
24+
<Channel
25+
onPressMessage={({ additionalInfo, defaultHandler, emitter }) => {
26+
if (emitter === 'textMention') {
27+
console.log(additionalInfo?.user);
28+
return;
29+
}
30+
defaultHandler?.();
31+
}}
32+
>
33+
```
34+
35+
:::info
36+
37+
The `additionalInfo` prop will change over time as we explore more usecases for different `emitter's`.
Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
---
2+
id: channel-background-customization
3+
sidebar_position: 13
4+
title: Channel Background Customization
5+
---
6+
7+
## Basic Custom Background
8+
9+
You can change the background statically by wrapping `MessageList` and `MessageInput` with the `ImageBackground` component.
10+
11+
<img
12+
src='https://user-images.githubusercontent.com/25864161/167857632-c0bc9d67-0a84-4cf5-9d75-305e3bcd1f3d.png'
13+
width='320px'
14+
/>
15+
16+
Also make sure you adjust the `theme` correctly.
17+
18+
```tsx
19+
import { Channel, MessageInput, MessageList, ThemeProvider } from 'stream-chat-react-native';
20+
import { ImageBackground } from 'react-native';
21+
22+
export const theme = {
23+
messageList: {
24+
container: {
25+
backgroundColor: 'transparent',
26+
},
27+
},
28+
};
29+
30+
const IMAGE_URI =
31+
'https://images.unsplash.com/photo-1549125764-91425ca48850?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxleHBsb3JlLWZlZWR8NjF8fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=800&q=60';
32+
33+
const ChannelScreen = ({ channel }) => (
34+
<ThemeProvider style={theme}>
35+
<Channel channel={channel}>
36+
<ImageBackground
37+
style={{ flex: 1 }}
38+
source={{
39+
uri: IMAGE_URI,
40+
}}
41+
>
42+
<MessageList />
43+
<MessageInput />
44+
</ImageBackground>
45+
</Channel>
46+
</ThemeProvider>
47+
);
48+
```
49+
50+
---
51+
52+
## Custom Background With Selection Screen
53+
54+
In this step, we will add a button that will navigate to a separate screen, where the user will be able to select their
55+
favorite background image for a specific channel.
56+
57+
<table>
58+
<tr>
59+
<td align='center' width='50%'>
60+
<img src='https://user-images.githubusercontent.com/25864161/168006715-acae4b85-00cb-4b45-a127-aa8f94c13895.png' />
61+
</td>
62+
<td align='center' width='50%'>
63+
<img src='https://user-images.githubusercontent.com/25864161/168006193-8fd4ad85-7553-4956-a7c6-5d6979e15ee4.png' />
64+
</td>
65+
</tr>
66+
<tr></tr>
67+
<tr>
68+
<td align='center'>
69+
<strong>Chat screen with customize background button</strong>
70+
</td>
71+
<td align='center'>
72+
<strong>Wallpaper overview screen with background image options</strong>
73+
</td>
74+
</tr>
75+
</table>
76+
77+
### Store and manage channel preferences
78+
79+
To persist the channel preferences (at the moment, only the URI of the selected background), we will need to store some data.
80+
We will do it by using `react-native-mmkv`, a key-value storage [framework](https://github.com/mrousavy/react-native-mmkv#mmkv).
81+
82+
Follow the [installation steps](https://github.com/mrousavy/react-native-mmkv#installation), and let's get started, shall we?
83+
84+
We will start by creating our `ChannelBackgroundView` component.
85+
This component will be in charge of rendering the custom background by retrieving it from our key-value store.
86+
We save an object to a key-value store to be scalable and future-proof.
87+
You might want to add other preferences later, such as dimming value, background color, etc.
88+
89+
```tsx
90+
import type { ViewProps } from 'react-native';
91+
import { useMMKVObject } from 'react-native-mmkv';
92+
93+
type ChannelPreferences = {
94+
imageUri: string;
95+
};
96+
97+
const DEFAULT_BACKGROUND_URI = 'https://i.redd.it/3jfjc53fsyb61.jpg';
98+
99+
const ChannelBackgroundView = ({
100+
channelId,
101+
...props
102+
}: {
103+
channelId: string;
104+
} & ViewProps) => {
105+
const [channelPreferences] = useMMKVObject<ChannelPreferences>(channelId);
106+
const uri = channelPreferences?.imageUri || DEFAULT_BACKGROUND_URI;
107+
108+
return <ImageBackground {...props} source={{ uri }} />;
109+
};
110+
```
111+
112+
We will then use it in our previously built `ChannelScreen`.
113+
Replace the static `ImageBackground` with `ChannelBackgroundView` and pass the `channelId`.
114+
115+
```tsx
116+
const ChannelScreen = ({ channel }) => {
117+
return (
118+
<ThemeProvider style={theme}>
119+
<Channel channel={channel}>
120+
<ChannelBackgroundView channelId={channel?.id} style={{ flex: 1 }}>
121+
<MessageList />
122+
<MessageInput />
123+
</ChannelBackgroundView>
124+
</Channel>
125+
</ThemeProvider>
126+
);
127+
};
128+
```
129+
130+
---
131+
132+
### Wallpaper overview screen
133+
134+
Let's now add a screen where the user can choose a wallpaper from a particular predefined list of images.
135+
136+
```tsx
137+
import { StackNavigationProp } from '@react-navigation/stack';
138+
import { RouteProp } from '@react-navigation/native';
139+
import { useMMKVObject } from 'react-native-mmkv';
140+
import { View, SafeAreaView, Pressable, Image, StyleSheet } from 'react-native';
141+
142+
const WallpaperOverviewScreen = ({
143+
navigation: { navigate },
144+
route: {
145+
params: { channelId },
146+
},
147+
}: WallpaperOverviewScreenProps) => {
148+
const [_, setChannelPreferences] = useMMKVObject<ChannelPreferences>(channelId);
149+
return (
150+
<SafeAreaView
151+
style={{
152+
flex: 1,
153+
justifyContent: 'center',
154+
}}
155+
>
156+
<View style={styles.container}>
157+
{BRIGHT_IMAGES?.map(({ imageUri = '' }, i) => {
158+
const handleOnPress = () => {
159+
setChannelPreferences({ imageUri });
160+
navigate('Channel');
161+
};
162+
return (
163+
<Pressable
164+
key={i}
165+
onPress={handleOnPress}
166+
style={{
167+
margin: 1,
168+
width: GRID_ITEM_WIDTH,
169+
}}
170+
>
171+
<Image style={styles.image} source={{ uri: imageUri }} />
172+
</Pressable>
173+
);
174+
})}
175+
</View>
176+
</SafeAreaView>
177+
);
178+
};
179+
180+
type StackNavigatorParamList = {
181+
WallpaperOverviewScreen: {
182+
channelId: string;
183+
};
184+
};
185+
186+
type WallpaperOverviewScreenProps = {
187+
navigation: StackNavigationProp<StackNavigatorParamList, 'WallpaperOverviewScreen'>;
188+
route: RouteProp<StackNavigatorParamList, 'WallpaperOverviewScreen'>;
189+
};
190+
191+
type ChannelPreferences = {
192+
imageUri: string;
193+
};
194+
195+
const GRID_ITEM_WIDTH = '32.7%';
196+
197+
// Some random images that will get you started
198+
const BRIGHT_IMAGES = [
199+
'https://images.unsplash.com/photo-1549125764-91425ca48850?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxleHBsb3JlLWZlZWR8NjF8fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=800&q=60',
200+
'https://images.unsplash.com/photo-1549241520-425e3dfc01cb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxleHBsb3JlLWZlZWR8ODB8fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=800&q=60',
201+
'https://images.unsplash.com/photo-1554226321-24fdcddd5a55?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxleHBsb3JlLWZlZWR8MjE5fHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=800&q=60',
202+
'https://images.unsplash.com/photo-1550006490-9f0656b79e9d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxleHBsb3JlLWZlZWR8ODl8fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=800&q=60',
203+
'https://images.unsplash.com/photo-1551506448-074afa034c05?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxleHBsb3JlLWZlZWR8MTEzfHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=800&q=60',
204+
'https://images.unsplash.com/photo-1553114835-6f7674d3c2c0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxleHBsb3JlLWZlZWR8MTMyfHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=800&q=60',
205+
'https://images.unsplash.com/photo-1553075712-453f7213c24f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxleHBsb3JlLWZlZWR8MTMzfHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=800&q=60',
206+
'https://images.unsplash.com/photo-1551917951-148edcd8ea8d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxleHBsb3JlLWZlZWR8MTU3fHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=800&q=60',
207+
'https://images.unsplash.com/photo-1553969923-bbf0cac2666b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxleHBsb3JlLWZlZWR8MjA3fHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=800&q=60',
208+
'https://images.unsplash.com/photo-1553194642-29b272a173b9?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxleHBsb3JlLWZlZWR8MTcwfHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=800&q=60',
209+
'https://images.unsplash.com/photo-1553356084-58ef4a67b2a7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxleHBsb3JlLWZlZWR8MTcxfHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=800&q=60',
210+
'https://images.unsplash.com/photo-1553526777-5ffa3b3248d8?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxleHBsb3JlLWZlZWR8MTk4fHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=800&q=60',
211+
].map(imageUri => ({
212+
imageUri,
213+
}));
214+
215+
const styles = StyleSheet.create({
216+
container: {
217+
flexDirection: 'row',
218+
flex: 1,
219+
alignContent: 'stretch',
220+
flexWrap: 'wrap',
221+
padding: 6,
222+
},
223+
image: {
224+
flex: 1,
225+
width: '100%',
226+
},
227+
});
228+
```
229+
230+
:::note
231+
Be aware of the fact that channel preferences were implemented with MMKV, a key-value storage framework.
232+
There are alternative approaches to achieving the same goal, such as saving the channel preferences as [custom data](https://getstream.io/chat/docs/javascript/channel_update/?language=javascript) on Stream's channel object.
233+
:::
234+
235+
### Add a configuration button
236+
237+
We will now add a button that will take the user from the Channel screen to our new WallpaperOverview screen.
238+
239+
```tsx
240+
import { useNavigation } from '@react-navigation/native';
241+
import { Channel, MessageInput, MessageList, ThemeProvider } from 'stream-chat-react-native';
242+
import { Pressable, Text, StyleSheet } from 'react-native';
243+
244+
const ChannelScreen = ({ channel }) => {
245+
const { navigate } = useNavigation();
246+
const handleMenuOnPress = () => navigate('WallpaperOverviewScreen', { channelId: channel?.id });
247+
248+
return (
249+
<ThemeProvider style={theme}>
250+
<Channel channel={channel}>
251+
<ChannelBackgroundView channelId={channel?.id} style={{ flex: 1 }}>
252+
<Pressable style={styles.menuButton} onPress={handleMenuOnPress}>
253+
<Text>🎨</Text>
254+
</Pressable>
255+
<MessageList />
256+
<MessageInput />
257+
</ChannelBackgroundView>
258+
</Channel>
259+
</ThemeProvider>
260+
);
261+
};
262+
263+
const styles = StyleSheet.create({
264+
menuButton: {
265+
position: 'absolute',
266+
right: 0,
267+
top: 0,
268+
backgroundColor: 'rgba(255,87,56,0.65)',
269+
borderRadius: 36,
270+
padding: 16,
271+
margin: 16,
272+
alignItems: 'center',
273+
zIndex: 10,
274+
},
275+
});
276+
277+
export const theme = {
278+
messageList: {
279+
container: {
280+
backgroundColor: 'transparent',
281+
},
282+
},
283+
};
284+
```
285+
286+
---
287+
288+
### Optional: Connect all screens by navigation
289+
290+
If applicable to your use case, add our screens to a Navigation Stack by doing the following:
291+
292+
```tsx
293+
import { createNativeStackNavigator } from 'react-native-screens/native-stack';
294+
import { NavigationContainer } from '@react-navigation/native';
295+
296+
const Stack = createNativeStackNavigator();
297+
298+
export default () => {
299+
return (
300+
<SafeAreaProvider>
301+
<ThemeProvider style={theme}>
302+
<NavigationContainer>
303+
<Stack.Navigator initialRouteName='Channel'>
304+
<Stack.Screen component={ChannelScreen} name='Channel' options={noHeaderOptions} />
305+
<Stack.Screen component={WallpaperOverviewScreen} name='WallpaperOverviewScreen' />
306+
</Stack.Navigator>
307+
</NavigationContainer>
308+
</ThemeProvider>
309+
</SafeAreaProvider>
310+
);
311+
};
312+
```

examples/SampleApp/ios/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -848,4 +848,4 @@ SPEC CHECKSUMS:
848848

849849
PODFILE CHECKSUM: a640bd2ecc4e73329d8379590f3ee5bc09ecba5f
850850

851-
COCOAPODS: 1.11.2
851+
COCOAPODS: 1.11.3

0 commit comments

Comments
 (0)