stream-chat-react-native-core 5.0.0-beta.0 → 5.0.0-beta.3

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 (165) hide show
  1. package/lib/commonjs/components/Attachment/FileAttachment.js +16 -7
  2. package/lib/commonjs/components/Attachment/FileAttachment.js.map +1 -1
  3. package/lib/commonjs/components/Attachment/Gallery.js +19 -17
  4. package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
  5. package/lib/commonjs/components/Attachment/Giphy.js +10 -10
  6. package/lib/commonjs/components/Attachment/Giphy.js.map +1 -1
  7. package/lib/commonjs/components/Attachment/utils/getGiphyMimeType.js +15 -0
  8. package/lib/commonjs/components/Attachment/utils/getGiphyMimeType.js.map +1 -0
  9. package/lib/commonjs/components/Channel/Channel.js +1 -1
  10. package/lib/commonjs/components/Channel/Channel.js.map +1 -1
  11. package/lib/commonjs/components/ChannelList/hooks/listeners/useNewMessage.js +16 -4
  12. package/lib/commonjs/components/ChannelList/hooks/listeners/useNewMessage.js.map +1 -1
  13. package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js +12 -7
  14. package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
  15. package/lib/commonjs/components/ChannelPreview/ChannelPreview.js +10 -6
  16. package/lib/commonjs/components/ChannelPreview/ChannelPreview.js.map +1 -1
  17. package/lib/commonjs/components/ImageGallery/ImageGallery.js +38 -30
  18. package/lib/commonjs/components/ImageGallery/ImageGallery.js.map +1 -1
  19. package/lib/commonjs/components/ImageGallery/components/ImageGrid.js +2 -2
  20. package/lib/commonjs/components/ImageGallery/components/ImageGrid.js.map +1 -1
  21. package/lib/commonjs/components/ImageGallery/hooks/useImageGalleryGestures.js +6 -0
  22. package/lib/commonjs/components/ImageGallery/hooks/useImageGalleryGestures.js.map +1 -1
  23. package/lib/commonjs/components/Message/Message.js +6 -6
  24. package/lib/commonjs/components/Message/Message.js.map +1 -1
  25. package/lib/commonjs/components/Message/MessageSimple/MessageTextContainer.js +7 -3
  26. package/lib/commonjs/components/Message/MessageSimple/MessageTextContainer.js.map +1 -1
  27. package/lib/commonjs/components/Message/MessageSimple/utils/renderText.js +1 -1
  28. package/lib/commonjs/components/Message/MessageSimple/utils/renderText.js.map +1 -1
  29. package/lib/commonjs/components/MessageList/MessageList.js +5 -5
  30. package/lib/commonjs/components/MessageList/MessageList.js.map +1 -1
  31. package/lib/commonjs/contexts/imageGalleryContext/ImageGalleryContext.js +13 -14
  32. package/lib/commonjs/contexts/imageGalleryContext/ImageGalleryContext.js.map +1 -1
  33. package/lib/commonjs/contexts/imageGalleryContext/ImageGalleryContext.md +1 -1
  34. package/lib/commonjs/index.js +13 -1
  35. package/lib/commonjs/index.js.map +1 -1
  36. package/lib/commonjs/mock-builders/DB/mock.js +1 -13
  37. package/lib/commonjs/mock-builders/DB/mock.js.map +1 -1
  38. package/lib/commonjs/mock-builders/event/messageNew.js +2 -0
  39. package/lib/commonjs/mock-builders/event/messageNew.js.map +1 -1
  40. package/lib/commonjs/store/QuickSqliteClient.js +7 -3
  41. package/lib/commonjs/store/QuickSqliteClient.js.map +1 -1
  42. package/lib/commonjs/store/apis/getChannels.js +2 -15
  43. package/lib/commonjs/store/apis/getChannels.js.map +1 -1
  44. package/lib/commonjs/store/apis/getChannelsForFilterSort.js +37 -0
  45. package/lib/commonjs/store/apis/getChannelsForFilterSort.js.map +1 -0
  46. package/lib/commonjs/store/apis/index.js +264 -0
  47. package/lib/commonjs/store/apis/index.js.map +1 -0
  48. package/lib/commonjs/store/apis/queries/selectChannelIdsForFilterSort.js +1 -1
  49. package/lib/commonjs/store/apis/queries/selectChannelIdsForFilterSort.js.map +1 -1
  50. package/lib/commonjs/store/apis/queries/selectChannels.js +2 -2
  51. package/lib/commonjs/store/apis/queries/selectChannels.js.map +1 -1
  52. package/lib/commonjs/store/sqlite-utils/appendWhereCluase.js +1 -2
  53. package/lib/commonjs/store/sqlite-utils/appendWhereCluase.js.map +1 -1
  54. package/lib/commonjs/test-utils/BetterSqlite.js +54 -0
  55. package/lib/commonjs/test-utils/BetterSqlite.js.map +1 -0
  56. package/lib/commonjs/version.json +1 -1
  57. package/lib/module/components/Attachment/FileAttachment.js +16 -7
  58. package/lib/module/components/Attachment/FileAttachment.js.map +1 -1
  59. package/lib/module/components/Attachment/Gallery.js +19 -17
  60. package/lib/module/components/Attachment/Gallery.js.map +1 -1
  61. package/lib/module/components/Attachment/Giphy.js +10 -10
  62. package/lib/module/components/Attachment/Giphy.js.map +1 -1
  63. package/lib/module/components/Attachment/utils/getGiphyMimeType.js +15 -0
  64. package/lib/module/components/Attachment/utils/getGiphyMimeType.js.map +1 -0
  65. package/lib/module/components/Channel/Channel.js +1 -1
  66. package/lib/module/components/Channel/Channel.js.map +1 -1
  67. package/lib/module/components/ChannelList/hooks/listeners/useNewMessage.js +16 -4
  68. package/lib/module/components/ChannelList/hooks/listeners/useNewMessage.js.map +1 -1
  69. package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js +12 -7
  70. package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
  71. package/lib/module/components/ChannelPreview/ChannelPreview.js +10 -6
  72. package/lib/module/components/ChannelPreview/ChannelPreview.js.map +1 -1
  73. package/lib/module/components/ImageGallery/ImageGallery.js +38 -30
  74. package/lib/module/components/ImageGallery/ImageGallery.js.map +1 -1
  75. package/lib/module/components/ImageGallery/components/ImageGrid.js +2 -2
  76. package/lib/module/components/ImageGallery/components/ImageGrid.js.map +1 -1
  77. package/lib/module/components/ImageGallery/hooks/useImageGalleryGestures.js +6 -0
  78. package/lib/module/components/ImageGallery/hooks/useImageGalleryGestures.js.map +1 -1
  79. package/lib/module/components/Message/Message.js +6 -6
  80. package/lib/module/components/Message/Message.js.map +1 -1
  81. package/lib/module/components/Message/MessageSimple/MessageTextContainer.js +7 -3
  82. package/lib/module/components/Message/MessageSimple/MessageTextContainer.js.map +1 -1
  83. package/lib/module/components/Message/MessageSimple/utils/renderText.js +1 -1
  84. package/lib/module/components/Message/MessageSimple/utils/renderText.js.map +1 -1
  85. package/lib/module/components/MessageList/MessageList.js +5 -5
  86. package/lib/module/components/MessageList/MessageList.js.map +1 -1
  87. package/lib/module/contexts/imageGalleryContext/ImageGalleryContext.js +13 -14
  88. package/lib/module/contexts/imageGalleryContext/ImageGalleryContext.js.map +1 -1
  89. package/lib/module/contexts/imageGalleryContext/ImageGalleryContext.md +1 -1
  90. package/lib/module/index.js +13 -1
  91. package/lib/module/index.js.map +1 -1
  92. package/lib/module/mock-builders/DB/mock.js +1 -13
  93. package/lib/module/mock-builders/DB/mock.js.map +1 -1
  94. package/lib/module/mock-builders/event/messageNew.js +2 -0
  95. package/lib/module/mock-builders/event/messageNew.js.map +1 -1
  96. package/lib/module/store/QuickSqliteClient.js +7 -3
  97. package/lib/module/store/QuickSqliteClient.js.map +1 -1
  98. package/lib/module/store/apis/getChannels.js +2 -15
  99. package/lib/module/store/apis/getChannels.js.map +1 -1
  100. package/lib/module/store/apis/getChannelsForFilterSort.js +37 -0
  101. package/lib/module/store/apis/getChannelsForFilterSort.js.map +1 -0
  102. package/lib/module/store/apis/index.js +264 -0
  103. package/lib/module/store/apis/index.js.map +1 -0
  104. package/lib/module/store/apis/queries/selectChannelIdsForFilterSort.js +1 -1
  105. package/lib/module/store/apis/queries/selectChannelIdsForFilterSort.js.map +1 -1
  106. package/lib/module/store/apis/queries/selectChannels.js +2 -2
  107. package/lib/module/store/apis/queries/selectChannels.js.map +1 -1
  108. package/lib/module/store/sqlite-utils/appendWhereCluase.js +1 -2
  109. package/lib/module/store/sqlite-utils/appendWhereCluase.js.map +1 -1
  110. package/lib/module/test-utils/BetterSqlite.js +54 -0
  111. package/lib/module/test-utils/BetterSqlite.js.map +1 -0
  112. package/lib/module/version.json +1 -1
  113. package/lib/typescript/components/Attachment/Gallery.d.ts +1 -1
  114. package/lib/typescript/components/Attachment/Giphy.d.ts +1 -1
  115. package/lib/typescript/components/Attachment/utils/getGiphyMimeType.d.ts +6 -0
  116. package/lib/typescript/components/ImageGallery/components/ImageGrid.d.ts +1 -1
  117. package/lib/typescript/components/ImageGallery/hooks/useImageGalleryGestures.d.ts +2 -1
  118. package/lib/typescript/components/Message/Message.d.ts +9 -3
  119. package/lib/typescript/components/MessageList/MessageList.d.ts +1 -1
  120. package/lib/typescript/contexts/imageGalleryContext/ImageGalleryContext.d.ts +9 -10
  121. package/lib/typescript/index.d.ts +2 -0
  122. package/lib/typescript/store/QuickSqliteClient.d.ts +4 -0
  123. package/lib/typescript/store/apis/getChannels.d.ts +13 -5
  124. package/lib/typescript/store/apis/getChannelsForFilterSort.d.ts +17 -0
  125. package/lib/typescript/store/apis/index.d.ts +20 -0
  126. package/lib/typescript/store/apis/queries/selectChannelIdsForFilterSort.d.ts +10 -1
  127. package/lib/typescript/{__tests__/utils → test-utils}/BetterSqlite.d.ts +1 -1
  128. package/package.json +5 -4
  129. package/src/__tests__/offline-feature.test.js +1 -2
  130. package/src/components/Attachment/FileAttachment.tsx +3 -0
  131. package/src/components/Attachment/Gallery.tsx +20 -17
  132. package/src/components/Attachment/Giphy.tsx +8 -8
  133. package/src/components/Attachment/utils/getGiphyMimeType.ts +13 -0
  134. package/src/components/Channel/Channel.tsx +1 -1
  135. package/src/components/ChannelList/__tests__/ChannelList.test.js +28 -0
  136. package/src/components/ChannelList/hooks/listeners/useNewMessage.ts +18 -5
  137. package/src/components/ChannelList/hooks/usePaginatedChannels.ts +19 -10
  138. package/src/components/ChannelPreview/ChannelPreview.tsx +6 -3
  139. package/src/components/ImageGallery/ImageGallery.tsx +32 -19
  140. package/src/components/ImageGallery/__tests__/ImageGallery.test.tsx +6 -6
  141. package/src/components/ImageGallery/__tests__/ImageGalleryFooter.test.tsx +3 -3
  142. package/src/components/ImageGallery/__tests__/ImageGalleryGrid.test.tsx +3 -3
  143. package/src/components/ImageGallery/__tests__/ImageGalleryHeader.test.tsx +3 -3
  144. package/src/components/ImageGallery/components/ImageGrid.tsx +3 -3
  145. package/src/components/ImageGallery/hooks/useImageGalleryGestures.tsx +16 -0
  146. package/src/components/Message/Message.tsx +9 -1
  147. package/src/components/Message/MessageSimple/MessageTextContainer.tsx +22 -2
  148. package/src/components/Message/MessageSimple/__tests__/__snapshots__/MessageAvatar.test.js.snap +1 -0
  149. package/src/components/Message/MessageSimple/utils/renderText.tsx +1 -1
  150. package/src/components/MessageList/MessageList.tsx +6 -6
  151. package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +4 -0
  152. package/src/contexts/imageGalleryContext/ImageGalleryContext.md +1 -1
  153. package/src/contexts/imageGalleryContext/ImageGalleryContext.tsx +19 -14
  154. package/src/index.ts +3 -0
  155. package/src/mock-builders/DB/mock.ts +4 -9
  156. package/src/mock-builders/event/messageNew.js +2 -0
  157. package/src/store/QuickSqliteClient.ts +11 -7
  158. package/src/store/apis/getChannels.ts +17 -14
  159. package/src/store/apis/getChannelsForFilterSort.ts +45 -0
  160. package/src/store/apis/index.ts +20 -0
  161. package/src/store/apis/queries/selectChannelIdsForFilterSort.ts +12 -2
  162. package/src/store/apis/queries/selectChannels.ts +9 -3
  163. package/src/store/sqlite-utils/appendWhereCluase.ts +1 -2
  164. package/src/{__tests__/utils → test-utils}/BetterSqlite.js +1 -1
  165. package/src/version.json +1 -1
