@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.
- package/lib/commonjs/ui/components/AnimationExample.js +213 -0
- package/lib/commonjs/ui/components/AnimationExample.js.map +1 -0
- package/lib/commonjs/ui/components/FollowButton.js +58 -47
- package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
- package/lib/commonjs/ui/components/GroupedItem.js +2 -1
- package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
- package/lib/commonjs/ui/components/GroupedSection.js +3 -0
- package/lib/commonjs/ui/components/GroupedSection.js.map +1 -1
- package/lib/commonjs/ui/components/Header.js +25 -11
- package/lib/commonjs/ui/components/Header.js.map +1 -1
- package/lib/commonjs/ui/components/OxyProvider.js +69 -33
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileCard.js +5 -1
- package/lib/commonjs/ui/components/ProfileCard.js.map +1 -1
- package/lib/commonjs/ui/components/index.js +0 -7
- package/lib/commonjs/ui/components/index.js.map +1 -1
- package/lib/commonjs/ui/components/internal/TextField.js +8 -4
- package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
- package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js +161 -0
- package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -0
- package/lib/commonjs/ui/context/OxyContext.js +97 -38
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/useFollow.types.js +2 -0
- package/lib/commonjs/ui/hooks/useFollow.types.js.map +1 -0
- package/lib/commonjs/ui/navigation/OxyRouter.js +10 -0
- package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountCenterScreen.js +26 -14
- package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js +3 -3
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +64 -15
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +4 -4
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FeedbackScreen.js +72 -75
- package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +286 -126
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +322 -0
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/ProfileScreen.js +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SessionManagementScreen.js +176 -174
- package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignInScreen.js +43 -52
- package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignUpScreen.js +6 -4
- package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +386 -0
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +25 -15
- package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +16 -9
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/styles/authStyles.js +1 -1
- package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
- package/lib/module/ui/components/AnimationExample.js +209 -0
- package/lib/module/ui/components/AnimationExample.js.map +1 -0
- package/lib/module/ui/components/FollowButton.js +58 -47
- package/lib/module/ui/components/FollowButton.js.map +1 -1
- package/lib/module/ui/components/GroupedItem.js +2 -1
- package/lib/module/ui/components/GroupedItem.js.map +1 -1
- package/lib/module/ui/components/GroupedSection.js +3 -0
- package/lib/module/ui/components/GroupedSection.js.map +1 -1
- package/lib/module/ui/components/Header.js +25 -11
- package/lib/module/ui/components/Header.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +70 -34
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/ProfileCard.js +5 -1
- package/lib/module/ui/components/ProfileCard.js.map +1 -1
- package/lib/module/ui/components/index.js +0 -1
- package/lib/module/ui/components/index.js.map +1 -1
- package/lib/module/ui/components/internal/TextField.js +8 -4
- package/lib/module/ui/components/internal/TextField.js.map +1 -1
- package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js +156 -0
- package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -0
- package/lib/module/ui/context/OxyContext.js +97 -39
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/useFollow.types.js +2 -0
- package/lib/module/ui/hooks/useFollow.types.js.map +1 -0
- package/lib/module/ui/navigation/OxyRouter.js +10 -0
- package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/module/ui/screens/AccountCenterScreen.js +12 -1
- package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountOverviewScreen.js +3 -3
- package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +64 -15
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +4 -4
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/module/ui/screens/FeedbackScreen.js +72 -75
- package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +285 -125
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js +319 -0
- package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -0
- package/lib/module/ui/screens/ProfileScreen.js +1 -1
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/SessionManagementScreen.js +177 -175
- package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/SignInScreen.js +44 -53
- package/lib/module/ui/screens/SignInScreen.js.map +1 -1
- package/lib/module/ui/screens/SignUpScreen.js +6 -4
- package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/module/ui/screens/WelcomeNewUserScreen.js +382 -0
- package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -0
- package/lib/module/ui/screens/internal/SignInPasswordStep.js +23 -14
- package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/internal/SignInUsernameStep.js +15 -9
- package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js +1 -1
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
- package/lib/module/ui/styles/authStyles.js +1 -1
- package/lib/module/ui/styles/authStyles.js.map +1 -1
- package/lib/typescript/models/interfaces.d.ts +1 -5
- package/lib/typescript/models/interfaces.d.ts.map +1 -1
- package/lib/typescript/models/session.d.ts +1 -4
- package/lib/typescript/models/session.d.ts.map +1 -1
- package/lib/typescript/ui/components/AnimationExample.d.ts +4 -0
- package/lib/typescript/ui/components/AnimationExample.d.ts.map +1 -0
- package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
- package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
- package/lib/typescript/ui/components/Header.d.ts +9 -0
- package/lib/typescript/ui/components/Header.d.ts.map +1 -1
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/components/ProfileCard.d.ts +1 -3
- package/lib/typescript/ui/components/ProfileCard.d.ts.map +1 -1
- package/lib/typescript/ui/components/index.d.ts +0 -1
- package/lib/typescript/ui/components/index.d.ts.map +1 -1
- package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
- package/lib/typescript/ui/components/photogrid/JustifiedPhotoGrid.d.ts +27 -0
- package/lib/typescript/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -0
- package/lib/typescript/ui/context/OxyContext.d.ts +6 -2
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useFollow.types.d.ts +33 -0
- package/lib/typescript/ui/hooks/useFollow.types.d.ts.map +1 -0
- package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
- package/lib/typescript/ui/navigation/types.d.ts +5 -0
- package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/FeedbackScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/FileManagementScreen.d.ts +18 -1
- package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts +7 -0
- package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts +13 -0
- package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts +5 -5
- package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts +4 -4
- package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts.map +1 -1
- package/lib/typescript/ui/styles/authStyles.d.ts +1 -1
- package/package.json +10 -2
- package/src/models/interfaces.ts +2 -5
- package/src/models/session.ts +1 -4
- package/src/ui/components/AnimationExample.tsx +194 -0
- package/src/ui/components/FollowButton.tsx +65 -45
- package/src/ui/components/GroupedItem.tsx +1 -0
- package/src/ui/components/GroupedSection.tsx +1 -1
- package/src/ui/components/Header.tsx +36 -12
- package/src/ui/components/OxyProvider.tsx +66 -32
- package/src/ui/components/ProfileCard.tsx +6 -8
- package/src/ui/components/index.ts +0 -1
- package/src/ui/components/internal/TextField.tsx +12 -6
- package/src/ui/components/photogrid/JustifiedPhotoGrid.tsx +158 -0
- package/src/ui/context/OxyContext.tsx +84 -54
- package/src/ui/hooks/useFollow.types.ts +33 -0
- package/src/ui/navigation/OxyRouter.tsx +10 -0
- package/src/ui/navigation/types.ts +6 -0
- package/src/ui/screens/AccountCenterScreen.tsx +13 -7
- package/src/ui/screens/AccountOverviewScreen.tsx +3 -3
- package/src/ui/screens/AccountSettingsScreen.tsx +65 -13
- package/src/ui/screens/AccountSwitcherScreen.tsx +4 -4
- package/src/ui/screens/FeedbackScreen.tsx +57 -80
- package/src/ui/screens/FileManagementScreen.tsx +278 -175
- package/src/ui/screens/LanguageSelectorScreen.tsx +322 -0
- package/src/ui/screens/ProfileScreen.tsx +6 -1
- package/src/ui/screens/SessionManagementScreen.tsx +148 -151
- package/src/ui/screens/SignInScreen.tsx +43 -62
- package/src/ui/screens/SignUpScreen.tsx +3 -5
- package/src/ui/screens/WelcomeNewUserScreen.tsx +272 -0
- package/src/ui/screens/internal/SignInPasswordStep.tsx +28 -13
- package/src/ui/screens/internal/SignInUsernameStep.tsx +21 -11
- package/src/ui/screens/karma/KarmaCenterScreen.tsx +1 -1
- 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
|
|
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
|
|
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
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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.
|
|
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.
|
|
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)
|
|
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
|
-
|
|
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
|
-
};
|
|
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)(
|
|
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
|
-
//
|
|
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.
|
|
1873
|
-
|
|
1874
|
-
|
|
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
|