@oxyhq/services 5.11.9 → 5.11.10

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 (192) hide show
  1. package/lib/commonjs/ui/components/AnimationExample.js +213 -0
  2. package/lib/commonjs/ui/components/AnimationExample.js.map +1 -0
  3. package/lib/commonjs/ui/components/FollowButton.js +58 -47
  4. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  5. package/lib/commonjs/ui/components/GroupedItem.js +2 -1
  6. package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
  7. package/lib/commonjs/ui/components/GroupedSection.js +3 -0
  8. package/lib/commonjs/ui/components/GroupedSection.js.map +1 -1
  9. package/lib/commonjs/ui/components/Header.js +25 -11
  10. package/lib/commonjs/ui/components/Header.js.map +1 -1
  11. package/lib/commonjs/ui/components/OxyProvider.js +69 -33
  12. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  13. package/lib/commonjs/ui/components/ProfileCard.js +5 -1
  14. package/lib/commonjs/ui/components/ProfileCard.js.map +1 -1
  15. package/lib/commonjs/ui/components/index.js +0 -7
  16. package/lib/commonjs/ui/components/index.js.map +1 -1
  17. package/lib/commonjs/ui/components/internal/TextField.js +8 -4
  18. package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
  19. package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js +161 -0
  20. package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -0
  21. package/lib/commonjs/ui/context/OxyContext.js +97 -38
  22. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  23. package/lib/commonjs/ui/hooks/useFollow.types.js +2 -0
  24. package/lib/commonjs/ui/hooks/useFollow.types.js.map +1 -0
  25. package/lib/commonjs/ui/navigation/OxyRouter.js +10 -0
  26. package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
  27. package/lib/commonjs/ui/screens/AccountCenterScreen.js +26 -14
  28. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  29. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +3 -3
  30. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  31. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +64 -15
  32. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  33. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +4 -4
  34. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  35. package/lib/commonjs/ui/screens/FeedbackScreen.js +72 -75
  36. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  37. package/lib/commonjs/ui/screens/FileManagementScreen.js +286 -126
  38. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  39. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +322 -0
  40. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -0
  41. package/lib/commonjs/ui/screens/ProfileScreen.js +1 -1
  42. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  43. package/lib/commonjs/ui/screens/SessionManagementScreen.js +176 -174
  44. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
  45. package/lib/commonjs/ui/screens/SignInScreen.js +43 -52
  46. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  47. package/lib/commonjs/ui/screens/SignUpScreen.js +6 -4
  48. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  49. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +386 -0
  50. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -0
  51. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +25 -15
  52. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  53. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +16 -9
  54. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  55. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +1 -1
  56. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  57. package/lib/commonjs/ui/styles/authStyles.js +1 -1
  58. package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
  59. package/lib/module/ui/components/AnimationExample.js +209 -0
  60. package/lib/module/ui/components/AnimationExample.js.map +1 -0
  61. package/lib/module/ui/components/FollowButton.js +58 -47
  62. package/lib/module/ui/components/FollowButton.js.map +1 -1
  63. package/lib/module/ui/components/GroupedItem.js +2 -1
  64. package/lib/module/ui/components/GroupedItem.js.map +1 -1
  65. package/lib/module/ui/components/GroupedSection.js +3 -0
  66. package/lib/module/ui/components/GroupedSection.js.map +1 -1
  67. package/lib/module/ui/components/Header.js +25 -11
  68. package/lib/module/ui/components/Header.js.map +1 -1
  69. package/lib/module/ui/components/OxyProvider.js +70 -34
  70. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  71. package/lib/module/ui/components/ProfileCard.js +5 -1
  72. package/lib/module/ui/components/ProfileCard.js.map +1 -1
  73. package/lib/module/ui/components/index.js +0 -1
  74. package/lib/module/ui/components/index.js.map +1 -1
  75. package/lib/module/ui/components/internal/TextField.js +8 -4
  76. package/lib/module/ui/components/internal/TextField.js.map +1 -1
  77. package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js +156 -0
  78. package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -0
  79. package/lib/module/ui/context/OxyContext.js +97 -39
  80. package/lib/module/ui/context/OxyContext.js.map +1 -1
  81. package/lib/module/ui/hooks/useFollow.types.js +2 -0
  82. package/lib/module/ui/hooks/useFollow.types.js.map +1 -0
  83. package/lib/module/ui/navigation/OxyRouter.js +10 -0
  84. package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
  85. package/lib/module/ui/screens/AccountCenterScreen.js +12 -1
  86. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  87. package/lib/module/ui/screens/AccountOverviewScreen.js +3 -3
  88. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  89. package/lib/module/ui/screens/AccountSettingsScreen.js +64 -15
  90. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  91. package/lib/module/ui/screens/AccountSwitcherScreen.js +4 -4
  92. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  93. package/lib/module/ui/screens/FeedbackScreen.js +72 -75
  94. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  95. package/lib/module/ui/screens/FileManagementScreen.js +285 -125
  96. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  97. package/lib/module/ui/screens/LanguageSelectorScreen.js +319 -0
  98. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -0
  99. package/lib/module/ui/screens/ProfileScreen.js +1 -1
  100. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  101. package/lib/module/ui/screens/SessionManagementScreen.js +177 -175
  102. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  103. package/lib/module/ui/screens/SignInScreen.js +44 -53
  104. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  105. package/lib/module/ui/screens/SignUpScreen.js +6 -4
  106. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  107. package/lib/module/ui/screens/WelcomeNewUserScreen.js +382 -0
  108. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -0
  109. package/lib/module/ui/screens/internal/SignInPasswordStep.js +23 -14
  110. package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  111. package/lib/module/ui/screens/internal/SignInUsernameStep.js +15 -9
  112. package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  113. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +1 -1
  114. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  115. package/lib/module/ui/styles/authStyles.js +1 -1
  116. package/lib/module/ui/styles/authStyles.js.map +1 -1
  117. package/lib/typescript/models/interfaces.d.ts +1 -5
  118. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  119. package/lib/typescript/models/session.d.ts +1 -4
  120. package/lib/typescript/models/session.d.ts.map +1 -1
  121. package/lib/typescript/ui/components/AnimationExample.d.ts +4 -0
  122. package/lib/typescript/ui/components/AnimationExample.d.ts.map +1 -0
  123. package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
  124. package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
  125. package/lib/typescript/ui/components/Header.d.ts +9 -0
  126. package/lib/typescript/ui/components/Header.d.ts.map +1 -1
  127. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  128. package/lib/typescript/ui/components/ProfileCard.d.ts +1 -3
  129. package/lib/typescript/ui/components/ProfileCard.d.ts.map +1 -1
  130. package/lib/typescript/ui/components/index.d.ts +0 -1
  131. package/lib/typescript/ui/components/index.d.ts.map +1 -1
  132. package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
  133. package/lib/typescript/ui/components/photogrid/JustifiedPhotoGrid.d.ts +27 -0
  134. package/lib/typescript/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -0
  135. package/lib/typescript/ui/context/OxyContext.d.ts +6 -2
  136. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  137. package/lib/typescript/ui/hooks/useFollow.types.d.ts +33 -0
  138. package/lib/typescript/ui/hooks/useFollow.types.d.ts.map +1 -0
  139. package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
  140. package/lib/typescript/ui/navigation/types.d.ts +5 -0
  141. package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
  142. package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  143. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  144. package/lib/typescript/ui/screens/FeedbackScreen.d.ts.map +1 -1
  145. package/lib/typescript/ui/screens/FileManagementScreen.d.ts +18 -1
  146. package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -1
  147. package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts +7 -0
  148. package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts.map +1 -0
  149. package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
  150. package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
  151. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  152. package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
  153. package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts +13 -0
  154. package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -0
  155. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts +5 -5
  156. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
  157. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts +4 -4
  158. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts.map +1 -1
  159. package/lib/typescript/ui/styles/authStyles.d.ts +1 -1
  160. package/package.json +10 -2
  161. package/src/models/interfaces.ts +2 -5
  162. package/src/models/session.ts +1 -4
  163. package/src/ui/components/AnimationExample.tsx +194 -0
  164. package/src/ui/components/FollowButton.tsx +65 -45
  165. package/src/ui/components/GroupedItem.tsx +1 -0
  166. package/src/ui/components/GroupedSection.tsx +1 -1
  167. package/src/ui/components/Header.tsx +36 -12
  168. package/src/ui/components/OxyProvider.tsx +66 -32
  169. package/src/ui/components/ProfileCard.tsx +6 -8
  170. package/src/ui/components/index.ts +0 -1
  171. package/src/ui/components/internal/TextField.tsx +12 -6
  172. package/src/ui/components/photogrid/JustifiedPhotoGrid.tsx +158 -0
  173. package/src/ui/context/OxyContext.tsx +84 -54
  174. package/src/ui/hooks/useFollow.types.ts +33 -0
  175. package/src/ui/navigation/OxyRouter.tsx +10 -0
  176. package/src/ui/navigation/types.ts +6 -0
  177. package/src/ui/screens/AccountCenterScreen.tsx +13 -7
  178. package/src/ui/screens/AccountOverviewScreen.tsx +3 -3
  179. package/src/ui/screens/AccountSettingsScreen.tsx +65 -13
  180. package/src/ui/screens/AccountSwitcherScreen.tsx +4 -4
  181. package/src/ui/screens/FeedbackScreen.tsx +57 -80
  182. package/src/ui/screens/FileManagementScreen.tsx +278 -175
  183. package/src/ui/screens/LanguageSelectorScreen.tsx +322 -0
  184. package/src/ui/screens/ProfileScreen.tsx +6 -1
  185. package/src/ui/screens/SessionManagementScreen.tsx +148 -151
  186. package/src/ui/screens/SignInScreen.tsx +43 -62
  187. package/src/ui/screens/SignUpScreen.tsx +3 -5
  188. package/src/ui/screens/WelcomeNewUserScreen.tsx +272 -0
  189. package/src/ui/screens/internal/SignInPasswordStep.tsx +28 -13
  190. package/src/ui/screens/internal/SignInUsernameStep.tsx +21 -11
  191. package/src/ui/screens/karma/KarmaCenterScreen.tsx +1 -1
  192. package/src/ui/styles/authStyles.ts +1 -1