@@ -65,6 +65,7 @@ import type { DefaultStreamChatGenerics } from '../../types/types';
65
65
  import { getResizedImageUrl } from '../../utils/getResizedImageUrl';
66
66
  import { getUrlOfImageAttachment } from '../../utils/getUrlOfImageAttachment';
67
67
  import { vh, vw } from '../../utils/utils';
68
+ import { getGiphyMimeType } from '../Attachment/utils/getGiphyMimeType';
68
69
 
69
70
  const isAndroid = Platform.OS === 'android';
70
71
  const fullScreenHeight = Dimensions.get('screen').height;
@@ -161,7 +162,8 @@ export const ImageGallery = <
161
162
  } = useTheme();
162
163
  const [gridPhotos, setGridPhotos] = useState<Photo<StreamChatGenerics>[]>([]);
163
164
  const { overlay, translucentStatusBar } = useOverlayContext();
164
- const { image, images, setImage } = useImageGalleryContext<StreamChatGenerics>();
165
+ const { messages, selectedMessage, setSelectedMessage } =
166
+ useImageGalleryContext<StreamChatGenerics>();
165
167
 
166
168
  /**
167
169
  * Height constants
@@ -256,20 +258,22 @@ export const ImageGallery = <
256
258
  * photo attachments
257
259
  */
