stream-chat-react-native-core 6.3.1 → 6.4.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/lib/commonjs/components/Attachment/AudioAttachment.js +255 -216
  2. package/lib/commonjs/components/Attachment/AudioAttachment.js.map +1 -1
  3. package/lib/commonjs/components/Attachment/FileAttachmentGroup.js +11 -11
  4. package/lib/commonjs/components/Attachment/FileAttachmentGroup.js.map +1 -1
  5. package/lib/commonjs/components/Attachment/Gallery.js +9 -0
  6. package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
  7. package/lib/commonjs/components/ChannelList/ChannelList.js +23 -0
  8. package/lib/commonjs/components/ChannelList/ChannelList.js.map +1 -1
  9. package/lib/commonjs/components/ChannelList/hooks/listeners/useAddedToChannelNotification.js +31 -8
  10. package/lib/commonjs/components/ChannelList/hooks/listeners/useAddedToChannelNotification.js.map +1 -1
  11. package/lib/commonjs/components/ChannelList/hooks/listeners/useChannelMemberUpdated.js +75 -0
  12. package/lib/commonjs/components/ChannelList/hooks/listeners/useChannelMemberUpdated.js.map +1 -0
  13. package/lib/commonjs/components/ChannelList/hooks/listeners/useNewMessage.js +21 -10
  14. package/lib/commonjs/components/ChannelList/hooks/listeners/useNewMessage.js.map +1 -1
  15. package/lib/commonjs/components/ChannelList/hooks/listeners/useNewMessageNotification.js +23 -7
  16. package/lib/commonjs/components/ChannelList/hooks/listeners/useNewMessageNotification.js.map +1 -1
  17. package/lib/commonjs/components/ChannelList/hooks/useChannelMembershipState.js +17 -0
  18. package/lib/commonjs/components/ChannelList/hooks/useChannelMembershipState.js.map +1 -0
  19. package/lib/commonjs/components/ChannelList/hooks/useSelectedChannelState.js +32 -0
  20. package/lib/commonjs/components/ChannelList/hooks/useSelectedChannelState.js.map +1 -0
  21. package/lib/commonjs/components/ChannelList/hooks/utils/index.js +102 -0
  22. package/lib/commonjs/components/ChannelList/hooks/utils/index.js.map +1 -0
  23. package/lib/commonjs/components/ChannelList/utils.js +23 -11
  24. package/lib/commonjs/components/ChannelList/utils.js.map +1 -1
  25. package/lib/commonjs/components/ChannelPreview/ChannelPreviewMessenger.js +1 -2
  26. package/lib/commonjs/components/ChannelPreview/ChannelPreviewMessenger.js.map +1 -1
  27. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js +24 -13
  28. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -1
  29. package/lib/commonjs/components/Message/Message.js.map +1 -1
  30. package/lib/commonjs/components/MessageInput/FileUploadPreview.js +35 -23
  31. package/lib/commonjs/components/MessageInput/FileUploadPreview.js.map +1 -1
  32. package/lib/commonjs/components/ProgressControl/ProgressControl.js +57 -54
  33. package/lib/commonjs/components/ProgressControl/ProgressControl.js.map +1 -1
  34. package/lib/commonjs/components/ProgressControl/WaveProgressBar.js +52 -52
  35. package/lib/commonjs/components/ProgressControl/WaveProgressBar.js.map +1 -1
  36. package/lib/commonjs/components/index.js +22 -0
  37. package/lib/commonjs/components/index.js.map +1 -1
  38. package/lib/commonjs/contexts/themeContext/utils/theme.js +1 -0
  39. package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
  40. package/lib/commonjs/hooks/useAudioPlayer.js +158 -0
  41. package/lib/commonjs/hooks/useAudioPlayer.js.map +1 -0
  42. package/lib/commonjs/icons/Archieve.js +33 -0
  43. package/lib/commonjs/icons/Archieve.js.map +1 -0
  44. package/lib/commonjs/icons/Pause.js +2 -2
  45. package/lib/commonjs/icons/Pause.js.map +1 -1
  46. package/lib/commonjs/icons/Play.js +2 -2
  47. package/lib/commonjs/icons/Play.js.map +1 -1
  48. package/lib/commonjs/icons/index.js +11 -0
  49. package/lib/commonjs/icons/index.js.map +1 -1
  50. package/lib/commonjs/native.js.map +1 -1
  51. package/lib/commonjs/types/types.js.map +1 -1
  52. package/lib/commonjs/version.json +1 -1
  53. package/lib/module/components/Attachment/AudioAttachment.js +255 -216
  54. package/lib/module/components/Attachment/AudioAttachment.js.map +1 -1
  55. package/lib/module/components/Attachment/FileAttachmentGroup.js +11 -11
  56. package/lib/module/components/Attachment/FileAttachmentGroup.js.map +1 -1
  57. package/lib/module/components/Attachment/Gallery.js +9 -0
  58. package/lib/module/components/Attachment/Gallery.js.map +1 -1
  59. package/lib/module/components/ChannelList/ChannelList.js +23 -0
  60. package/lib/module/components/ChannelList/ChannelList.js.map +1 -1
  61. package/lib/module/components/ChannelList/hooks/listeners/useAddedToChannelNotification.js +31 -8
  62. package/lib/module/components/ChannelList/hooks/listeners/useAddedToChannelNotification.js.map +1 -1
  63. package/lib/module/components/ChannelList/hooks/listeners/useChannelMemberUpdated.js +75 -0
  64. package/lib/module/components/ChannelList/hooks/listeners/useChannelMemberUpdated.js.map +1 -0
  65. package/lib/module/components/ChannelList/hooks/listeners/useNewMessage.js +21 -10
  66. package/lib/module/components/ChannelList/hooks/listeners/useNewMessage.js.map +1 -1
  67. package/lib/module/components/ChannelList/hooks/listeners/useNewMessageNotification.js +23 -7
  68. package/lib/module/components/ChannelList/hooks/listeners/useNewMessageNotification.js.map +1 -1
  69. package/lib/module/components/ChannelList/hooks/useChannelMembershipState.js +17 -0
  70. package/lib/module/components/ChannelList/hooks/useChannelMembershipState.js.map +1 -0
  71. package/lib/module/components/ChannelList/hooks/useSelectedChannelState.js +32 -0
  72. package/lib/module/components/ChannelList/hooks/useSelectedChannelState.js.map +1 -0
  73. package/lib/module/components/ChannelList/hooks/utils/index.js +102 -0
  74. package/lib/module/components/ChannelList/hooks/utils/index.js.map +1 -0
  75. package/lib/module/components/ChannelList/utils.js +23 -11
  76. package/lib/module/components/ChannelList/utils.js.map +1 -1
  77. package/lib/module/components/ChannelPreview/ChannelPreviewMessenger.js +1 -2
  78. package/lib/module/components/ChannelPreview/ChannelPreviewMessenger.js.map +1 -1
  79. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js +24 -13
  80. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -1
  81. package/lib/module/components/Message/Message.js.map +1 -1
  82. package/lib/module/components/MessageInput/FileUploadPreview.js +35 -23
  83. package/lib/module/components/MessageInput/FileUploadPreview.js.map +1 -1
  84. package/lib/module/components/ProgressControl/ProgressControl.js +57 -54
  85. package/lib/module/components/ProgressControl/ProgressControl.js.map +1 -1
  86. package/lib/module/components/ProgressControl/WaveProgressBar.js +52 -52
  87. package/lib/module/components/ProgressControl/WaveProgressBar.js.map +1 -1
  88. package/lib/module/components/index.js +22 -0
  89. package/lib/module/components/index.js.map +1 -1
  90. package/lib/module/contexts/themeContext/utils/theme.js +1 -0
  91. package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
  92. package/lib/module/hooks/useAudioPlayer.js +158 -0
  93. package/lib/module/hooks/useAudioPlayer.js.map +1 -0
  94. package/lib/module/icons/Archieve.js +33 -0
  95. package/lib/module/icons/Archieve.js.map +1 -0
  96. package/lib/module/icons/Pause.js +2 -2
  97. package/lib/module/icons/Pause.js.map +1 -1
  98. package/lib/module/icons/Play.js +2 -2
  99. package/lib/module/icons/Play.js.map +1 -1
  100. package/lib/module/icons/index.js +11 -0
  101. package/lib/module/icons/index.js.map +1 -1
  102. package/lib/module/native.js.map +1 -1
  103. package/lib/module/types/types.js.map +1 -1
  104. package/lib/module/version.json +1 -1
  105. package/lib/typescript/components/Attachment/AudioAttachment.d.ts +2 -2
  106. package/lib/typescript/components/Attachment/AudioAttachment.d.ts.map +1 -1
  107. package/lib/typescript/components/Attachment/FileAttachmentGroup.d.ts.map +1 -1
  108. package/lib/typescript/components/Attachment/Gallery.d.ts.map +1 -1
  109. package/lib/typescript/components/ChannelList/ChannelList.d.ts +20 -6
  110. package/lib/typescript/components/ChannelList/ChannelList.d.ts.map +1 -1
  111. package/lib/typescript/components/ChannelList/hooks/listeners/useAddedToChannelNotification.d.ts +4 -3
  112. package/lib/typescript/components/ChannelList/hooks/listeners/useAddedToChannelNotification.d.ts.map +1 -1
  113. package/lib/typescript/components/ChannelList/hooks/listeners/useChannelMemberUpdated.d.ts +12 -0
  114. package/lib/typescript/components/ChannelList/hooks/listeners/useChannelMemberUpdated.d.ts.map +1 -0
  115. package/lib/typescript/components/ChannelList/hooks/listeners/useNewMessage.d.ts +4 -3
  116. package/lib/typescript/components/ChannelList/hooks/listeners/useNewMessage.d.ts.map +1 -1
  117. package/lib/typescript/components/ChannelList/hooks/listeners/useNewMessageNotification.d.ts +4 -3
  118. package/lib/typescript/components/ChannelList/hooks/listeners/useNewMessageNotification.d.ts.map +1 -1
  119. package/lib/typescript/components/ChannelList/hooks/useChannelMembershipState.d.ts +5 -0
  120. package/lib/typescript/components/ChannelList/hooks/useChannelMembershipState.d.ts.map +1 -0
  121. package/lib/typescript/components/ChannelList/hooks/useSelectedChannelState.d.ts +13 -0
  122. package/lib/typescript/components/ChannelList/hooks/useSelectedChannelState.d.ts.map +1 -0
  123. package/lib/typescript/components/ChannelList/hooks/utils/index.d.ts +22 -0
  124. package/lib/typescript/components/ChannelList/hooks/utils/index.d.ts.map +1 -0
  125. package/lib/typescript/components/ChannelList/utils.d.ts +10 -4
  126. package/lib/typescript/components/ChannelList/utils.d.ts.map +1 -1
  127. package/lib/typescript/components/ChannelPreview/ChannelPreviewMessenger.d.ts.map +1 -1
  128. package/lib/typescript/components/ImageGallery/components/ImageGalleryVideoControl.d.ts.map +1 -1
  129. package/lib/typescript/components/Message/Message.d.ts +22 -11
  130. package/lib/typescript/components/Message/Message.d.ts.map +1 -1
  131. package/lib/typescript/components/MessageInput/FileUploadPreview.d.ts.map +1 -1
  132. package/lib/typescript/components/ProgressControl/ProgressControl.d.ts +35 -2
  133. package/lib/typescript/components/ProgressControl/ProgressControl.d.ts.map +1 -1
  134. package/lib/typescript/components/ProgressControl/WaveProgressBar.d.ts +27 -0
  135. package/lib/typescript/components/ProgressControl/WaveProgressBar.d.ts.map +1 -1
  136. package/lib/typescript/components/index.d.ts +2 -0
  137. package/lib/typescript/components/index.d.ts.map +1 -1
  138. package/lib/typescript/contexts/themeContext/utils/theme.d.ts +1 -0
  139. package/lib/typescript/contexts/themeContext/utils/theme.d.ts.map +1 -1
  140. package/lib/typescript/hooks/useAudioPlayer.d.ts +16 -0
  141. package/lib/typescript/hooks/useAudioPlayer.d.ts.map +1 -0
  142. package/lib/typescript/icons/Archieve.d.ts +4 -0
  143. package/lib/typescript/icons/Archieve.d.ts.map +1 -0
  144. package/lib/typescript/icons/Pause.d.ts.map +1 -1
  145. package/lib/typescript/icons/index.d.ts +1 -0
  146. package/lib/typescript/icons/index.d.ts.map +1 -1
  147. package/lib/typescript/native.d.ts +10 -3
  148. package/lib/typescript/native.d.ts.map +1 -1
  149. package/lib/typescript/types/types.d.ts +5 -1
  150. package/lib/typescript/types/types.d.ts.map +1 -1
  151. package/package.json +4 -2
  152. package/src/components/Attachment/AudioAttachment.tsx +173 -137
  153. package/src/components/Attachment/FileAttachmentGroup.tsx +9 -16
  154. package/src/components/Attachment/Gallery.tsx +3 -0
  155. package/src/components/ChannelList/ChannelList.tsx +38 -3
  156. package/src/components/ChannelList/hooks/listeners/useAddedToChannelNotification.ts +32 -3
  157. package/src/components/ChannelList/hooks/listeners/useChannelMemberUpdated.ts +116 -0
  158. package/src/components/ChannelList/hooks/listeners/useNewMessage.ts +46 -17
  159. package/src/components/ChannelList/hooks/listeners/useNewMessageNotification.ts +18 -3
  160. package/src/components/ChannelList/hooks/useChannelMembershipState.ts +22 -0
  161. package/src/components/ChannelList/hooks/useSelectedChannelState.ts +57 -0
  162. package/src/components/ChannelList/hooks/utils/index.ts +130 -0
  163. package/src/components/ChannelList/utils.ts +50 -14
  164. package/src/components/ChannelPreview/ChannelPreviewMessenger.tsx +1 -2
  165. package/src/components/ImageGallery/components/ImageGalleryVideoControl.tsx +23 -13
  166. package/src/components/Message/Message.tsx +26 -4
  167. package/src/components/MessageInput/FileUploadPreview.tsx +29 -28
  168. package/src/components/ProgressControl/ProgressControl.tsx +115 -92
  169. package/src/components/ProgressControl/WaveProgressBar.tsx +96 -59
  170. package/src/components/index.ts +2 -0
  171. package/src/contexts/themeContext/utils/theme.ts +2 -0
  172. package/src/hooks/useAudioPlayer.ts +59 -0
  173. package/src/icons/Archieve.tsx +10 -0
  174. package/src/icons/Pause.tsx +2 -5
  175. package/src/icons/Play.tsx +2 -2
  176. package/src/icons/index.ts +1 -0
  177. package/src/native.ts +11 -3
  178. package/src/types/types.ts +14 -1
  179. package/src/version.json +1 -1
