Skip to content

Commit 1495d0d

Browse files
authored
fix: ui redesign bugs (#3507)
## 🎯 Goal This PR restores a few message and audio UX behaviours that regressed from develop. It brings thread-list draft previews back, moves message timestamps into the footer next to status, stops audio from auto-resuming after seek in both message attachments and composer previews, and slightly tightens the voice recording autosend path. Included changes: - Restore thread draft previews in `ThreadListItem` - Move `MessageTimestamp` out of `MessageStatus` and render it in `MessageFooter` - Stop autoplay after seeking in `AudioAttachment` and `AudioRecordingPreview` - Reduce voice-recording autosend overhead in `useAudioRecorder` - Add the thread-list draft preview theming/context support and update the related thread snapshot/test coverage ## 🛠 Implementation details <!-- Provide a description of the implementation --> ## 🎨 UI Changes <!-- Add relevant screenshots --> <details> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch - [ ] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android
1 parent 19dcc2f commit 1495d0d

File tree

10 files changed

+149
-70
lines changed

10 files changed

+149
-70
lines changed

package/src/components/Attachment/Audio/AudioAttachment.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@ export const AudioAttachment = (props: AudioAttachmentProps) => {
168168
const dragEnd = async (currentProgress: number) => {
169169
const positionInSeconds = (currentProgress * duration) / ONE_SECOND_IN_MILLISECONDS;
170170
await audioPlayer.seek(positionInSeconds);
171-
audioPlayer.play();
172171
};
173172

174173
const onSpeedChangeHandler = async () => {

package/src/components/Message/MessageItemView/MessageFooter.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type MessageFooterPropsWithContext = Pick<
3737
| 'lastGroupMessage'
3838
| 'isMessageAIGenerated'
3939
> &
40-
Pick<MessagesContextValue, 'MessageStatus'> &
40+
Pick<MessagesContextValue, 'MessageStatus' | 'MessageTimestamp'> &
4141
MessageFooterComponentProps;
4242

4343
const MessageFooterWithContext = (props: MessageFooterPropsWithContext) => {
@@ -50,6 +50,7 @@ const MessageFooterWithContext = (props: MessageFooterPropsWithContext) => {
5050
members,
5151
message,
5252
MessageStatus,
53+
MessageTimestamp,
5354
showMessageStatus,
5455
} = props;
5556
const styles = useStyles();
@@ -77,9 +78,12 @@ const MessageFooterWithContext = (props: MessageFooterPropsWithContext) => {
7778
return (
7879
<View style={[styles.container, container]} testID='message-status-time'>
7980
{Object.keys(members).length > 2 && alignment === 'left' && message.user?.name ? (
80-
<Text style={[styles.name, name]}>{message.user.name}</Text>
81+
<Text numberOfLines={1} ellipsizeMode='tail' style={[styles.name, name]}>
82+
{message.user.name}
83+
</Text>
8184
) : null}
82-
{showMessageStatus && <MessageStatus formattedDate={formattedDate} timestamp={date} />}
85+
{showMessageStatus ? <MessageStatus /> : null}
86+
<MessageTimestamp formattedDate={formattedDate} timestamp={date} />
8387
{isEdited ? <Text style={[styles.editedText, editedText]}>{t('Edited')}</Text> : null}
8488
</View>
8589
);
@@ -201,13 +205,15 @@ const useStyles = () => {
201205
return useMemo(() => {
202206
return StyleSheet.create({
203207
container: {
208+
maxWidth: '100%',
204209
alignItems: 'center',
205210
flexDirection: 'row',
206211
justifyContent: 'center',
207212
paddingVertical: primitives.spacingXxs,
208213
gap: primitives.spacingXs,
209214
},
210215
name: {
216+
flexShrink: 1,
211217
color: shouldUseOverlayStyles ? semantics.textOnAccent : semantics.chatTextUsername,
212218
fontSize: primitives.typographyFontSizeXs,
213219
fontWeight: primitives.typographyFontWeightSemiBold,

package/src/components/Message/MessageItemView/MessageStatus.tsx

Lines changed: 4 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ import {
66
MessageContextValue,
77
useMessageContext,
88
} from '../../../contexts/messageContext/MessageContext';
9-
import {
10-
MessagesContextValue,
11-
useMessagesContext,
12-
} from '../../../contexts/messagesContext/MessagesContext';
139
import { useTheme } from '../../../contexts/themeContext/ThemeContext';
1410
import { Check } from '../../../icons/Check';
1511
import { CheckAll } from '../../../icons/CheckAll';
@@ -21,14 +17,10 @@ import { useShouldUseOverlayStyles } from '../hooks/useShouldUseOverlayStyles';
2117
export type MessageStatusPropsWithContext = Pick<
2218
MessageContextValue,
2319
'deliveredToCount' | 'message' | 'readBy'
24-
> &
25-
Pick<MessagesContextValue, 'MessageTimestamp'> & {
26-
formattedDate?: string | Date;
27-
timestamp?: string | Date;
28-
};
20+
>;
2921

3022
const MessageStatusWithContext = (props: MessageStatusPropsWithContext) => {
31-
const { deliveredToCount, formattedDate, message, readBy, timestamp, MessageTimestamp } = props;
23+
const { deliveredToCount, message, readBy } = props;
3224

3325
const styles = useStyles();
3426

@@ -92,7 +84,6 @@ const MessageStatusWithContext = (props: MessageStatusPropsWithContext) => {
9284
{...checkIcon}
9385
/>
9486
) : null}
95-
<MessageTimestamp formattedDate={formattedDate} timestamp={timestamp} />
9687
</View>
9788
);
9889
};
@@ -101,20 +92,8 @@ const areEqual = (
10192
prevProps: MessageStatusPropsWithContext,
10293
nextProps: MessageStatusPropsWithContext,
10394
) => {
104-
const {
105-
deliveredToCount: prevDeliveredBy,
106-
message: prevMessage,
107-
readBy: prevReadBy,
108-
formattedDate: prevFormattedDate,
109-
timestamp: prevTimestamp,
110-
} = prevProps;
111-
const {
112-
deliveredToCount: nextDeliveredBy,
113-
message: nextMessage,
114-
readBy: nextReadBy,
115-
formattedDate: nextFormattedDate,
116-
timestamp: nextTimestamp,
117-
} = nextProps;
95+
const { deliveredToCount: prevDeliveredBy, message: prevMessage, readBy: prevReadBy } = prevProps;
96+
const { deliveredToCount: nextDeliveredBy, message: nextMessage, readBy: nextReadBy } = nextProps;
11897

11998
const deliveredByEqual = prevDeliveredBy === nextDeliveredBy;
12099
if (!deliveredByEqual) {
@@ -132,16 +111,6 @@ const areEqual = (
132111
return false;
133112
}
134113

135-
const timestampEqual = prevTimestamp === nextTimestamp;
136-
if (!timestampEqual) {
137-
return false;
138-
}
139-
140-
const formattedDateEqual = prevFormattedDate === nextFormattedDate;
141-
if (!formattedDateEqual) {
142-
return false;
143-
}
144-
145114
return true;
146115
};
147116

@@ -155,7 +124,6 @@ export type MessageStatusProps = Partial<MessageStatusPropsWithContext>;
155124
export const MessageStatus = (props: MessageStatusProps) => {
156125
const { channel } = useChannelContext();
157126
const { deliveredToCount, message, readBy } = useMessageContext();
158-
const { MessageTimestamp } = useMessagesContext();
159127

160128
const channelMembersCount = Object.keys(channel?.state.members).length;
161129

@@ -167,7 +135,6 @@ export const MessageStatus = (props: MessageStatusProps) => {
167135
deliveredToCount,
168136
message,
169137
readBy,
170-
MessageTimestamp,
171138
}}
172139
{...props}
173140
/>

package/src/components/MessageInput/components/AudioRecorder/AudioRecordingPreview.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ export const AudioRecordingPreview = () => {
108108
const dragEnd = useStableCallback(async (currentProgress: number) => {
109109
const positionInSeconds = (currentProgress * duration) / ONE_SECOND_IN_MILLISECONDS;
110110
await audioPlayer.seek(positionInSeconds);
111-
audioPlayer.play();
112111
});
113112

114113
return (

package/src/components/MessageInput/hooks/useAudioRecorder.tsx

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useCallback, useEffect, useState } from 'react';
1+
import { useCallback, useEffect } from 'react';
22

33
import { LocalVoiceRecordingAttachment } from 'stream-chat';
44

@@ -12,14 +12,11 @@ import { resampleWaveformData } from '../utils/audioSampling';
1212

1313
/**
1414
* The hook that controls all the async audio core features including start/stop or recording, player, upload/delete of the recorded audio.
15-
*
16-
* FIXME: Change the name to `useAudioRecorder` in the next major version as the hook will only be used for audio recording.
1715
*/
1816
export const useAudioRecorder = ({
1917
audioRecorderManager,
2018
sendMessage,
2119
}: Pick<MessageInputContextValue, 'audioRecorderManager' | 'sendMessage'>) => {
22-
const [isScheduledForSubmit, setIsScheduleForSubmit] = useState(false);
2320
const { attachmentManager } = useMessageComposer();
2421

2522
/**
@@ -43,13 +40,6 @@ export const useAudioRecorder = ({
4340
[stopVoiceRecording],
4441
);
4542

46-
useEffect(() => {
47-
if (isScheduledForSubmit) {
48-
sendMessage();
49-
setIsScheduleForSubmit(false);
50-
}
51-
}, [isScheduledForSubmit, sendMessage]);
52-
5343
/**
5444
* Function to start voice recording. Will return whether access is granted
5545
* with regards to the microphone permission as that's how the underlying
@@ -113,16 +103,16 @@ export const useAudioRecorder = ({
113103
audioRecorderManager.reset();
114104

115105
if (sendOnComplete) {
116-
await attachmentManager.uploadAttachment(audioFile);
117-
setIsScheduleForSubmit(true);
106+
attachmentManager.upsertAttachments([audioFile]);
107+
sendMessage();
118108
} else {
119109
await attachmentManager.uploadAttachment(audioFile);
120110
}
121111
} catch (error) {
122112
console.log('Error uploading voice recording: ', error);
123113
}
124114
},
125-
[audioRecorderManager, attachmentManager, stopVoiceRecording],
115+
[audioRecorderManager, attachmentManager, sendMessage, stopVoiceRecording],
126116
);
127117

128118
return {

package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,13 +620,26 @@ exports[`Thread should match thread snapshot 1`] = `
620620
"flexDirection": "row",
621621
"gap": 8,
622622
"justifyContent": "center",
623+
"maxWidth": "100%",
623624
"paddingVertical": 4,
624625
},
625626
{},
626627
]
627628
}
628629
testID="message-status-time"
629630
>
631+
<Text
632+
style={
633+
{
634+
"color": "#687385",
635+
"fontSize": 13,
636+
"fontWeight": 400,
637+
"lineHeight": 16,
638+
}
639+
}
640+
>
641+
2:50 PM
642+
</Text>
630643
<Text
631644
style={
632645
[
@@ -944,13 +957,26 @@ exports[`Thread should match thread snapshot 1`] = `
944957
"flexDirection": "row",
945958
"gap": 8,
946959
"justifyContent": "center",
960+
"maxWidth": "100%",
947961
"paddingVertical": 4,
948962
},
949963
{},
950964
]
951965
}
952966
testID="message-status-time"
953967
>
968+
<Text
969+
style={
970+
{
971+
"color": "#687385",
972+
"fontSize": 13,
973+
"fontWeight": 400,
974+
"lineHeight": 16,
975+
}
976+
}
977+
>
978+
2:50 PM
979+
</Text>
954980
<Text
955981
style={
956982
[
@@ -1301,13 +1327,26 @@ exports[`Thread should match thread snapshot 1`] = `
13011327
"flexDirection": "row",
13021328
"gap": 8,
13031329
"justifyContent": "center",
1330+
"maxWidth": "100%",
13041331
"paddingVertical": 4,
13051332
},
13061333
{},
13071334
]
13081335
}
13091336
testID="message-status-time"
13101337
>
1338+
<Text
1339+
style={
1340+
{
1341+
"color": "#687385",
1342+
"fontSize": 13,
1343+
"fontWeight": 400,
1344+
"lineHeight": 16,
1345+
}
1346+
}
1347+
>
1348+
2:50 PM
1349+
</Text>
13111350
<Text
13121351
style={
13131352
[
@@ -1616,13 +1655,26 @@ exports[`Thread should match thread snapshot 1`] = `
16161655
"flexDirection": "row",
16171656
"gap": 8,
16181657
"justifyContent": "center",
1658+
"maxWidth": "100%",
16191659
"paddingVertical": 4,
16201660
},
16211661
{},
16221662
]
16231663
}
16241664
testID="message-status-time"
16251665
>
1666+
<Text
1667+
style={
1668+
{
1669+
"color": "#687385",
1670+
"fontSize": 13,
1671+
"fontWeight": 400,
1672+
"lineHeight": 16,
1673+
}
1674+
}
1675+
>
1676+
2:50 PM
1677+
</Text>
16261678
<Text
16271679
style={
16281680
[

0 commit comments

Comments
 (0)