@oxyhq/services 22.4.2 → 22.6.0
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/LICENSE +661 -21
- package/README.md +1 -1
- package/lib/commonjs/index.js +20 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/client.js +1 -1
- package/lib/commonjs/ui/components/FontLoader.js +18 -145
- package/lib/commonjs/ui/components/FontLoader.js.map +1 -1
- package/lib/commonjs/ui/components/FontLoader.native.js +88 -0
- package/lib/commonjs/ui/components/FontLoader.native.js.map +1 -0
- package/lib/commonjs/ui/components/OxyProvider.js +1 -1
- package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js +16 -27
- package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
- package/lib/commonjs/ui/components/fileManagement/UploadPreview.js.map +1 -1
- package/lib/commonjs/ui/components/fileManagement/styles.js +1 -225
- package/lib/commonjs/ui/components/fileManagement/styles.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +5 -2
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/commonjs/ui/context/useOxyAccountGraph.js +7 -0
- package/lib/commonjs/ui/context/useOxyAccountGraph.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +14 -5
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/userCache.js +286 -0
- package/lib/commonjs/ui/hooks/queries/userCache.js.map +1 -0
- package/lib/commonjs/ui/hooks/useAvatarPicker.js +23 -8
- package/lib/commonjs/ui/hooks/useAvatarPicker.js.map +1 -1
- package/lib/commonjs/ui/hooks/useFileDownloadUrl.js +7 -21
- package/lib/commonjs/ui/hooks/useFileDownloadUrl.js.map +1 -1
- package/lib/commonjs/ui/hooks/useResolvedFileUrls.js +163 -0
- package/lib/commonjs/ui/hooks/useResolvedFileUrls.js.map +1 -0
- package/lib/commonjs/ui/index.js +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +51 -22
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js +216 -203
- package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
- package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js +26 -9
- package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
- package/lib/commonjs/ui/screens/fileManagement/photoGridLayout.js +44 -0
- package/lib/commonjs/ui/screens/fileManagement/photoGridLayout.js.map +1 -0
- package/lib/commonjs/ui/session/tokenTransport.js +21 -10
- package/lib/commonjs/ui/session/tokenTransport.js.map +1 -1
- package/lib/commonjs/ui/utils/fileManagement.js +0 -40
- package/lib/commonjs/ui/utils/fileManagement.js.map +1 -1
- package/lib/module/index.js +7 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/client.js +1 -1
- package/lib/module/ui/client.js.map +1 -1
- package/lib/module/ui/components/FontLoader.js +18 -146
- package/lib/module/ui/components/FontLoader.js.map +1 -1
- package/lib/module/ui/components/FontLoader.native.js +83 -0
- package/lib/module/ui/components/FontLoader.native.js.map +1 -0
- package/lib/module/ui/components/OxyProvider.js +1 -1
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/fileManagement/FileDetailsModal.js +16 -27
- package/lib/module/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
- package/lib/module/ui/components/fileManagement/UploadPreview.js.map +1 -1
- package/lib/module/ui/components/fileManagement/styles.js +0 -224
- package/lib/module/ui/components/fileManagement/styles.js.map +1 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +5 -2
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/module/ui/context/useOxyAccountGraph.js +7 -0
- package/lib/module/ui/context/useOxyAccountGraph.js.map +1 -1
- package/lib/module/ui/hooks/queries/useAccountQueries.js +14 -5
- package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/module/ui/hooks/queries/userCache.js +282 -0
- package/lib/module/ui/hooks/queries/userCache.js.map +1 -0
- package/lib/module/ui/hooks/useAvatarPicker.js +23 -8
- package/lib/module/ui/hooks/useAvatarPicker.js.map +1 -1
- package/lib/module/ui/hooks/useFileDownloadUrl.js +7 -21
- package/lib/module/ui/hooks/useFileDownloadUrl.js.map +1 -1
- package/lib/module/ui/hooks/useResolvedFileUrls.js +157 -0
- package/lib/module/ui/hooks/useResolvedFileUrls.js.map +1 -0
- package/lib/module/ui/index.js +1 -1
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +52 -23
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js +218 -205
- package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
- package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js +26 -9
- package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
- package/lib/module/ui/screens/fileManagement/photoGridLayout.js +39 -0
- package/lib/module/ui/screens/fileManagement/photoGridLayout.js.map +1 -0
- package/lib/module/ui/session/tokenTransport.js +21 -10
- package/lib/module/ui/session/tokenTransport.js.map +1 -1
- package/lib/module/ui/utils/fileManagement.js +0 -39
- package/lib/module/ui/utils/fileManagement.js.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +2 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/FontLoader.d.ts +14 -5
- package/lib/typescript/commonjs/ui/components/FontLoader.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/FontLoader.native.d.ts +13 -0
- package/lib/typescript/commonjs/ui/components/FontLoader.native.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/fileManagement/styles.d.ts +0 -218
- package/lib/typescript/commonjs/ui/components/fileManagement/styles.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/useOxyAccountGraph.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/useAccountQueries.d.ts +9 -0
- package/lib/typescript/commonjs/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/userCache.d.ts +96 -0
- package/lib/typescript/commonjs/ui/hooks/queries/userCache.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useFileDownloadUrl.d.ts +3 -2
- package/lib/typescript/commonjs/ui/hooks/useFileDownloadUrl.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useResolvedFileUrls.d.ts +48 -0
- package/lib/typescript/commonjs/ui/hooks/useResolvedFileUrls.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/photoGridLayout.d.ts +37 -0
- package/lib/typescript/commonjs/ui/screens/fileManagement/photoGridLayout.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/session/tokenTransport.d.ts +15 -8
- package/lib/typescript/commonjs/ui/session/tokenTransport.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts +4 -11
- package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +3 -1
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/client.d.ts +1 -1
- package/lib/typescript/module/ui/client.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/FontLoader.d.ts +14 -5
- package/lib/typescript/module/ui/components/FontLoader.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/FontLoader.native.d.ts +13 -0
- package/lib/typescript/module/ui/components/FontLoader.native.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/fileManagement/styles.d.ts +0 -218
- package/lib/typescript/module/ui/components/fileManagement/styles.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/useOxyAccountGraph.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/useAccountQueries.d.ts +9 -0
- package/lib/typescript/module/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/userCache.d.ts +96 -0
- package/lib/typescript/module/ui/hooks/queries/userCache.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useFileDownloadUrl.d.ts +3 -2
- package/lib/typescript/module/ui/hooks/useFileDownloadUrl.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useResolvedFileUrls.d.ts +48 -0
- package/lib/typescript/module/ui/hooks/useResolvedFileUrls.d.ts.map +1 -0
- package/lib/typescript/module/ui/index.d.ts +1 -1
- package/lib/typescript/module/ui/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/photoGridLayout.d.ts +37 -0
- package/lib/typescript/module/ui/screens/fileManagement/photoGridLayout.d.ts.map +1 -0
- package/lib/typescript/module/ui/session/tokenTransport.d.ts +15 -8
- package/lib/typescript/module/ui/session/tokenTransport.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/fileManagement.d.ts +4 -11
- package/lib/typescript/module/ui/utils/fileManagement.d.ts.map +1 -1
- package/package.json +6 -11
- package/src/index.ts +8 -0
- package/src/ui/components/FontLoader.native.tsx +88 -0
- package/src/ui/components/FontLoader.tsx +16 -151
- package/src/ui/components/fileManagement/FileDetailsModal.tsx +17 -18
- package/src/ui/components/fileManagement/UploadPreview.tsx +1 -1
- package/src/ui/components/fileManagement/styles.ts +0 -225
- package/src/ui/context/hooks/useAuthOperations.ts +5 -2
- package/src/ui/context/useOxyAccountGraph.ts +5 -0
- package/src/ui/hooks/queries/__tests__/userCache.test.ts +361 -0
- package/src/ui/hooks/queries/useAccountQueries.ts +14 -5
- package/src/ui/hooks/queries/userCache.ts +308 -0
- package/src/ui/hooks/useAvatarPicker.ts +27 -7
- package/src/ui/hooks/useFileDownloadUrl.ts +7 -23
- package/src/ui/hooks/useResolvedFileUrls.ts +170 -0
- package/src/ui/screens/FileManagementScreen.tsx +55 -27
- package/src/ui/screens/__tests__/photoGridLayout.test.ts +57 -0
- package/src/ui/screens/fileManagement/PhotoPickerSection.tsx +215 -213
- package/src/ui/screens/fileManagement/hooks/useFileUploadState.ts +27 -3
- package/src/ui/screens/fileManagement/photoGridLayout.ts +45 -0
- package/src/ui/session/__tests__/tokenTransport.test.ts +25 -10
- package/src/ui/session/tokenTransport.ts +21 -10
- package/src/ui/utils/fileManagement.ts +3 -46
- package/lib/typescript/types/expo-vector-icons.d.ts +0 -22
- package/src/types/expo-vector-icons.d.ts +0 -22
|
@@ -28,8 +28,8 @@ import { useUploadFile } from '../hooks/mutations/useAccountMutations';
|
|
|
28
28
|
import {
|
|
29
29
|
formatFileSize,
|
|
30
30
|
getFileIcon,
|
|
31
|
-
getSafeDownloadUrl,
|
|
32
31
|
} from '../utils/fileManagement';
|
|
32
|
+
import { useResolvedFileUrls, fileThumbSource } from '../hooks/useResolvedFileUrls';
|
|
33
33
|
import { FileViewer } from '../components/fileManagement/FileViewer';
|
|
34
34
|
import { FileDetailsModal } from '../components/fileManagement/FileDetailsModal';
|
|
35
35
|
import { UploadPreview } from '../components/fileManagement/UploadPreview';
|
|
@@ -356,12 +356,18 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
356
356
|
onClose?.();
|
|
357
357
|
}, [selectMode, multiSelect, selectedIds, files, onConfirmSelection, onClose, defaultVisibility, oxyServices, linkContext]);
|
|
358
358
|
|
|
359
|
-
//
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
359
|
+
// Private-safe thumbnail URLs for the currently-shown files, resolved in
|
|
360
|
+
// ONE batch per page (not N per-tile) and cached by React Query. Uploads
|
|
361
|
+
// default to private, so the synchronous public-CDN URL would 404 for
|
|
362
|
+
// every private thumbnail.
|
|
363
|
+
const resolvedThumbUrls = useResolvedFileUrls(oxyServices, filteredFiles, user?.id);
|
|
364
|
+
|
|
365
|
+
// Image source for a grid tile: the resolved private-safe URL for a
|
|
366
|
+
// persisted file, or the locally-picked preview for an in-flight optimistic
|
|
367
|
+
// entry. Never builds an asset URL from a `temp-…`/uploading id.
|
|
368
|
+
const thumbSourceFor = useCallback(
|
|
369
|
+
(file: FileMetadata): string | undefined => fileThumbSource(file, resolvedThumbUrls),
|
|
370
|
+
[resolvedThumbUrls],
|
|
365
371
|
);
|
|
366
372
|
|
|
367
373
|
const bloomTheme = useTheme();
|
|
@@ -480,7 +486,14 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
480
486
|
await Promise.all(
|
|
481
487
|
photosToLoad.map(async (photo) => {
|
|
482
488
|
try {
|
|
483
|
-
const downloadUrl =
|
|
489
|
+
const downloadUrl = thumbSourceFor(photo);
|
|
490
|
+
// URL not resolved yet — skip (do NOT record fallback
|
|
491
|
+
// dims) so this photo is re-measured once its private-safe
|
|
492
|
+
// URL resolves. Measuring the broken public URL is exactly
|
|
493
|
+
// the bug we are fixing.
|
|
494
|
+
if (!downloadUrl) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
484
497
|
|
|
485
498
|
// Unified approach using Image.getSize (works on all platforms)
|
|
486
499
|
await new Promise<void>((resolve) => {
|
|
@@ -515,7 +528,19 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
515
528
|
} finally {
|
|
516
529
|
setLoadingDimensions(false);
|
|
517
530
|
}
|
|
518
|
-
}, [
|
|
531
|
+
}, [thumbSourceFor, photoDimensions]);
|
|
532
|
+
|
|
533
|
+
// Re-measure photo dimensions when their private-safe URLs resolve. The
|
|
534
|
+
// justified grid's own trigger fires on the photo SET, not on URL
|
|
535
|
+
// availability, so newly-resolved private tiles would otherwise keep their
|
|
536
|
+
// skipped (unmeasured) state and render with fallback geometry.
|
|
537
|
+
useEffect(() => {
|
|
538
|
+
if (viewMode !== 'photos') return;
|
|
539
|
+
const photos = filteredFiles.filter((file) => file.contentType.startsWith('image/'));
|
|
540
|
+
if (photos.length > 0) {
|
|
541
|
+
loadPhotoDimensions(photos);
|
|
542
|
+
}
|
|
543
|
+
}, [resolvedThumbUrls, viewMode, filteredFiles, loadPhotoDimensions]);
|
|
519
544
|
|
|
520
545
|
// Create justified rows from photos with responsive algorithm
|
|
521
546
|
const createJustifiedRows = useCallback((photos: FileMetadata[], containerWidth: number) => {
|
|
@@ -646,9 +671,10 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
646
671
|
// Unified download function - works on all platforms
|
|
647
672
|
const handleFileDownload = async (fileId: string, filename: string) => {
|
|
648
673
|
try {
|
|
649
|
-
//
|
|
650
|
-
//
|
|
651
|
-
|
|
674
|
+
// Resolve an authenticated, private-safe URL. The synchronous
|
|
675
|
+
// `getFileDownloadUrl` yields the public CDN origin, which 404s for
|
|
676
|
+
// private assets (the default visibility).
|
|
677
|
+
const downloadUrl = await oxyServices.getFileDownloadUrlAsync(fileId);
|
|
652
678
|
|
|
653
679
|
// For web platforms, use link download
|
|
654
680
|
if (typeof window !== 'undefined' && window.document) {
|
|
@@ -715,8 +741,10 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
715
741
|
file.contentType.includes('pdf') ||
|
|
716
742
|
file.contentType.startsWith('video/') ||
|
|
717
743
|
file.contentType.startsWith('audio/')) {
|
|
718
|
-
// For images, PDFs, videos, and audio, we
|
|
719
|
-
|
|
744
|
+
// For images, PDFs, videos, and audio, we render the URL
|
|
745
|
+
// directly. Resolve the authenticated, private-safe URL —
|
|
746
|
+
// the synchronous public-CDN URL 404s for private assets.
|
|
747
|
+
const downloadUrl = await oxyServices.getFileDownloadUrlAsync(file.id);
|
|
720
748
|
setFileContent(downloadUrl);
|
|
721
749
|
} else {
|
|
722
750
|
// For text files, get the content using authenticated request
|
|
@@ -755,7 +783,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
755
783
|
};
|
|
756
784
|
|
|
757
785
|
const renderSimplePhotoItem = useCallback((photo: FileMetadata, index: number) => {
|
|
758
|
-
const downloadUrl =
|
|
786
|
+
const downloadUrl = thumbSourceFor(photo);
|
|
759
787
|
|
|
760
788
|
// Calculate photo item width based on actual container size from bottom sheet
|
|
761
789
|
let itemsPerRow = 3; // Default for mobile
|
|
@@ -803,10 +831,10 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
803
831
|
</View>
|
|
804
832
|
</TouchableOpacity>
|
|
805
833
|
);
|
|
806
|
-
}, [
|
|
834
|
+
}, [thumbSourceFor, safeContainerWidth, selectMode, selectedIds, colors.primary, colors.text]);
|
|
807
835
|
|
|
808
836
|
const renderJustifiedPhotoItem = useCallback((photo: FileMetadata, width: number, height: number, isLast: boolean) => {
|
|
809
|
-
const downloadUrl =
|
|
837
|
+
const downloadUrl = thumbSourceFor(photo);
|
|
810
838
|
|
|
811
839
|
return (
|
|
812
840
|
<TouchableOpacity
|
|
@@ -843,7 +871,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
843
871
|
</View>
|
|
844
872
|
</TouchableOpacity>
|
|
845
873
|
);
|
|
846
|
-
}, [
|
|
874
|
+
}, [thumbSourceFor, selectMode, selectedIds, multiSelect, colors.primary, colors.text]);
|
|
847
875
|
|
|
848
876
|
// Run initial load once per targetUserId change to avoid accidental loops
|
|
849
877
|
const lastLoadedFor = useRef<string | undefined>(undefined);
|
|
@@ -879,7 +907,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
879
907
|
<View style={fileManagementStyles.filePreview}>
|
|
880
908
|
{isImage && (
|
|
881
909
|
<ExpoImage
|
|
882
|
-
source={{ uri:
|
|
910
|
+
source={{ uri: thumbSourceFor(file) }}
|
|
883
911
|
style={fileManagementStyles.previewImage}
|
|
884
912
|
contentFit="cover"
|
|
885
913
|
transition={120}
|
|
@@ -899,7 +927,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
899
927
|
{isVideo && (
|
|
900
928
|
<View style={fileManagementStyles.videoPreviewWrapper}>
|
|
901
929
|
<ExpoImage
|
|
902
|
-
source={{ uri:
|
|
930
|
+
source={{ uri: thumbSourceFor(file) }}
|
|
903
931
|
style={fileManagementStyles.videoPosterImage}
|
|
904
932
|
contentFit="cover"
|
|
905
933
|
transition={120}
|
|
@@ -919,7 +947,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
919
947
|
style={[fileManagementStyles.fallbackIcon, { display: isImage ? 'none' : 'flex' }]}
|
|
920
948
|
>
|
|
921
949
|
<Ionicons
|
|
922
|
-
name={getFileIcon(file.contentType)
|
|
950
|
+
name={getFileIcon(file.contentType)}
|
|
923
951
|
size={32}
|
|
924
952
|
color={colors.primary}
|
|
925
953
|
/>
|
|
@@ -934,7 +962,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
934
962
|
) : (
|
|
935
963
|
<View style={fileManagementStyles.fileIconContainer}>
|
|
936
964
|
<Ionicons
|
|
937
|
-
name={getFileIcon(file.contentType)
|
|
965
|
+
name={getFileIcon(file.contentType)}
|
|
938
966
|
size={32}
|
|
939
967
|
color={colors.primary}
|
|
940
968
|
/>
|
|
@@ -1016,7 +1044,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1016
1044
|
fileIcon = (
|
|
1017
1045
|
<View style={{ width: 36, height: 36, borderRadius: 18, overflow: 'hidden' }}>
|
|
1018
1046
|
<ExpoImage
|
|
1019
|
-
source={{ uri:
|
|
1047
|
+
source={{ uri: thumbSourceFor(file) }}
|
|
1020
1048
|
style={{ width: 36, height: 36 }}
|
|
1021
1049
|
contentFit="cover"
|
|
1022
1050
|
transition={120}
|
|
@@ -1032,7 +1060,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1032
1060
|
fileIcon = (
|
|
1033
1061
|
<View style={{ width: 36, height: 36, borderRadius: 18, overflow: 'hidden', backgroundColor: '#000000', position: 'relative' }}>
|
|
1034
1062
|
<ExpoImage
|
|
1035
|
-
source={{ uri:
|
|
1063
|
+
source={{ uri: thumbSourceFor(file) }}
|
|
1036
1064
|
style={{ width: 36, height: 36 }}
|
|
1037
1065
|
contentFit="cover"
|
|
1038
1066
|
transition={120}
|
|
@@ -1102,7 +1130,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1102
1130
|
) : undefined,
|
|
1103
1131
|
};
|
|
1104
1132
|
});
|
|
1105
|
-
}, [filteredFiles, theme, deleting, handleFileDownload, confirmFileDelete, handleFileOpen,
|
|
1133
|
+
}, [filteredFiles, theme, deleting, handleFileDownload, confirmFileDelete, handleFileOpen, thumbSourceFor, selectMode, selectedIds]);
|
|
1106
1134
|
|
|
1107
1135
|
// Scroll to selected file after selection
|
|
1108
1136
|
useEffect(() => {
|
|
@@ -1191,7 +1219,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1191
1219
|
}, [lastSelectedFileId]);
|
|
1192
1220
|
|
|
1193
1221
|
const renderPhotoItem = (photo: FileMetadata, index: number) => {
|
|
1194
|
-
const downloadUrl =
|
|
1222
|
+
const downloadUrl = thumbSourceFor(photo);
|
|
1195
1223
|
|
|
1196
1224
|
// Calculate photo item width based on actual container size from bottom sheet
|
|
1197
1225
|
let itemsPerRow = 3; // Default for mobile
|
|
@@ -1570,7 +1598,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1570
1598
|
hasMore={paging.hasMore}
|
|
1571
1599
|
loadingMore={paging.loadingMore}
|
|
1572
1600
|
reduceMotion={reduceMotion}
|
|
1573
|
-
getThumbUrl={
|
|
1601
|
+
getThumbUrl={thumbSourceFor}
|
|
1574
1602
|
primaryColor={colors.primary}
|
|
1575
1603
|
isOwner={isOwner}
|
|
1576
1604
|
onTogglePhoto={toggleSelect}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computePhotoGridLayout,
|
|
3
|
+
PHOTO_GRID_GUTTER,
|
|
4
|
+
PHOTO_GRID_WIDE_BREAKPOINT,
|
|
5
|
+
} from '../fileManagement/photoGridLayout';
|
|
6
|
+
|
|
7
|
+
describe('computePhotoGridLayout', () => {
|
|
8
|
+
it('uses 3 columns below the wide breakpoint', () => {
|
|
9
|
+
expect(computePhotoGridLayout(390).columns).toBe(3);
|
|
10
|
+
expect(computePhotoGridLayout(500).columns).toBe(3);
|
|
11
|
+
expect(computePhotoGridLayout(PHOTO_GRID_WIDE_BREAKPOINT - 1).columns).toBe(3);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('uses 4 columns at/above the wide breakpoint', () => {
|
|
15
|
+
expect(computePhotoGridLayout(PHOTO_GRID_WIDE_BREAKPOINT).columns).toBe(4);
|
|
16
|
+
expect(computePhotoGridLayout(700).columns).toBe(4);
|
|
17
|
+
expect(computePhotoGridLayout(1024).columns).toBe(4);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('floors the tile size so a full row never exceeds the container', () => {
|
|
21
|
+
// The whole point of the bug fix: geometry derives from the passed
|
|
22
|
+
// container width, and a full row of tiles + gutters must fit inside it.
|
|
23
|
+
for (const width of [320, 375, 390, 428, 500, 599, 600, 768, 834, 1024]) {
|
|
24
|
+
const { columns, cellSize, gutter } = computePhotoGridLayout(width);
|
|
25
|
+
const rowWidth = columns * cellSize + (columns - 1) * gutter;
|
|
26
|
+
expect(rowWidth).toBeLessThanOrEqual(width);
|
|
27
|
+
// ...and the floor is tight (adding one px per tile would overflow).
|
|
28
|
+
expect((columns * (cellSize + 1)) + (columns - 1) * gutter).toBeGreaterThan(width);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('derives smaller tiles from a narrow sheet than from a wide screen', () => {
|
|
33
|
+
// Regression guard for the original bug: a centered dialog (narrow
|
|
34
|
+
// container) must NOT size tiles from a wider screen width.
|
|
35
|
+
const narrowSheet = computePhotoGridLayout(500); // 3 cols
|
|
36
|
+
const wideScreen = computePhotoGridLayout(1200); // 4 cols
|
|
37
|
+
expect(narrowSheet.cellSize).toBeLessThan(wideScreen.cellSize);
|
|
38
|
+
// Cross-check the exact arithmetic against the gutter constant.
|
|
39
|
+
expect(narrowSheet.cellSize).toBe(
|
|
40
|
+
Math.floor((500 - PHOTO_GRID_GUTTER * 2) / 3),
|
|
41
|
+
);
|
|
42
|
+
expect(wideScreen.cellSize).toBe(
|
|
43
|
+
Math.floor((1200 - PHOTO_GRID_GUTTER * 3) / 4),
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('returns cellSize 0 for a not-yet-measured (<= 0) width', () => {
|
|
48
|
+
expect(computePhotoGridLayout(0).cellSize).toBe(0);
|
|
49
|
+
expect(computePhotoGridLayout(-10).cellSize).toBe(0);
|
|
50
|
+
// Columns still resolve to the narrow default so callers can render.
|
|
51
|
+
expect(computePhotoGridLayout(0).columns).toBe(3);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('exposes the gutter it used to derive the tile size', () => {
|
|
55
|
+
expect(computePhotoGridLayout(500).gutter).toBe(PHOTO_GRID_GUTTER);
|
|
56
|
+
});
|
|
57
|
+
});
|