258
260
 
259
- const photos = images.reduce((acc: Photo<StreamChatGenerics>[], cur) => {
261
+ const photos = messages.reduce((acc: Photo<StreamChatGenerics>[], cur) => {
260
262
  const attachmentImages =
261
- cur.attachments?.filter(
262
- (attachment) =>
263
- (attachment.type === 'giphy' &&
264
- (attachment.giphy?.[giphyVersion]?.url ||
265
- attachment.thumb_url ||
266
- attachment.image_url)) ||
267
- (attachment.type === 'image' &&
268
- !attachment.title_link &&
269
- !attachment.og_scrape_url &&
270
- getUrlOfImageAttachment(attachment)) ||
271
- (isVideoPackageAvailable() && attachment.type === 'video'),
272
- ) || [];
263
+ cur.attachments
264
+ ?.filter(
265
+ (attachment) =>
266
+ (attachment.type === 'giphy' &&
267
+ (attachment.giphy?.[giphyVersion]?.url ||
268
+ attachment.thumb_url ||
269
+ attachment.image_url)) ||
270
+ (attachment.type === 'image' &&
271
+ !attachment.title_link &&
272
+ !attachment.og_scrape_url &&
273
+ getUrlOfImageAttachment(attachment)) ||
274
+ (isVideoPackageAvailable() && attachment.type === 'video'),
275
+ )
276
+ .reverse() || [];
273
277
 
274
278
  const attachmentPhotos = attachmentImages.map((a) => {
275
279
  const imageUrl = getUrlOfImageAttachment(a) as string;
@@ -280,7 +284,7 @@ export const ImageGallery = <
280
284
  created_at: cur.created_at,
281
285
  id: `photoId-${cur.id}-${imageUrl}`,
282
286
  messageId: cur.id,
283
- mime_type: a.type === 'giphy' ? 'image/gif' : a.mime_type,
287
+ mime_type: a.type === 'giphy' ? getGiphyMimeType(giphyURL ?? '') : a.mime_type,
284
288
  original_height: a.original_height,
285
289
  original_width: a.original_width,
286
290
  type: a.type,
@@ -297,7 +301,7 @@ export const ImageGallery = <
297
301
  };
298
302
  });
299
303
 
300
- return [...acc, ...attachmentPhotos] as Photo<StreamChatGenerics>[];
304
+ return [...attachmentPhotos, ...acc] as Photo<StreamChatGenerics>[];
301
305
  }, []);
302
306
 
303
307
  /**
@@ -308,6 +312,12 @@ export const ImageGallery = <
308
312
  */
309
313
  const photoLength = photos.length;
310
314
 
315
+ /**
316
+ * The URL for the images may differ because of dimensions passed as
317
+ * part of the query.
318
+ */
319
+ const stripQueryFromUrl = (url: string) => url.split('?')[0];
320
+
311
321
  /**
312
322
  * Set selected photo when changed via pressing in the message list
313
323
  */
@@ -323,7 +333,9 @@ export const ImageGallery = <
323
333
  };