@@ -13,10 +13,13 @@ var _sonner = require("../../lib/sonner");
13
13
  var _vectorIcons = require("@expo/vector-icons");
14
14
  var _fileStore = require("../stores/fileStore");
15
15
  var _Header = _interopRequireDefault(require("../components/Header"));
16
+ var _JustifiedPhotoGrid = _interopRequireDefault(require("../components/photogrid/JustifiedPhotoGrid"));
16
17
  var _components = require("../components");
17
18
  var _jsxRuntime = require("react/jsx-runtime");
18
19
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
19
20
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
21
+ // Exporting props & callback types so external callers (e.g. showBottomSheet config objects) can annotate
22
+
20
23
  // Add this helper function near the top (after imports):
21
24
  async function uploadFileRaw(file, userId, oxyServices) {
22
25
  return await oxyServices.uploadRawFile(file);
@@ -27,7 +30,17 @@ const FileManagementScreen = ({
27
30
  goBack,
28
31
  navigate,
29
32
  userId,
30
- containerWidth = 400 // Fallback for when not provided by the router
33
+ containerWidth = 400,
34
+ // Fallback for when not provided by the router
35
+ selectMode = false,
36
+ multiSelect = false,
37
+ onSelect,
38
+ onConfirmSelection,
39
+ initialSelectedIds = [],
40
+ maxSelection,
41
+ disabledMimeTypes = [],
42
+ afterSelect = 'close',
43
+ allowUploadInSelectMode = true
31
44
  }) => {
32
45
  const {
33
46
  user,
@@ -51,8 +64,16 @@ const FileManagementScreen = ({
51
64
  const deleting = (0, _fileStore.useDeleting)();
52
65
  const [loading, setLoading] = (0, _react.useState)(true);
53
66
  const [refreshing, setRefreshing] = (0, _react.useState)(false);
67
+ const [paging, setPaging] = (0, _react.useState)({
68
+ offset: 0,
69
+ limit: 40,
70
+ total: 0,
71
+ hasMore: true,
72
+ loadingMore: false
73
+ });
54
74
  const [selectedFile, setSelectedFile] = (0, _react.useState)(null);
55
75
  const [showFileDetails, setShowFileDetails] = (0, _react.useState)(false);
76
+ // In selectMode we never open the detailed viewer
56
77
  const [openedFile, setOpenedFile] = (0, _react.useState)(null);
57
78
  const [fileContent, setFileContent] = (0, _react.useState)(null);
58
79
  const [loadingFileContent, setLoadingFileContent] = (0, _react.useState)(false);
@@ -77,6 +98,56 @@ const FileManagementScreen = ({
77
98
  const [hoveredPreview, setHoveredPreview] = (0, _react.useState)(null);
78
99
  const uploadStartRef = (0, _react.useRef)(null);
79
100
  const MIN_BANNER_MS = 600;
101
+ // Selection state
102
+ const [selectedIds, setSelectedIds] = (0, _react.useState)(new Set(initialSelectedIds));
103
+ (0, _react.useEffect)(() => {
104
+ if (initialSelectedIds && initialSelectedIds.length) {
105
+ setSelectedIds(new Set(initialSelectedIds));
106
+ }
107
+ }, [initialSelectedIds]);
108
+ const toggleSelect = (0, _react.useCallback)(file => {
109
+ if (!selectMode) return;
110
+ if (disabledMimeTypes.length) {
111
+ const blocked = disabledMimeTypes.some(mt => file.contentType === mt || file.contentType.startsWith(mt.endsWith('/') ? mt : mt + '/'));
112
+ if (blocked) {
113
+ _sonner.toast.error('This file type cannot be selected');
114
+ return;
115
+ }
116
+ }
117
+ if (!multiSelect) {
118
+ onSelect?.(file);
119
+ if (afterSelect === 'back') {
120
+ goBack?.();
121
+ } else if (afterSelect === 'close') {
122
+ onClose?.();
123
+ }
124
+ return;
125
+ }
126
+ setSelectedIds(prev => {
127
+ const next = new Set(prev);
128
+ const already = next.has(file.id);
129
+ if (!already) {
130
+ if (maxSelection && next.size >= maxSelection) {
131
+ _sonner.toast.error(`You can select up to ${maxSelection}`);
132
+ return prev;
133
+ }
134
+ next.add(file.id);
135
+ } else {
136
+ next.delete(file.id);
137
+ }
138
+ return next;
139
+ });
140
+ }, [selectMode, multiSelect, onSelect, onClose, goBack, disabledMimeTypes, maxSelection, afterSelect]);
141
+ const confirmMultiSelection = (0, _react.useCallback)(() => {
142
+ if (!selectMode || !multiSelect) return;
143
+ const map = {};
144
+ files.forEach(f => {
145
+ map[f.id] = f;
146
+ });
147
+ const chosen = Array.from(selectedIds).map(id => map[id]).filter(Boolean);
148
+ onConfirmSelection?.(chosen);
149
+ onClose?.();
150
+ }, [selectMode, multiSelect, selectedIds, files, onConfirmSelection, onClose]);
80
151
  const endUpload = (0, _react.useCallback)(() => {
81
152
  const started = uploadStartRef.current;
82
153
  const elapsed = started ? Date.now() - started : MIN_BANNER_MS;
@@ -149,8 +220,21 @@ const FileManagementScreen = ({
149
220
  setRefreshing(true);
150
221
  } else if (mode === 'initial') {
151
222
  setLoading(true);
223
+ setPaging(p => ({
224
+ ...p,
225
+ offset: 0,
226
+ hasMore: true
227
+ }));
228
+ } else if (mode === 'more') {
229
+ // Prevent duplicate fetches
230
+ setPaging(p => ({
231
+ ...p,
232
+ loadingMore: true
233
+ }));
152
234
  }
153
- const response = await oxyServices.listUserFiles();
235
+ const currentPaging = mode === 'more' ? prevPagingRef.current ?? paging : paging;
236
+ const effectiveOffset = mode === 'more' ? currentPaging.offset + currentPaging.limit : 0;
237
+ const response = await oxyServices.listUserFiles(currentPaging.limit, effectiveOffset);
154
238
  const assets = (response.files || []).map(f => ({
155
239
  id: f.id,
156
240
  filename: f.originalName || f.sha256,
@@ -161,18 +245,48 @@ const FileManagementScreen = ({
161
245
  metadata: f.metadata || {},
162
246
  variants: f.variants || []
163
247
  }));
164
- // Merge to preserve existing order & allow incremental updates
165
- _fileStore.useFileStore.getState().setFiles(assets, {
166
- merge: true
167
- });
248
+ if (mode === 'more') {
249
+ // append
250
+ _fileStore.useFileStore.getState().setFiles(assets, {
251
+ merge: true
252
+ });
253
+ setPaging(p => ({
254
+ ...p,
255
+ offset: effectiveOffset,
256
+ total: response.total || effectiveOffset + assets.length,
257
+ hasMore: response.hasMore,
258
+ loadingMore: false
259
+ }));
260
+ } else {
261
+ _fileStore.useFileStore.getState().setFiles(assets, {
262
+ merge: false
263
+ });
264
+ setPaging(p => ({
265
+ ...p,
266
+ offset: 0,
267
+ total: response.total || assets.length,
268
+ hasMore: response.hasMore,
269
+ loadingMore: false
270
+ }));
271
+ }
168
272
  } catch (error) {
169
273
  console.error('Failed to load files:', error);
170
274
  _sonner.toast.error(error.message || 'Failed to load files');
171
275
  } finally {
172
276
  setLoading(false);
173
277
  setRefreshing(false);
278
+ setPaging(p => ({
279
+ ...p,
280
+ loadingMore: false
281
+ }));
174
282
  }
175
- }, [targetUserId, oxyServices]);
283
+ }, [targetUserId, oxyServices, paging]);
284
+
285
+ // Keep a ref to avoid stale closure when calculating next offset
286
+ const prevPagingRef = (0, _react.useRef)(paging);
287
+ (0, _react.useEffect)(() => {
288
+ prevPagingRef.current = paging;
289
+ }, [paging]);
176
290
 
177
291
  // (removed effect; filteredFiles is memoized)
178
292
 
@@ -596,6 +710,10 @@ const FileManagementScreen = ({
596
710
  return 'document-outline';
597
711
  };
598
712
  const handleFileOpen = async file => {
713
+ if (selectMode) {
714
+ toggleSelect(file);
715
+ return;
716
+ }
599
717
  try {
600
718
  setLoadingFileContent(true);
601
719
  setOpenedFile(file);
@@ -659,13 +777,17 @@ const FileManagementScreen = ({
659
777
  style: [styles.simplePhotoItem, {
660
778
  width: itemWidth,
661
779
  height: itemWidth,
662
- marginRight: (index + 1) % itemsPerRow === 0 ? 0 : 4
780
+ marginRight: (index + 1) % itemsPerRow === 0 ? 0 : 4,
781
+ ...(selectMode && selectedIds.has(photo.id) ? {
782
+ borderWidth: 2,
783
+ borderColor: themeStyles.primaryColor
784
+ } : {})
663
785
  }],
664
786
  onPress: () => handleFileOpen(photo),
665
787
  activeOpacity: 0.8,
666
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
788
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
667
789
  style: styles.simplePhotoContainer,
668
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_expoImage.Image, {
790
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_expoImage.Image, {
669
791
  source: {
670
792
  uri: downloadUrl
671
793
  },
@@ -677,22 +799,36 @@ const FileManagementScreen = ({
677
799
  console.error('Photo failed to load:', e?.nativeEvent ?? e);
678
800
  },
679
801
  accessibilityLabel: photo.filename
680
- })
802
+ }), selectMode && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
803
+ style: styles.selectionBadge,
804
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
805
+ name: selectedIds.has(photo.id) ? 'checkmark-circle' : 'ellipse-outline',
806
+ size: 20,
807
+ color: selectedIds.has(photo.id) ? themeStyles.primaryColor : themeStyles.textColor
808
+ })
809
+ })]
681
810
  })
682
811
  }, photo.id);
683
- }, [oxyServices, containerWidth]);
812
+ }, [oxyServices, containerWidth, selectMode, selectedIds, themeStyles.primaryColor, themeStyles.textColor]);
684
813
  const renderJustifiedPhotoItem = (0, _react.useCallback)((photo, width, height, isLast) => {
685
814
  const downloadUrl = getSafeDownloadUrl(photo, 'thumb');
686
815
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
687
816
  style: [styles.justifiedPhotoItem, {
688
817
  width,
689
- height
818
+ height,
819
+ ...(selectMode && selectedIds.has(photo.id) ? {
820
+ borderWidth: 2,
821
+ borderColor: themeStyles.primaryColor
822
+ } : {}),
823
+ ...(selectMode && multiSelect && selectedIds.size > 0 && !selectedIds.has(photo.id) ? {
824
+ opacity: 0.4
825
+ } : {})
690
826
  }],
691
827
  onPress: () => handleFileOpen(photo),
692
828
  activeOpacity: 0.8,
693
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
829
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
694
830
  style: styles.justifiedPhotoContainer,
695
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_expoImage.Image, {
831
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_expoImage.Image, {
696
832
  source: {
697
833
  uri: downloadUrl
698
834
  },
@@ -704,10 +840,17 @@ const FileManagementScreen = ({
704
840
  console.error('Photo failed to load:', e?.nativeEvent ?? e);
705
841
  },
706
842
  accessibilityLabel: photo.filename
707
- })
843
+ }), selectMode && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
844
+ style: styles.selectionBadge,
845
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
846
+ name: selectedIds.has(photo.id) ? 'checkmark-circle' : 'ellipse-outline',
847
+ size: 20,
848
+ color: selectedIds.has(photo.id) ? themeStyles.primaryColor : themeStyles.textColor
849
+ })
850
+ })]
708
851
  })