@@ -1,31 +1,67 @@
1
- import uniqBy from 'lodash/uniqBy';
2
- import type { Channel, StreamChat } from 'stream-chat';
1
+ import type { Channel, ChannelSort, StreamChat } from 'stream-chat';
2
+
3
+ import { findLastPinnedChannelIndex, shouldConsiderPinnedChannels } from './hooks/utils';
3
4
 
4
5
  import type { DefaultStreamChatGenerics } from '../../types/types';
5
6
 
6
7
  type MoveParameters<
7
8
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
8
9
  > = {
9
- channels: Channel<StreamChatGenerics>[];
10
- cid: string;
10
+ channels: Array<Channel<StreamChatGenerics>>;
11
+ channelToMove: Channel<StreamChatGenerics>;
12
+ /**
13
+ * If the index of the channel within `channels` list which is being moved upwards
14
+ * (`channelToMove`) is known, you can supply it to skip extra calculation.
15
+ */
16
+ channelToMoveIndexWithinChannels?: number;
17
+ sort?: ChannelSort<StreamChatGenerics>;
11
18
  };
12
19
 
13
20
  export const moveChannelUp = <
14
21
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
15
22
  >({
16
- channels = [],
17
- cid,
23
+ channels,
24
+ channelToMove,
25
+ channelToMoveIndexWithinChannels,
26
+ sort,
18
27
  }: MoveParameters<StreamChatGenerics>) => {
19
- // get channel from channels
20
- const index = channels.findIndex((c) => c.cid === cid);
21
- if (index <= 0) return channels;
22
- const channel = channels[index];
28
+ // get index of channel to move up
29
+ const targetChannelIndex =
30
+ channelToMoveIndexWithinChannels ??
31
+ channels.findIndex((channel) => channel.cid === channelToMove.cid);
32
+
33
+ const targetChannelExistsWithinList = targetChannelIndex >= 0;
34
+ const targetChannelAlreadyAtTheTop = targetChannelIndex === 0;
35
+
36
+ // pinned channels should not move within the list based on recent activity, channels which
37
+ // receive messages and are not pinned should move upwards but only under the last pinned channel
38
+ // in the list
39
+ const considerPinnedChannels = shouldConsiderPinnedChannels(sort);
40
+
41
+ if (targetChannelAlreadyAtTheTop) return channels;
42
+
43
+ const newChannels = [...channels];
44
+
45
+ // target channel index is known, remove it from the list
46
+ if (targetChannelExistsWithinList) {
47
+ newChannels.splice(targetChannelIndex, 1);
48
+ }
49
+
50
+ // as position of pinned channels has to stay unchanged, we need to
51
+ // find last pinned channel in the list to move the target channel after
52
+ let lastPinnedChannelIndex: number | null = null;
53
+ if (considerPinnedChannels) {
54
+ lastPinnedChannelIndex = findLastPinnedChannelIndex({ channels: newChannels });
55
+ }
23
56
 
24
- // remove channel from current position and add to start
25
- channels.splice(index, 1);
26
- channels.unshift(channel);
57
+ // re-insert it at the new place (to specific index if pinned channels are considered)
58
+ newChannels.splice(
59
+ typeof lastPinnedChannelIndex === 'number' ? lastPinnedChannelIndex + 1 : 0,
60
+ 0,
61
+ channelToMove,
62
+ );
27
63
 
28
- return uniqBy([channel, ...channels], 'cid');
64
+ return newChannels;
29
65
  };