324
334
 
325
335
  const newIndex = photos.findIndex(
326
- (photo) => photo.messageId === image?.messageId && photo.uri === image?.url,
336
+ (photo) =>
337
+ photo.messageId === selectedMessage?.messageId &&
338
+ stripQueryFromUrl(photo.uri) === stripQueryFromUrl(selectedMessage?.url || ''),
327
339
  );
328
340
 
329
341
  if (photoLength > 1) {
@@ -331,7 +343,7 @@ export const ImageGallery = <
331
343
  }
332
344
 
333
345
  runOnUI(updatePosition)(newIndex);
334
- }, [image, photoLength]);
346
+ }, [selectedMessage, photoLength]);
335
347
 
336
348
  /**
337
349
  * Image heights are not provided and therefore need to be calculated.
@@ -370,6 +382,7 @@ export const ImageGallery = <
370
382
  scale,
371
383
  screenHeight,
372
384
  screenWidth,
385
+ selectedIndex,
373
386
  setSelectedIndex,
374
387
  translateX,
375
388
  translateY,
@@ -664,7 +677,7 @@ export const ImageGallery = <
664
677
  closeGridView={closeGridView}
665
678
  numberOfImageGalleryGridColumns={numberOfImageGalleryGridColumns}
666
679
  photos={gridPhotos}
667
- setImage={setImage}
680
+ setSelectedMessage={setSelectedMessage}
668
681
  {...imageGalleryCustomComponents?.grid}
669
682
  />
670
683
  </BottomSheetModal>
@@ -48,7 +48,7 @@ describe('ImageGallery', () => {
48
48
  it('render image gallery component', () => {
49
49
  const { queryAllByA11yLabel } = render(
50
50
  getComponent({
51
- images: [
51
+ messages: [
52
52
  generateMessage({
53
53
  attachments: [
54
54
  generateImageAttachment(),
@@ -66,7 +66,7 @@ describe('ImageGallery', () => {
66
66
  it('handle handleLoad function when video item present and payload duration is available', () => {
67
67
  const { getByA11yLabel } = render(
68
68
  getComponent({
69
- images: [
69
+ messages: [
70
70
  generateMessage({
71
71
  attachments: [generateVideoAttachment({ type: 'video' })],
72
72
  }),
@@ -89,7 +89,7 @@ describe('ImageGallery', () => {
89
89
  it('handle handleLoad function when video item present and payload duration is undefined', () => {
90
90
  const { getByA11yLabel } = render(
91
91
  getComponent({
92
- images: [
92
+ messages: [
93
93
  generateMessage({
94
94
  attachments: [generateVideoAttachment({ type: 'video' })],
95
95
  }),
@@ -112,7 +112,7 @@ describe('ImageGallery', () => {
112
112
  it('handle handleProgress function when video item present and payload is well defined', () => {
113
113
  const { getByA11yLabel } = render(
114
114
  getComponent({
115
- images: [
115
+ messages: [
116
116
  generateMessage({
117
117
  attachments: [generateVideoAttachment({ type: 'video' })],
118
118
  }),
@@ -140,7 +140,7 @@ describe('ImageGallery', () => {
140
140
  it('handle handleProgress function when video item present and payload is not defined', () => {
141
141
  const { getByA11yLabel } = render(
142
142
  getComponent({
143
- images: [
143
+ messages: [
144
144
  generateMessage({
145
145
  attachments: [generateVideoAttachment({ type: 'video' })],
146
146
  }),
@@ -168,7 +168,7 @@ describe('ImageGallery', () => {
168
168
  it('handle handleEnd function when video item present', () => {
169
169
  const { getByA11yLabel } = render(
170
170
  getComponent({
171
- images: [
171
+ messages: [
172
172
  generateMessage({
173
173
  attachments: [generateVideoAttachment({ type: 'video' })],
174
174
  }),
@@ -71,7 +71,7 @@ describe('ImageGalleryFooter', () => {
71
71
  <ImageGalleryContext.Provider
72
72
  value={
73
73
  {
74
- images: [
74
+ messages: [
75
75
  generateMessage({
76
76
  attachments: [generateVideoAttachment({ type: 'video' })],
77
77
  }),
@@ -123,7 +123,7 @@ describe('ImageGalleryFooter', () => {
123
123
  <ImageGalleryContext.Provider
124
124
  value={
125
125
  {
126
- images: [
126
+ messages: [
127
127
  generateMessage({
128
128
  attachments: [generateVideoAttachment({ type: 'video' })],
129
129
  }),
@@ -162,7 +162,7 @@ describe('ImageGalleryFooter', () => {
162
162
  <ImageGalleryContext.Provider
163
163
  value={
164
164
  {
165
- images: [
165
+ messages: [
166
166
  generateMessage({
167
167
  attachments: [generateImageAttachment()],
168
168
  }),
@@ -76,13 +76,13 @@ describe('ImageGalleryOverlay', () => {
76
76
 
77
77
  it('should trigger the selectAndClose when the Image item is pressed', () => {
78
78
  const closeGridViewMock = jest.fn();
79
- const setImageMock = jest.fn();
79
+ const setSelectedMessageMock = jest.fn();
80
80
 
81
81
  const { getAllByA11yLabel } = render(
82
82
  getComponent({
83
83
  closeGridView: closeGridViewMock,
84
84
  photos: [generateImageAttachment(), generateVideoAttachment({ type: 'video' })],
85
- setImage: setImageMock,
85
+ setSelectedMessage: setSelectedMessageMock,
86
86
  }),
87
87
  );
88
88
 
@@ -93,6 +93,6 @@ describe('ImageGalleryOverlay', () => {
93
93
  });
94
94
 
95
95
  expect(closeGridViewMock).toHaveBeenCalledTimes(1);
96
- expect(setImageMock).toHaveBeenCalledTimes(1);
96
+ expect(setSelectedMessageMock).toHaveBeenCalledTimes(1);
97
97
  });
98
98
  });
@@ -65,7 +65,7 @@ describe('ImageGalleryHeader', () => {
65
65
  <ImageGalleryContext.Provider
66
66
  value={
67
67
  {
68
- images: [
68
+ messages: [
69
69
  generateMessage({
70
70
  attachments: [generateImageAttachment()],
71
71
  }),
@@ -109,7 +109,7 @@ describe('ImageGalleryHeader', () => {
109
109
  <ImageGalleryContext.Provider
110
110
  value={
111
111
  {
112
- images: [
112
+ messages: [
113
113
  generateMessage({
114
114
  attachments: [generateVideoAttachment({ type: 'video' })],
115
115
  }),
@@ -146,7 +146,7 @@ describe('ImageGalleryHeader', () => {
146
146
  <ImageGalleryContext.Provider
147
147
  value={
148
148
  {
149
- images: [
149
+ messages: [
150
150
  generateMessage({
151
151
  attachments: [generateImageAttachment()],
152
152
  }),
@@ -107,7 +107,7 @@ export type ImageGridType<
107
107
  > = ImageGalleryGridImageComponents<StreamChatGenerics> & {
108
108
  closeGridView: () => void;
109
109
  photos: Photo<StreamChatGenerics>[];
110
- setImage: React.Dispatch<
110
+ setSelectedMessage: React.Dispatch<
111
111
  React.SetStateAction<
112
112
  | {
113
113
  messageId?: string | undefined;
@@ -130,7 +130,7 @@ export const ImageGrid = <
130
130
  imageComponent,
131
131
  numberOfImageGalleryGridColumns,
132
132
  photos,
133
- setImage,
133
+ setSelectedMessage,
134
134
  } = props;
135
135
 
136
136
  const {
@@ -148,7 +148,7 @@ export const ImageGrid = <
148
148
  imageComponent,
149
149
  numberOfImageGalleryGridColumns,
150
150
  selectAndClose: () => {
151
- setImage({ messageId: photo.messageId, url: photo.uri });
151
+ setSelectedMessage({ messageId: photo.messageId, url: photo.uri });
152
152
  closeGridView();
153
153
  },
154
154
  }));
@@ -42,6 +42,7 @@ export const useImageGalleryGestures = ({
42
42
  scale,
43
43
  screenHeight,
44
44
  screenWidth,
45
+ selectedIndex,
45
46
  setSelectedIndex,
46
47
  translateX,
47
48
  translateY,
@@ -57,6 +58,7 @@ export const useImageGalleryGestures = ({
57
58
  scale: SharedValue<number>;
58
59
  screenHeight: number;
59
60
  screenWidth: number;
61
+ selectedIndex: number;
60
62
  setSelectedIndex: React.Dispatch<React.SetStateAction<number>>;
61
63
  translateX: SharedValue<number>;
62
64
  translateY: SharedValue<number>;
@@ -82,6 +84,20 @@ export const useImageGalleryGestures = ({
82
84
  const focalY = useSharedValue(0);
83
85
  const index = useSharedValue(0);
84
86
 
87
+ /**
88
+ * if a specific image index > 0 has been passed in
89
+ * while creating the hook, set the value of the index
90
+ * reference to its value.
91
+ *
92
+ * This makes it possible to seelct an image in the list,
93
+ * and scroll/pan as normal. Prior to this,
94
+ * it was always assumed that one started at index 0 in the
95
+ * gallery.
96
+ * */
97
+ if (index.value !== selectedIndex) {
98
+ index.value = selectedIndex;
99
+ }
100
+
85
101
  /**
86
102
  * Shared values for movement
87
103
  */