709
852
  }, photo.id);
710
- }, [oxyServices]);
853
+ }, [oxyServices, selectMode, selectedIds, multiSelect, themeStyles.primaryColor, themeStyles.textColor]);
711
854
 
712
855
  // Run initial load once per targetUserId change to avoid accidental loops
713
856
  const lastLoadedFor = (0, _react.useRef)(undefined);
@@ -730,6 +873,9 @@ const FileManagementScreen = ({
730
873
  style: [styles.fileItem, {
731
874
  backgroundColor: themeStyles.secondaryBackgroundColor,
732
875
  borderColor
876
+ }, selectMode && selectedIds.has(file.id) && {
877
+ borderColor: themeStyles.primaryColor,
878
+ borderWidth: 2
733
879
  }],
734
880
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
735
881
  style: styles.fileContent,
@@ -800,13 +946,20 @@ const FileManagementScreen = ({
800
946
  size: 32,
801
947
  color: themeStyles.primaryColor
802
948
  })
803
- }), _reactNative.Platform.OS === 'web' && hoveredPreview === file.id && isImage && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
949
+ }), !selectMode && _reactNative.Platform.OS === 'web' && hoveredPreview === file.id && isImage && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
804
950
  style: styles.previewOverlay,
805
951
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
806
952
  name: "eye",
