@oxyhq/services 22.9.0 → 22.11.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/lib/commonjs/index.js +24 -5
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/components/AvatarCameraBadge.js +42 -0
- package/lib/commonjs/ui/components/AvatarCameraBadge.js.map +1 -0
- package/lib/commonjs/ui/components/{OxyAccountDialog.js → OxyAccountDialogScreen.js} +55 -133
- package/lib/commonjs/ui/components/OxyAccountDialogScreen.js.map +1 -0
- package/lib/commonjs/ui/components/OxyAuthChooser.js +657 -88
- package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
- package/lib/commonjs/ui/components/OxyConsentScreen.js +1 -1
- package/lib/commonjs/ui/components/ProfileButton.js +15 -1
- package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileSummaryCard.js +3 -23
- package/lib/commonjs/ui/components/ProfileSummaryCard.js.map +1 -1
- package/lib/commonjs/ui/components/RequireOxyAuth.js +1 -1
- package/lib/commonjs/ui/components/SurfaceHeaderAction.js +63 -0
- package/lib/commonjs/ui/components/SurfaceHeaderAction.js.map +1 -0
- package/lib/commonjs/ui/components/SurfaceScreen.js +91 -8
- package/lib/commonjs/ui/components/SurfaceScreen.js.map +1 -1
- package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js +46 -29
- package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
- package/lib/commonjs/ui/components/modals/DeleteAccountModal.js +47 -23
- package/lib/commonjs/ui/components/modals/DeleteAccountModal.js.map +1 -1
- package/lib/commonjs/ui/components/oxyAuthChooserStyles.js +81 -19
- package/lib/commonjs/ui/components/oxyAuthChooserStyles.js.map +1 -1
- package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js +83 -23
- package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
- package/lib/commonjs/ui/components/surfaces/ActionSheetSurface.js +83 -0
- package/lib/commonjs/ui/components/surfaces/ActionSheetSurface.js.map +1 -0
- package/lib/commonjs/ui/context/OxyContext.js +79 -29
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/queryKeys.js +18 -1
- package/lib/commonjs/ui/hooks/queries/queryKeys.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useFileQueries.js +129 -0
- package/lib/commonjs/ui/hooks/queries/useFileQueries.js.map +1 -0
- package/lib/commonjs/ui/hooks/useAvatarPicker.js +38 -55
- package/lib/commonjs/ui/hooks/useAvatarPicker.js.map +1 -1
- package/lib/commonjs/ui/hooks/useReduceMotion.js +57 -0
- package/lib/commonjs/ui/hooks/useReduceMotion.js.map +1 -0
- package/lib/commonjs/ui/hooks/useSurfaceHeader.js +46 -0
- package/lib/commonjs/ui/hooks/useSurfaceHeader.js.map +1 -0
- package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +1 -1
- package/lib/commonjs/ui/navigation/accountDialogManager.js +36 -2
- package/lib/commonjs/ui/navigation/accountDialogManager.js.map +1 -1
- package/lib/commonjs/ui/navigation/bottomSheetManager.js +5 -6
- package/lib/commonjs/ui/navigation/bottomSheetManager.js.map +1 -1
- package/lib/commonjs/ui/navigation/routes.js +4 -3
- package/lib/commonjs/ui/navigation/routes.js.map +1 -1
- package/lib/commonjs/ui/navigation/surfaceBackBridge.js +68 -0
- package/lib/commonjs/ui/navigation/surfaceBackBridge.js.map +1 -0
- package/lib/commonjs/ui/navigation/surfaceNavStack.js +62 -15
- package/lib/commonjs/ui/navigation/surfaceNavStack.js.map +1 -1
- package/lib/commonjs/ui/navigation/surfaceRegistry.js +84 -19
- package/lib/commonjs/ui/navigation/surfaceRegistry.js.map +1 -1
- package/lib/commonjs/ui/navigation/surfaces.js +139 -25
- package/lib/commonjs/ui/navigation/surfaces.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountMembersScreen.js +214 -283
- package/lib/commonjs/ui/screens/AccountMembersScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +88 -118
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountVerificationScreen.js +22 -36
- package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AppInfoScreen.js +219 -226
- package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AvatarCropScreen.js +287 -289
- package/lib/commonjs/ui/screens/AvatarCropScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ChangeAvatarScreen.js +301 -0
- package/lib/commonjs/ui/screens/ChangeAvatarScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/ConnectedAppsScreen.js +24 -39
- package/lib/commonjs/ui/screens/ConnectedAppsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/CreateAccountScreen.js +136 -158
- package/lib/commonjs/ui/screens/CreateAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +29 -36
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/EditProfileScreen.js +101 -109
- package/lib/commonjs/ui/screens/EditProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FAQScreen.js +10 -15
- package/lib/commonjs/ui/screens/FAQScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FeedbackScreen.js +8 -16
- package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +403 -627
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/HelpSupportScreen.js +62 -69
- package/lib/commonjs/ui/screens/HelpSupportScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/HistoryViewScreen.js +63 -79
- package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +69 -98
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LearnMoreUsernamesScreen.js +8 -14
- package/lib/commonjs/ui/screens/LearnMoreUsernamesScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +77 -94
- package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ManageAccountScreen.js +99 -134
- package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/NotificationsScreen.js +69 -76
- package/lib/commonjs/ui/screens/NotificationsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +3 -8
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PreferencesScreen.js +67 -74
- package/lib/commonjs/ui/screens/PreferencesScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +55 -91
- package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +291 -304
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +100 -114
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SavesCollectionsScreen.js +38 -45
- package/lib/commonjs/ui/screens/SavesCollectionsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SearchSettingsScreen.js +44 -57
- package/lib/commonjs/ui/screens/SearchSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/UserLinksScreen.js +24 -31
- package/lib/commonjs/ui/screens/UserLinksScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/UserListScreen.js +14 -24
- package/lib/commonjs/ui/screens/UserListScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +16 -48
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/fileManagement/FileLibraryError.js +63 -0
- package/lib/commonjs/ui/screens/fileManagement/FileLibraryError.js.map +1 -0
- package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js +54 -41
- package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
- package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js +44 -81
- package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustAboutScreen.js +66 -75
- package/lib/commonjs/ui/screens/trust/TrustAboutScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js +111 -139
- package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustFAQScreen.js +13 -20
- package/lib/commonjs/ui/screens/trust/TrustFAQScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js +14 -27
- package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js +68 -85
- package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js +28 -36
- package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js.map +1 -1
- package/lib/commonjs/ui/stores/resetSessionScopedStores.js +8 -3
- package/lib/commonjs/ui/stores/resetSessionScopedStores.js.map +1 -1
- package/lib/commonjs/ui/utils/avatarUtils.js +11 -2
- package/lib/commonjs/ui/utils/avatarUtils.js.map +1 -1
- package/lib/commonjs/ui/utils/fileManagement.js +0 -79
- package/lib/commonjs/ui/utils/fileManagement.js.map +1 -1
- package/lib/module/index.js +12 -5
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/components/AvatarCameraBadge.js +40 -0
- package/lib/module/ui/components/AvatarCameraBadge.js.map +1 -0
- package/lib/module/ui/components/{OxyAccountDialog.js → OxyAccountDialogScreen.js} +57 -135
- package/lib/module/ui/components/OxyAccountDialogScreen.js.map +1 -0
- package/lib/module/ui/components/OxyAuthChooser.js +659 -91
- package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
- package/lib/module/ui/components/OxyConsentScreen.js +1 -1
- package/lib/module/ui/components/ProfileButton.js +16 -2
- package/lib/module/ui/components/ProfileButton.js.map +1 -1
- package/lib/module/ui/components/ProfileSummaryCard.js +2 -23
- package/lib/module/ui/components/ProfileSummaryCard.js.map +1 -1
- package/lib/module/ui/components/RequireOxyAuth.js +1 -1
- package/lib/module/ui/components/SurfaceHeaderAction.js +58 -0
- package/lib/module/ui/components/SurfaceHeaderAction.js.map +1 -0
- package/lib/module/ui/components/SurfaceScreen.js +93 -10
- package/lib/module/ui/components/SurfaceScreen.js.map +1 -1
- package/lib/module/ui/components/fileManagement/FileDetailsModal.js +46 -29
- package/lib/module/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
- package/lib/module/ui/components/modals/DeleteAccountModal.js +46 -23
- package/lib/module/ui/components/modals/DeleteAccountModal.js.map +1 -1
- package/lib/module/ui/components/oxyAuthChooserStyles.js +81 -19
- package/lib/module/ui/components/oxyAuthChooserStyles.js.map +1 -1
- package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js +83 -25
- package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
- package/lib/module/ui/components/surfaces/ActionSheetSurface.js +78 -0
- package/lib/module/ui/components/surfaces/ActionSheetSurface.js.map +1 -0
- package/lib/module/ui/context/OxyContext.js +80 -30
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/queries/queryKeys.js +16 -0
- package/lib/module/ui/hooks/queries/queryKeys.js.map +1 -1
- package/lib/module/ui/hooks/queries/useFileQueries.js +120 -0
- package/lib/module/ui/hooks/queries/useFileQueries.js.map +1 -0
- package/lib/module/ui/hooks/useAvatarPicker.js +38 -55
- package/lib/module/ui/hooks/useAvatarPicker.js.map +1 -1
- package/lib/module/ui/hooks/useReduceMotion.js +53 -0
- package/lib/module/ui/hooks/useReduceMotion.js.map +1 -0
- package/lib/module/ui/hooks/useSurfaceHeader.js +42 -0
- package/lib/module/ui/hooks/useSurfaceHeader.js.map +1 -0
- package/lib/module/ui/hooks/useSwitchableAccounts.js +1 -1
- package/lib/module/ui/navigation/accountDialogManager.js +34 -2
- package/lib/module/ui/navigation/accountDialogManager.js.map +1 -1
- package/lib/module/ui/navigation/bottomSheetManager.js +6 -7
- package/lib/module/ui/navigation/bottomSheetManager.js.map +1 -1
- package/lib/module/ui/navigation/routes.js +4 -3
- package/lib/module/ui/navigation/routes.js.map +1 -1
- package/lib/module/ui/navigation/surfaceBackBridge.js +63 -0
- package/lib/module/ui/navigation/surfaceBackBridge.js.map +1 -0
- package/lib/module/ui/navigation/surfaceNavStack.js +62 -15
- package/lib/module/ui/navigation/surfaceNavStack.js.map +1 -1
- package/lib/module/ui/navigation/surfaceRegistry.js +84 -19
- package/lib/module/ui/navigation/surfaceRegistry.js.map +1 -1
- package/lib/module/ui/navigation/surfaces.js +138 -26
- package/lib/module/ui/navigation/surfaces.js.map +1 -1
- package/lib/module/ui/screens/AccountMembersScreen.js +218 -286
- package/lib/module/ui/screens/AccountMembersScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +92 -121
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountVerificationScreen.js +25 -38
- package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
- package/lib/module/ui/screens/AppInfoScreen.js +220 -227
- package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/module/ui/screens/AvatarCropScreen.js +289 -291
- package/lib/module/ui/screens/AvatarCropScreen.js.map +1 -1
- package/lib/module/ui/screens/ChangeAvatarScreen.js +298 -0
- package/lib/module/ui/screens/ChangeAvatarScreen.js.map +1 -0
- package/lib/module/ui/screens/ConnectedAppsScreen.js +26 -40
- package/lib/module/ui/screens/ConnectedAppsScreen.js.map +1 -1
- package/lib/module/ui/screens/CreateAccountScreen.js +139 -160
- package/lib/module/ui/screens/CreateAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/EditProfileFieldScreen.js +32 -38
- package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/module/ui/screens/EditProfileScreen.js +102 -110
- package/lib/module/ui/screens/EditProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/FAQScreen.js +11 -15
- package/lib/module/ui/screens/FAQScreen.js.map +1 -1
- package/lib/module/ui/screens/FeedbackScreen.js +10 -17
- package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +408 -631
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/HelpSupportScreen.js +64 -70
- package/lib/module/ui/screens/HelpSupportScreen.js.map +1 -1
- package/lib/module/ui/screens/HistoryViewScreen.js +65 -81
- package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js +71 -99
- package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/module/ui/screens/LearnMoreUsernamesScreen.js +10 -15
- package/lib/module/ui/screens/LearnMoreUsernamesScreen.js.map +1 -1
- package/lib/module/ui/screens/LegalDocumentsScreen.js +78 -94
- package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -1
- package/lib/module/ui/screens/ManageAccountScreen.js +102 -137
- package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/NotificationsScreen.js +71 -77
- package/lib/module/ui/screens/NotificationsScreen.js.map +1 -1
- package/lib/module/ui/screens/PaymentGatewayScreen.js +4 -9
- package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/module/ui/screens/PreferencesScreen.js +69 -75
- package/lib/module/ui/screens/PreferencesScreen.js.map +1 -1
- package/lib/module/ui/screens/PremiumSubscriptionScreen.js +58 -93
- package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
- package/lib/module/ui/screens/PrivacySettingsScreen.js +293 -305
- package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +102 -116
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/SavesCollectionsScreen.js +40 -46
- package/lib/module/ui/screens/SavesCollectionsScreen.js.map +1 -1
- package/lib/module/ui/screens/SearchSettingsScreen.js +46 -58
- package/lib/module/ui/screens/SearchSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/UserLinksScreen.js +26 -32
- package/lib/module/ui/screens/UserLinksScreen.js.map +1 -1
- package/lib/module/ui/screens/UserListScreen.js +14 -24
- package/lib/module/ui/screens/UserListScreen.js.map +1 -1
- package/lib/module/ui/screens/WelcomeNewUserScreen.js +17 -49
- package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/module/ui/screens/fileManagement/FileLibraryError.js +59 -0
- package/lib/module/ui/screens/fileManagement/FileLibraryError.js.map +1 -0
- package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js +54 -42
- package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
- package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js +45 -81
- package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustAboutScreen.js +67 -75
- package/lib/module/ui/screens/trust/TrustAboutScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustCenterScreen.js +112 -139
- package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustFAQScreen.js +15 -21
- package/lib/module/ui/screens/trust/TrustFAQScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js +14 -26
- package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustRewardsScreen.js +69 -85
- package/lib/module/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustRulesScreen.js +30 -37
- package/lib/module/ui/screens/trust/TrustRulesScreen.js.map +1 -1
- package/lib/module/ui/stores/resetSessionScopedStores.js +8 -3
- package/lib/module/ui/stores/resetSessionScopedStores.js.map +1 -1
- package/lib/module/ui/utils/avatarUtils.js +11 -2
- package/lib/module/ui/utils/avatarUtils.js.map +1 -1
- package/lib/module/ui/utils/fileManagement.js +0 -78
- 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/AvatarCameraBadge.d.ts +4 -0
- package/lib/typescript/commonjs/ui/components/AvatarCameraBadge.d.ts.map +1 -0
- package/lib/typescript/{module/ui/components/OxyAccountDialog.d.ts → commonjs/ui/components/OxyAccountDialogScreen.d.ts} +5 -4
- package/lib/typescript/commonjs/ui/components/OxyAccountDialogScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts +3 -3
- package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +2 -2
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileSummaryCard.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/RequireOxyAuth.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/SurfaceHeaderAction.d.ts +16 -0
- package/lib/typescript/commonjs/ui/components/SurfaceHeaderAction.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/SurfaceScreen.d.ts +3 -4
- package/lib/typescript/commonjs/ui/components/SurfaceScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts +14 -4
- package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/modals/DeleteAccountModal.d.ts +17 -2
- package/lib/typescript/commonjs/ui/components/modals/DeleteAccountModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/oxyAuthChooserStyles.d.ts +75 -13
- package/lib/typescript/commonjs/ui/components/oxyAuthChooserStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/photogrid/JustifiedPhotoGrid.d.ts +10 -8
- package/lib/typescript/commonjs/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/surfaces/ActionSheetSurface.d.ts +38 -0
- package/lib/typescript/commonjs/ui/components/surfaces/ActionSheetSurface.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/queryKeys.d.ts +9 -0
- package/lib/typescript/commonjs/ui/hooks/queries/queryKeys.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/useFileQueries.d.ts +50 -0
- package/lib/typescript/commonjs/ui/hooks/queries/useFileQueries.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts +17 -16
- package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useReduceMotion.d.ts +14 -0
- package/lib/typescript/commonjs/ui/hooks/useReduceMotion.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts +31 -0
- package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts +1 -1
- package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts +27 -2
- package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/bottomSheetManager.d.ts +4 -5
- package/lib/typescript/commonjs/ui/navigation/bottomSheetManager.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/surfaceBackBridge.d.ts +16 -0
- package/lib/typescript/commonjs/ui/navigation/surfaceBackBridge.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/navigation/surfaceNavStack.d.ts +21 -0
- package/lib/typescript/commonjs/ui/navigation/surfaceNavStack.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/surfaceRegistry.d.ts +101 -23
- package/lib/typescript/commonjs/ui/navigation/surfaceRegistry.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/surfaces.d.ts +42 -11
- package/lib/typescript/commonjs/ui/navigation/surfaces.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AccountMembersScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AccountVerificationScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AppInfoScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AvatarCropScreen.d.ts +18 -9
- package/lib/typescript/commonjs/ui/screens/AvatarCropScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ChangeAvatarScreen.d.ts +34 -0
- package/lib/typescript/commonjs/ui/screens/ChangeAvatarScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/CreateAccountScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/EditProfileScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/FAQScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/FeedbackScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/HelpSupportScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/HistoryViewScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/LearnMoreUsernamesScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/LegalDocumentsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts +1 -1
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/NotificationsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/PreferencesScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ProfileScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/SearchSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/UserLinksScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/UserListScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/FileLibraryError.d.ts +23 -0
- package/lib/typescript/commonjs/ui/screens/fileManagement/FileLibraryError.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts +4 -0
- package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +10 -2
- package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustAboutScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustCenterScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustFAQScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustRewardsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/stores/resetSessionScopedStores.d.ts +8 -1
- package/lib/typescript/commonjs/ui/stores/resetSessionScopedStores.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/types/navigation.d.ts +10 -0
- package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts +0 -48
- package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +2 -0
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/AvatarCameraBadge.d.ts +4 -0
- package/lib/typescript/module/ui/components/AvatarCameraBadge.d.ts.map +1 -0
- package/lib/typescript/{commonjs/ui/components/OxyAccountDialog.d.ts → module/ui/components/OxyAccountDialogScreen.d.ts} +5 -4
- package/lib/typescript/module/ui/components/OxyAccountDialogScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts +3 -3
- package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ProfileButton.d.ts +2 -2
- package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ProfileSummaryCard.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/RequireOxyAuth.d.ts +1 -1
- package/lib/typescript/module/ui/components/SurfaceHeaderAction.d.ts +16 -0
- package/lib/typescript/module/ui/components/SurfaceHeaderAction.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/SurfaceScreen.d.ts +3 -4
- package/lib/typescript/module/ui/components/SurfaceScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts +14 -4
- package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/modals/DeleteAccountModal.d.ts +17 -2
- package/lib/typescript/module/ui/components/modals/DeleteAccountModal.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/oxyAuthChooserStyles.d.ts +75 -13
- package/lib/typescript/module/ui/components/oxyAuthChooserStyles.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/photogrid/JustifiedPhotoGrid.d.ts +10 -8
- package/lib/typescript/module/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/surfaces/ActionSheetSurface.d.ts +38 -0
- package/lib/typescript/module/ui/components/surfaces/ActionSheetSurface.d.ts.map +1 -0
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/queryKeys.d.ts +9 -0
- package/lib/typescript/module/ui/hooks/queries/queryKeys.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/useFileQueries.d.ts +50 -0
- package/lib/typescript/module/ui/hooks/queries/useFileQueries.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts +17 -16
- package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useReduceMotion.d.ts +14 -0
- package/lib/typescript/module/ui/hooks/useReduceMotion.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts +31 -0
- package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts +1 -1
- package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts +27 -2
- package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/bottomSheetManager.d.ts +4 -5
- package/lib/typescript/module/ui/navigation/bottomSheetManager.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/surfaceBackBridge.d.ts +16 -0
- package/lib/typescript/module/ui/navigation/surfaceBackBridge.d.ts.map +1 -0
- package/lib/typescript/module/ui/navigation/surfaceNavStack.d.ts +21 -0
- package/lib/typescript/module/ui/navigation/surfaceNavStack.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/surfaceRegistry.d.ts +101 -23
- package/lib/typescript/module/ui/navigation/surfaceRegistry.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/surfaces.d.ts +42 -11
- package/lib/typescript/module/ui/navigation/surfaces.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AccountMembersScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AccountVerificationScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AppInfoScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts +18 -9
- package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ChangeAvatarScreen.d.ts +34 -0
- package/lib/typescript/module/ui/screens/ChangeAvatarScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/CreateAccountScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/EditProfileScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FAQScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FeedbackScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/HelpSupportScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/HistoryViewScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/LearnMoreUsernamesScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/LegalDocumentsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/NotificationsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/PreferencesScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ProfileScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/SearchSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/UserLinksScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/UserListScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/FileLibraryError.d.ts +23 -0
- package/lib/typescript/module/ui/screens/fileManagement/FileLibraryError.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts +4 -0
- package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +10 -2
- package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustAboutScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustCenterScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustFAQScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustRewardsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/stores/resetSessionScopedStores.d.ts +8 -1
- package/lib/typescript/module/ui/stores/resetSessionScopedStores.d.ts.map +1 -1
- package/lib/typescript/module/ui/types/navigation.d.ts +10 -0
- package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/avatarUtils.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/fileManagement.d.ts +0 -48
- package/lib/typescript/module/ui/utils/fileManagement.d.ts.map +1 -1
- package/package.json +9 -5
- package/src/index.ts +12 -5
- package/src/ui/components/AvatarCameraBadge.tsx +35 -0
- package/src/ui/components/{OxyAccountDialog.tsx → OxyAccountDialogScreen.tsx} +50 -116
- package/src/ui/components/OxyAuthChooser.tsx +743 -86
- package/src/ui/components/OxyConsentScreen.tsx +1 -1
- package/src/ui/components/ProfileButton.tsx +18 -3
- package/src/ui/components/ProfileSummaryCard.tsx +2 -25
- package/src/ui/components/RequireOxyAuth.tsx +1 -1
- package/src/ui/components/SurfaceHeaderAction.tsx +60 -0
- package/src/ui/components/SurfaceScreen.tsx +108 -14
- package/src/ui/components/fileManagement/FileDetailsModal.tsx +50 -36
- package/src/ui/components/modals/DeleteAccountModal.tsx +47 -26
- package/src/ui/components/oxyAuthChooserStyles.ts +78 -16
- package/src/ui/components/photogrid/JustifiedPhotoGrid.tsx +158 -84
- package/src/ui/components/photogrid/__tests__/chunkPhotos.test.ts +51 -0
- package/src/ui/components/surfaces/ActionSheetSurface.tsx +98 -0
- package/src/ui/context/OxyContext.tsx +79 -25
- package/src/ui/hooks/queries/queryKeys.ts +15 -0
- package/src/ui/hooks/queries/useFileQueries.ts +162 -0
- package/src/ui/hooks/useAvatarPicker.ts +46 -74
- package/src/ui/hooks/useReduceMotion.ts +58 -0
- package/src/ui/hooks/useSurfaceHeader.ts +57 -0
- package/src/ui/hooks/useSwitchableAccounts.ts +1 -1
- package/src/ui/navigation/__tests__/getSurfaceConfig.test.ts +55 -7
- package/src/ui/navigation/__tests__/surfaceNavStack.test.ts +149 -0
- package/src/ui/navigation/accountDialogManager.ts +42 -2
- package/src/ui/navigation/bottomSheetManager.ts +6 -7
- package/src/ui/navigation/routes.ts +6 -4
- package/src/ui/navigation/surfaceBackBridge.ts +69 -0
- package/src/ui/navigation/surfaceNavStack.ts +72 -9
- package/src/ui/navigation/surfaceRegistry.ts +164 -24
- package/src/ui/navigation/surfaces.ts +137 -30
- package/src/ui/screens/AccountMembersScreen.tsx +39 -100
- package/src/ui/screens/AccountSettingsScreen.tsx +32 -54
- package/src/ui/screens/AccountVerificationScreen.tsx +23 -51
- package/src/ui/screens/AppInfoScreen.tsx +6 -13
- package/src/ui/screens/AvatarCropScreen.tsx +340 -311
- package/src/ui/screens/ChangeAvatarScreen.tsx +359 -0
- package/src/ui/screens/ConnectedAppsScreen.tsx +39 -60
- package/src/ui/screens/CreateAccountScreen.tsx +13 -39
- package/src/ui/screens/EditProfileFieldScreen.tsx +30 -48
- package/src/ui/screens/EditProfileScreen.tsx +7 -16
- package/src/ui/screens/FAQScreen.tsx +9 -13
- package/src/ui/screens/FeedbackScreen.tsx +8 -22
- package/src/ui/screens/FileManagementScreen.tsx +370 -610
- package/src/ui/screens/HelpSupportScreen.tsx +7 -13
- package/src/ui/screens/HistoryViewScreen.tsx +26 -31
- package/src/ui/screens/LanguageSelectorScreen.tsx +12 -46
- package/src/ui/screens/LearnMoreUsernamesScreen.tsx +8 -16
- package/src/ui/screens/LegalDocumentsScreen.tsx +7 -22
- package/src/ui/screens/ManageAccountScreen.tsx +96 -165
- package/src/ui/screens/NotificationsScreen.tsx +7 -13
- package/src/ui/screens/PaymentGatewayScreen.tsx +3 -10
- package/src/ui/screens/PreferencesScreen.tsx +7 -13
- package/src/ui/screens/PremiumSubscriptionScreen.tsx +52 -90
- package/src/ui/screens/PrivacySettingsScreen.tsx +9 -21
- package/src/ui/screens/ProfileScreen.tsx +9 -11
- package/src/ui/screens/SavesCollectionsScreen.tsx +7 -13
- package/src/ui/screens/SearchSettingsScreen.tsx +9 -21
- package/src/ui/screens/UserLinksScreen.tsx +7 -14
- package/src/ui/screens/UserListScreen.tsx +2 -5
- package/src/ui/screens/WelcomeNewUserScreen.tsx +18 -48
- package/src/ui/screens/fileManagement/FileLibraryError.tsx +56 -0
- package/src/ui/screens/fileManagement/PhotoPickerSection.tsx +56 -46
- package/src/ui/screens/fileManagement/hooks/useFileUploadState.ts +55 -71
- package/src/ui/screens/trust/TrustAboutScreen.tsx +10 -17
- package/src/ui/screens/trust/TrustCenterScreen.tsx +9 -28
- package/src/ui/screens/trust/TrustFAQScreen.tsx +15 -18
- package/src/ui/screens/trust/TrustLeaderboardScreen.tsx +3 -5
- package/src/ui/screens/trust/TrustRewardsScreen.tsx +11 -26
- package/src/ui/screens/trust/TrustRulesScreen.tsx +10 -13
- package/src/ui/stores/resetSessionScopedStores.ts +8 -3
- package/src/ui/types/navigation.ts +10 -0
- package/src/ui/utils/avatarUtils.ts +11 -2
- package/src/ui/utils/fileManagement.ts +1 -101
- package/lib/commonjs/ui/components/Header.js +0 -305
- package/lib/commonjs/ui/components/Header.js.map +0 -1
- package/lib/commonjs/ui/components/OxyAccountDialog.js.map +0 -1
- package/lib/commonjs/ui/stores/fileStore.js +0 -153
- package/lib/commonjs/ui/stores/fileStore.js.map +0 -1
- package/lib/module/ui/components/Header.js +0 -299
- package/lib/module/ui/components/Header.js.map +0 -1
- package/lib/module/ui/components/OxyAccountDialog.js.map +0 -1
- package/lib/module/ui/stores/fileStore.js +0 -145
- package/lib/module/ui/stores/fileStore.js.map +0 -1
- package/lib/typescript/commonjs/ui/components/Header.d.ts +0 -33
- package/lib/typescript/commonjs/ui/components/Header.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/stores/fileStore.d.ts +0 -31
- package/lib/typescript/commonjs/ui/stores/fileStore.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/Header.d.ts +0 -33
- package/lib/typescript/module/ui/components/Header.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts.map +0 -1
- package/lib/typescript/module/ui/stores/fileStore.d.ts +0 -31
- package/lib/typescript/module/ui/stores/fileStore.d.ts.map +0 -1
- package/src/ui/components/Header.tsx +0 -224
- package/src/ui/stores/fileStore.ts +0 -118
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState,
|
|
1
|
+
import React, { useState, useCallback, useMemo, useRef } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
View,
|
|
4
4
|
Text,
|
|
@@ -8,22 +8,26 @@ import {
|
|
|
8
8
|
ActivityIndicator,
|
|
9
9
|
RefreshControl,
|
|
10
10
|
TextInput,
|
|
11
|
-
Image,
|
|
12
|
-
AccessibilityInfo,
|
|
13
11
|
useWindowDimensions,
|
|
14
12
|
} from 'react-native';
|
|
13
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
15
14
|
import { Image as ExpoImage } from 'expo-image';
|
|
16
15
|
import type { FileManagementScreenProps } from '../types/fileManagement';
|
|
17
|
-
import {
|
|
16
|
+
import { toast } from '@oxyhq/bloom';
|
|
17
|
+
import { surfaces } from '@oxyhq/bloom/surfaces';
|
|
18
18
|
import * as Skeleton from '@oxyhq/bloom/skeleton';
|
|
19
19
|
import { Ionicons, MaterialCommunityIcons } from '@expo/vector-icons';
|
|
20
|
+
import { Pressable } from 'react-native';
|
|
20
21
|
import type { FileMetadata } from '@oxyhq/core';
|
|
21
|
-
import {
|
|
22
|
-
import
|
|
22
|
+
import { queryKeys } from '../hooks/queries/queryKeys';
|
|
23
|
+
import { useUserFilesInfinite, removeFileFromCache, patchFileMetadataInCache } from '../hooks/queries/useFileQueries';
|
|
24
|
+
import { useSurfaceHeader } from '../hooks/useSurfaceHeader';
|
|
25
|
+
import { SurfaceHeaderAction } from '../components/SurfaceHeaderAction';
|
|
23
26
|
import JustifiedPhotoGrid from '../components/photogrid/JustifiedPhotoGrid';
|
|
24
27
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
25
28
|
import { useOxy } from '../context/OxyContext';
|
|
26
29
|
import { useI18n } from '../hooks/useI18n';
|
|
30
|
+
import { useReduceMotion } from '../hooks/useReduceMotion';
|
|
27
31
|
import { useUploadFile } from '../hooks/mutations/useAccountMutations';
|
|
28
32
|
import {
|
|
29
33
|
formatFileSize,
|
|
@@ -31,18 +35,35 @@ import {
|
|
|
31
35
|
} from '../utils/fileManagement';
|
|
32
36
|
import { useResolvedFileUrls, fileThumbSource } from '../hooks/useResolvedFileUrls';
|
|
33
37
|
import { FileViewer } from '../components/fileManagement/FileViewer';
|
|
34
|
-
import {
|
|
38
|
+
import { presentFileDetails } from '../components/fileManagement/FileDetailsModal';
|
|
35
39
|
import { UploadPreview } from '../components/fileManagement/UploadPreview';
|
|
40
|
+
import { presentActionSheet } from '../components/surfaces/ActionSheetSurface';
|
|
36
41
|
import { getErrorMessage } from './fileManagement/shared';
|
|
37
42
|
import { useFileUploadState } from './fileManagement/hooks/useFileUploadState';
|
|
38
43
|
import PhotoPickerView from './fileManagement/PhotoPickerSection';
|
|
39
44
|
import FileListSection, { type FileListItem } from './fileManagement/FileListSection';
|
|
45
|
+
import FileLibraryError from './fileManagement/FileLibraryError';
|
|
40
46
|
import UploadBar from './fileManagement/UploadBar';
|
|
41
47
|
import { AnimatedButton } from '../components/fileManagement/AnimatedButton';
|
|
42
48
|
|
|
43
49
|
// Genuinely-inline-only styles: `viewModeButton` is spread into an Animated.View
|
|
44
50
|
// style array (interpolated backgroundColor), and the photo tiles are
|
|
45
51
|
// `expo-image` (no className remap). Everything else uses NativeWind classNames.
|
|
52
|
+
// Nav-header slot layout for this screen's action row + review-mode back button.
|
|
53
|
+
const fmHeaderStyles = StyleSheet.create({
|
|
54
|
+
actionsRow: {
|
|
55
|
+
flexDirection: 'row',
|
|
56
|
+
gap: 8,
|
|
57
|
+
},
|
|
58
|
+
backButton: {
|
|
59
|
+
width: 36,
|
|
60
|
+
height: 36,
|
|
61
|
+
borderRadius: 18,
|
|
62
|
+
alignItems: 'center',
|
|
63
|
+
justifyContent: 'center',
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
46
67
|
const screenStyles = StyleSheet.create({
|
|
47
68
|
viewModeButton: {
|
|
48
69
|
paddingHorizontal: 10,
|
|
@@ -53,15 +74,14 @@ const screenStyles = StyleSheet.create({
|
|
|
53
74
|
justifyContent: 'center',
|
|
54
75
|
marginHorizontal: 1,
|
|
55
76
|
},
|
|
56
|
-
photoImage: { width: '100%', height: '100%', borderRadius: 8 },
|
|
57
77
|
justifiedPhotoImage: { width: '100%', height: '100%', borderRadius: 6 },
|
|
58
78
|
});
|
|
59
79
|
|
|
60
80
|
const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
61
81
|
onClose,
|
|
62
|
-
theme,
|
|
63
82
|
goBack,
|
|
64
83
|
navigate,
|
|
84
|
+
dismiss,
|
|
65
85
|
userId,
|
|
66
86
|
containerWidth,
|
|
67
87
|
selectMode = false,
|
|
@@ -82,13 +102,35 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
82
102
|
// against `user`, so switching shows/manages that account's files.
|
|
83
103
|
const { user, oxyServices } = useOxy();
|
|
84
104
|
const { t } = useI18n();
|
|
105
|
+
const queryClient = useQueryClient();
|
|
85
106
|
const uploadFileMutation = useUploadFile();
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
107
|
+
|
|
108
|
+
// Files are owned by the ACTIVE account. `targetUserId` scopes the query key,
|
|
109
|
+
// so switching accounts (or an explicit `userId` prop) shows that account's
|
|
110
|
+
// library with no manual reset.
|
|
111
|
+
const targetUserId = userId || user?.id;
|
|
112
|
+
|
|
113
|
+
// The file list is React Query's, NOT a store: infinite-paginated, fetched on
|
|
114
|
+
// mount + on owner change, edited optimistically via cache helpers. The
|
|
115
|
+
// rendered list is the flattened pages.
|
|
116
|
+
const filesQuery = useUserFilesInfinite(targetUserId);
|
|
117
|
+
const files = useMemo(
|
|
118
|
+
() => filesQuery.data?.pages.flatMap((page) => page.files) ?? [],
|
|
119
|
+
[filesQuery.data],
|
|
120
|
+
);
|
|
121
|
+
// No owner resolved yet reads as "loading" (matches the old skeleton-until-
|
|
122
|
+
// first-load behaviour); `isLoading` is the first-page fetch only.
|
|
123
|
+
const isLoadingFiles = !targetUserId || filesQuery.isLoading;
|
|
124
|
+
const isRefreshingFiles = filesQuery.isRefetching;
|
|
125
|
+
const isFetchingMore = filesQuery.isFetchingNextPage;
|
|
126
|
+
const hasMoreFiles = filesQuery.hasNextPage ?? false;
|
|
127
|
+
// Terminal load failure with nothing cached — render a DISTINCT error state
|
|
128
|
+
// (not the empty state) so a failed load never looks like an empty library.
|
|
129
|
+
const hasLoadError = filesQuery.isError && files.length === 0;
|
|
130
|
+
const invalidateFiles = useCallback(() => {
|
|
131
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.files.list(targetUserId) });
|
|
132
|
+
}, [queryClient, targetUserId]);
|
|
133
|
+
|
|
92
134
|
const { width: windowWidth } = useWindowDimensions();
|
|
93
135
|
// Prefer an explicit sheet width from the router; fall back to the window
|
|
94
136
|
// so photo grids never size against a hardcoded 400px default.
|
|
@@ -96,40 +138,16 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
96
138
|
typeof containerWidth === 'number' && containerWidth > 0
|
|
97
139
|
? containerWidth
|
|
98
140
|
: windowWidth;
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
const deleting = useDeletingStore();
|
|
102
|
-
const [loading, setLoading] = useState(true);
|
|
103
|
-
const [refreshing, setRefreshing] = useState(false);
|
|
104
|
-
const [paging, setPaging] = useState({ offset: 0, limit: 40, total: 0, hasMore: true, loadingMore: false });
|
|
105
|
-
const [selectedFile, setSelectedFile] = useState<FileMetadata | null>(null);
|
|
106
|
-
const fileDetailsControl = useDialogControl();
|
|
141
|
+
// In-flight delete target (local UI state — was in the file store).
|
|
142
|
+
const [deletingId, setDeletingId] = useState<string | null>(null);
|
|
107
143
|
// In selectMode we never open the detailed viewer
|
|
108
144
|
const [openedFile, setOpenedFile] = useState<FileMetadata | null>(null);
|
|
109
145
|
const [fileContent, setFileContent] = useState<string | null>(null);
|
|
110
146
|
const [loadingFileContent, setLoadingFileContent] = useState(false);
|
|
111
147
|
const [showFileDetailsInViewer, setShowFileDetailsInViewer] = useState(false);
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
// Used by `PhotoPickerView` to skip cell stagger animations.
|
|
116
|
-
useEffect(() => {
|
|
117
|
-
let cancelled = false;
|
|
118
|
-
AccessibilityInfo.isReduceMotionEnabled()
|
|
119
|
-
.then((enabled) => {
|
|
120
|
-
if (!cancelled) setReduceMotion(enabled);
|
|
121
|
-
})
|
|
122
|
-
.catch(() => {
|
|
123
|
-
// Defaults to false; no action needed.
|
|
124
|
-
});
|
|
125
|
-
const sub = AccessibilityInfo.addEventListener('reduceMotionChanged', (enabled) => {
|
|
126
|
-
setReduceMotion(enabled);
|
|
127
|
-
});
|
|
128
|
-
return () => {
|
|
129
|
-
cancelled = true;
|
|
130
|
-
sub.remove();
|
|
131
|
-
};
|
|
132
|
-
}, []);
|
|
148
|
+
// Reduce-motion preference, read as an external store (no effect). Passed to
|
|
149
|
+
// `PhotoPickerView` to skip cell stagger animations.
|
|
150
|
+
const reduceMotion = useReduceMotion();
|
|
133
151
|
|
|
134
152
|
// Image-only picker mode: when the consumer restricts to image MIME types
|
|
135
153
|
// (e.g. avatar picker), photos grid is the more useful default view.
|
|
@@ -203,25 +221,54 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
203
221
|
|
|
204
222
|
return sorted;
|
|
205
223
|
}, [files, searchQuery, viewMode, sortBy, sortOrder]);
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const [
|
|
210
|
-
// Selection state
|
|
211
|
-
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set(initialSelectedIds));
|
|
212
|
-
const [lastSelectedFileId, setLastSelectedFileId] = useState<string | null>(null);
|
|
224
|
+
// Selection state. `initialSelectedIds` is the INITIAL selection only (lazy
|
|
225
|
+
// init) — there is no prop→state sync effect, since no caller mutates it
|
|
226
|
+
// after mount.
|
|
227
|
+
const [selectedIds, setSelectedIds] = useState<Set<string>>(() => new Set(initialSelectedIds));
|
|
213
228
|
const scrollViewRef = useRef<ScrollView>(null);
|
|
214
229
|
const photoScrollViewRef = useRef<ScrollView>(null);
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
230
|
+
|
|
231
|
+
// Scroll the browse list/grid to a just-selected file. Driven directly from
|
|
232
|
+
// the selection event handler (double-rAF so the selection re-render has
|
|
233
|
+
// committed first) — not an effect. No-ops in the image-only picker, whose
|
|
234
|
+
// own FlatList is not either ScrollView ref.
|
|
235
|
+
const scrollToSelectedFile = useCallback((fileId: string) => {
|
|
236
|
+
if (viewMode === 'all' && scrollViewRef.current) {
|
|
237
|
+
const itemIndex = filteredFiles.findIndex(file => file.id === fileId);
|
|
238
|
+
if (itemIndex < 0) return;
|
|
239
|
+
// GroupedItem dense rows are ~65px, +30px when a description wraps.
|
|
240
|
+
const baseItemHeight = 65;
|
|
241
|
+
const descriptionHeight = 30;
|
|
242
|
+
let scrollPosition = 0;
|
|
243
|
+
for (let i = 0; i <= itemIndex && i < filteredFiles.length; i++) {
|
|
244
|
+
scrollPosition += baseItemHeight;
|
|
245
|
+
if (filteredFiles[i].metadata?.description) scrollPosition += descriptionHeight;
|
|
246
|
+
}
|
|
247
|
+
// Offset for the header/controls/search/stats chrome (~250px) so the
|
|
248
|
+
// item lands near the top, not under the chrome.
|
|
249
|
+
const finalScrollPosition = 250 + scrollPosition - 150;
|
|
250
|
+
requestAnimationFrame(() => {
|
|
251
|
+
requestAnimationFrame(() => {
|
|
252
|
+
scrollViewRef.current?.scrollTo({ y: Math.max(0, finalScrollPosition), animated: true });
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
} else if (viewMode === 'photos' && photoScrollViewRef.current) {
|
|
256
|
+
const photos = filteredFiles.filter(file => file.contentType.startsWith('image/'));
|
|
257
|
+
const photoIndex = photos.findIndex(p => p.id === fileId);
|
|
258
|
+
if (photoIndex < 0) return;
|
|
259
|
+
// Rough estimate for the justified grid (3 photos/row, variable heights).
|
|
260
|
+
const row = Math.floor(photoIndex / 3);
|
|
261
|
+
const finalScrollPosition = row * (150 + 4) - 100;
|
|
262
|
+
requestAnimationFrame(() => {
|
|
263
|
+
requestAnimationFrame(() => {
|
|
264
|
+
photoScrollViewRef.current?.scrollTo({ y: Math.max(0, finalScrollPosition), animated: true });
|
|
265
|
+
});
|
|
266
|
+
});
|
|
219
267
|
}
|
|
220
|
-
}, [
|
|
268
|
+
}, [viewMode, filteredFiles]);
|
|
221
269
|
|
|
222
270
|
const toggleSelect = useCallback(async (file: FileMetadata) => {
|
|
223
|
-
//
|
|
224
|
-
// if (!selectMode) return;
|
|
271
|
+
// Selection is allowed in regular mode too (for bulk operations).
|
|
225
272
|
if (disabledMimeTypes.length) {
|
|
226
273
|
const blocked = disabledMimeTypes.some(mt => file.contentType === mt || file.contentType.startsWith(mt.endsWith('/') ? mt : `${mt}/`));
|
|
227
274
|
if (blocked) {
|
|
@@ -240,9 +287,6 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
240
287
|
}
|
|
241
288
|
}
|
|
242
289
|
|
|
243
|
-
// Track the selected file for scrolling
|
|
244
|
-
setLastSelectedFileId(file.id);
|
|
245
|
-
|
|
246
290
|
// Link file to entity if linkContext is provided
|
|
247
291
|
if (linkContext) {
|
|
248
292
|
try {
|
|
@@ -260,11 +304,19 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
260
304
|
}
|
|
261
305
|
|
|
262
306
|
if (!multiSelect) {
|
|
263
|
-
onSelect
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
307
|
+
if (onSelect) {
|
|
308
|
+
// Legacy callback caller (inbox, WelcomeNewUser): keep the
|
|
309
|
+
// callback + afterSelect behaviour unchanged.
|
|
310
|
+
onSelect(file);
|
|
311
|
+
if (afterSelect === 'back') {
|
|
312
|
+
goBack?.();
|
|
313
|
+
} else if (afterSelect === 'close') {
|
|
314
|
+
onClose?.();
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
// Promise-based picker (avatar picker): resolve the surface's
|
|
318
|
+
// present() promise with the picked file.
|
|
319
|
+
dismiss?.(file);
|
|
268
320
|
}
|
|
269
321
|
return;
|
|
270
322
|
}
|
|
@@ -282,12 +334,13 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
282
334
|
}
|
|
283
335
|
return next;
|
|
284
336
|
});
|
|
285
|
-
|
|
337
|
+
scrollToSelectedFile(file.id);
|
|
338
|
+
}, [multiSelect, onSelect, onClose, goBack, dismiss, disabledMimeTypes, maxSelection, afterSelect, defaultVisibility, oxyServices, linkContext, t, scrollToSelectedFile]);
|
|
286
339
|
|
|
287
340
|
const confirmMultiSelection = useCallback(async () => {
|
|
288
341
|
if (!selectMode || !multiSelect) return;
|
|
289
342
|
const map: Record<string, FileMetadata> = {};
|
|
290
|
-
|
|
343
|
+
for (const f of files) { map[f.id] = f; }
|
|
291
344
|
const chosen = Array.from(selectedIds).map(id => map[id]).filter(Boolean);
|
|
292
345
|
|
|
293
346
|
// Update visibility and link files if needed
|
|
@@ -322,9 +375,15 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
322
375
|
// Wait for all updates (but don't block on failures)
|
|
323
376
|
await Promise.allSettled(updatePromises);
|
|
324
377
|
|
|
325
|
-
onConfirmSelection
|
|
326
|
-
|
|
327
|
-
|
|
378
|
+
if (onConfirmSelection) {
|
|
379
|
+
// Legacy callback caller (inbox): keep the callback + close.
|
|
380
|
+
onConfirmSelection(chosen);
|
|
381
|
+
onClose?.();
|
|
382
|
+
} else {
|
|
383
|
+
// Promise-based picker: resolve the surface with the chosen files.
|
|
384
|
+
dismiss?.(chosen);
|
|
385
|
+
}
|
|
386
|
+
}, [selectMode, multiSelect, selectedIds, files, onConfirmSelection, onClose, dismiss, defaultVisibility, oxyServices, linkContext]);
|
|
328
387
|
|
|
329
388
|
// Private-safe thumbnail URLs for the currently-shown files, resolved in
|
|
330
389
|
// ONE batch per page (not N per-tile) and cached by React Query. Uploads
|
|
@@ -346,70 +405,15 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
346
405
|
const backgroundColor = colors.backgroundSecondary;
|
|
347
406
|
const borderColor = colors.border;
|
|
348
407
|
|
|
349
|
-
const targetUserId = userId || user?.id;
|
|
350
|
-
|
|
351
|
-
const storeSetDeleting = useFileStore(s => s.setDeleting);
|
|
352
|
-
|
|
353
|
-
const loadFiles = useCallback(async (mode: 'initial' | 'refresh' | 'silent' | 'more' = 'initial') => {
|
|
354
|
-
if (!targetUserId) return;
|
|
355
|
-
|
|
356
|
-
try {
|
|
357
|
-
if (mode === 'refresh') {
|
|
358
|
-
setRefreshing(true);
|
|
359
|
-
} else if (mode === 'initial') {
|
|
360
|
-
setLoading(true);
|
|
361
|
-
setPaging(p => ({ ...p, offset: 0, hasMore: true }));
|
|
362
|
-
} else if (mode === 'more') {
|
|
363
|
-
// Prevent duplicate fetches
|
|
364
|
-
setPaging(p => ({ ...p, loadingMore: true }));
|
|
365
|
-
}
|
|
366
|
-
const currentPaging = mode === 'more' ? (prevPagingRef.current ?? paging) : paging;
|
|
367
|
-
const effectiveOffset = mode === 'more' ? currentPaging.offset + currentPaging.limit : 0;
|
|
368
|
-
const response = await oxyServices.listUserFiles(currentPaging.limit, effectiveOffset);
|
|
369
|
-
const assets: FileMetadata[] = (response.files || []).map((f: { id: string; originalName?: string; sha256?: string; mime?: string; size?: number; createdAt?: string; metadata?: Record<string, unknown>; variants?: unknown[] }) => ({
|
|
370
|
-
id: f.id,
|
|
371
|
-
filename: f.originalName ?? f.sha256 ?? '',
|
|
372
|
-
contentType: f.mime ?? '',
|
|
373
|
-
length: f.size ?? 0,
|
|
374
|
-
chunkSize: 0,
|
|
375
|
-
uploadDate: f.createdAt ?? '',
|
|
376
|
-
metadata: f.metadata ?? {},
|
|
377
|
-
variants: (f.variants ?? []) as FileMetadata['variants'],
|
|
378
|
-
}));
|
|
379
|
-
if (mode === 'more') {
|
|
380
|
-
// append
|
|
381
|
-
useFileStore.getState().setFiles(assets, { merge: true });
|
|
382
|
-
setPaging(p => ({
|
|
383
|
-
...p,
|
|
384
|
-
offset: effectiveOffset,
|
|
385
|
-
total: response.total || (effectiveOffset + assets.length),
|
|
386
|
-
hasMore: response.hasMore,
|
|
387
|
-
loadingMore: false,
|
|
388
|
-
}));
|
|
389
|
-
} else {
|
|
390
|
-
useFileStore.getState().setFiles(assets, { merge: false });
|
|
391
|
-
setPaging(p => ({
|
|
392
|
-
...p,
|
|
393
|
-
offset: 0,
|
|
394
|
-
total: response.total || assets.length,
|
|
395
|
-
hasMore: response.hasMore,
|
|
396
|
-
loadingMore: false,
|
|
397
|
-
}));
|
|
398
|
-
}
|
|
399
|
-
} catch (error: unknown) {
|
|
400
|
-
toast.error(getErrorMessage(error) || t('fileManagement.toasts.loadFailed'));
|
|
401
|
-
} finally {
|
|
402
|
-
setLoading(false);
|
|
403
|
-
setRefreshing(false);
|
|
404
|
-
setPaging(p => ({ ...p, loadingMore: false }));
|
|
405
|
-
}
|
|
406
|
-
}, [targetUserId, oxyServices, paging]);
|
|
407
|
-
|
|
408
408
|
// Self-contained document-picking + upload-preview state and handlers.
|
|
409
|
+
// Optimistic uploads edit the file query cache directly (see
|
|
410
|
+
// useFileQueries), so no loader is threaded in.
|
|
409
411
|
const {
|
|
410
412
|
isPickingDocument,
|
|
411
413
|
pendingFiles,
|
|
412
414
|
showUploadPreview,
|
|
415
|
+
uploading,
|
|
416
|
+
uploadProgress,
|
|
413
417
|
handleFileUpload,
|
|
414
418
|
handleConfirmUpload,
|
|
415
419
|
handleCancelUpload,
|
|
@@ -426,156 +430,61 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
426
430
|
onClose,
|
|
427
431
|
selectedIds,
|
|
428
432
|
setSelectedIds,
|
|
429
|
-
loadFiles,
|
|
430
433
|
t,
|
|
431
434
|
});
|
|
432
435
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
if (
|
|
442
|
-
|
|
443
|
-
setLoadingDimensions(true);
|
|
444
|
-
|
|
445
|
-
// Snapshot ids missing from the cache at kick-off; concurrent runs may
|
|
446
|
-
// overlap but each merge is applied via a functional updater.
|
|
447
|
-
const photosToLoad = photos.filter((photo) => !photoDimensionsRef.current[photo.id]);
|
|
448
|
-
|
|
449
|
-
if (photosToLoad.length === 0) {
|
|
450
|
-
setLoadingDimensions(false);
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
try {
|
|
455
|
-
const measured: { [key: string]: { width: number; height: number } } = {};
|
|
456
|
-
|
|
457
|
-
await Promise.all(
|
|
458
|
-
photosToLoad.map(async (photo) => {
|
|
459
|
-
try {
|
|
460
|
-
const downloadUrl = thumbSourceFor(photo);
|
|
461
|
-
// URL not resolved yet — skip (do NOT record fallback
|
|
462
|
-
// dims) so this photo is re-measured once its private-safe
|
|
463
|
-
// URL resolves. Measuring the broken public URL is exactly
|
|
464
|
-
// the bug we are fixing.
|
|
465
|
-
if (!downloadUrl) {
|
|
466
|
-
return;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// Unified approach using Image.getSize (works on all platforms)
|
|
470
|
-
await new Promise<void>((resolve) => {
|
|
471
|
-
Image.getSize(
|
|
472
|
-
downloadUrl,
|
|
473
|
-
(width: number, height: number) => {
|
|
474
|
-
measured[photo.id] = { width, height };
|
|
475
|
-
resolve();
|
|
476
|
-
},
|
|
477
|
-
() => {
|
|
478
|
-
// Fallback dimensions
|
|
479
|
-
measured[photo.id] = { width: 1, height: 1 };
|
|
480
|
-
resolve();
|
|
481
|
-
}
|
|
482
|
-
);
|
|
483
|
-
});
|
|
484
|
-
} catch (error) {
|
|
485
|
-
// Fallback dimensions for any errors
|
|
486
|
-
measured[photo.id] = { width: 1, height: 1 };
|
|
487
|
-
}
|
|
488
|
-
})
|
|
489
|
-
);
|
|
490
|
-
|
|
491
|
-
if (Object.keys(measured).length > 0) {
|
|
492
|
-
setPhotoDimensions((prev) => ({ ...prev, ...measured }));
|
|
493
|
-
}
|
|
494
|
-
} catch (error) {
|
|
495
|
-
// Photo dimensions loading failed, continue without dimensions
|
|
496
|
-
} finally {
|
|
497
|
-
setLoadingDimensions(false);
|
|
498
|
-
}
|
|
499
|
-
}, [thumbSourceFor]);
|
|
500
|
-
|
|
501
|
-
// Re-measure photo dimensions when their private-safe URLs resolve. The
|
|
502
|
-
// justified grid's own trigger fires on the photo SET, not on URL
|
|
503
|
-
// availability, so newly-resolved private tiles would otherwise keep their
|
|
504
|
-
// skipped (unmeasured) state and render with fallback geometry.
|
|
505
|
-
useEffect(() => {
|
|
506
|
-
if (viewMode !== 'photos') return;
|
|
507
|
-
const photos = filteredFiles.filter((file) => file.contentType.startsWith('image/'));
|
|
508
|
-
if (photos.length > 0) {
|
|
509
|
-
loadPhotoDimensions(photos);
|
|
510
|
-
}
|
|
511
|
-
}, [resolvedThumbUrls, viewMode, filteredFiles, loadPhotoDimensions]);
|
|
512
|
-
|
|
513
|
-
// Create justified rows from photos with responsive algorithm
|
|
514
|
-
const createJustifiedRows = useCallback((photos: FileMetadata[], containerWidth: number) => {
|
|
515
|
-
if (photos.length === 0) return [];
|
|
516
|
-
|
|
517
|
-
const rows: FileMetadata[][] = [];
|
|
518
|
-
const photosPerRow = 3; // Fixed 3 photos per row for consistency
|
|
519
|
-
|
|
520
|
-
for (let i = 0; i < photos.length; i += photosPerRow) {
|
|
521
|
-
const rowPhotos = photos.slice(i, i + photosPerRow);
|
|
522
|
-
rows.push(rowPhotos);
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
return rows;
|
|
526
|
-
}, []);
|
|
527
|
-
|
|
528
|
-
const confirmFileDelete = useCallback((fileId: string, filename: string) => {
|
|
529
|
-
setPendingDeleteFile({ id: fileId, name: filename });
|
|
530
|
-
fileDeleteDialog.open();
|
|
531
|
-
}, [fileDeleteDialog]);
|
|
532
|
-
|
|
533
|
-
const handleFileDelete = useCallback(async () => {
|
|
534
|
-
if (!pendingDeleteFile) return;
|
|
535
|
-
const { id: fileId } = pendingDeleteFile;
|
|
436
|
+
const confirmFileDelete = useCallback(async (fileId: string, filename: string) => {
|
|
437
|
+
const confirmed = await surfaces.confirm({
|
|
438
|
+
title: t('fileManagement.deleteFile') || 'Delete File',
|
|
439
|
+
message: t('fileManagement.confirms.deleteFile', { filename }),
|
|
440
|
+
confirmLabel: t('fileManagement.confirm') || 'Delete',
|
|
441
|
+
cancelLabel: t('common.cancel') || 'Cancel',
|
|
442
|
+
destructive: true,
|
|
443
|
+
});
|
|
444
|
+
if (!confirmed) return;
|
|
536
445
|
|
|
537
446
|
try {
|
|
538
|
-
|
|
447
|
+
setDeletingId(fileId);
|
|
539
448
|
await oxyServices.deleteFile(fileId);
|
|
540
449
|
|
|
541
450
|
toast.success(t('fileManagement.toasts.deleteSuccess'));
|
|
542
451
|
|
|
543
|
-
//
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
// Silent background reconcile
|
|
547
|
-
setTimeout(() => loadFiles('silent'), 800);
|
|
452
|
+
// Remove from the query cache, then reconcile against the server.
|
|
453
|
+
removeFileFromCache(queryClient, targetUserId, fileId);
|
|
454
|
+
invalidateFiles();
|
|
548
455
|
} catch (error: unknown) {
|
|
549
|
-
|
|
550
456
|
// Provide specific error messages
|
|
551
457
|
if (getErrorMessage(error)?.includes('File not found') || getErrorMessage(error)?.includes('404')) {
|
|
552
458
|
toast.error(t('fileManagement.toasts.fileNotFound'));
|
|
553
|
-
//
|
|
554
|
-
|
|
459
|
+
// It's already gone server-side — reconcile the list.
|
|
460
|
+
invalidateFiles();
|
|
555
461
|
} else if (getErrorMessage(error)?.includes('permission') || getErrorMessage(error)?.includes('403')) {
|
|
556
462
|
toast.error(t('fileManagement.toasts.noPermission'));
|
|
557
463
|
} else {
|
|
558
464
|
toast.error(getErrorMessage(error) || t('fileManagement.toasts.deleteFailed'));
|
|
559
465
|
}
|
|
560
466
|
} finally {
|
|
561
|
-
|
|
562
|
-
setPendingDeleteFile(null);
|
|
467
|
+
setDeletingId(null);
|
|
563
468
|
}
|
|
564
|
-
}, [
|
|
469
|
+
}, [oxyServices, queryClient, targetUserId, invalidateFiles, t]);
|
|
565
470
|
|
|
566
|
-
const confirmBulkDelete = useCallback(() => {
|
|
471
|
+
const confirmBulkDelete = useCallback(async () => {
|
|
567
472
|
if (selectedIds.size === 0) return;
|
|
568
|
-
bulkDeleteDialog.open();
|
|
569
|
-
}, [selectedIds.size, bulkDeleteDialog]);
|
|
570
473
|
|
|
571
|
-
|
|
572
|
-
|
|
474
|
+
const confirmed = await surfaces.confirm({
|
|
475
|
+
title: t('fileManagement.deleteFiles') || 'Delete Files',
|
|
476
|
+
message: t('fileManagement.confirms.deleteFiles', { count: selectedIds.size }),
|
|
477
|
+
confirmLabel: t('fileManagement.confirm') || 'Delete',
|
|
478
|
+
cancelLabel: t('common.cancel') || 'Cancel',
|
|
479
|
+
destructive: true,
|
|
480
|
+
});
|
|
481
|
+
if (!confirmed) return;
|
|
573
482
|
|
|
574
483
|
try {
|
|
575
484
|
const deletePromises = Array.from(selectedIds).map(async (fileId) => {
|
|
576
485
|
try {
|
|
577
486
|
await oxyServices.deleteFile(fileId);
|
|
578
|
-
|
|
487
|
+
removeFileFromCache(queryClient, targetUserId, fileId);
|
|
579
488
|
return { success: true, fileId };
|
|
580
489
|
} catch (error: unknown) {
|
|
581
490
|
return { success: false, fileId, error };
|
|
@@ -594,11 +503,11 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
594
503
|
}
|
|
595
504
|
|
|
596
505
|
setSelectedIds(new Set());
|
|
597
|
-
|
|
506
|
+
invalidateFiles();
|
|
598
507
|
} catch (error: unknown) {
|
|
599
508
|
toast.error(getErrorMessage(error) || t('fileManagement.toasts.bulkDeleteError'));
|
|
600
509
|
}
|
|
601
|
-
}, [selectedIds,
|
|
510
|
+
}, [selectedIds, oxyServices, queryClient, targetUserId, invalidateFiles, t]);
|
|
602
511
|
|
|
603
512
|
const handleBulkVisibilityChange = useCallback(async (visibility: 'private' | 'public' | 'unlisted') => {
|
|
604
513
|
if (selectedIds.size === 0) return;
|
|
@@ -619,25 +528,38 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
619
528
|
|
|
620
529
|
if (successful > 0) {
|
|
621
530
|
toast.success(t('fileManagement.toasts.visibilitySuccess', { count: successful, visibility }));
|
|
622
|
-
//
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
});
|
|
627
|
-
});
|
|
531
|
+
// Reflect the new visibility in the cached files.
|
|
532
|
+
for (const fileId of selectedIds) {
|
|
533
|
+
patchFileMetadataInCache(queryClient, targetUserId, fileId, { visibility });
|
|
534
|
+
}
|
|
628
535
|
}
|
|
629
536
|
if (failed > 0) {
|
|
630
537
|
toast.error(t('fileManagement.toasts.visibilityFailed', { count: failed }));
|
|
631
538
|
}
|
|
632
539
|
|
|
633
|
-
|
|
540
|
+
invalidateFiles();
|
|
634
541
|
} catch (error: unknown) {
|
|
635
542
|
toast.error(getErrorMessage(error) || t('fileManagement.toasts.visibilityError'));
|
|
636
543
|
}
|
|
637
|
-
}, [selectedIds, oxyServices,
|
|
544
|
+
}, [selectedIds, oxyServices, queryClient, targetUserId, invalidateFiles, t]);
|
|
545
|
+
|
|
546
|
+
const handleVisibilityChange = useCallback(async () => {
|
|
547
|
+
if (selectedIds.size === 0) return;
|
|
548
|
+
const visibility = await presentActionSheet<'private' | 'public' | 'unlisted'>({
|
|
549
|
+
title: t('fileManagement.changeVisibility') || 'Change Visibility',
|
|
550
|
+
message: t('fileManagement.changeVisibilityConfirm', { count: selectedIds.size }),
|
|
551
|
+
options: [
|
|
552
|
+
{ label: t('fileManagement.private') || 'Private', value: 'private' },
|
|
553
|
+
{ label: t('fileManagement.public') || 'Public', value: 'public' },
|
|
554
|
+
{ label: t('fileManagement.unlisted') || 'Unlisted', value: 'unlisted' },
|
|
555
|
+
],
|
|
556
|
+
cancelLabel: t('common.cancel') || 'Cancel',
|
|
557
|
+
});
|
|
558
|
+
if (visibility) await handleBulkVisibilityChange(visibility);
|
|
559
|
+
}, [selectedIds.size, handleBulkVisibilityChange, t]);
|
|
638
560
|
|
|
639
561
|
// Unified download function - works on all platforms
|
|
640
|
-
const handleFileDownload = async (fileId: string, filename: string) => {
|
|
562
|
+
const handleFileDownload = useCallback(async (fileId: string, filename: string) => {
|
|
641
563
|
try {
|
|
642
564
|
// Resolve an authenticated, private-safe URL. The synchronous
|
|
643
565
|
// `getFileDownloadUrl` yields the public CDN origin, which 404s for
|
|
@@ -681,10 +603,9 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
681
603
|
} catch (error: unknown) {
|
|
682
604
|
toast.error(getErrorMessage(error) || t('fileManagement.toasts.downloadFailed'));
|
|
683
605
|
}
|
|
684
|
-
};
|
|
606
|
+
}, [oxyServices, t]);
|
|
685
607
|
|
|
686
|
-
|
|
687
|
-
const handleFileOpen = async (file: FileMetadata) => {
|
|
608
|
+
const handleFileOpen = useCallback(async (file: FileMetadata) => {
|
|
688
609
|
if (selectMode) {
|
|
689
610
|
toggleSelect(file);
|
|
690
611
|
return;
|
|
@@ -736,19 +657,23 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
736
657
|
} finally {
|
|
737
658
|
setLoadingFileContent(false);
|
|
738
659
|
}
|
|
739
|
-
};
|
|
660
|
+
}, [selectMode, toggleSelect, oxyServices, t]);
|
|
740
661
|
|
|
741
|
-
const handleCloseFile = () => {
|
|
662
|
+
const handleCloseFile = useCallback(() => {
|
|
742
663
|
setOpenedFile(null);
|
|
743
664
|
setFileContent(null);
|
|
744
665
|
setShowFileDetailsInViewer(false);
|
|
745
666
|
// Don't reset view mode when closing a file
|
|
746
|
-
};
|
|
667
|
+
}, []);
|
|
747
668
|
|
|
748
|
-
const showFileDetailsModal = (file: FileMetadata) => {
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
669
|
+
const showFileDetailsModal = useCallback((file: FileMetadata) => {
|
|
670
|
+
presentFileDetails({
|
|
671
|
+
file,
|
|
672
|
+
onDownload: handleFileDownload,
|
|
673
|
+
onDelete: confirmFileDelete,
|
|
674
|
+
isOwner: user?.id === targetUserId,
|
|
675
|
+
});
|
|
676
|
+
}, [handleFileDownload, confirmFileDelete, user?.id, targetUserId]);
|
|
752
677
|
|
|
753
678
|
const renderJustifiedPhotoItem = useCallback((photo: FileMetadata, width: number, height: number, isLast: boolean) => {
|
|
754
679
|
const downloadUrl = thumbSourceFor(photo);
|
|
@@ -786,18 +711,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
786
711
|
</View>
|
|
787
712
|
</TouchableOpacity>
|
|
788
713
|
);
|
|
789
|
-
}, [thumbSourceFor, selectMode, selectedIds, multiSelect, colors.primary, colors.text]);
|
|
790
|
-
|
|
791
|
-
// Run initial load once per targetUserId change to avoid accidental loops
|
|
792
|
-
const lastLoadedFor = useRef<string | undefined>(undefined);
|
|
793
|
-
useEffect(() => {
|
|
794
|
-
const key = targetUserId || 'anonymous';
|
|
795
|
-
if (lastLoadedFor.current !== key) {
|
|
796
|
-
lastLoadedFor.current = key;
|
|
797
|
-
loadFiles('initial');
|
|
798
|
-
}
|
|
799
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
800
|
-
}, [targetUserId]);
|
|
714
|
+
}, [thumbSourceFor, selectMode, selectedIds, multiSelect, colors.primary, colors.text, handleFileOpen]);
|
|
801
715
|
|
|
802
716
|
// SettingsListItem-based file items (for 'all' view)
|
|
803
717
|
const groupedFileItems: FileListItem[] = useMemo(() => {
|
|
@@ -895,9 +809,9 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
895
809
|
className="w-[34px] h-[34px] rounded-[8px] items-center justify-center"
|
|
896
810
|
style={{ backgroundColor: colors.negativeSubtle }}
|
|
897
811
|
onPress={() => confirmFileDelete(file.id, file.filename)}
|
|
898
|
-
disabled={
|
|
812
|
+
disabled={deletingId === file.id}
|
|
899
813
|
>
|
|
900
|
-
{
|
|
814
|
+
{deletingId === file.id ? (
|
|
901
815
|
<ActivityIndicator size="small" color={colors.error} />
|
|
902
816
|
) : (
|
|
903
817
|
<Ionicons name="trash" size={18} color={colors.error} />
|
|
@@ -907,89 +821,30 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
907
821
|
) : undefined,
|
|
908
822
|
};
|
|
909
823
|
});
|
|
910
|
-
}, [filteredFiles,
|
|
911
|
-
|
|
912
|
-
//
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
const sortedFiles = filteredFiles;
|
|
926
|
-
|
|
927
|
-
// Calculate total height up to this item
|
|
928
|
-
let scrollPosition = 0;
|
|
929
|
-
for (let i = 0; i <= itemIndex && i < sortedFiles.length; i++) {
|
|
930
|
-
const file = sortedFiles[i];
|
|
931
|
-
scrollPosition += baseItemHeight;
|
|
932
|
-
if (file.metadata?.description) {
|
|
933
|
-
scrollPosition += descriptionHeight;
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
// Add header, controls, search, and stats height (approximately 250px)
|
|
938
|
-
const headerHeight = 250;
|
|
939
|
-
const finalScrollPosition = headerHeight + scrollPosition - 150; // Offset to show item near top
|
|
940
|
-
|
|
941
|
-
// Use requestAnimationFrame to ensure DOM is updated before scrolling
|
|
942
|
-
requestAnimationFrame(() => {
|
|
943
|
-
requestAnimationFrame(() => {
|
|
944
|
-
scrollViewRef.current?.scrollTo({
|
|
945
|
-
y: Math.max(0, finalScrollPosition),
|
|
946
|
-
animated: true,
|
|
947
|
-
});
|
|
948
|
-
});
|
|
949
|
-
});
|
|
950
|
-
}
|
|
951
|
-
} else if (viewMode === 'photos' && photoScrollViewRef.current) {
|
|
952
|
-
// For photo grid, find the photo index
|
|
953
|
-
const photos = filteredFiles.filter(file => file.contentType.startsWith('image/'));
|
|
954
|
-
const photoIndex = photos.findIndex(p => p.id === lastSelectedFileId);
|
|
955
|
-
|
|
956
|
-
if (photoIndex >= 0) {
|
|
957
|
-
// Rough scroll estimate for the justified grid (3 photos/row; variable row heights).
|
|
958
|
-
const itemsPerRow = 3;
|
|
959
|
-
const estimatedRowHeight = 150;
|
|
960
|
-
const rowGap = 4;
|
|
961
|
-
const row = Math.floor(photoIndex / itemsPerRow);
|
|
962
|
-
const finalScrollPosition = row * (estimatedRowHeight + rowGap) - 100;
|
|
963
|
-
|
|
964
|
-
// Use requestAnimationFrame to ensure DOM is updated before scrolling
|
|
965
|
-
requestAnimationFrame(() => {
|
|
966
|
-
requestAnimationFrame(() => {
|
|
967
|
-
photoScrollViewRef.current?.scrollTo({
|
|
968
|
-
y: Math.max(0, finalScrollPosition),
|
|
969
|
-
animated: true,
|
|
970
|
-
});
|
|
971
|
-
});
|
|
972
|
-
});
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
}, [lastSelectedFileId, selectMode, viewMode, filteredFiles, safeContainerWidth]);
|
|
977
|
-
|
|
978
|
-
// Clear selected file ID after scroll animation completes
|
|
979
|
-
useEffect(() => {
|
|
980
|
-
if (lastSelectedFileId && scrollViewRef.current) {
|
|
981
|
-
const timeoutId = setTimeout(() => {
|
|
982
|
-
setLastSelectedFileId(null);
|
|
983
|
-
}, 600); // Allow time for scroll animation to complete
|
|
984
|
-
|
|
985
|
-
return () => clearTimeout(timeoutId);
|
|
986
|
-
}
|
|
987
|
-
}, [lastSelectedFileId]);
|
|
824
|
+
}, [filteredFiles, colors, deletingId, toggleSelect, handleFileDownload, confirmFileDelete, handleFileOpen, thumbSourceFor, selectMode, selectedIds]);
|
|
825
|
+
|
|
826
|
+
// Browse-themed terminal load-failure state — DISTINCT from the empty state.
|
|
827
|
+
const renderLoadError = () => (
|
|
828
|
+
<FileLibraryError
|
|
829
|
+
title={t('fileManagement.loadError.title')}
|
|
830
|
+
description={t('fileManagement.loadError.description')}
|
|
831
|
+
retryLabel={t('fileManagement.retry')}
|
|
832
|
+
onRetry={() => filesQuery.refetch()}
|
|
833
|
+
iconColor={colors.error}
|
|
834
|
+
titleColor={colors.text}
|
|
835
|
+
descriptionColor={colors.textSecondary}
|
|
836
|
+
buttonColor={colors.primary}
|
|
837
|
+
/>
|
|
838
|
+
);
|
|
988
839
|
|
|
989
|
-
|
|
840
|
+
// Browse "photos" view. The justified grid owns its own dimension
|
|
841
|
+
// measurement + reflow (see JustifiedPhotoGrid); this only supplies the
|
|
842
|
+
// photo set, the private-safe URL resolver, and the tile renderer.
|
|
843
|
+
const renderPhotoGrid = () => {
|
|
990
844
|
const photos = filteredFiles.filter(file => file.contentType.startsWith('image/'));
|
|
991
845
|
|
|
992
846
|
if (photos.length === 0) {
|
|
847
|
+
if (hasLoadError) return renderLoadError();
|
|
993
848
|
return (
|
|
994
849
|
<View className="items-center py-[40px] px-[24px]">
|
|
995
850
|
<Ionicons name="images-outline" size={64} color={colors.textTertiary} />
|
|
@@ -1006,9 +861,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1006
861
|
onPress={handleFileUpload}
|
|
1007
862
|
disabled={uploading || isPickingDocument}
|
|
1008
863
|
>
|
|
1009
|
-
{uploading ? (
|
|
1010
|
-
<ActivityIndicator size="small" color="#FFFFFF" />
|
|
1011
|
-
) : isPickingDocument ? (
|
|
864
|
+
{(uploading || isPickingDocument) ? (
|
|
1012
865
|
<ActivityIndicator size="small" color="#FFFFFF" />
|
|
1013
866
|
) : (
|
|
1014
867
|
<>
|
|
@@ -1029,8 +882,8 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1029
882
|
contentContainerClassName="p-[10px]"
|
|
1030
883
|
refreshControl={
|
|
1031
884
|
<RefreshControl
|
|
1032
|
-
refreshing={
|
|
1033
|
-
onRefresh={() =>
|
|
885
|
+
refreshing={isRefreshingFiles}
|
|
886
|
+
onRefresh={() => filesQuery.refetch()}
|
|
1034
887
|
tintColor={colors.primary}
|
|
1035
888
|
/>
|
|
1036
889
|
}
|
|
@@ -1038,24 +891,15 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1038
891
|
onScroll={({ nativeEvent }) => {
|
|
1039
892
|
const { layoutMeasurement, contentOffset, contentSize } = nativeEvent;
|
|
1040
893
|
const distanceFromBottom = contentSize.height - (contentOffset.y + layoutMeasurement.height);
|
|
1041
|
-
if (distanceFromBottom < 200 && !
|
|
1042
|
-
|
|
894
|
+
if (distanceFromBottom < 200 && !isFetchingMore && hasMoreFiles) {
|
|
895
|
+
filesQuery.fetchNextPage();
|
|
1043
896
|
}
|
|
1044
897
|
}}
|
|
1045
898
|
scrollEventThrottle={250}
|
|
1046
899
|
>
|
|
1047
|
-
{loadingDimensions && (
|
|
1048
|
-
<View className="flex-row items-center justify-center py-[16px] gap-[8px]">
|
|
1049
|
-
<ActivityIndicator size="small" color={colors.primary} />
|
|
1050
|
-
<Text className="text-[14px] italic" style={{ color: colors.textSecondary }}>{t('fileManagement.loadingPhotoLayout')}</Text>
|
|
1051
|
-
</View>
|
|
1052
|
-
)}
|
|
1053
|
-
|
|
1054
900
|
<JustifiedPhotoGrid
|
|
1055
901
|
photos={photos}
|
|
1056
|
-
|
|
1057
|
-
loadPhotoDimensions={loadPhotoDimensions}
|
|
1058
|
-
createJustifiedRows={createJustifiedRows}
|
|
902
|
+
getThumbUrl={thumbSourceFor}
|
|
1059
903
|
renderJustifiedPhotoItem={renderJustifiedPhotoItem}
|
|
1060
904
|
textColor={colors.text}
|
|
1061
905
|
containerWidth={
|
|
@@ -1066,28 +910,9 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1066
910
|
/>
|
|
1067
911
|
</ScrollView>
|
|
1068
912
|
);
|
|
1069
|
-
}
|
|
1070
|
-
filteredFiles,
|
|
1071
|
-
colors,
|
|
1072
|
-
user?.id,
|
|
1073
|
-
targetUserId,
|
|
1074
|
-
uploading,
|
|
1075
|
-
handleFileUpload,
|
|
1076
|
-
refreshing,
|
|
1077
|
-
loadFiles,
|
|
1078
|
-
loadingDimensions,
|
|
1079
|
-
photoDimensions,
|
|
1080
|
-
loadPhotoDimensions,
|
|
1081
|
-
createJustifiedRows,
|
|
1082
|
-
renderJustifiedPhotoItem,
|
|
1083
|
-
containerWidth,
|
|
1084
|
-
]);
|
|
1085
|
-
|
|
1086
|
-
// Inline justified grid removed (moved to components/photogrid/JustifiedPhotoGrid.tsx)
|
|
1087
|
-
|
|
1088
|
-
|
|
913
|
+
};
|
|
1089
914
|
|
|
1090
|
-
const renderEmptyState = () => (
|
|
915
|
+
const renderEmptyState = () => hasLoadError ? renderLoadError() : (
|
|
1091
916
|
<View className="items-center py-[40px] px-[24px]">
|
|
1092
917
|
<Ionicons name="folder-open-outline" size={64} color={colors.textTertiary} />
|
|
1093
918
|
<Text className="text-[24px] font-bold mt-[16px] mb-[8px]" style={{ color: colors.text }}>{t('fileManagement.emptyFiles.title')}</Text>
|
|
@@ -1104,9 +929,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1104
929
|
onPress={handleFileUpload}
|
|
1105
930
|
disabled={uploading || isPickingDocument}
|
|
1106
931
|
>
|
|
1107
|
-
{uploading ? (
|
|
1108
|
-
<ActivityIndicator size="small" color="#FFFFFF" />
|
|
1109
|
-
) : isPickingDocument ? (
|
|
932
|
+
{(uploading || isPickingDocument) ? (
|
|
1110
933
|
<ActivityIndicator size="small" color="#FFFFFF" />
|
|
1111
934
|
) : (
|
|
1112
935
|
<>
|
|
@@ -1129,7 +952,65 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1129
952
|
// picker's placement-aware container width / columns / tile size and the
|
|
1130
953
|
// Dialog-vs-bottom-sheet sizing. Skipping the browse chrome here is what keeps
|
|
1131
954
|
// the picker from flashing the wrong (file-manager) skeleton inside the Dialog.
|
|
1132
|
-
|
|
955
|
+
// The Dialog owns the nav header; this screen contributes its state-dependent
|
|
956
|
+
// title/subtitle + action slots. The image-only picker mode is headerless
|
|
957
|
+
// (PhotoPickerView owns its own bar), so this config is simply ignored there.
|
|
958
|
+
const fmHeaderRight = useMemo<React.ReactNode>(() => {
|
|
959
|
+
const actions = selectMode && multiSelect
|
|
960
|
+
? [
|
|
961
|
+
{ key: 'clear', label: t('fileManagement.clear'), onPress: () => setSelectedIds(new Set()), disabled: selectedIds.size === 0 },
|
|
962
|
+
{ key: 'confirm', label: t('fileManagement.confirm'), onPress: confirmMultiSelection, disabled: selectedIds.size === 0 },
|
|
963
|
+
]
|
|
964
|
+
: !selectMode && selectedIds.size > 0
|
|
965
|
+
? [
|
|
966
|
+
{ key: 'clear', label: t('fileManagement.clear'), onPress: () => setSelectedIds(new Set()), disabled: false },
|
|
967
|
+
{ key: 'delete', label: t('fileManagement.delete', { count: selectedIds.size }), onPress: confirmBulkDelete, disabled: false },
|
|
968
|
+
{ key: 'visibility', label: t('fileManagement.visibility'), onPress: handleVisibilityChange, disabled: false },
|
|
969
|
+
]
|
|
970
|
+
: [];
|
|
971
|
+
if (actions.length === 0) return undefined;
|
|
972
|
+
return (
|
|
973
|
+
<View style={fmHeaderStyles.actionsRow}>
|
|
974
|
+
{actions.map((a) => (
|
|
975
|
+
<SurfaceHeaderAction key={a.key} label={a.label} onPress={a.onPress} disabled={a.disabled} />
|
|
976
|
+
))}
|
|
977
|
+
</View>
|
|
978
|
+
);
|
|
979
|
+
}, [selectMode, multiSelect, selectedIds, t, confirmMultiSelection, confirmBulkDelete, handleVisibilityChange]);
|
|
980
|
+
|
|
981
|
+
const fmHeaderBack = useMemo<React.ReactNode>(() => (
|
|
982
|
+
<Pressable
|
|
983
|
+
onPress={handleCancelUpload}
|
|
984
|
+
accessibilityRole="button"
|
|
985
|
+
accessibilityLabel={t('common.back') || 'Back'}
|
|
986
|
+
hitSlop={8}
|
|
987
|
+
style={fmHeaderStyles.backButton}
|
|
988
|
+
>
|
|
989
|
+
<Ionicons name="chevron-back" size={20} color={colors.text} />
|
|
990
|
+
</Pressable>
|
|
991
|
+
), [handleCancelUpload, colors.text, t]);
|
|
992
|
+
|
|
993
|
+
useSurfaceHeader(
|
|
994
|
+
showUploadPreview
|
|
995
|
+
? {
|
|
996
|
+
title: t('fileManagement.reviewFiles'),
|
|
997
|
+
subtitle: t('fileManagement.readyToUpload', { count: pendingFiles.length }),
|
|
998
|
+
left: fmHeaderBack,
|
|
999
|
+
largeTitle: false,
|
|
1000
|
+
}
|
|
1001
|
+
: {
|
|
1002
|
+
title: selectMode
|
|
1003
|
+
? (multiSelect ? (maxSelection ? t('fileManagement.selectedWithMax', { count: selectedIds.size, max: maxSelection }) : t('fileManagement.selected', { count: selectedIds.size })) : t('fileManagement.selectFile'))
|
|
1004
|
+
: (viewMode === 'photos' ? t('fileManagement.photos') : t('fileManagement.title')),
|
|
1005
|
+
subtitle: selectMode
|
|
1006
|
+
? (multiSelect ? t('fileManagement.available', { count: filteredFiles.length }) : t('fileManagement.tapToSelect'))
|
|
1007
|
+
: (filteredFiles.length === 1 ? t('fileManagement.itemCount', { count: filteredFiles.length }) : t('fileManagement.itemCount_plural', { count: filteredFiles.length })),
|
|
1008
|
+
right: fmHeaderRight,
|
|
1009
|
+
largeTitle: false,
|
|
1010
|
+
},
|
|
1011
|
+
);
|
|
1012
|
+
|
|
1013
|
+
if (isLoadingFiles && !isImageOnlyPicker) {
|
|
1133
1014
|
const GRID_PADDING = 10;
|
|
1134
1015
|
const TILE_GAP = 4;
|
|
1135
1016
|
const GRID_COLUMNS = 3;
|
|
@@ -1190,71 +1071,61 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1190
1071
|
const allowUpload = isOwner && allowUploadInSelectMode;
|
|
1191
1072
|
|
|
1192
1073
|
return (
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1074
|
+
<PhotoPickerView
|
|
1075
|
+
photos={photosOnly}
|
|
1076
|
+
selectedIds={selectedIds}
|
|
1077
|
+
multiSelect={multiSelect}
|
|
1078
|
+
maxSelection={maxSelection}
|
|
1079
|
+
allowUpload={allowUpload}
|
|
1080
|
+
refreshing={isRefreshingFiles}
|
|
1081
|
+
uploading={uploading}
|
|
1082
|
+
isPickingDocument={isPickingDocument}
|
|
1083
|
+
uploadProgress={uploadProgress}
|
|
1084
|
+
hasMore={hasMoreFiles}
|
|
1085
|
+
loadingMore={isFetchingMore}
|
|
1086
|
+
loading={isLoadingFiles}
|
|
1087
|
+
loadError={hasLoadError}
|
|
1088
|
+
onRetry={() => filesQuery.refetch()}
|
|
1089
|
+
reduceMotion={reduceMotion}
|
|
1090
|
+
getThumbUrl={thumbSourceFor}
|
|
1091
|
+
primaryColor={colors.primary}
|
|
1092
|
+
isOwner={isOwner}
|
|
1093
|
+
onTogglePhoto={toggleSelect}
|
|
1094
|
+
// Long-press preview surfaces the file-detail panel on the stack.
|
|
1095
|
+
onPreviewPhoto={(file) => showFileDetailsModal(file)}
|
|
1096
|
+
onUpload={handleFileUpload}
|
|
1097
|
+
onRefresh={() => filesQuery.refetch()}
|
|
1098
|
+
onLoadMore={() => filesQuery.fetchNextPage()}
|
|
1099
|
+
onCancel={() => {
|
|
1100
|
+
if (onSelect || onConfirmSelection) {
|
|
1101
|
+
// Legacy callback caller: preserve close/back behaviour.
|
|
1217
1102
|
if (onClose) onClose();
|
|
1218
1103
|
else goBack?.();
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
onDownload={handleFileDownload}
|
|
1228
|
-
onDelete={confirmFileDelete}
|
|
1229
|
-
isOwner={isOwner}
|
|
1230
|
-
/>
|
|
1231
|
-
</>
|
|
1104
|
+
} else {
|
|
1105
|
+
// Promise picker (avatar): dismiss just this surface.
|
|
1106
|
+
dismiss?.();
|
|
1107
|
+
}
|
|
1108
|
+
}}
|
|
1109
|
+
onConfirm={confirmMultiSelection}
|
|
1110
|
+
t={t}
|
|
1111
|
+
/>
|
|
1232
1112
|
);
|
|
1233
1113
|
}
|
|
1234
1114
|
|
|
1235
1115
|
// If a file is opened, show the file viewer
|
|
1236
1116
|
if (!selectMode && openedFile) {
|
|
1237
1117
|
return (
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
/>
|
|
1250
|
-
<FileDetailsModal
|
|
1251
|
-
control={fileDetailsControl}
|
|
1252
|
-
file={selectedFile}
|
|
1253
|
-
onDownload={handleFileDownload}
|
|
1254
|
-
onDelete={confirmFileDelete}
|
|
1255
|
-
isOwner={user?.id === targetUserId}
|
|
1256
|
-
/>
|
|
1257
|
-
</>
|
|
1118
|
+
<FileViewer
|
|
1119
|
+
file={openedFile}
|
|
1120
|
+
fileContent={fileContent}
|
|
1121
|
+
loadingFileContent={loadingFileContent}
|
|
1122
|
+
showFileDetailsInViewer={showFileDetailsInViewer}
|
|
1123
|
+
onToggleDetails={() => setShowFileDetailsInViewer(!showFileDetailsInViewer)}
|
|
1124
|
+
onClose={handleCloseFile}
|
|
1125
|
+
onDownload={handleFileDownload}
|
|
1126
|
+
onDelete={confirmFileDelete}
|
|
1127
|
+
isOwner={user?.id === targetUserId}
|
|
1128
|
+
/>
|
|
1258
1129
|
);
|
|
1259
1130
|
}
|
|
1260
1131
|
|
|
@@ -1262,15 +1133,6 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1262
1133
|
if (showUploadPreview) {
|
|
1263
1134
|
return (
|
|
1264
1135
|
<View className="flex-1">
|
|
1265
|
-
<Header
|
|
1266
|
-
title={t('fileManagement.reviewFiles')}
|
|
1267
|
-
subtitle={t('fileManagement.readyToUpload', { count: pendingFiles.length })}
|
|
1268
|
-
onBack={handleCancelUpload}
|
|
1269
|
-
showBackButton
|
|
1270
|
-
variant="minimal"
|
|
1271
|
-
elevation="none"
|
|
1272
|
-
titleAlignment="left"
|
|
1273
|
-
/>
|
|
1274
1136
|
<UploadPreview
|
|
1275
1137
|
pendingFiles={pendingFiles}
|
|
1276
1138
|
onConfirm={handleConfirmUpload}
|
|
@@ -1284,51 +1146,6 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1284
1146
|
|
|
1285
1147
|
return (
|
|
1286
1148
|
<View className="flex-1">
|
|
1287
|
-
<Header
|
|
1288
|
-
title={selectMode ? (multiSelect ? (maxSelection ? t('fileManagement.selectedWithMax', { count: selectedIds.size, max: maxSelection }) : t('fileManagement.selected', { count: selectedIds.size })) : t('fileManagement.selectFile')) : (viewMode === 'photos' ? t('fileManagement.photos') : t('fileManagement.title'))}
|
|
1289
|
-
subtitle={selectMode ? (multiSelect ? t('fileManagement.available', { count: filteredFiles.length }) : t('fileManagement.tapToSelect')) : (filteredFiles.length === 1 ? t('fileManagement.itemCount', { count: filteredFiles.length }) : t('fileManagement.itemCount_plural', { count: filteredFiles.length }))}
|
|
1290
|
-
actions={selectMode && multiSelect ? [
|
|
1291
|
-
{
|
|
1292
|
-
key: 'clear',
|
|
1293
|
-
text: t('fileManagement.clear'),
|
|
1294
|
-
onPress: () => setSelectedIds(new Set()),
|
|
1295
|
-
disabled: selectedIds.size === 0,
|
|
1296
|
-
},
|
|
1297
|
-
{
|
|
1298
|
-
key: 'confirm',
|
|
1299
|
-
text: t('fileManagement.confirm'),
|
|
1300
|
-
onPress: confirmMultiSelection,
|
|
1301
|
-
disabled: selectedIds.size === 0,
|
|
1302
|
-
}
|
|
1303
|
-
] : !selectMode && selectedIds.size > 0 ? [
|
|
1304
|
-
{
|
|
1305
|
-
key: 'clear',
|
|
1306
|
-
text: t('fileManagement.clear'),
|
|
1307
|
-
onPress: () => setSelectedIds(new Set()),
|
|
1308
|
-
},
|
|
1309
|
-
{
|
|
1310
|
-
key: 'delete',
|
|
1311
|
-
text: t('fileManagement.delete', { count: selectedIds.size }),
|
|
1312
|
-
onPress: confirmBulkDelete,
|
|
1313
|
-
icon: 'delete',
|
|
1314
|
-
},
|
|
1315
|
-
{
|
|
1316
|
-
key: 'visibility',
|
|
1317
|
-
text: t('fileManagement.visibility'),
|
|
1318
|
-
onPress: () => {
|
|
1319
|
-
visibilityChangeDialog.open();
|
|
1320
|
-
},
|
|
1321
|
-
icon: 'eye',
|
|
1322
|
-
}
|
|
1323
|
-
] : undefined}
|
|
1324
|
-
onBack={onClose || goBack}
|
|
1325
|
-
|
|
1326
|
-
showBackButton
|
|
1327
|
-
variant="minimal"
|
|
1328
|
-
elevation="none"
|
|
1329
|
-
titleAlignment="left"
|
|
1330
|
-
/>
|
|
1331
|
-
|
|
1332
1149
|
<View className="flex-row items-center justify-between px-[12px] py-[12px] gap-[12px]">
|
|
1333
1150
|
<ScrollView
|
|
1334
1151
|
horizontal
|
|
@@ -1358,37 +1175,33 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1358
1175
|
style={screenStyles.viewModeButton}
|
|
1359
1176
|
accessibilityLabel={t('fileManagement.a11y.viewPhotos') || 'Show photos only'}
|
|
1360
1177
|
/>
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
accessibilityLabel={t('fileManagement.a11y.viewAudio') || 'Show audio only'}
|
|
1389
|
-
/>
|
|
1390
|
-
</>
|
|
1391
|
-
)}
|
|
1178
|
+
<AnimatedButton
|
|
1179
|
+
isSelected={viewMode === 'videos'}
|
|
1180
|
+
onPress={() => setViewMode('videos')}
|
|
1181
|
+
icon={viewMode === 'videos' ? 'video' : 'video-outline'}
|
|
1182
|
+
primaryColor={colors.primary}
|
|
1183
|
+
textColor={colors.text}
|
|
1184
|
+
style={screenStyles.viewModeButton}
|
|
1185
|
+
accessibilityLabel={t('fileManagement.a11y.viewVideos') || 'Show videos only'}
|
|
1186
|
+
/>
|
|
1187
|
+
<AnimatedButton
|
|
1188
|
+
isSelected={viewMode === 'documents'}
|
|
1189
|
+
onPress={() => setViewMode('documents')}
|
|
1190
|
+
icon={viewMode === 'documents' ? 'file-document' : 'file-document-outline'}
|
|
1191
|
+
primaryColor={colors.primary}
|
|
1192
|
+
textColor={colors.text}
|
|
1193
|
+
style={screenStyles.viewModeButton}
|
|
1194
|
+
accessibilityLabel={t('fileManagement.a11y.viewDocuments') || 'Show documents only'}
|
|
1195
|
+
/>
|
|
1196
|
+
<AnimatedButton
|
|
1197
|
+
isSelected={viewMode === 'audio'}
|
|
1198
|
+
onPress={() => setViewMode('audio')}
|
|
1199
|
+
icon={viewMode === 'audio' ? 'music-note' : 'music-note-outline'}
|
|
1200
|
+
primaryColor={colors.primary}
|
|
1201
|
+
textColor={colors.text}
|
|
1202
|
+
style={screenStyles.viewModeButton}
|
|
1203
|
+
accessibilityLabel={t('fileManagement.a11y.viewAudio') || 'Show audio only'}
|
|
1204
|
+
/>
|
|
1392
1205
|
</View>
|
|
1393
1206
|
</ScrollView>
|
|
1394
1207
|
<TouchableOpacity
|
|
@@ -1426,18 +1239,14 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1426
1239
|
color={colors.textSecondary}
|
|
1427
1240
|
/>
|
|
1428
1241
|
</TouchableOpacity>
|
|
1429
|
-
{user?.id === targetUserId && (!selectMode ||
|
|
1242
|
+
{user?.id === targetUserId && (!selectMode || allowUploadInSelectMode) && (
|
|
1430
1243
|
<TouchableOpacity
|
|
1431
|
-
className=
|
|
1244
|
+
className="h-[44px] w-[44px] rounded-[22px] items-center justify-center"
|
|
1432
1245
|
style={{ backgroundColor: colors.primary }}
|
|
1433
1246
|
onPress={handleFileUpload}
|
|
1434
1247
|
disabled={uploading || isPickingDocument}
|
|
1435
1248
|
accessibilityRole="button"
|
|
1436
|
-
accessibilityLabel={
|
|
1437
|
-
isImageOnlyPicker
|
|
1438
|
-
? (t('fileManagement.a11y.uploadFromDevice') || 'Upload photo from device')
|
|
1439
|
-
: (t('fileManagement.a11y.uploadFile') || 'Upload file')
|
|
1440
|
-
}
|
|
1249
|
+
accessibilityLabel={t('fileManagement.a11y.uploadFile') || 'Upload file'}
|
|
1441
1250
|
accessibilityState={{ busy: uploading || isPickingDocument }}
|
|
1442
1251
|
>
|
|
1443
1252
|
{uploading ? (
|
|
@@ -1451,13 +1260,6 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1451
1260
|
</View>
|
|
1452
1261
|
) : isPickingDocument ? (
|
|
1453
1262
|
<ActivityIndicator size="small" color="#FFFFFF" />
|
|
1454
|
-
) : isImageOnlyPicker ? (
|
|
1455
|
-
<View className="flex-row items-center gap-[6px]">
|
|
1456
|
-
<Ionicons name="cloud-upload" size={18} color="#FFFFFF" />
|
|
1457
|
-
<Text className="text-white text-[14px] font-semibold" numberOfLines={1}>
|
|
1458
|
-
{t('fileManagement.upload') || 'Upload'}
|
|
1459
|
-
</Text>
|
|
1460
|
-
</View>
|
|
1461
1263
|
) : (
|
|
1462
1264
|
<Ionicons name="add" size={22} color="#FFFFFF" />
|
|
1463
1265
|
)}
|
|
@@ -1531,27 +1333,17 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1531
1333
|
filteredFiles={filteredFiles}
|
|
1532
1334
|
searchQuery={searchQuery}
|
|
1533
1335
|
items={groupedFileItems}
|
|
1534
|
-
paging={
|
|
1535
|
-
refreshing={
|
|
1336
|
+
paging={{ loadingMore: isFetchingMore, hasMore: hasMoreFiles }}
|
|
1337
|
+
refreshing={isRefreshingFiles}
|
|
1536
1338
|
colors={colors}
|
|
1537
1339
|
t={t}
|
|
1538
|
-
onRefresh={() =>
|
|
1539
|
-
onLoadMore={() =>
|
|
1340
|
+
onRefresh={() => filesQuery.refetch()}
|
|
1341
|
+
onLoadMore={() => filesQuery.fetchNextPage()}
|
|
1540
1342
|
onClearSearch={() => setSearchQuery('')}
|
|
1541
1343
|
renderEmptyState={renderEmptyState}
|
|
1542
1344
|
/>
|
|
1543
1345
|
)}
|
|
1544
1346
|
|
|
1545
|
-
{!selectMode && (
|
|
1546
|
-
<FileDetailsModal
|
|
1547
|
-
control={fileDetailsControl}
|
|
1548
|
-
file={selectedFile}
|
|
1549
|
-
onDownload={handleFileDownload}
|
|
1550
|
-
onDelete={confirmFileDelete}
|
|
1551
|
-
isOwner={user?.id === targetUserId}
|
|
1552
|
-
/>
|
|
1553
|
-
)}
|
|
1554
|
-
|
|
1555
1347
|
{/* Uploading banner overlay with progress */}
|
|
1556
1348
|
{!selectMode && uploading && (
|
|
1557
1349
|
<UploadBar
|
|
@@ -1561,38 +1353,6 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1561
1353
|
t={t}
|
|
1562
1354
|
/>
|
|
1563
1355
|
)}
|
|
1564
|
-
|
|
1565
|
-
{/* Selection bar removed; actions are now in header */}
|
|
1566
|
-
{/* Global loadingMore bar removed; now inline in scroll areas */}
|
|
1567
|
-
<Dialog
|
|
1568
|
-
control={fileDeleteDialog}
|
|
1569
|
-
title={t('fileManagement.deleteFile') || 'Delete File'}
|
|
1570
|
-
description={pendingDeleteFile ? t('fileManagement.confirms.deleteFile', { filename: pendingDeleteFile.name }) : ''}
|
|
1571
|
-
actions={[
|
|
1572
|
-
{ label: t('fileManagement.confirm') || 'Delete', color: 'destructive', onPress: handleFileDelete },
|
|
1573
|
-
{ label: t('common.cancel') || 'Cancel', color: 'cancel' },
|
|
1574
|
-
]}
|
|
1575
|
-
/>
|
|
1576
|
-
<Dialog
|
|
1577
|
-
control={bulkDeleteDialog}
|
|
1578
|
-
title={t('fileManagement.deleteFiles') || 'Delete Files'}
|
|
1579
|
-
description={t('fileManagement.confirms.deleteFiles', { count: selectedIds.size })}
|
|
1580
|
-
actions={[
|
|
1581
|
-
{ label: t('fileManagement.confirm') || 'Delete', color: 'destructive', onPress: handleBulkDelete },
|
|
1582
|
-
{ label: t('common.cancel') || 'Cancel', color: 'cancel' },
|
|
1583
|
-
]}
|
|
1584
|
-
/>
|
|
1585
|
-
<Dialog
|
|
1586
|
-
control={visibilityChangeDialog}
|
|
1587
|
-
title={t('fileManagement.changeVisibility') || 'Change Visibility'}
|
|
1588
|
-
description={t('fileManagement.changeVisibilityConfirm', { count: selectedIds.size })}
|
|
1589
|
-
actions={[
|
|
1590
|
-
{ label: t('fileManagement.private') || 'Private', onPress: () => handleBulkVisibilityChange('private') },
|
|
1591
|
-
{ label: t('fileManagement.public') || 'Public', onPress: () => handleBulkVisibilityChange('public') },
|
|
1592
|
-
{ label: t('fileManagement.unlisted') || 'Unlisted', onPress: () => handleBulkVisibilityChange('unlisted') },
|
|
1593
|
-
{ label: t('common.cancel') || 'Cancel', color: 'cancel' },
|
|
1594
|
-
]}
|
|
1595
|
-
/>
|
|
1596
1356
|
</View>
|
|
1597
1357
|
);
|
|
1598
1358
|
};
|