30
66
 
31
67
  type GetParameters<
@@ -1,6 +1,5 @@
1
1
  import React from 'react';
2
- import { StyleSheet, View } from 'react-native';
3
- import { TouchableOpacity } from 'react-native-gesture-handler';
2
+ import { StyleSheet, TouchableOpacity, View } from 'react-native';
4
3
 
5
4
  import { ChannelAvatar } from './ChannelAvatar';
6
5
  import type { ChannelPreviewProps } from './ChannelPreview';
@@ -12,6 +12,14 @@ import { ProgressControl } from '../../ProgressControl/ProgressControl';
12
12
  const styles = StyleSheet.create({
13
13
  durationTextStyle: {
14
14
  fontWeight: 'bold',
15
+ marginLeft: 16,
16
+ },
17
+ progressContainer: {
18
+ flex: 1,
19
+ },
20
+ progressDurationText: {
21
+ fontWeight: 'bold',
22
+ marginRight: 16,
15
23
  },
16
24
  roundedView: {
17
25
  alignItems: 'center',
@@ -20,15 +28,15 @@ const styles = StyleSheet.create({
20
28
  elevation: 2,
21
29
  height: 36,
22
30
  justifyContent: 'center',
31
+ marginRight: 16,
23
32
  width: 36,
24
33
  },
25
34
  videoContainer: {
26
35
  alignItems: 'center',
27
36
  backgroundColor: 'rgba(52, 52, 52, 0.1)',
28
- display: 'flex',
29
37
  flexDirection: 'row',
30
- justifyContent: 'space-between',
31
- padding: 10,
38
+ justifyContent: 'space-evenly',
39
+ padding: 12,
32
40
  },
33
41
  });
34
42
 
@@ -46,7 +54,7 @@ export const ImageGalleryVideoControl = React.memo(
46
54
  theme: {
47
55
  colors: { accent_blue, black, static_black, static_white },
48
56
  imageGallery: {
49
- videoControl: { durationTextStyle, roundedView, videoContainer },
57
+ videoControl: { durationTextStyle, progressDurationText, roundedView, videoContainer },
50
58
  },
51
59
  },
52
60
  } = useTheme();
@@ -74,18 +82,20 @@ export const ImageGalleryVideoControl = React.memo(
74
82
  </TouchableOpacity>
75
83
  <Text
76
84
  accessibilityLabel='Progress Duration'
77
- style={[styles.durationTextStyle, { color: black }, durationTextStyle]}
85
+ style={[styles.progressDurationText, { color: black }, progressDurationText]}
78
86
  >
79
87
  {progressDuration}
80
88
  </Text>
81
- <ProgressControl
82
- duration={duration}
83
- filledColor={accent_blue}
84
- onPlayPause={onPlayPause}
85
- progress={progress}
86
- testID={'progress-control'}
87
- width={180}
88
- />
89
+ <View style={styles.progressContainer}>
90
+ <ProgressControl
91
+ duration={duration}
92
+ filledColor={accent_blue}
93
+ progress={progress}
94
+ testID={'progress-control'}
95
+ width={180}
96
+ />
97
+ </View>
98
+
89
99
  <Text
90
100
  accessibilityLabel='Video Duration'
91
101
  style={[styles.durationTextStyle, { color: black }, durationTextStyle]}
@@ -40,6 +40,7 @@ import {
40
40
  isEditedMessage,
41
41
  MessageStatusTypes,
42
42
  } from '../../utils/utils';
43
+ import type { Thumbnail } from '../Attachment/utils/buildGallery/types';
43
44
 
44
45
  import {
45
46
  isMessageWithStylesReadByAndDateSeparator,
@@ -55,23 +56,40 @@ export type TouchableEmitter =
55
56
  | 'messageReplies'
56
57
  | 'reactionList';
57
58
 
59
+ export type TextMentionTouchableHandlerAdditionalInfo<
60
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
61
+ > = { user?: UserResponse<StreamChatGenerics> };
62
+
58
63
  export type TextMentionTouchableHandlerPayload<
59
64
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
60
65
  > = {
61
66
  emitter: 'textMention';
62
- additionalInfo?: { user?: UserResponse<StreamChatGenerics> };
67
+ additionalInfo?: TextMentionTouchableHandlerAdditionalInfo<StreamChatGenerics>;
63
68
  };
64
69
 
70
+ export type UrlTouchableHandlerAdditionalInfo = { url?: string };
71
+
65
72
  export type UrlTouchableHandlerPayload = {
66
73
  emitter: 'textLink' | 'card';
67
- additionalInfo?: { url?: string };
74
+ additionalInfo?: UrlTouchableHandlerAdditionalInfo;
68
75
  };
69
76
 
77
+ export type FileAttachmentTouchableHandlerAdditionalInfo<
78
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
79
+ > = { attachment?: Attachment<StreamChatGenerics> };
80
+
70
81
  export type FileAttachmentTouchableHandlerPayload<
71
82
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
72
83
  > = {
73
84
  emitter: 'fileAttachment';
74
- additionalInfo?: { attachment?: Attachment<StreamChatGenerics> };
85
+ additionalInfo?: FileAttachmentTouchableHandlerAdditionalInfo<StreamChatGenerics>;
86
+ };
87
+
88
+ export type GalleryThumbnailTouchableHandlerAdditionalInfo = { thumbnail?: Thumbnail };
89
+
90
+ export type GalleryThumbnailTouchableHandlerPayload = {
91
+ emitter: 'gallery';
92
+ additionalInfo?: GalleryThumbnailTouchableHandlerAdditionalInfo;
75
93
  };
76
94
 
77
95
  export type PressableHandlerPayload = {
@@ -79,11 +97,15 @@ export type PressableHandlerPayload = {
79
97
  event?: GestureResponderEvent;
80
98
  } & (
81
99
  | {
82
- emitter?: Exclude<TouchableEmitter, 'textMention' | 'textLink' | 'card' | 'fileAttachment'>;
100
+ emitter?: Exclude<
101
+ TouchableEmitter,
102
+ 'textMention' | 'textLink' | 'card' | 'fileAttachment' | 'gallery'
103
+ >;
83
104
  }
84
105
  | TextMentionTouchableHandlerPayload
85
106
  | UrlTouchableHandlerPayload
86
107
  | FileAttachmentTouchableHandlerPayload
108
+ | GalleryThumbnailTouchableHandlerPayload
87
109
  );
88
110
 
89
111
  export type MessagePressableHandlerPayload<
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef, useState } from 'react';
1
+ import React, { useEffect, useMemo, useRef, useState } from 'react';
2
2
  import { FlatList, I18nManager, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
3
3
 
4
4
  import { UploadProgressIndicator } from './UploadProgressIndicator';
@@ -143,18 +143,19 @@ const FileUploadPreviewWithContext = <
143
143
  FileAttachmentIcon,
144
144
  fileUploads,
145
145
  removeFile,
146
- setFileUploads,
147
146
  uploadFile,
148
147
  } = props;
149
148
 
149
+ const [filesToDisplay, setFilesToDisplay] = useState<FileUpload[]>([]);
150
+
150
151
  const flatListRef = useRef<FlatList<FileUpload> | null>(null);
151
152
  const [flatListWidth, setFlatListWidth] = useState(0);
152
153
 
153
154
  useEffect(() => {
154
- setFileUploads(
155
+ setFilesToDisplay(
155
156
  fileUploads.map((file) => ({
156
157
  ...file,
157
- duration: file.duration || 0,
158
+ duration: file.duration || filesToDisplay.find((f) => f.id === file.id)?.duration || 0,
158
159
  paused: true,
159
160
  progress: 0,
160
161
  })),
@@ -164,31 +165,20 @@ const FileUploadPreviewWithContext = <
164
165
 
165
166
  // Handler triggered when an audio is loaded in the message input. The initial state is defined for the audio here and the duration is set.
166
167
  const onLoad = (index: string, duration: number) => {
167
- setFileUploads((prevFileUploads) =>
168
- prevFileUploads.map((fileUpload) => ({
168
+ setFilesToDisplay((prevFilesUploads) =>
169
+ prevFilesUploads.map((fileUpload, id) => ({
169
170
  ...fileUpload,
170
- duration: fileUpload.id === index ? duration : fileUpload.duration,
171
- file: {
172
- ...fileUpload.file,
173
- duration: fileUpload.id === index ? duration : fileUpload.duration,
174
- },
171
+ duration: id.toString() === index ? duration : fileUpload.duration,
175
172
  })),
176
173
  );
177
174
  };
178
175
 
179
176
  // The handler which is triggered when the audio progresses/ the thumb is dragged in the progress control. The progressed duration is set here.
180
- const onProgress = (index: string, currentTime?: number, hasEnd?: boolean) => {
181
- setFileUploads((prevFileUploads) =>
182
- prevFileUploads.map((fileUpload) => ({
177
+ const onProgress = (index: string, progress: number) => {
178
+ setFilesToDisplay((prevFilesUploads) =>
179
+ prevFilesUploads.map((fileUpload, id) => ({
183
180
  ...fileUpload,
184
- progress:
185
- fileUpload.id === index
186
- ? hasEnd
187
- ? 1
188
- : currentTime
189
- ? currentTime / (fileUpload.duration as number)
190
- : 0
191
- : fileUpload.progress,
181
+ progress: id.toString() === index ? progress : fileUpload.progress,
192
182
  })),
193
183
  );
194
184
  };
@@ -197,15 +187,15 @@ const FileUploadPreviewWithContext = <
197
187
  const onPlayPause = (index: string, pausedStatus?: boolean) => {
198
188
  if (pausedStatus === false) {
199
189
  // If the status is false we set the audio with the index as playing and the others as paused.
200
- setFileUploads((prevFileUploads) =>
201
- prevFileUploads.map((fileUpload) => ({
190
+ setFilesToDisplay((prevFileUploads) =>
191
+ prevFileUploads.map((fileUpload, id) => ({
202
192
  ...fileUpload,
203
- paused: fileUpload.id !== index,
193
+ paused: id.toString() !== index,
204
194
  })),
205
195
  );
206
196
  } else {
207
197
  // If the status is true we simply set all the audio's paused state as true.
208
- setFileUploads((prevFileUploads) =>
198
+ setFilesToDisplay((prevFileUploads) =>
209
199
  prevFileUploads.map((fileUpload) => ({
210
200
  ...fileUpload,
211
201
  paused: true,
@@ -225,6 +215,7 @@ const FileUploadPreviewWithContext = <
225
215
 
226
216
  const renderItem = ({ item }: { item: FileUpload }) => {
227
217
  const indicatorType = getIndicatorTypeForFileState(item.state, enableOfflineSupport);
218
+ const isAudio = item.file.mimeType?.startsWith('audio/');
228
219
 
229
220
  return (
230
221
  <>
@@ -235,13 +226,14 @@ const FileUploadPreviewWithContext = <
235
226
  style={styles.overlay}
236
227
  type={indicatorType}
237
228
  >
238
- {item.file.mimeType?.startsWith('audio/') && isSoundPackageAvailable() ? (
229
+ {isAudio && isSoundPackageAvailable() ? (
239
230
  <AudioAttachmentUploadPreview
240
231
  hideProgressBar={true}
241
232
  item={item}
242
233
  onLoad={onLoad}
243
234
  onPlayPause={onPlayPause}
244
235
  onProgress={onProgress}
236
+ showSpeedSettings={false}
245
237
  testID='audio-attachment-upload-preview'
246
238
  />
247
239
  ) : (
@@ -308,9 +300,18 @@ const FileUploadPreviewWithContext = <
308
300
  }
309
301
  }, [fileUploadsLength]);
310
302
 
303
+ const memoizedFilesToDisplay = useMemo(
304
+ () =>
305
+ filesToDisplay.map((file, index) => ({
306
+ ...file,
307
+ id: index.toString(),
308
+ })),
309
+ [filesToDisplay],
310
+ );
311
+
311
312
  return fileUploadsLength ? (
312
313
  <FlatList
313
- data={fileUploads}
314
+ data={memoizedFilesToDisplay}
314
315
  getItemLayout={(_, index) => ({
315
316
  index,
316
317
  length: FILE_PREVIEW_HEIGHT + 8,
@@ -1,26 +1,52 @@
1
- import React, { useEffect } from 'react';
2
- import { Dimensions, StyleSheet, View } from 'react-native';
1
+ import React, { useState } from 'react';
2
+ import { StyleSheet, View } from 'react-native';
3
3
  import { Gesture, GestureDetector } from 'react-native-gesture-handler';
4
- import Animated, {
5
- cancelAnimation,
6
- runOnJS,
7
- useAnimatedStyle,
8
- useSharedValue,
9
- } from 'react-native-reanimated';
4
+ import Animated, { runOnJS, useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
10
5
 
11
6
  import { useTheme } from '../../contexts/themeContext/ThemeContext';
12
7
 
13
8
  export type ProgressControlProps = {
9
+ /**
10
+ * The duration of the audio in seconds
11
+ */
14
12
  duration: number;
13
+ /**
14
+ * The color of the filled progress bar
15
+ */
15
16
  filledColor: string;
17
+ /**
18
+ * The progress of the progress bar in percentage
19
+ */
16
20
  progress: number;
21
+ /**
22
+ * The test ID of the progress control
23
+ */
17
24
  testID: string;
18
- width: number | string;
25
+ /**
26
+ * The function to be called when the user ends dragging the progress bar
27
+ */
28
+ onEndDrag?: (progress: number) => void;
29
+ /**
30
+ * The function to be called when the user plays or pauses the audio
31
+ * @deprecated Use onStartDrag and onEndDrag instead
32
+ */
19
33
  onPlayPause?: (status?: boolean) => void;
34
+ /**
35
+ * The function to be called when the user is dragging the progress bar
36
+ */
20
37
  onProgressDrag?: (progress: number) => void;
38
+ /**
39
+ * The function to be called when the user starts dragging the progress bar
40
+ */
41
+ onStartDrag?: (progress: number) => void;
42
+ /**
43
+ * The width of the progress control
44
+ */
45
+ width?: number | string;
21
46
  };
22
47
 
23
- const height = 2;
48
+ const TRACK_HEIGHT = 3;
49
+ const THUMB_WIDTH = 8;
24
50
 
25
51
  const ProgressControlThumb = () => {
26
52
  const {
@@ -38,100 +64,97 @@ const ProgressControlThumb = () => {
38
64
  );
39
65
  };
40
66
 
41
- export const ProgressControl = React.memo(
42
- (props: ProgressControlProps) => {
43
- const {
44
- duration,
45
- filledColor: filledColorFromProp,
46
- onPlayPause,
47
- onProgressDrag,
48
- progress,
49
- testID,
50
- width,
51
- } = props;
52
- const state = useSharedValue(0);
53
- const translateX = useSharedValue(0);
54
- const { width: windowWidth } = Dimensions.get('screen');
55
- const widthInNumbers = width
56
- ? typeof width === 'string'
57
- ? (windowWidth * Number(width?.substring(0, width.length - 1))) / 100
58
- : width
59
- : 0;
60
- const {
61
- theme: {
62
- colors: { grey_dark },
63
- progressControl: { container, filledColor: filledColorFromTheme, filledStyles, thumb },
64
- },
65
- } = useTheme();
66
- const pan = Gesture.Pan()
67
- .maxPointers(1)
68
- .onStart(() => {
69
- if (onPlayPause) runOnJS(onPlayPause)(true);
70
- cancelAnimation(translateX);
71
- state.value = translateX.value;
72
- })
73
- .onChange((event) => {
74
- state.value = translateX.value + event.translationX;
75
- if (state.value > widthInNumbers) state.value = widthInNumbers;
76
- else if (state.value < 0) state.value = 0;
77
- })
78
- .onEnd(() => {
79
- translateX.value = state.value;
80
- const dragFinishLocationInSeconds = (state.value / widthInNumbers) * duration;
81
- if (onProgressDrag) runOnJS(onProgressDrag)(dragFinishLocationInSeconds);
82
- if (onPlayPause) runOnJS(onPlayPause)(false);
83
- })
84
- .withTestId(testID);
67
+ export const ProgressControl = (props: ProgressControlProps) => {
68
+ const [widthInNumbers, setWidthInNumbers] = useState(0);
69
+ const {
70
+ filledColor: filledColorFromProp,
71
+ onEndDrag,
72
+ onPlayPause,
73
+ onProgressDrag,
74
+ onStartDrag,
75
+ progress,
76
+ testID,
77
+ } = props;
85
78
 
86
- const filledColor = filledColorFromProp || filledColorFromTheme;
79
+ const progressValue = useSharedValue(progress);
80
+ const {
81
+ theme: {
82
+ colors: { grey_dark },
83
+ progressControl: { container, filledColor: filledColorFromTheme, filledStyles, thumb },
84
+ },
85
+ } = useTheme();
87
86
 
88
- useEffect(() => {
89
- if (progress <= 1) {
90
- state.value = progress * widthInNumbers;
91
- translateX.value = progress * widthInNumbers;
92
- }
93
- // eslint-disable-next-line react-hooks/exhaustive-deps
94
- }, [progress, widthInNumbers]);
87
+ const pan = Gesture.Pan()
88
+ .maxPointers(1)
89
+ .onStart((event) => {
90
+ const currentProgress = (progressValue.value + event.x) / widthInNumbers;
91
+ progressValue.value = Math.max(0, Math.min(currentProgress, 1));
92
+ if (onStartDrag) runOnJS(onStartDrag)(progressValue.value);
93
+ if (onPlayPause) runOnJS(onPlayPause)(true);
94
+ })
95
+ .onUpdate((event) => {
96
+ const currentProgress = (progressValue.value + event.x) / widthInNumbers;
97
+ progressValue.value = Math.max(0, Math.min(currentProgress, 1));
98
+ if (onProgressDrag) runOnJS(onProgressDrag)(progressValue.value);
99
+ })
100
+ .onEnd((event) => {
101
+ const currentProgress = (progressValue.value + event.x) / widthInNumbers;
102
+ progressValue.value = Math.max(0, Math.min(currentProgress, 1));
103
+ if (onEndDrag) runOnJS(onEndDrag)(progressValue.value);
104
+ if (onPlayPause) runOnJS(onPlayPause)(false);
105
+ })
106
+ .withTestId(testID);
95
107
 
96
- const animatedStyles = useAnimatedStyle(() => ({
97
- backgroundColor: filledColor,
98
- width: state.value,
99
- }));
108
+ const filledColor = filledColorFromProp || filledColorFromTheme;
100
109
 
101
- const thumbStyles = useAnimatedStyle(() => ({
102
- transform: [{ translateX: state.value }],
103
- }));
110
+ const thumbStyles = useAnimatedStyle(
111
+ () => ({
112
+ transform: [{ translateX: progress * widthInNumbers - THUMB_WIDTH / 2 }],
113
+ }),
114
+ [progress],
115
+ );
104
116
 
105
- return (
117
+ const animatedFilledStyles = useAnimatedStyle(
118
+ () => ({
119
+ width: progress * widthInNumbers,
120
+ }),
121
+ [progress],
122
+ );
123
+
124
+ return (
125
+ <GestureDetector gesture={pan}>
106
126
  <View
107
- style={[styles.container, { backgroundColor: grey_dark, width: widthInNumbers }, container]}
127
+ onLayout={({ nativeEvent }) => {
128
+ setWidthInNumbers(nativeEvent.layout.width);
129
+ }}
130
+ style={[styles.container, { backgroundColor: grey_dark }, container]}
108
131
  >
109
- <Animated.View style={[styles.filledStyle, animatedStyles, filledStyles]} />
110
- <GestureDetector gesture={pan}>
111
- <Animated.View style={[thumbStyles, thumb]}>
112
- {onProgressDrag ? <ProgressControlThumb /> : null}
113
- </Animated.View>
114
- </GestureDetector>
132
+ <Animated.View
133
+ style={[
134
+ styles.filledStyle,
135
+ animatedFilledStyles,
136
+ {
137
+ backgroundColor: filledColor,
138
+ },
139
+ filledStyles,
140
+ ]}
141
+ />
142
+ <Animated.View style={[thumbStyles, thumb]}>
143
+ {onEndDrag || onProgressDrag ? <ProgressControlThumb /> : null}
144
+ </Animated.View>
115
145
  </View>
116
- );
117
- },
118
- (prevProps, nextProps) => {
119
- if (
120
- prevProps.duration === nextProps.duration &&
121
- prevProps.progress === nextProps.progress &&
122
- prevProps.width === nextProps.width
123
- )
124
- return true;
125
- else return false;
126
- },
127
- );
146
+ </GestureDetector>
147
+ );
148
+ };
128
149
 
129
150
  const styles = StyleSheet.create({
130
151
  container: {
131
- height,
152
+ borderRadius: 2,
153
+ height: TRACK_HEIGHT,
132
154
  },
133
155
  filledStyle: {
134
- height,
156
+ borderRadius: 2,
157
+ height: TRACK_HEIGHT,
135
158
  },
136
159
  progressControlThumbStyle: {
137
160
  borderRadius: 5,
@@ -145,7 +168,7 @@ const styles = StyleSheet.create({
145
168
  shadowOpacity: 0.27,
146
169
  shadowRadius: 4.65,
147
170
  top: -15,
148
- width: 6,
171
+ width: THUMB_WIDTH,
149
172
  },
150
173
  });
151
174
  ProgressControl.displayName = 'ProgressControl';