807
953
  size: 24,
808
954
  color: "#FFFFFF"
809
955
  })
956
+ }), selectMode && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
957
+ style: styles.selectionBadge,
958
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
959
+ name: selectedIds.has(file.id) ? 'checkmark-circle' : 'ellipse-outline',
960
+ size: 22,
961
+ color: selectedIds.has(file.id) ? themeStyles.primaryColor : themeStyles.textColor
962
+ })
810
963
  })]
811
964
  }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
812
965
  style: styles.fileIconContainer,
@@ -837,7 +990,7 @@ const FileManagementScreen = ({
837
990
  children: file.metadata.description
838
991
  })]
839
992
  })]
840
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
993
+ }), !selectMode && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
841
994
  style: styles.fileActions,
842
995
  children: [hasPreview && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
843
996
  style: [styles.actionButton, {
@@ -882,12 +1035,12 @@ const FileManagementScreen = ({
882
1035
 
883
1036
  // GroupedSection-based file items (for 'all' view) replacing legacy flat list look
884
1037
  const groupedFileItems = (0, _react.useMemo)(() => {
885
- return filteredFiles.filter(f => true) // placeholder for future filtering
886
- .sort((a, b) => new Date(b.uploadDate).getTime() - new Date(a.uploadDate).getTime()).map(file => {
1038
+ return filteredFiles.filter(f => true).sort((a, b) => new Date(b.uploadDate).getTime() - new Date(a.uploadDate).getTime()).map(file => {
887
1039
  const isImage = file.contentType.startsWith('image/');
888
1040
  const isVideo = file.contentType.startsWith('video/');
889
1041
  const hasPreview = isImage || isVideo;
890
1042
  const previewUrl = hasPreview ? isVideo ? getSafeDownloadUrl(file, 'poster') : getSafeDownloadUrl(file, 'thumb') : undefined;
1043
+ const isSelected = selectedIds.has(file.id);
891
1044
  return {
892
1045
  id: file.id,
893
1046
  image: previewUrl,
@@ -901,7 +1054,9 @@ const FileManagementScreen = ({
901
1054
  showChevron: false,
902
1055
  dense: true,
903
1056
  multiRow: !!file.metadata?.description,
904
- customContent: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1057
+ selected: selectMode && isSelected,
1058
+ // Hide action buttons when selecting
1059
+ customContent: !selectMode ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
905
1060
  style: styles.groupedActions,
906
1061
  children: [(isImage || isVideo || file.contentType.includes('pdf')) && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
907
1062
  style: [styles.groupedActionBtn, {
@@ -938,7 +1093,7 @@ const FileManagementScreen = ({
938
1093
  color: themeStyles.dangerColor
939
1094
  })
940
1095
  })]
941
- }),
1096
+ }) : undefined,
942
1097
  customContentBelow: file.metadata?.description ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
943
1098
  style: [styles.groupedDescription, {
944
1099
  color: themeStyles.isDarkTheme ? '#AAAAAA' : '#666666'
@@ -946,9 +1101,9 @@ const FileManagementScreen = ({
946
1101
  numberOfLines: 2,
947
1102
  children: file.metadata.description
948
1103
  }) : undefined
949
- }; // GroupedSectionItem shape
1104
+ };
950
1105
  });
951
- }, [filteredFiles, theme, themeStyles, deleting, handleFileDownload, handleFileDelete, handleFileOpen, getSafeDownloadUrl]);
1106
+ }, [filteredFiles, theme, themeStyles, deleting, handleFileDownload, handleFileDelete, handleFileOpen, getSafeDownloadUrl, selectMode, selectedIds]);
952
1107
  const renderPhotoItem = (photo, index) => {
953
1108
  const downloadUrl = getSafeDownloadUrl(photo, 'thumb');
954
1109
 
@@ -1037,6 +1192,20 @@ const FileManagementScreen = ({
1037
1192
  tintColor: themeStyles.primaryColor
1038
1193
  }),
1039
1194
  showsVerticalScrollIndicator: false,
1195
+ onScroll: ({
1196
+ nativeEvent
1197
+ }) => {
1198
+ const {
1199
+ layoutMeasurement,
1200
+ contentOffset,
1201
+ contentSize
1202
+ } = nativeEvent;
1203
+ const distanceFromBottom = contentSize.height - (contentOffset.y + layoutMeasurement.height);
1204
+ if (distanceFromBottom < 200 && !paging.loadingMore && paging.hasMore) {
1205
+ loadFiles('more');
1206
+ }
1207
+ },
1208
+ scrollEventThrottle: 250,
1040
1209
  children: [loadingDimensions && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1041
1210
  style: styles.dimensionsLoadingIndicator,
1042
1211
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
@@ -1048,7 +1217,7 @@ const FileManagementScreen = ({
1048
1217
  }],
1049
1218
  children: "Loading photo layout..."
1050
1219
  })]
1051
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(JustifiedPhotoGrid, {
1220
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_JustifiedPhotoGrid.default, {
1052
1221
  photos: photos,
1053
1222
  photoDimensions: photoDimensions,
1054
1223
  loadPhotoDimensions: loadPhotoDimensions,
@@ -1061,98 +1230,8 @@ const FileManagementScreen = ({
1061
1230
  });
1062
1231
  }, [filteredFiles, themeStyles, user?.id, targetUserId, uploading, handleFileUpload, refreshing, loadFiles, loadingDimensions, photoDimensions, loadPhotoDimensions, createJustifiedRows, renderJustifiedPhotoItem, renderPhotoItem, containerWidth]);
1063
1232
 
1064
- // Separate component for the photo grid to optimize rendering
1065
- const JustifiedPhotoGrid = /*#__PURE__*/_react.default.memo(({
1066
- photos,
1067
- photoDimensions,
1068
- loadPhotoDimensions,
1069
- createJustifiedRows,
1070
- renderJustifiedPhotoItem,
1071
- renderSimplePhotoItem,
1072
- textColor,
1073
- containerWidth
1074
- }) => {
1075
- // Load dimensions for new photos
1076
- _react.default.useEffect(() => {
1077
- loadPhotoDimensions(photos);
1078
- // Depend only on photo IDs to avoid re-running from dimension state changes
1079
- // eslint-disable-next-line react-hooks/exhaustive-deps
1080
- }, [photos.map(p => p.id).join(',')]);
1081
-
1082
- // Group photos by date
1083
- const photosByDate = _react.default.useMemo(() => {
1084
- return photos.reduce((groups, photo) => {
1085
- const date = new Date(photo.uploadDate).toDateString();
1086
- if (!groups[date]) {
1087
- groups[date] = [];
1088
- }
1089
- groups[date].push(photo);
1090
- return groups;
1091
- }, {});
1092
- }, [photos]);
1093
- const sortedDates = _react.default.useMemo(() => {
1094
- return Object.keys(photosByDate).sort((a, b) => new Date(b).getTime() - new Date(a).getTime());
1095
- }, [photosByDate]);
1096
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
1097
- children: sortedDates.map(date => {
1098
- const dayPhotos = photosByDate[date];
1099
- const justifiedRows = createJustifiedRows(dayPhotos, containerWidth);
1100
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1101
- style: styles.photoDateSection,
1102
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1103
- style: [styles.photoDateHeader, {
1104
- color: themeStyles.textColor
1105
- }],
1106
- children: new Date(date).toLocaleDateString('en-US', {
1107
- weekday: 'long',
1108
- year: 'numeric',
1109
- month: 'long',
1110
- day: 'numeric'
1111
- })
1112
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1113
- style: styles.justifiedPhotoGrid,
1114
- children: justifiedRows.map((row, rowIndex) => {
1115
- // Calculate row height based on available width
1116
- const gap = 4;
1117
- let totalAspectRatio = 0;
1118
-
1119
- // Calculate total aspect ratio for this row
1120
- row.forEach(photo => {
1121
- const dimensions = photoDimensions[photo.id];
1122
- const aspectRatio = dimensions ? dimensions.width / dimensions.height : 1.33; // Default 4:3 ratio
1123
- totalAspectRatio += aspectRatio;
1124
- });
1125
-
1126
- // Calculate the height that makes the row fill the available width
1127
- // Account for photoScrollContainer padding (32px total) and gaps between photos
1128
- const scrollContainerPadding = 32;
1129
- const availableWidth = containerWidth - scrollContainerPadding - gap * (row.length - 1);
1130
- const calculatedHeight = availableWidth / totalAspectRatio;
1233
+ // Inline justified grid removed (moved to components/photogrid/JustifiedPhotoGrid.tsx)
1131
1234
 
1132
- // Clamp height for visual consistency
1133
- const rowHeight = Math.max(120, Math.min(calculatedHeight, 300));
1134
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1135
- style: [styles.justifiedPhotoRow, {
1136
- height: rowHeight,
1137
- maxWidth: containerWidth - 32,
1138
- // Account for scroll container padding
1139
- gap: 4 // Add horizontal gap between photos in row
1140
- }],
1141
- children: row.map((photo, photoIndex) => {
1142
- const dimensions = photoDimensions[photo.id];
1143
- const aspectRatio = dimensions ? dimensions.width / dimensions.height : 1.33; // Default 4:3 ratio
1144
-
1145
- const photoWidth = rowHeight * aspectRatio;
1146
- const isLast = photoIndex === row.length - 1;
1147
- return renderJustifiedPhotoItem(photo, photoWidth, rowHeight, isLast);
1148
- })
1149
- }, `row-${rowIndex}`);
1150
- })
1151
- })]
1152
- }, date);
1153
- })
1154
- });
1155
- });
1156
1235
  const renderFileDetailsModal = () => {
1157
1236
  const backgroundColor = themeStyles.backgroundColor;
1158
1237
  const borderColor = themeStyles.borderColor;
@@ -1688,7 +1767,7 @@ const FileManagementScreen = ({
1688
1767
  }
1689
1768
 
1690
1769
  // If a file is opened, show the file viewer
1691
- if (openedFile) {
1770
+ if (!selectMode && openedFile) {
1692
1771
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
1693
1772
  children: [renderFileViewer(), renderFileDetailsModal()]
1694
1773
  });
@@ -1702,8 +1781,19 @@ const FileManagementScreen = ({
1702
1781
  onDrop: handleDrop
1703
1782
  } : {}),
1704
1783
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Header.default, {
1705
- title: viewMode === 'photos' ? 'Photos' : 'File Management',
1706
- subtitle: `${filteredFiles.length} ${filteredFiles.length === 1 ? 'item' : 'items'}`,
1784
+ title: selectMode ? multiSelect ? `${selectedIds.size}${maxSelection ? '/' + maxSelection : ''} Selected` : 'Select a File' : viewMode === 'photos' ? 'Photos' : 'File Management',
1785
+ subtitle: selectMode ? multiSelect ? `${filteredFiles.length} available` : 'Tap to select' : `${filteredFiles.length} ${filteredFiles.length === 1 ? 'item' : 'items'}`,
1786
+ rightActions: selectMode && multiSelect ? [{
1787
+ key: 'clear',
1788
+ text: 'Clear',
1789
+ onPress: () => setSelectedIds(new Set()),
1790
+ disabled: selectedIds.size === 0
1791
+ }, {
1792
+ key: 'confirm',
1793
+ text: 'Confirm',
1794
+ onPress: confirmMultiSelection,
1795
+ disabled: selectedIds.size === 0
1796
+ }] : undefined,
1707
1797
  onBack: onClose || goBack,
1708
1798
  theme: theme,
1709
1799
  showBackButton: true,
@@ -1739,7 +1829,7 @@ const FileManagementScreen = ({
1739
1829
  color: viewMode === 'photos' ? '#FFFFFF' : themeStyles.textColor
1740
1830
  })
1741
1831
  })]
