Skip to content
This repository was archived by the owner on Sep 12, 2023. It is now read-only.

Commit cdef4bc

Browse files
committed
docs: adds custom background steps
1 parent 7a1f216 commit cdef4bc

File tree

1 file changed

+323
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)