@@ -73,15 +73,23 @@ export type UrlTouchableHandlerPayload = {
73
73
  additionalInfo?: { url?: string };
74
74
  };
75
75
 
76
+ export type FileAttachmentTouchableHandlerPayload<
77
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
78
+ > = {
79
+ emitter: 'fileAttachment';
80
+ additionalInfo?: { attachment?: Attachment<StreamChatGenerics> };
81
+ };
82
+
76
83
  export type TouchableHandlerPayload = {
77
84
  defaultHandler?: () => void;
78
85
  event?: GestureResponderEvent;
79
86
  } & (
80
87
  | {
81
- emitter?: TouchableEmitter;
88
+ emitter?: Exclude<TouchableEmitter, 'textMention' | 'textLink' | 'card' | 'fileAttachment'>;
82
89
  }
83
90
  | TextMentionTouchableHandlerPayload
84
91
  | UrlTouchableHandlerPayload
92
+ | FileAttachmentTouchableHandlerPayload
85
93
  );
86
94
 
87
95
  export type MessageTouchableHandlerPayload<
@@ -117,8 +117,16 @@ const areEqual = <StreamChatGenerics extends DefaultStreamChatGenerics = Default
117
117
  prevProps: MessageTextContainerPropsWithContext<StreamChatGenerics>,