1742
- }), user?.id === targetUserId && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1832
+ }), user?.id === targetUserId && (!selectMode || selectMode && allowUploadInSelectMode) && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1743
1833
  style: [styles.uploadButton, {
1744
1834
  backgroundColor: themeStyles.primaryColor
1745
1835
  }],
@@ -1839,6 +1929,20 @@ const FileManagementScreen = ({
1839
1929
  onRefresh: () => loadFiles('refresh'),
1840
1930
  tintColor: themeStyles.primaryColor
1841
1931
  }),
1932
+ onScroll: ({
1933
+ nativeEvent
1934
+ }) => {
1935
+ const {
1936
+ layoutMeasurement,
1937
+ contentOffset,
1938
+ contentSize
1939
+ } = nativeEvent;
1940
+ const distanceFromBottom = contentSize.height - (contentOffset.y + layoutMeasurement.height);
1941
+ if (distanceFromBottom < 200 && !paging.loadingMore && paging.hasMore) {
1942
+ loadFiles('more');
1943
+ }
1944
+ },
1945
+ scrollEventThrottle: 250,
1842
1946
  children: filteredFiles.length === 0 && searchQuery.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1843
1947
  style: styles.emptyState,
1844
1948
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
@@ -1869,11 +1973,24 @@ const FileManagementScreen = ({
1869
1973
  children: "Clear Search"
1870
1974
  })]
1871
1975
  })]
1872
- }) : filteredFiles.length === 0 ? renderEmptyState() : /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.GroupedSection, {
1873
- items: groupedFileItems,
1874
- theme: theme
1976
+ }) : filteredFiles.length === 0 ? renderEmptyState() : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
1977
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.GroupedSection, {
1978
+ items: groupedFileItems,
1979
+ theme: theme
1980
+ }), paging.loadingMore && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1981
+ style: styles.loadingMoreBar,
1982
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
1983
+ size: "small",
1984
+ color: themeStyles.primaryColor
1985
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1986
+ style: [styles.loadingMoreText, {
1987
+ color: themeStyles.textColor
1988
+ }],
1989
+ children: "Loading more..."
1990
+ })]
1991
+ })]
1875
1992
  })
1876
- }), renderFileDetailsModal(), uploading && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1993
+ }), !selectMode && renderFileDetailsModal(), !selectMode && uploading && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1877
1994
  pointerEvents: "none",
1878
1995
  style: styles.uploadBannerContainer,
1879
1996
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
@@ -1926,6 +2043,48 @@ const styles = _reactNative.StyleSheet.create({
1926
2043
  container: {
1927
2044
  flex: 1
1928
2045
  },
2046
+ selectionBadge: {
2047
+ position: 'absolute',
2048
+ top: 4,
2049
+ right: 4,
2050
+ backgroundColor: 'rgba(0,0,0,0.4)',
2051
+ borderRadius: 12,
2052
+ padding: 2
2053
+ },
2054
+ selectionBar: {
2055
+ position: 'absolute',
2056
+ left: 0,
2057
+ right: 0,
2058
+ bottom: 0,
2059
+ flexDirection: 'row',
2060
+ justifyContent: 'space-between',
2061
+ padding: 12,
2062
+ backgroundColor: 'rgba(0,0,0,0.55)',
2063
+ gap: 12
2064
+ },
2065
+ selectionBarButton: {
2066
+ flex: 1,
2067
+ paddingVertical: 14,
2068
+ borderRadius: 10,
2069
+ alignItems: 'center',
2070
+ justifyContent: 'center'
2071
+ },
2072
+ selectionBarButtonText: {
2073
+ color: '#FFFFFF',
2074
+ fontSize: 15,
2075
+ fontWeight: '600'
2076
+ },
2077
+ loadingMoreBar: {
2078
+ flexDirection: 'row',
2079
+ alignItems: 'center',
2080
+ justifyContent: 'center',
2081
+ paddingVertical: 12,
2082
+ gap: 8
2083
+ },
2084
+ loadingMoreText: {
2085
+ fontSize: 13,
2086
+ fontWeight: '500'
2087
+ },
1929
2088
  dragOverlay: {
1930
2089
  backgroundColor: 'rgba(0, 122, 255, 0.06)',
1931
2090
  borderWidth: 1,
@@ -2086,7 +2245,8 @@ const styles = _reactNative.StyleSheet.create({
2086
2245
  letterSpacing: 0.2
2087
2246
  },
2088
2247
  scrollView: {
2089
- flex: 1
2248
+ flex: 1,
2249
+ backgroundColor: '#e5f1ff'
2090
2250
  },
2091
2251
  scrollContainer: {
2092
2252
  padding: 12