118
118
  nextProps: MessageTextContainerPropsWithContext<StreamChatGenerics>,
119
119
  ) => {
120
- const { message: prevMessage, onlyEmojis: prevOnlyEmojis } = prevProps;
121
- const { message: nextMessage, onlyEmojis: nextOnlyEmojis } = nextProps;
120
+ const {
121
+ markdownStyles: prevMarkdownStyles,
122
+ message: prevMessage,
123
+ onlyEmojis: prevOnlyEmojis,
124
+ } = prevProps;
125
+ const {
126
+ markdownStyles: nextMarkdownStyles,
127
+ message: nextMessage,
128
+ onlyEmojis: nextOnlyEmojis,
129
+ } = nextProps;
122
130
 
123
131
  const messageTextEqual = prevMessage.text === nextMessage.text;
124
132
  if (!messageTextEqual) return false;
@@ -134,6 +142,18 @@ const areEqual = <StreamChatGenerics extends DefaultStreamChatGenerics = Default
134
142
  prevMessage.mentioned_users[0].name === nextMessage.mentioned_users[0].name));
135
143
  if (!mentionedUsersEqual) return false;
136
144
 
145
+ // stringify could be an expensive operation, so lets rule out the obvious
146
+ // possibilities first such as different object reference or empty objects etc.
147
+ // Also keeping markdown equality check at the last to make sure other less
148
+ // expensive equality checks get executed first and markdown check will be skipped if returned
149
+ // false from previous checks.
150
+ const markdownStylesEqual =
151
+ prevMarkdownStyles === nextMarkdownStyles ||
152
+ (Object.keys(prevMarkdownStyles || {}).length === 0 &&
153
+ Object.keys(nextMarkdownStyles || {}).length === 0) ||
154
+ JSON.stringify(prevMarkdownStyles) === JSON.stringify(nextMarkdownStyles);
155
+ if (!markdownStylesEqual) return false;
156
+
137
157
  return true;
138
158
  };
139
159
 
@@ -47,6 +47,7 @@ exports[`MessageAvatar should render message avatar 1`] = `
47
47
  "width": 32,
48
48
  },
49
49
  Object {
50
+ "backgroundColor": "#ececec",
50
51
  "borderRadius": 16,
51
52
  "height": 32,
52
53
  "width": 32,
@@ -261,7 +261,7 @@ export const renderText = <
261
261
  );
262
262
 
263
263
  const customRules = {
264
- link: { link },
264
+ link: { react: link },
265
265
  list: { react: list },
266
266
  // Truncate long text content in the message overlay
267
267
  paragraph: messageTextNumberOfLines ? { react: paragraphText } : {},
@@ -124,7 +124,7 @@ type MessageListPropsWithContext<
124
124
  | 'targetedMessage'
125
125
  > &
126
126
  Pick<ChatContextValue<StreamChatGenerics>, 'client'> &
127
- Pick<ImageGalleryContextValue<StreamChatGenerics>, 'setImages'> &
127
+ Pick<ImageGalleryContextValue<StreamChatGenerics>, 'setMessages'> &
128
128
  Pick<
129
129
  PaginatedMessageListContextValue<StreamChatGenerics>,
130
130
  'hasNoMoreRecentMessagesToLoad' | 'loadMore' | 'loadMoreRecent'
@@ -270,7 +270,7 @@ const MessageListWithContext = <
270
270
  scrollToFirstUnreadThreshold,
271
271
  selectedPicker,
272
272
  setFlatListRef,
273
- setImages,
273
+ setMessages,
274
274
  setSelectedPicker,
275
275
  setTargetedMessage,
276
276
  StickyHeader,
@@ -530,7 +530,7 @@ const MessageListWithContext = <
530
530
  index: number;
531
531
  item: MessageType<StreamChatGenerics>;
532
532
  }) => {
533
- if (!channel || (!channel.initialized && !channel.staticState)) return null;
533
+ if (!channel || (!channel.initialized && !channel.offlineMode)) return null;
534
534
 
535
535
  const lastRead = channel.lastRead();
536
536
 
@@ -898,7 +898,7 @@ const MessageListWithContext = <
898
898
  isListActive &&
899
899
  ((threadList && thread) || (!threadList && !thread))
900
900
  ) {
901
- setImages(messagesWithImages as MessageType<StreamChatGenerics>[]);
901
+ setMessages(messagesWithImages as MessageType<StreamChatGenerics>[]);
902
902
  }
903
903
  }, [
904
904
  imageString,
@@ -1044,7 +1044,7 @@ export const MessageList = <
1044
1044
  targetedMessage,
1045
1045
  } = useChannelContext<StreamChatGenerics>();
1046
1046
  const { client } = useChatContext<StreamChatGenerics>();
1047
- const { setImages } = useImageGalleryContext<StreamChatGenerics>();
1047
+ const { setMessages } = useImageGalleryContext<StreamChatGenerics>();
1048
1048
  const {
1049
1049
  DateHeader,
1050
1050
  deletedMessagesVisibilityType,
@@ -1104,7 +1104,7 @@ export const MessageList = <
1104
1104
  ScrollToBottomButton,
1105
1105
  scrollToFirstUnreadThreshold,
1106
1106
  selectedPicker,
1107
- setImages,
1107
+ setMessages,
1108
1108
  setSelectedPicker,
1109
1109
  setTargetedMessage,
1110
1110
  StickyHeader,
@@ -321,6 +321,7 @@ exports[`Thread should match thread snapshot 1`] = `
321
321
  "width": 32,
322
322
  },
323
323
  Object {
324
+ "backgroundColor": "#ececec",
324
325
  "borderRadius": 16,
325
326
  "height": 32,
326
327
  "width": 32,
@@ -569,6 +570,7 @@ exports[`Thread should match thread snapshot 1`] = `
569
570
  "width": 32,
570
571
  },
571
572
  Object {
573
+ "backgroundColor": "#ececec",
572
574
  "borderRadius": 16,
573
575
  "height": 32,
574
576
  "width": 32,
@@ -817,6 +819,7 @@ exports[`Thread should match thread snapshot 1`] = `
817
819
  "width": 32,
818
820
  },
819
821
  Object {
822
+ "backgroundColor": "#ececec",
820
823
  "borderRadius": 16,
821
824
  "height": 32,
822
825
  "width": 32,
@@ -1108,6 +1111,7 @@ exports[`Thread should match thread snapshot 1`] = `
1108
1111
  "width": 32,
1109
1112
  },
1110
1113
  Object {
1114
+ "backgroundColor": "#ececec",
1111
1115
  "borderRadius": 16,
1112
1116
  "height": 32,
1113
1117
  "width": 32,
@@ -8,7 +8,7 @@ can get access to context as following:
8
8
  import { useChannelsContext } from 'stream-chat-react-native';
9
9
 
10
10
  const SomeChildComponent = () => {
11
- const { image, setImage, setImages } = useImageGalleryContext();
11
+ const { selectedMessage, setSelectedMessage, setMessages } = useImageGalleryContext();
12
12
 
13
13
  return (
14
14
  <View />
@@ -7,13 +7,18 @@ import { DEFAULT_BASE_CONTEXT_VALUE } from '../utils/defaultBaseContextValue';
7
7
  import { getDisplayName } from '../utils/getDisplayName';
8
8
  import { isTestEnvironment } from '../utils/isTestEnvironment';
9
9
 
10
+ type SelectedMessage = {
11
+ messageId?: string;
12
+ url?: string;
13
+ };
14
+
10
15
  export type ImageGalleryContextValue<
11
16
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
12
17
  > = {
13
- images: MessageType<StreamChatGenerics>[];
14
- setImage: React.Dispatch<React.SetStateAction<{ messageId?: string; url?: string } | undefined>>;
15
- setImages: React.Dispatch<React.SetStateAction<MessageType<StreamChatGenerics>[]>>;
16
- image?: { messageId?: string; url?: string };
18
+ messages: MessageType<StreamChatGenerics>[];
19
+ setMessages: React.Dispatch<React.SetStateAction<MessageType<StreamChatGenerics>[]>>;
20
+ setSelectedMessage: React.Dispatch<React.SetStateAction<SelectedMessage | undefined>>;
21
+ selectedMessage?: SelectedMessage;
17
22
  };
18
23
 
19
24
  export const ImageGalleryContext = React.createContext(
@@ -25,19 +30,19 @@ export const ImageGalleryProvider = <
25
30
  >({
26
31
  children,
27
32
  }: PropsWithChildren<UnknownType>) => {
28
- const [images, setImages] = useState<MessageType<StreamChatGenerics>[]>([]);
29
- const [image, setImage] = useState<{ messageId?: string; url?: string }>();
30
-
31
- const imageGalleryContext = {
32
- image,
33
- images,
34
- setImage,
35
- setImages,
36
- };
33
+ const [messages, setMessages] = useState<MessageType<StreamChatGenerics>[]>([]);
34
+ const [selectedMessage, setSelectedMessage] = useState<SelectedMessage>();
37
35
 
38
36
  return (
39
37
  <ImageGalleryContext.Provider
40
- value={imageGalleryContext as unknown as ImageGalleryContextValue}
38
+ value={
39
+ {
40
+ messages,
41
+ selectedMessage,
42
+ setMessages,
43
+ setSelectedMessage,
44
+ } as unknown as ImageGalleryContextValue
45
+ }
41
46
  >
42
47
  {children}
43
48
  </ImageGalleryContext.Provider>
package/src/index.ts CHANGED
@@ -22,3 +22,6 @@ export { default as heTranslations } from './i18n/he.json';
22
22
 
23
23
  export { QuickSqliteClient } from './store/QuickSqliteClient';
24
24
  export { version } from './version.json';
25
+
26
+ import * as OfflineStoreApis from './store/apis';
27
+ export { OfflineStoreApis };
@@ -1,8 +1,8 @@
1
- import Database from 'better-sqlite3';
1
+ import Sqlite3 from 'better-sqlite3';
2
2
 
3
3
  import type { PreparedQueries } from '../../store/types';
4
4
 
5
- export let db: Database;
5
+ export let db: Sqlite3.Database;
6
6
 
7
7
  export const sqliteMock = {
8
8
  close: () => {
@@ -15,7 +15,7 @@ export const sqliteMock = {
15
15
  executeSql: (dbName: string, queryInput: string, params: unknown[]) => {
16
16
  const query = queryInput.trim().toLowerCase();
17
17
  const stmt = db.prepare(query);
18
- let result = [];
18
+ let result: unknown[] = [];
19
19
 
20
20
  if (query.indexOf('select') === 0) {
21
21
  if (params) {
@@ -98,15 +98,10 @@ export const sqliteMock = {
98
98
  };
99
99
  },
100
100
  open: () => {
101
- db = new Database('foobar.db');
101
+ db = new Sqlite3('foobar.db');
102
102
  return {
103
103
  message: '',
104
104
  status: 0,
105
105
  };
106
106
  },
107
107
  };
108
-
109
- export const initializeDBMocking = () => {
110
- global.sqlite = sqliteMock;
111
- };
112
- export const resetDBMocking = () => (global.sqlite = undefined);
@@ -1,6 +1,8 @@
1
1
  export default (client, newMessage, channel = {}) => {
2
2
  client.dispatchEvent({
3
3
  channel,
4
+ channel_id: channel.id,
5
+ channel_type: channel.type,
4
6
  cid: channel.cid,
5
7
  message: newMessage,
6
8
  type: 'message.new',
@@ -1,11 +1,9 @@
1
1
  /* eslint-disable no-underscore-dangle */
2
- // Importing following package just to avoid errors using sqlite global.
3
- // @ts-ignore
4
- // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars
5
- import types from 'react-native-quick-sqlite';
2
+ import type { QuickSQLite } from 'react-native-quick-sqlite';
3
+ let sqlite: typeof QuickSQLite;
6
4
 
7
5
  try {
8
- require('react-native-quick-sqlite');
6
+ sqlite = require('react-native-quick-sqlite')?.QuickSQLite;
9
7
  } catch (e) {
10
8
  // Failed for one of the reason
11
9
  // 1. Running on expo, where we don't support offline storage yet.
@@ -17,13 +15,18 @@ import { tables } from './schema';
17
15
  import { createCreateTableQuery } from './sqlite-utils/createCreateTableQuery';
18
16
  import type { PreparedQueries, Table } from './types';
19
17
 
18
+ /**
19
+ * QuickSqliteClient takes care of any direct interaction with sqlite.
20
+ * This way usage react-native-quick-sqlite package is scoped to a single class/file.
21
+ */
20
22
  export class QuickSqliteClient {
21
- static dbVersion = 0;
23
+ static dbVersion = 2;
22
24
 
23
25
  static dbName = DB_NAME;
24
26
  static dbLocation = DB_LOCATION;
25
27
 
26
28
  static getDbVersion = () => this.dbVersion;
29
+ // Force a specific db version. This is mainly useful for testsuit.
27
30
  static setDbVersion = (version: number) => (this.dbVersion = version);
28
31
 
29
32
  static openDB = () => {
@@ -89,13 +92,14 @@ export class QuickSqliteClient {
89
92
 
90
93
  static initializeDatabase = () => {
91
94
  // @ts-ignore
92
- if (window.sqlite === undefined) {
95
+ if (sqlite === undefined) {
93
96
  throw new Error(
94
97
  'Please install "react-native-quick-sqlite" package to enable offline support',
95
98
  );
96
99
  }
97
100
 
98
101
  const version = this.getUserPragmaVersion();
102
+
99
103
  if (version !== this.dbVersion) {
100
104
  this.dropTables();
101
105
  this.updateUserPragmaVersion(this.dbVersion);