@oxyhq/services 5.14.0 → 5.15.1
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/README.md +130 -54
- package/lib/commonjs/assets/assets/lottie/welcomeheader_background_op1.json +1 -0
- package/lib/commonjs/assets/lottie/welcomeheader_background_op1.json +1 -0
- package/lib/commonjs/core/HttpService.js +94 -4
- package/lib/commonjs/core/HttpService.js.map +1 -1
- package/lib/commonjs/core/OxyServices.base.js +3 -1
- package/lib/commonjs/core/OxyServices.base.js.map +1 -1
- package/lib/commonjs/core/mixins/OxyServices.assets.js +213 -22
- package/lib/commonjs/core/mixins/OxyServices.assets.js.map +1 -1
- package/lib/commonjs/core/mixins/OxyServices.auth.js +70 -99
- package/lib/commonjs/core/mixins/OxyServices.auth.js.map +1 -1
- package/lib/commonjs/crypto/index.js +33 -0
- package/lib/commonjs/crypto/index.js.map +1 -0
- package/lib/commonjs/crypto/keyManager.js +208 -0
- package/lib/commonjs/crypto/keyManager.js.map +1 -0
- package/lib/commonjs/crypto/recoveryPhrase.js +137 -0
- package/lib/commonjs/crypto/recoveryPhrase.js.map +1 -0
- package/lib/commonjs/crypto/signatureService.js +251 -0
- package/lib/commonjs/crypto/signatureService.js.map +1 -0
- package/lib/commonjs/i18n/locales/en-US.json +4 -0
- package/lib/commonjs/index.js +22 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/components/ActivityIndicator.js +203 -0
- package/lib/commonjs/ui/components/ActivityIndicator.js.map +1 -0
- package/lib/commonjs/ui/components/AutoHeightScrollView.js +46 -0
- package/lib/commonjs/ui/components/AutoHeightScrollView.js.map +1 -0
- package/lib/commonjs/ui/components/BottomSheet.js +407 -0
- package/lib/commonjs/ui/components/BottomSheet.js.map +1 -0
- package/lib/commonjs/ui/components/BottomSheetRouter.js +366 -0
- package/lib/commonjs/ui/components/BottomSheetRouter.js.map +1 -0
- package/lib/commonjs/ui/components/CrossFadeIcon.js +106 -0
- package/lib/commonjs/ui/components/CrossFadeIcon.js.map +1 -0
- package/lib/commonjs/ui/components/EmptyState.js +41 -0
- package/lib/commonjs/ui/components/EmptyState.js.map +1 -0
- package/lib/commonjs/ui/components/GroupedItem.js +87 -82
- package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
- package/lib/commonjs/ui/components/GroupedSection.js +25 -25
- package/lib/commonjs/ui/components/GroupedSection.js.map +1 -1
- package/lib/commonjs/ui/components/Header.js +111 -47
- package/lib/commonjs/ui/components/Header.js.map +1 -1
- package/lib/commonjs/ui/components/HelperText.js +103 -0
- package/lib/commonjs/ui/components/HelperText.js.map +1 -0
- package/lib/commonjs/ui/components/Icon.js +109 -0
- package/lib/commonjs/ui/components/Icon.js.map +1 -0
- package/lib/commonjs/ui/components/IconButton/IconButton.js +159 -0
- package/lib/commonjs/ui/components/IconButton/IconButton.js.map +1 -0
- package/lib/commonjs/ui/components/IconButton/utils.js +155 -0
- package/lib/commonjs/ui/components/IconButton/utils.js.map +1 -0
- package/lib/commonjs/ui/components/LoadingState.js +47 -0
- package/lib/commonjs/ui/components/LoadingState.js.map +1 -0
- package/lib/commonjs/ui/components/OxyPayButton.js +1 -14
- package/lib/commonjs/ui/components/OxyPayButton.js.map +1 -1
- package/lib/commonjs/ui/components/OxyProvider.js +41 -391
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/OxySignInButton.js +9 -13
- package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileCard.js +7 -4
- package/lib/commonjs/ui/components/ProfileCard.js.map +1 -1
- package/lib/commonjs/ui/components/QuickActions.js +7 -4
- package/lib/commonjs/ui/components/QuickActions.js.map +1 -1
- package/lib/commonjs/ui/components/Section.js +4 -1
- package/lib/commonjs/ui/components/Section.js.map +1 -1
- package/lib/commonjs/ui/components/SectionTitle.js +6 -3
- package/lib/commonjs/ui/components/SectionTitle.js.map +1 -1
- package/lib/commonjs/ui/components/SettingRow.js +77 -0
- package/lib/commonjs/ui/components/SettingRow.js.map +1 -0
- package/lib/commonjs/ui/components/StepBasedScreen.js +188 -172
- package/lib/commonjs/ui/components/StepBasedScreen.js.map +1 -1
- package/lib/commonjs/ui/components/Surface.js +258 -0
- package/lib/commonjs/ui/components/Surface.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/Addons/Outline.js +46 -0
- package/lib/commonjs/ui/components/TextField/Addons/Outline.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/Addons/Underline.js +53 -0
- package/lib/commonjs/ui/components/TextField/Addons/Underline.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/Adornment/TextFieldAdornment.js +155 -0
- package/lib/commonjs/ui/components/TextField/Adornment/TextFieldAdornment.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/Adornment/TextFieldAffix.js +144 -0
- package/lib/commonjs/ui/components/TextField/Adornment/TextFieldAffix.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/Adornment/TextFieldIcon.js +137 -0
- package/lib/commonjs/ui/components/TextField/Adornment/TextFieldIcon.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/Adornment/enums.js +22 -0
- package/lib/commonjs/ui/components/TextField/Adornment/enums.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/Adornment/types.js +6 -0
- package/lib/commonjs/ui/components/TextField/Adornment/types.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/Adornment/utils.js +62 -0
- package/lib/commonjs/ui/components/TextField/Adornment/utils.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/Label/InputLabel.js +176 -0
- package/lib/commonjs/ui/components/TextField/Label/InputLabel.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/Label/LabelBackground.js +84 -0
- package/lib/commonjs/ui/components/TextField/Label/LabelBackground.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/TextFieldFlat.js +377 -0
- package/lib/commonjs/ui/components/TextField/TextFieldFlat.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/TextFieldOutlined.js +361 -0
- package/lib/commonjs/ui/components/TextField/TextFieldOutlined.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/constants.js +50 -0
- package/lib/commonjs/ui/components/TextField/constants.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/helpers.js +490 -0
- package/lib/commonjs/ui/components/TextField/helpers.js.map +1 -0
- package/lib/commonjs/ui/components/TextField/types.js +6 -0
- package/lib/commonjs/ui/components/TextField/types.js.map +1 -0
- package/lib/commonjs/ui/components/TextField.js +339 -0
- package/lib/commonjs/ui/components/TextField.js.map +1 -0
- package/lib/commonjs/ui/components/TouchableRipple/Pressable.js +12 -0
- package/lib/commonjs/ui/components/TouchableRipple/Pressable.js.map +1 -0
- package/lib/commonjs/ui/components/TouchableRipple/TouchableRipple.js +258 -0
- package/lib/commonjs/ui/components/TouchableRipple/TouchableRipple.js.map +1 -0
- package/lib/commonjs/ui/components/TouchableRipple/TouchableRipple.native.js +107 -0
- package/lib/commonjs/ui/components/TouchableRipple/TouchableRipple.native.js.map +1 -0
- package/lib/commonjs/ui/components/TouchableRipple/utils.js +56 -0
- package/lib/commonjs/ui/components/TouchableRipple/utils.js.map +1 -0
- package/lib/commonjs/ui/components/Typography/AnimatedText.js +62 -0
- package/lib/commonjs/ui/components/Typography/AnimatedText.js.map +1 -0
- package/lib/commonjs/ui/components/Typography/types.js +26 -0
- package/lib/commonjs/ui/components/Typography/types.js.map +1 -0
- package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js +171 -0
- package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js.map +1 -0
- package/lib/commonjs/ui/components/fileManagement/FileViewer.js +409 -0
- package/lib/commonjs/ui/components/fileManagement/FileViewer.js.map +1 -0
- package/lib/commonjs/ui/components/fileManagement/UploadPreview.js +181 -0
- package/lib/commonjs/ui/components/fileManagement/UploadPreview.js.map +1 -0
- package/lib/commonjs/ui/components/fileManagement/styles.js +868 -0
- package/lib/commonjs/ui/components/fileManagement/styles.js.map +1 -0
- package/lib/commonjs/ui/components/index.js +29 -1
- package/lib/commonjs/ui/components/index.js.map +1 -1
- package/lib/commonjs/ui/components/profile/EditBioModal.js +181 -0
- package/lib/commonjs/ui/components/profile/EditBioModal.js.map +1 -0
- package/lib/commonjs/ui/components/profile/EditDisplayNameModal.js +207 -0
- package/lib/commonjs/ui/components/profile/EditDisplayNameModal.js.map +1 -0
- package/lib/commonjs/ui/components/profile/EditEmailModal.js +184 -0
- package/lib/commonjs/ui/components/profile/EditEmailModal.js.map +1 -0
- package/lib/commonjs/ui/components/profile/EditLinksModal.js +315 -0
- package/lib/commonjs/ui/components/profile/EditLinksModal.js.map +1 -0
- package/lib/commonjs/ui/components/profile/EditLocationModal.js +273 -0
- package/lib/commonjs/ui/components/profile/EditLocationModal.js.map +1 -0
- package/lib/commonjs/ui/components/profile/EditUsernameModal.js +180 -0
- package/lib/commonjs/ui/components/profile/EditUsernameModal.js.map +1 -0
- package/lib/commonjs/ui/components/profile/TwoFactorSetupModal.js +467 -0
- package/lib/commonjs/ui/components/profile/TwoFactorSetupModal.js.map +1 -0
- package/lib/commonjs/ui/components/styles/overlay.js +85 -0
- package/lib/commonjs/ui/components/styles/overlay.js.map +1 -0
- package/lib/commonjs/ui/components/styles/shadow.js +132 -0
- package/lib/commonjs/ui/components/styles/shadow.js.map +1 -0
- package/lib/commonjs/ui/components/theming.js +116 -0
- package/lib/commonjs/ui/components/theming.js.map +1 -0
- package/lib/commonjs/ui/components/types.js +2 -0
- package/lib/commonjs/ui/components/types.js.map +1 -0
- package/lib/commonjs/ui/components/utils/forwardRef.js +18 -0
- package/lib/commonjs/ui/components/utils/forwardRef.js.map +1 -0
- package/lib/commonjs/ui/components/utils/hasTouchHandler.js +13 -0
- package/lib/commonjs/ui/components/utils/hasTouchHandler.js.map +1 -0
- package/lib/commonjs/ui/components/utils/roundLayoutSize.js +9 -0
- package/lib/commonjs/ui/components/utils/roundLayoutSize.js.map +1 -0
- package/lib/commonjs/ui/components/utils/splitStyles.js +50 -0
- package/lib/commonjs/ui/components/utils/splitStyles.js.map +1 -0
- package/lib/commonjs/ui/constants/iconColors.js +84 -0
- package/lib/commonjs/ui/constants/iconColors.js.map +1 -0
- package/lib/commonjs/ui/constants/spacing.js +50 -0
- package/lib/commonjs/ui/constants/spacing.js.map +1 -0
- package/lib/commonjs/ui/constants/theme.js +123 -0
- package/lib/commonjs/ui/constants/theme.js.map +1 -0
- package/lib/commonjs/ui/context/OxyContext.js +198 -853
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/ThemeContext.js +36 -0
- package/lib/commonjs/ui/context/ThemeContext.js.map +1 -0
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +349 -0
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -0
- package/lib/commonjs/ui/context/hooks/useDeviceManagement.js +73 -0
- package/lib/commonjs/ui/context/hooks/useDeviceManagement.js.map +1 -0
- package/lib/commonjs/ui/context/hooks/useLanguageManagement.js +112 -0
- package/lib/commonjs/ui/context/hooks/useLanguageManagement.js.map +1 -0
- package/lib/commonjs/ui/context/hooks/useSessionManagement.js +261 -0
- package/lib/commonjs/ui/context/hooks/useSessionManagement.js.map +1 -0
- package/lib/commonjs/ui/context/hooks/useStorage.js +79 -0
- package/lib/commonjs/ui/context/hooks/useStorage.js.map +1 -0
- package/lib/commonjs/ui/context/utils/errorHandlers.js +90 -0
- package/lib/commonjs/ui/context/utils/errorHandlers.js.map +1 -0
- package/lib/commonjs/ui/context/utils/sessionHelpers.js +103 -0
- package/lib/commonjs/ui/context/utils/sessionHelpers.js.map +1 -0
- package/lib/commonjs/ui/context/utils/storageHelpers.js +119 -0
- package/lib/commonjs/ui/context/utils/storageHelpers.js.map +1 -0
- package/lib/commonjs/ui/hooks/index.js +14 -0
- package/lib/commonjs/ui/hooks/index.js.map +1 -1
- package/lib/commonjs/ui/hooks/use-color-scheme.js +29 -0
- package/lib/commonjs/ui/hooks/use-color-scheme.js.map +1 -0
- package/lib/commonjs/ui/hooks/use-haptic-press.js +21 -0
- package/lib/commonjs/ui/hooks/use-haptic-press.js.map +1 -0
- package/lib/commonjs/ui/hooks/useAssets.js.map +1 -1
- package/lib/commonjs/ui/hooks/useDeviceManagement.js +73 -0
- package/lib/commonjs/ui/hooks/useDeviceManagement.js.map +1 -0
- package/lib/commonjs/ui/hooks/useLanguageManagement.js +112 -0
- package/lib/commonjs/ui/hooks/useLanguageManagement.js.map +1 -0
- package/lib/commonjs/ui/hooks/useProfileEditing.js +123 -0
- package/lib/commonjs/ui/hooks/useProfileEditing.js.map +1 -0
- package/lib/commonjs/ui/hooks/useSessionManagement.js +261 -0
- package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -0
- package/lib/commonjs/ui/hooks/useStorage.js +79 -0
- package/lib/commonjs/ui/hooks/useStorage.js.map +1 -0
- package/lib/commonjs/ui/hooks/useThemeColors.js +31 -0
- package/lib/commonjs/ui/hooks/useThemeColors.js.map +1 -0
- package/lib/commonjs/ui/hooks/useThemeStyles.js +69 -0
- package/lib/commonjs/ui/hooks/useThemeStyles.js.map +1 -0
- package/lib/commonjs/ui/index.js +1 -4
- package/lib/commonjs/ui/index.js.map +1 -1
- package/lib/commonjs/ui/navigation/bottomSheetManager.js +180 -0
- package/lib/commonjs/ui/navigation/bottomSheetManager.js.map +1 -0
- package/lib/commonjs/ui/navigation/routes.js +80 -154
- package/lib/commonjs/ui/navigation/routes.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountCenterScreen.js +67 -67
- package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js +217 -98
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +514 -429
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +44 -59
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountVerificationScreen.js +12 -19
- package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AppInfoScreen.js +36 -43
- package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FeedbackScreen.js +14 -14
- package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +674 -1968
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/HelpSupportScreen.js +26 -23
- package/lib/commonjs/ui/screens/HelpSupportScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/HistoryViewScreen.js +19 -59
- package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +79 -170
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +13 -40
- package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/OxyAuthScreen.js +436 -0
- package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +18 -24
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +21 -9
- package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +180 -252
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +7 -5
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SavesCollectionsScreen.js +32 -70
- package/lib/commonjs/ui/screens/SavesCollectionsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SearchSettingsScreen.js +26 -99
- package/lib/commonjs/ui/screens/SearchSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SessionManagementScreen.js +24 -16
- package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/UserLinksScreen.js +8 -10
- package/lib/commonjs/ui/screens/UserLinksScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +64 -67
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +11 -8
- package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +124 -122
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +99 -112
- package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +12 -9
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +552 -79
- package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +12 -8
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
- package/lib/commonjs/ui/styles/authStyles.js +5 -11
- package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
- package/lib/commonjs/ui/styles/spacing.js +60 -2
- package/lib/commonjs/ui/styles/spacing.js.map +1 -1
- package/lib/commonjs/ui/styles/theme.js +1 -1
- package/lib/commonjs/ui/types/fileManagement.js +6 -0
- package/lib/commonjs/ui/types/fileManagement.js.map +1 -0
- package/lib/commonjs/ui/types/navigation.js +6 -0
- package/lib/commonjs/ui/types/navigation.js.map +1 -0
- package/lib/commonjs/ui/utils/colorUtils.js +52 -0
- package/lib/commonjs/ui/utils/colorUtils.js.map +1 -0
- package/lib/commonjs/ui/utils/errorHandlers.js +90 -0
- package/lib/commonjs/ui/utils/errorHandlers.js.map +1 -0
- package/lib/commonjs/ui/utils/fileManagement.js +181 -0
- package/lib/commonjs/ui/utils/fileManagement.js.map +1 -0
- package/lib/commonjs/ui/utils/sessionHelpers.js +103 -0
- package/lib/commonjs/ui/utils/sessionHelpers.js.map +1 -0
- package/lib/commonjs/ui/utils/storageHelpers.js +119 -0
- package/lib/commonjs/ui/utils/storageHelpers.js.map +1 -0
- package/lib/commonjs/ui/utils/themeUtils.js +47 -0
- package/lib/commonjs/ui/utils/themeUtils.js.map +1 -0
- package/lib/commonjs/ui/utils/user-utils.js +53 -0
- package/lib/commonjs/ui/utils/user-utils.js.map +1 -0
- package/lib/commonjs/utils/errorUtils.js +14 -4
- package/lib/commonjs/utils/errorUtils.js.map +1 -1
- package/lib/module/assets/assets/lottie/welcomeheader_background_op1.json +1 -0
- package/lib/module/assets/lottie/welcomeheader_background_op1.json +1 -0
- package/lib/module/core/HttpService.js +94 -4
- package/lib/module/core/HttpService.js.map +1 -1
- package/lib/module/core/OxyServices.base.js +3 -1
- package/lib/module/core/OxyServices.base.js.map +1 -1
- package/lib/module/core/mixins/OxyServices.assets.js +212 -20
- package/lib/module/core/mixins/OxyServices.assets.js.map +1 -1
- package/lib/module/core/mixins/OxyServices.auth.js +70 -99
- package/lib/module/core/mixins/OxyServices.auth.js.map +1 -1
- package/lib/module/crypto/index.js +16 -0
- package/lib/module/crypto/index.js.map +1 -0
- package/lib/module/crypto/keyManager.js +204 -0
- package/lib/module/crypto/keyManager.js.map +1 -0
- package/lib/module/crypto/recoveryPhrase.js +131 -0
- package/lib/module/crypto/recoveryPhrase.js.map +1 -0
- package/lib/module/crypto/signatureService.js +248 -0
- package/lib/module/crypto/signatureService.js.map +1 -0
- package/lib/module/i18n/locales/en-US.json +4 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/components/ActivityIndicator.js +198 -0
- package/lib/module/ui/components/ActivityIndicator.js.map +1 -0
- package/lib/module/ui/components/AutoHeightScrollView.js +41 -0
- package/lib/module/ui/components/AutoHeightScrollView.js.map +1 -0
- package/lib/module/ui/components/BottomSheet.js +402 -0
- package/lib/module/ui/components/BottomSheet.js.map +1 -0
- package/lib/module/ui/components/BottomSheetRouter.js +356 -0
- package/lib/module/ui/components/BottomSheetRouter.js.map +1 -0
- package/lib/module/ui/components/CrossFadeIcon.js +101 -0
- package/lib/module/ui/components/CrossFadeIcon.js.map +1 -0
- package/lib/module/ui/components/EmptyState.js +36 -0
- package/lib/module/ui/components/EmptyState.js.map +1 -0
- package/lib/module/ui/components/GroupedItem.js +88 -82
- package/lib/module/ui/components/GroupedItem.js.map +1 -1
- package/lib/module/ui/components/GroupedSection.js +23 -23
- package/lib/module/ui/components/GroupedSection.js.map +1 -1
- package/lib/module/ui/components/Header.js +109 -46
- package/lib/module/ui/components/Header.js.map +1 -1
- package/lib/module/ui/components/HelperText.js +99 -0
- package/lib/module/ui/components/HelperText.js.map +1 -0
- package/lib/module/ui/components/Icon.js +102 -0
- package/lib/module/ui/components/Icon.js.map +1 -0
- package/lib/module/ui/components/IconButton/IconButton.js +153 -0
- package/lib/module/ui/components/IconButton/IconButton.js.map +1 -0
- package/lib/module/ui/components/IconButton/utils.js +149 -0
- package/lib/module/ui/components/IconButton/utils.js.map +1 -0
- package/lib/module/ui/components/LoadingState.js +42 -0
- package/lib/module/ui/components/LoadingState.js.map +1 -0
- package/lib/module/ui/components/OxyPayButton.js +1 -14
- package/lib/module/ui/components/OxyPayButton.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +45 -396
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/OxySignInButton.js +9 -13
- package/lib/module/ui/components/OxySignInButton.js.map +1 -1
- package/lib/module/ui/components/ProfileCard.js +7 -4
- package/lib/module/ui/components/ProfileCard.js.map +1 -1
- package/lib/module/ui/components/QuickActions.js +7 -4
- package/lib/module/ui/components/QuickActions.js.map +1 -1
- package/lib/module/ui/components/Section.js +4 -1
- package/lib/module/ui/components/Section.js.map +1 -1
- package/lib/module/ui/components/SectionTitle.js +6 -3
- package/lib/module/ui/components/SectionTitle.js.map +1 -1
- package/lib/module/ui/components/SettingRow.js +72 -0
- package/lib/module/ui/components/SettingRow.js.map +1 -0
- package/lib/module/ui/components/StepBasedScreen.js +190 -174
- package/lib/module/ui/components/StepBasedScreen.js.map +1 -1
- package/lib/module/ui/components/Surface.js +252 -0
- package/lib/module/ui/components/Surface.js.map +1 -0
- package/lib/module/ui/components/TextField/Addons/Outline.js +40 -0
- package/lib/module/ui/components/TextField/Addons/Outline.js.map +1 -0
- package/lib/module/ui/components/TextField/Addons/Underline.js +47 -0
- package/lib/module/ui/components/TextField/Addons/Underline.js.map +1 -0
- package/lib/module/ui/components/TextField/Adornment/TextFieldAdornment.js +148 -0
- package/lib/module/ui/components/TextField/Adornment/TextFieldAdornment.js.map +1 -0
- package/lib/module/ui/components/TextField/Adornment/TextFieldAffix.js +141 -0
- package/lib/module/ui/components/TextField/Adornment/TextFieldAffix.js.map +1 -0
- package/lib/module/ui/components/TextField/Adornment/TextFieldIcon.js +135 -0
- package/lib/module/ui/components/TextField/Adornment/TextFieldIcon.js.map +1 -0
- package/lib/module/ui/components/TextField/Adornment/enums.js +18 -0
- package/lib/module/ui/components/TextField/Adornment/enums.js.map +1 -0
- package/lib/module/ui/components/TextField/Adornment/types.js +4 -0
- package/lib/module/ui/components/TextField/Adornment/types.js.map +1 -0
- package/lib/module/ui/components/TextField/Adornment/utils.js +57 -0
- package/lib/module/ui/components/TextField/Adornment/utils.js.map +1 -0
- package/lib/module/ui/components/TextField/Label/InputLabel.js +171 -0
- package/lib/module/ui/components/TextField/Label/InputLabel.js.map +1 -0
- package/lib/module/ui/components/TextField/Label/LabelBackground.js +78 -0
- package/lib/module/ui/components/TextField/Label/LabelBackground.js.map +1 -0
- package/lib/module/ui/components/TextField/TextFieldFlat.js +372 -0
- package/lib/module/ui/components/TextField/TextFieldFlat.js.map +1 -0
- package/lib/module/ui/components/TextField/TextFieldOutlined.js +355 -0
- package/lib/module/ui/components/TextField/TextFieldOutlined.js.map +1 -0
- package/lib/module/ui/components/TextField/constants.js +46 -0
- package/lib/module/ui/components/TextField/constants.js.map +1 -0
- package/lib/module/ui/components/TextField/helpers.js +472 -0
- package/lib/module/ui/components/TextField/helpers.js.map +1 -0
- package/lib/module/ui/components/TextField/types.js +4 -0
- package/lib/module/ui/components/TextField/types.js.map +1 -0
- package/lib/module/ui/components/TextField.js +333 -0
- package/lib/module/ui/components/TextField.js.map +1 -0
- package/lib/module/ui/components/TouchableRipple/Pressable.js +9 -0
- package/lib/module/ui/components/TouchableRipple/Pressable.js.map +1 -0
- package/lib/module/ui/components/TouchableRipple/TouchableRipple.js +253 -0
- package/lib/module/ui/components/TouchableRipple/TouchableRipple.js.map +1 -0
- package/lib/module/ui/components/TouchableRipple/TouchableRipple.native.js +101 -0
- package/lib/module/ui/components/TouchableRipple/TouchableRipple.native.js.map +1 -0
- package/lib/module/ui/components/TouchableRipple/utils.js +50 -0
- package/lib/module/ui/components/TouchableRipple/utils.js.map +1 -0
- package/lib/module/ui/components/Typography/AnimatedText.js +56 -0
- package/lib/module/ui/components/Typography/AnimatedText.js.map +1 -0
- package/lib/module/ui/components/Typography/types.js +22 -0
- package/lib/module/ui/components/Typography/types.js.map +1 -0
- package/lib/module/ui/components/fileManagement/FileDetailsModal.js +165 -0
- package/lib/module/ui/components/fileManagement/FileDetailsModal.js.map +1 -0
- package/lib/module/ui/components/fileManagement/FileViewer.js +402 -0
- package/lib/module/ui/components/fileManagement/FileViewer.js.map +1 -0
- package/lib/module/ui/components/fileManagement/UploadPreview.js +175 -0
- package/lib/module/ui/components/fileManagement/UploadPreview.js.map +1 -0
- package/lib/module/ui/components/fileManagement/styles.js +864 -0
- package/lib/module/ui/components/fileManagement/styles.js.map +1 -0
- package/lib/module/ui/components/index.js +4 -1
- package/lib/module/ui/components/index.js.map +1 -1
- package/lib/module/ui/components/profile/EditBioModal.js +175 -0
- package/lib/module/ui/components/profile/EditBioModal.js.map +1 -0
- package/lib/module/ui/components/profile/EditDisplayNameModal.js +201 -0
- package/lib/module/ui/components/profile/EditDisplayNameModal.js.map +1 -0
- package/lib/module/ui/components/profile/EditEmailModal.js +178 -0
- package/lib/module/ui/components/profile/EditEmailModal.js.map +1 -0
- package/lib/module/ui/components/profile/EditLinksModal.js +309 -0
- package/lib/module/ui/components/profile/EditLinksModal.js.map +1 -0
- package/lib/module/ui/components/profile/EditLocationModal.js +267 -0
- package/lib/module/ui/components/profile/EditLocationModal.js.map +1 -0
- package/lib/module/ui/components/profile/EditUsernameModal.js +174 -0
- package/lib/module/ui/components/profile/EditUsernameModal.js.map +1 -0
- package/lib/module/ui/components/profile/TwoFactorSetupModal.js +460 -0
- package/lib/module/ui/components/profile/TwoFactorSetupModal.js.map +1 -0
- package/lib/module/ui/components/styles/overlay.js +80 -0
- package/lib/module/ui/components/styles/overlay.js.map +1 -0
- package/lib/module/ui/components/styles/shadow.js +128 -0
- package/lib/module/ui/components/styles/shadow.js.map +1 -0
- package/lib/module/ui/components/theming.js +111 -0
- package/lib/module/ui/components/theming.js.map +1 -0
- package/lib/module/ui/components/types.js +2 -0
- package/lib/module/ui/components/types.js.map +1 -0
- package/lib/module/ui/components/utils/forwardRef.js +13 -0
- package/lib/module/ui/components/utils/forwardRef.js.map +1 -0
- package/lib/module/ui/components/utils/hasTouchHandler.js +9 -0
- package/lib/module/ui/components/utils/hasTouchHandler.js.map +1 -0
- package/lib/module/ui/components/utils/roundLayoutSize.js +4 -0
- package/lib/module/ui/components/utils/roundLayoutSize.js.map +1 -0
- package/lib/module/ui/components/utils/splitStyles.js +46 -0
- package/lib/module/ui/components/utils/splitStyles.js.map +1 -0
- package/lib/module/ui/constants/iconColors.js +78 -0
- package/lib/module/ui/constants/iconColors.js.map +1 -0
- package/lib/module/ui/constants/spacing.js +45 -0
- package/lib/module/ui/constants/spacing.js.map +1 -0
- package/lib/module/ui/constants/theme.js +119 -0
- package/lib/module/ui/constants/theme.js.map +1 -0
- package/lib/module/ui/context/OxyContext.js +199 -855
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/ThemeContext.js +29 -0
- package/lib/module/ui/context/ThemeContext.js.map +1 -0
- package/lib/module/ui/context/hooks/useAuthOperations.js +344 -0
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -0
- package/lib/module/ui/context/hooks/useDeviceManagement.js +68 -0
- package/lib/module/ui/context/hooks/useDeviceManagement.js.map +1 -0
- package/lib/module/ui/context/hooks/useLanguageManagement.js +107 -0
- package/lib/module/ui/context/hooks/useLanguageManagement.js.map +1 -0
- package/lib/module/ui/context/hooks/useSessionManagement.js +256 -0
- package/lib/module/ui/context/hooks/useSessionManagement.js.map +1 -0
- package/lib/module/ui/context/hooks/useStorage.js +74 -0
- package/lib/module/ui/context/hooks/useStorage.js.map +1 -0
- package/lib/module/ui/context/utils/errorHandlers.js +83 -0
- package/lib/module/ui/context/utils/errorHandlers.js.map +1 -0
- package/lib/module/ui/context/utils/sessionHelpers.js +96 -0
- package/lib/module/ui/context/utils/sessionHelpers.js.map +1 -0
- package/lib/module/ui/context/utils/storageHelpers.js +111 -0
- package/lib/module/ui/context/utils/storageHelpers.js.map +1 -0
- package/lib/module/ui/hooks/index.js +2 -0
- package/lib/module/ui/hooks/index.js.map +1 -1
- package/lib/module/ui/hooks/use-color-scheme.js +26 -0
- package/lib/module/ui/hooks/use-color-scheme.js.map +1 -0
- package/lib/module/ui/hooks/use-haptic-press.js +17 -0
- package/lib/module/ui/hooks/use-haptic-press.js.map +1 -0
- package/lib/module/ui/hooks/useAssets.js.map +1 -1
- package/lib/module/ui/hooks/useDeviceManagement.js +68 -0
- package/lib/module/ui/hooks/useDeviceManagement.js.map +1 -0
- package/lib/module/ui/hooks/useLanguageManagement.js +107 -0
- package/lib/module/ui/hooks/useLanguageManagement.js.map +1 -0
- package/lib/module/ui/hooks/useProfileEditing.js +118 -0
- package/lib/module/ui/hooks/useProfileEditing.js.map +1 -0
- package/lib/module/ui/hooks/useSessionManagement.js +256 -0
- package/lib/module/ui/hooks/useSessionManagement.js.map +1 -0
- package/lib/module/ui/hooks/useStorage.js +74 -0
- package/lib/module/ui/hooks/useStorage.js.map +1 -0
- package/lib/module/ui/hooks/useThemeColors.js +27 -0
- package/lib/module/ui/hooks/useThemeColors.js.map +1 -0
- package/lib/module/ui/hooks/useThemeStyles.js +64 -0
- package/lib/module/ui/hooks/useThemeStyles.js.map +1 -0
- package/lib/module/ui/index.js +2 -4
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/navigation/bottomSheetManager.js +168 -0
- package/lib/module/ui/navigation/bottomSheetManager.js.map +1 -0
- package/lib/module/ui/navigation/routes.js +77 -152
- package/lib/module/ui/navigation/routes.js.map +1 -1
- package/lib/module/ui/screens/AccountCenterScreen.js +67 -67
- package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountOverviewScreen.js +218 -100
- package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +515 -430
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +45 -60
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountVerificationScreen.js +12 -19
- package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
- package/lib/module/ui/screens/AppInfoScreen.js +36 -43
- package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/module/ui/screens/FeedbackScreen.js +14 -14
- package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +670 -1965
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/HelpSupportScreen.js +26 -23
- package/lib/module/ui/screens/HelpSupportScreen.js.map +1 -1
- package/lib/module/ui/screens/HistoryViewScreen.js +22 -62
- package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js +80 -171
- package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/module/ui/screens/LegalDocumentsScreen.js +16 -43
- package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -1
- package/lib/module/ui/screens/OxyAuthScreen.js +432 -0
- package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -0
- package/lib/module/ui/screens/PaymentGatewayScreen.js +18 -24
- package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/module/ui/screens/PremiumSubscriptionScreen.js +21 -9
- package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
- package/lib/module/ui/screens/PrivacySettingsScreen.js +167 -239
- package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +7 -5
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/SavesCollectionsScreen.js +35 -73
- package/lib/module/ui/screens/SavesCollectionsScreen.js.map +1 -1
- package/lib/module/ui/screens/SearchSettingsScreen.js +29 -102
- package/lib/module/ui/screens/SearchSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/SessionManagementScreen.js +24 -16
- package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/UserLinksScreen.js +8 -10
- package/lib/module/ui/screens/UserLinksScreen.js.map +1 -1
- package/lib/module/ui/screens/WelcomeNewUserScreen.js +65 -68
- package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaAboutScreen.js +11 -8
- package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js +124 -121
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaFAQScreen.js +101 -114
- package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +12 -9
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +554 -81
- package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js +12 -8
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
- package/lib/module/ui/styles/authStyles.js +5 -11
- package/lib/module/ui/styles/authStyles.js.map +1 -1
- package/lib/module/ui/styles/spacing.js +12 -2
- package/lib/module/ui/styles/spacing.js.map +1 -1
- package/lib/module/ui/styles/theme.js +1 -1
- package/lib/module/ui/types/fileManagement.js +4 -0
- package/lib/module/ui/types/fileManagement.js.map +1 -0
- package/lib/module/ui/types/navigation.js +4 -0
- package/lib/module/ui/types/navigation.js.map +1 -0
- package/lib/module/ui/utils/colorUtils.js +46 -0
- package/lib/module/ui/utils/colorUtils.js.map +1 -0
- package/lib/module/ui/utils/errorHandlers.js +83 -0
- package/lib/module/ui/utils/errorHandlers.js.map +1 -0
- package/lib/module/ui/utils/fileManagement.js +172 -0
- package/lib/module/ui/utils/fileManagement.js.map +1 -0
- package/lib/module/ui/utils/sessionHelpers.js +96 -0
- package/lib/module/ui/utils/sessionHelpers.js.map +1 -0
- package/lib/module/ui/utils/storageHelpers.js +111 -0
- package/lib/module/ui/utils/storageHelpers.js.map +1 -0
- package/lib/module/ui/utils/themeUtils.js +41 -0
- package/lib/module/ui/utils/themeUtils.js.map +1 -0
- package/lib/module/ui/utils/user-utils.js +46 -0
- package/lib/module/ui/utils/user-utils.js.map +1 -0
- package/lib/module/utils/errorUtils.js +14 -4
- package/lib/module/utils/errorUtils.js.map +1 -1
- package/lib/typescript/core/HttpService.d.ts +48 -0
- package/lib/typescript/core/HttpService.d.ts.map +1 -1
- package/lib/typescript/core/OxyServices.base.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.analytics.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.assets.d.ts +23 -1
- package/lib/typescript/core/mixins/OxyServices.assets.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.auth.d.ts +70 -42
- package/lib/typescript/core/mixins/OxyServices.auth.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.developer.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.devices.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.karma.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.language.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.location.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.payment.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.privacy.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.totp.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.user.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.utility.d.ts.map +1 -1
- package/lib/typescript/core/mixins/index.d.ts +26 -34
- package/lib/typescript/core/mixins/index.d.ts.map +1 -1
- package/lib/typescript/crypto/index.d.ts +11 -0
- package/lib/typescript/crypto/index.d.ts.map +1 -0
- package/lib/typescript/crypto/keyManager.d.ts +73 -0
- package/lib/typescript/crypto/keyManager.d.ts.map +1 -0
- package/lib/typescript/crypto/recoveryPhrase.d.ts +57 -0
- package/lib/typescript/crypto/recoveryPhrase.d.ts.map +1 -0
- package/lib/typescript/crypto/signatureService.d.ts +81 -0
- package/lib/typescript/crypto/signatureService.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +2 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/models/interfaces.d.ts +1 -0
- package/lib/typescript/models/interfaces.d.ts.map +1 -1
- package/lib/typescript/types/bip39.d.ts +29 -0
- package/lib/typescript/types/color.d.ts +19 -0
- package/lib/typescript/types/elliptic.d.ts +61 -0
- package/lib/typescript/types/expo-crypto.d.ts +29 -0
- package/lib/typescript/types/expo-random.d.ts +9 -0
- package/lib/typescript/types/expo-secure-store.d.ts +21 -0
- package/lib/typescript/types/expo-vector-icons.d.ts +9 -0
- package/lib/typescript/ui/components/ActivityIndicator.d.ts +45 -0
- package/lib/typescript/ui/components/ActivityIndicator.d.ts.map +1 -0
- package/lib/typescript/ui/components/AutoHeightScrollView.d.ts +23 -0
- package/lib/typescript/ui/components/AutoHeightScrollView.d.ts.map +1 -0
- package/lib/typescript/ui/components/BottomSheet.d.ts +29 -0
- package/lib/typescript/ui/components/BottomSheet.d.ts.map +1 -0
- package/lib/typescript/ui/components/BottomSheetRouter.d.ts +14 -0
- package/lib/typescript/ui/components/BottomSheetRouter.d.ts.map +1 -0
- package/lib/typescript/ui/components/CrossFadeIcon.d.ts +27 -0
- package/lib/typescript/ui/components/CrossFadeIcon.d.ts.map +1 -0
- package/lib/typescript/ui/components/EmptyState.d.ts +8 -0
- package/lib/typescript/ui/components/EmptyState.d.ts.map +1 -0
- package/lib/typescript/ui/components/GroupedItem.d.ts +5 -9
- package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
- package/lib/typescript/ui/components/GroupedSection.d.ts +6 -7
- package/lib/typescript/ui/components/GroupedSection.d.ts.map +1 -1
- package/lib/typescript/ui/components/Header.d.ts +6 -1
- package/lib/typescript/ui/components/Header.d.ts.map +1 -1
- package/lib/typescript/ui/components/HelperText.d.ts +47 -0
- package/lib/typescript/ui/components/HelperText.d.ts.map +1 -0
- package/lib/typescript/ui/components/Icon.d.ts +60 -0
- package/lib/typescript/ui/components/Icon.d.ts.map +1 -0
- package/lib/typescript/ui/components/IconButton/IconButton.d.ts +99 -0
- package/lib/typescript/ui/components/IconButton/IconButton.d.ts.map +1 -0
- package/lib/typescript/ui/components/IconButton/utils.d.ts +19 -0
- package/lib/typescript/ui/components/IconButton/utils.d.ts.map +1 -0
- package/lib/typescript/ui/components/LoadingState.d.ts +9 -0
- package/lib/typescript/ui/components/LoadingState.d.ts.map +1 -0
- package/lib/typescript/ui/components/OxyPayButton.d.ts.map +1 -1
- package/lib/typescript/ui/components/OxyProvider.d.ts +4 -5
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/components/OxySignInButton.d.ts +3 -8
- package/lib/typescript/ui/components/OxySignInButton.d.ts.map +1 -1
- package/lib/typescript/ui/components/ProfileCard.d.ts.map +1 -1
- package/lib/typescript/ui/components/QuickActions.d.ts.map +1 -1
- package/lib/typescript/ui/components/Section.d.ts +1 -1
- package/lib/typescript/ui/components/Section.d.ts.map +1 -1
- package/lib/typescript/ui/components/SectionTitle.d.ts +1 -1
- package/lib/typescript/ui/components/SectionTitle.d.ts.map +1 -1
- package/lib/typescript/ui/components/SettingRow.d.ts +14 -0
- package/lib/typescript/ui/components/SettingRow.d.ts.map +1 -0
- package/lib/typescript/ui/components/StepBasedScreen.d.ts +3 -2
- package/lib/typescript/ui/components/StepBasedScreen.d.ts.map +1 -1
- package/lib/typescript/ui/components/Surface.d.ts +76 -0
- package/lib/typescript/ui/components/Surface.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/Addons/Outline.d.ts +16 -0
- package/lib/typescript/ui/components/TextField/Addons/Outline.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/Addons/Underline.d.ts +19 -0
- package/lib/typescript/ui/components/TextField/Addons/Underline.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/Adornment/TextFieldAdornment.d.ts +45 -0
- package/lib/typescript/ui/components/TextField/Adornment/TextFieldAdornment.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/Adornment/TextFieldAffix.d.ts +73 -0
- package/lib/typescript/ui/components/TextField/Adornment/TextFieldAffix.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/Adornment/TextFieldIcon.d.ts +78 -0
- package/lib/typescript/ui/components/TextField/Adornment/TextFieldIcon.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/Adornment/enums.d.ts +13 -0
- package/lib/typescript/ui/components/TextField/Adornment/enums.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/Adornment/types.d.ts +12 -0
- package/lib/typescript/ui/components/TextField/Adornment/types.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/Adornment/utils.d.ts +12 -0
- package/lib/typescript/ui/components/TextField/Adornment/utils.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/Label/InputLabel.d.ts +5 -0
- package/lib/typescript/ui/components/TextField/Label/InputLabel.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/Label/LabelBackground.d.ts +4 -0
- package/lib/typescript/ui/components/TextField/Label/LabelBackground.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/TextFieldFlat.d.ts +4 -0
- package/lib/typescript/ui/components/TextField/TextFieldFlat.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/TextFieldOutlined.d.ts +4 -0
- package/lib/typescript/ui/components/TextField/TextFieldOutlined.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/constants.d.ts +32 -0
- package/lib/typescript/ui/components/TextField/constants.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/helpers.d.ts +97 -0
- package/lib/typescript/ui/components/TextField/helpers.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField/types.d.ts +156 -0
- package/lib/typescript/ui/components/TextField/types.d.ts.map +1 -0
- package/lib/typescript/ui/components/TextField.d.ts +192 -0
- package/lib/typescript/ui/components/TextField.d.ts.map +1 -0
- package/lib/typescript/ui/components/TouchableRipple/Pressable.d.ts +13 -0
- package/lib/typescript/ui/components/TouchableRipple/Pressable.d.ts.map +1 -0
- package/lib/typescript/ui/components/TouchableRipple/TouchableRipple.d.ts +62 -0
- package/lib/typescript/ui/components/TouchableRipple/TouchableRipple.d.ts.map +1 -0
- package/lib/typescript/ui/components/TouchableRipple/TouchableRipple.native.d.ts +25 -0
- package/lib/typescript/ui/components/TouchableRipple/TouchableRipple.native.d.ts.map +1 -0
- package/lib/typescript/ui/components/TouchableRipple/utils.d.ts +11 -0
- package/lib/typescript/ui/components/TouchableRipple/utils.d.ts.map +1 -0
- package/lib/typescript/ui/components/Typography/AnimatedText.d.ts +35 -0
- package/lib/typescript/ui/components/Typography/AnimatedText.d.ts.map +1 -0
- package/lib/typescript/ui/components/Typography/types.d.ts +19 -0
- package/lib/typescript/ui/components/Typography/types.d.ts.map +1 -0
- package/lib/typescript/ui/components/fileManagement/FileDetailsModal.d.ts +15 -0
- package/lib/typescript/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -0
- package/lib/typescript/ui/components/fileManagement/FileViewer.d.ts +18 -0
- package/lib/typescript/ui/components/fileManagement/FileViewer.d.ts.map +1 -0
- package/lib/typescript/ui/components/fileManagement/UploadPreview.d.ts +21 -0
- package/lib/typescript/ui/components/fileManagement/UploadPreview.d.ts.map +1 -0
- package/lib/typescript/ui/components/fileManagement/styles.d.ts +860 -0
- package/lib/typescript/ui/components/fileManagement/styles.d.ts.map +1 -0
- package/lib/typescript/ui/components/index.d.ts +4 -1
- package/lib/typescript/ui/components/index.d.ts.map +1 -1
- package/lib/typescript/ui/components/profile/EditBioModal.d.ts +11 -0
- package/lib/typescript/ui/components/profile/EditBioModal.d.ts.map +1 -0
- package/lib/typescript/ui/components/profile/EditDisplayNameModal.d.ts +12 -0
- package/lib/typescript/ui/components/profile/EditDisplayNameModal.d.ts.map +1 -0
- package/lib/typescript/ui/components/profile/EditEmailModal.d.ts +11 -0
- package/lib/typescript/ui/components/profile/EditEmailModal.d.ts.map +1 -0
- package/lib/typescript/ui/components/profile/EditLinksModal.d.ts +18 -0
- package/lib/typescript/ui/components/profile/EditLinksModal.d.ts.map +1 -0
- package/lib/typescript/ui/components/profile/EditLocationModal.d.ts +20 -0
- package/lib/typescript/ui/components/profile/EditLocationModal.d.ts.map +1 -0
- package/lib/typescript/ui/components/profile/EditUsernameModal.d.ts +11 -0
- package/lib/typescript/ui/components/profile/EditUsernameModal.d.ts.map +1 -0
- package/lib/typescript/ui/components/profile/TwoFactorSetupModal.d.ts +11 -0
- package/lib/typescript/ui/components/profile/TwoFactorSetupModal.d.ts.map +1 -0
- package/lib/typescript/ui/components/styles/overlay.d.ts +4 -0
- package/lib/typescript/ui/components/styles/overlay.d.ts.map +1 -0
- package/lib/typescript/ui/components/styles/shadow.d.ts +3 -0
- package/lib/typescript/ui/components/styles/shadow.d.ts.map +1 -0
- package/lib/typescript/ui/components/theming.d.ts +8 -0
- package/lib/typescript/ui/components/theming.d.ts.map +1 -0
- package/lib/typescript/ui/components/types.d.ts +80 -0
- package/lib/typescript/ui/components/types.d.ts.map +1 -0
- package/lib/typescript/ui/components/utils/forwardRef.d.ts +12 -0
- package/lib/typescript/ui/components/utils/forwardRef.d.ts.map +1 -0
- package/lib/typescript/ui/components/utils/hasTouchHandler.d.ts +6 -0
- package/lib/typescript/ui/components/utils/hasTouchHandler.d.ts.map +1 -0
- package/lib/typescript/ui/components/utils/roundLayoutSize.d.ts +2 -0
- package/lib/typescript/ui/components/utils/roundLayoutSize.d.ts.map +1 -0
- package/lib/typescript/ui/components/utils/splitStyles.d.ts +20 -0
- package/lib/typescript/ui/components/utils/splitStyles.d.ts.map +1 -0
- package/lib/typescript/ui/constants/iconColors.d.ts +130 -0
- package/lib/typescript/ui/constants/iconColors.d.ts.map +1 -0
- package/lib/typescript/ui/constants/spacing.d.ts +33 -0
- package/lib/typescript/ui/constants/spacing.d.ts.map +1 -0
- package/lib/typescript/ui/constants/theme.d.ts +97 -0
- package/lib/typescript/ui/constants/theme.d.ts.map +1 -0
- package/lib/typescript/ui/context/OxyContext.d.ts +23 -17
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/context/ThemeContext.d.ts +19 -0
- package/lib/typescript/ui/context/ThemeContext.d.ts.map +1 -0
- package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts +51 -0
- package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +1 -0
- package/lib/typescript/ui/context/hooks/useDeviceManagement.d.ts +27 -0
- package/lib/typescript/ui/context/hooks/useDeviceManagement.d.ts.map +1 -0
- package/lib/typescript/ui/context/hooks/useLanguageManagement.d.ts +25 -0
- package/lib/typescript/ui/context/hooks/useLanguageManagement.d.ts.map +1 -0
- package/lib/typescript/ui/context/hooks/useSessionManagement.d.ts +39 -0
- package/lib/typescript/ui/context/hooks/useSessionManagement.d.ts.map +1 -0
- package/lib/typescript/ui/context/hooks/useStorage.d.ts +22 -0
- package/lib/typescript/ui/context/hooks/useStorage.d.ts.map +1 -0
- package/lib/typescript/ui/context/utils/errorHandlers.d.ts +30 -0
- package/lib/typescript/ui/context/utils/errorHandlers.d.ts.map +1 -0
- package/lib/typescript/ui/context/utils/sessionHelpers.d.ts +59 -0
- package/lib/typescript/ui/context/utils/sessionHelpers.d.ts.map +1 -0
- package/lib/typescript/ui/context/utils/storageHelpers.d.ts +31 -0
- package/lib/typescript/ui/context/utils/storageHelpers.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/index.d.ts +2 -0
- package/lib/typescript/ui/hooks/index.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/use-color-scheme.d.ts +8 -0
- package/lib/typescript/ui/hooks/use-color-scheme.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/use-haptic-press.d.ts +8 -0
- package/lib/typescript/ui/hooks/use-haptic-press.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/useDeviceManagement.d.ts +27 -0
- package/lib/typescript/ui/hooks/useDeviceManagement.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/useLanguageManagement.d.ts +25 -0
- package/lib/typescript/ui/hooks/useLanguageManagement.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/useProfileEditing.d.ts +36 -0
- package/lib/typescript/ui/hooks/useProfileEditing.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/useSessionManagement.d.ts +39 -0
- package/lib/typescript/ui/hooks/useSessionManagement.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/useStorage.d.ts +22 -0
- package/lib/typescript/ui/hooks/useStorage.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/useThemeColors.d.ts +94 -0
- package/lib/typescript/ui/hooks/useThemeColors.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/useThemeStyles.d.ts +45 -0
- package/lib/typescript/ui/hooks/useThemeStyles.d.ts.map +1 -0
- package/lib/typescript/ui/index.d.ts +2 -2
- package/lib/typescript/ui/index.d.ts.map +1 -1
- package/lib/typescript/ui/navigation/bottomSheetManager.d.ts +74 -0
- package/lib/typescript/ui/navigation/bottomSheetManager.d.ts.map +1 -0
- package/lib/typescript/ui/navigation/routes.d.ts +4 -7
- package/lib/typescript/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountCenterScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountVerificationScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/AccountVerificationScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AppInfoScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/AppInfoScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/FeedbackScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/FeedbackScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/FileManagementScreen.d.ts +1 -36
- package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/HelpSupportScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/HelpSupportScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/HistoryViewScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/HistoryViewScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/LegalDocumentsScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/LegalDocumentsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/OxyAuthScreen.d.ts +16 -0
- package/lib/typescript/ui/screens/OxyAuthScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/PaymentGatewayScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/PremiumSubscriptionScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/PrivacySettingsScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/ProfileScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SavesCollectionsScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SearchSettingsScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/SearchSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SessionManagementScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/UserLinksScreen.d.ts +2 -2
- package/lib/typescript/ui/screens/UserLinksScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts +1 -1
- package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts.map +1 -1
- package/lib/typescript/ui/stores/authStore.d.ts +1 -2
- package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
- package/lib/typescript/ui/styles/authStyles.d.ts +0 -10
- package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -1
- package/lib/typescript/ui/styles/spacing.d.ts +7 -1
- package/lib/typescript/ui/styles/spacing.d.ts.map +1 -1
- package/lib/typescript/ui/types/fileManagement.d.ts +41 -0
- package/lib/typescript/ui/types/fileManagement.d.ts.map +1 -0
- package/lib/typescript/ui/types/navigation.d.ts +36 -0
- package/lib/typescript/ui/types/navigation.d.ts.map +1 -0
- package/lib/typescript/ui/utils/colorUtils.d.ts +14 -0
- package/lib/typescript/ui/utils/colorUtils.d.ts.map +1 -0
- package/lib/typescript/ui/utils/errorHandlers.d.ts +30 -0
- package/lib/typescript/ui/utils/errorHandlers.d.ts.map +1 -0
- package/lib/typescript/ui/utils/fileManagement.d.ts +39 -0
- package/lib/typescript/ui/utils/fileManagement.d.ts.map +1 -0
- package/lib/typescript/ui/utils/sessionHelpers.d.ts +59 -0
- package/lib/typescript/ui/utils/sessionHelpers.d.ts.map +1 -0
- package/lib/typescript/ui/utils/storageHelpers.d.ts +31 -0
- package/lib/typescript/ui/utils/storageHelpers.d.ts.map +1 -0
- package/lib/typescript/ui/utils/themeUtils.d.ts +24 -0
- package/lib/typescript/ui/utils/themeUtils.d.ts.map +1 -0
- package/lib/typescript/ui/utils/user-utils.d.ts +29 -0
- package/lib/typescript/ui/utils/user-utils.d.ts.map +1 -0
- package/lib/typescript/utils/errorUtils.d.ts.map +1 -1
- package/package.json +26 -15
- package/src/assets/lottie/welcomeheader_background_op1.json +1 -0
- package/src/core/HttpService.ts +97 -4
- package/src/core/OxyServices.base.ts +3 -1
- package/src/core/mixins/OxyServices.assets.ts +225 -27
- package/src/core/mixins/OxyServices.auth.ts +144 -80
- package/src/crypto/index.ts +21 -0
- package/src/crypto/keyManager.ts +214 -0
- package/src/crypto/recoveryPhrase.ts +147 -0
- package/src/crypto/signatureService.ts +280 -0
- package/src/i18n/locales/en-US.json +4 -0
- package/src/index.ts +13 -0
- package/src/models/interfaces.ts +1 -0
- package/src/types/bip39.d.ts +29 -0
- package/src/types/color.d.ts +19 -0
- package/src/types/elliptic.d.ts +61 -0
- package/src/types/expo-crypto.d.ts +29 -0
- package/src/types/expo-random.d.ts +9 -0
- package/src/types/expo-secure-store.d.ts +21 -0
- package/src/types/expo-vector-icons.d.ts +9 -0
- package/src/ui/components/ActivityIndicator.tsx +254 -0
- package/src/ui/components/AutoHeightScrollView.tsx +50 -0
- package/src/ui/components/BottomSheet.tsx +443 -0
- package/src/ui/components/BottomSheetRouter.tsx +407 -0
- package/src/ui/components/CrossFadeIcon.tsx +140 -0
- package/src/ui/components/EmptyState.tsx +39 -0
- package/src/ui/components/GroupedItem.tsx +98 -96
- package/src/ui/components/GroupedSection.tsx +24 -29
- package/src/ui/components/Header.tsx +129 -49
- package/src/ui/components/HelperText.tsx +160 -0
- package/src/ui/components/Icon.tsx +181 -0
- package/src/ui/components/IconButton/IconButton.tsx +235 -0
- package/src/ui/components/IconButton/utils.ts +190 -0
- package/src/ui/components/LoadingState.tsx +46 -0
- package/src/ui/components/OxyPayButton.tsx +1 -12
- package/src/ui/components/OxyProvider.tsx +49 -409
- package/src/ui/components/OxySignInButton.tsx +11 -18
- package/src/ui/components/ProfileCard.tsx +7 -4
- package/src/ui/components/QuickActions.tsx +7 -4
- package/src/ui/components/Section.tsx +6 -2
- package/src/ui/components/SectionTitle.tsx +7 -4
- package/src/ui/components/SettingRow.tsx +76 -0
- package/src/ui/components/StepBasedScreen.tsx +205 -187
- package/src/ui/components/Surface.tsx +384 -0
- package/src/ui/components/TextField/Addons/Outline.tsx +64 -0
- package/src/ui/components/TextField/Addons/Underline.tsx +78 -0
- package/src/ui/components/TextField/Adornment/TextFieldAdornment.tsx +208 -0
- package/src/ui/components/TextField/Adornment/TextFieldAffix.tsx +212 -0
- package/src/ui/components/TextField/Adornment/TextFieldIcon.tsx +195 -0
- package/src/ui/components/TextField/Adornment/enums.tsx +12 -0
- package/src/ui/components/TextField/Adornment/types.tsx +11 -0
- package/src/ui/components/TextField/Adornment/utils.ts +66 -0
- package/src/ui/components/TextField/Label/InputLabel.tsx +219 -0
- package/src/ui/components/TextField/Label/LabelBackground.tsx +100 -0
- package/src/ui/components/TextField/TextFieldFlat.tsx +488 -0
- package/src/ui/components/TextField/TextFieldOutlined.tsx +464 -0
- package/src/ui/components/TextField/constants.tsx +48 -0
- package/src/ui/components/TextField/helpers.tsx +612 -0
- package/src/ui/components/TextField/types.tsx +156 -0
- package/src/ui/components/TextField.tsx +578 -0
- package/src/ui/components/TouchableRipple/Pressable.tsx +41 -0
- package/src/ui/components/TouchableRipple/TouchableRipple.native.tsx +146 -0
- package/src/ui/components/TouchableRipple/TouchableRipple.tsx +347 -0
- package/src/ui/components/TouchableRipple/utils.ts +66 -0
- package/src/ui/components/Typography/AnimatedText.tsx +107 -0
- package/src/ui/components/Typography/types.tsx +22 -0
- package/src/ui/components/fileManagement/FileDetailsModal.tsx +137 -0
- package/src/ui/components/fileManagement/FileViewer.tsx +380 -0
- package/src/ui/components/fileManagement/UploadPreview.tsx +175 -0
- package/src/ui/components/fileManagement/styles.ts +860 -0
- package/src/ui/components/index.ts +4 -1
- package/src/ui/components/profile/EditBioModal.tsx +184 -0
- package/src/ui/components/profile/EditDisplayNameModal.tsx +205 -0
- package/src/ui/components/profile/EditEmailModal.tsx +188 -0
- package/src/ui/components/profile/EditLinksModal.tsx +316 -0
- package/src/ui/components/profile/EditLocationModal.tsx +278 -0
- package/src/ui/components/profile/EditUsernameModal.tsx +183 -0
- package/src/ui/components/profile/TwoFactorSetupModal.tsx +442 -0
- package/src/ui/components/styles/overlay.tsx +88 -0
- package/src/ui/components/styles/shadow.tsx +136 -0
- package/src/ui/components/theming.tsx +114 -0
- package/src/ui/components/types.tsx +90 -0
- package/src/ui/components/utils/forwardRef.tsx +23 -0
- package/src/ui/components/utils/hasTouchHandler.tsx +23 -0
- package/src/ui/components/utils/roundLayoutSize.ts +2 -0
- package/src/ui/components/utils/splitStyles.ts +60 -0
- package/src/ui/constants/iconColors.ts +88 -0
- package/src/ui/constants/spacing.ts +45 -0
- package/src/ui/constants/theme.ts +120 -0
- package/src/ui/context/OxyContext.tsx +276 -894
- package/src/ui/context/ThemeContext.tsx +41 -0
- package/src/ui/context/hooks/useAuthOperations.ts +400 -0
- package/src/ui/context/hooks/useDeviceManagement.ts +108 -0
- package/src/ui/context/hooks/useLanguageManagement.ts +152 -0
- package/src/ui/context/hooks/useSessionManagement.ts +378 -0
- package/src/ui/context/hooks/useStorage.ts +104 -0
- package/src/ui/context/utils/errorHandlers.ts +136 -0
- package/src/ui/context/utils/sessionHelpers.ts +146 -0
- package/src/ui/context/utils/storageHelpers.ts +134 -0
- package/src/ui/hooks/index.ts +3 -1
- package/src/ui/hooks/use-color-scheme.ts +24 -0
- package/src/ui/hooks/use-haptic-press.ts +15 -0
- package/src/ui/hooks/useAssets.ts +1 -1
- package/src/ui/hooks/useDeviceManagement.ts +108 -0
- package/src/ui/hooks/useLanguageManagement.ts +152 -0
- package/src/ui/hooks/useProfileEditing.ts +151 -0
- package/src/ui/hooks/useSessionManagement.ts +378 -0
- package/src/ui/hooks/useStorage.ts +104 -0
- package/src/ui/hooks/useThemeColors.ts +26 -0
- package/src/ui/hooks/useThemeStyles.ts +85 -0
- package/src/ui/index.ts +1 -4
- package/src/ui/navigation/bottomSheetManager.ts +191 -0
- package/src/ui/navigation/routes.ts +107 -189
- package/src/ui/screens/AccountCenterScreen.tsx +67 -63
- package/src/ui/screens/AccountOverviewScreen.tsx +237 -95
- package/src/ui/screens/AccountSettingsScreen.tsx +546 -474
- package/src/ui/screens/AccountSwitcherScreen.tsx +113 -116
- package/src/ui/screens/AccountVerificationScreen.tsx +18 -20
- package/src/ui/screens/AppInfoScreen.tsx +37 -38
- package/src/ui/screens/FeedbackScreen.tsx +15 -12
- package/src/ui/screens/FileManagementScreen.tsx +764 -2026
- package/src/ui/screens/HelpSupportScreen.tsx +30 -23
- package/src/ui/screens/HistoryViewScreen.tsx +25 -56
- package/src/ui/screens/LanguageSelectorScreen.tsx +84 -170
- package/src/ui/screens/LegalDocumentsScreen.tsx +18 -41
- package/src/ui/screens/OxyAuthScreen.tsx +403 -0
- package/src/ui/screens/PaymentGatewayScreen.tsx +20 -22
- package/src/ui/screens/PremiumSubscriptionScreen.tsx +13 -10
- package/src/ui/screens/PrivacySettingsScreen.tsx +150 -198
- package/src/ui/screens/ProfileScreen.tsx +7 -6
- package/src/ui/screens/SavesCollectionsScreen.tsx +39 -62
- package/src/ui/screens/SearchSettingsScreen.tsx +36 -86
- package/src/ui/screens/SessionManagementScreen.tsx +25 -17
- package/src/ui/screens/UserLinksScreen.tsx +10 -11
- package/src/ui/screens/WelcomeNewUserScreen.tsx +41 -41
- package/src/ui/screens/karma/KarmaAboutScreen.tsx +13 -9
- package/src/ui/screens/karma/KarmaCenterScreen.tsx +70 -70
- package/src/ui/screens/karma/KarmaFAQScreen.tsx +96 -96
- package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +15 -10
- package/src/ui/screens/karma/KarmaRewardsScreen.tsx +605 -60
- package/src/ui/screens/karma/KarmaRulesScreen.tsx +14 -9
- package/src/ui/stores/authStore.ts +1 -1
- package/src/ui/styles/authStyles.ts +5 -11
- package/src/ui/styles/spacing.ts +21 -2
- package/src/ui/styles/theme.ts +1 -1
- package/src/ui/types/fileManagement.ts +51 -0
- package/src/ui/types/navigation.ts +61 -0
- package/src/ui/utils/colorUtils.ts +46 -0
- package/src/ui/utils/errorHandlers.ts +136 -0
- package/src/ui/utils/fileManagement.ts +190 -0
- package/src/ui/utils/sessionHelpers.ts +146 -0
- package/src/ui/utils/storageHelpers.ts +134 -0
- package/src/ui/utils/themeUtils.ts +43 -0
- package/src/ui/utils/user-utils.ts +58 -0
- package/src/utils/errorUtils.ts +14 -4
- package/lib/commonjs/ui/components/internal/TextField.js +0 -665
- package/lib/commonjs/ui/components/internal/TextField.js.map +0 -1
- package/lib/commonjs/ui/navigation/OxyRouter.js +0 -213
- package/lib/commonjs/ui/navigation/OxyRouter.js.map +0 -1
- package/lib/commonjs/ui/navigation/types.js +0 -13
- package/lib/commonjs/ui/navigation/types.js.map +0 -1
- package/lib/commonjs/ui/screens/AccountManagementDemo.js +0 -298
- package/lib/commonjs/ui/screens/AccountManagementDemo.js.map +0 -1
- package/lib/commonjs/ui/screens/RecoverAccountScreen.js +0 -137
- package/lib/commonjs/ui/screens/RecoverAccountScreen.js.map +0 -1
- package/lib/commonjs/ui/screens/SignInScreen.js +0 -270
- package/lib/commonjs/ui/screens/SignInScreen.js.map +0 -1
- package/lib/commonjs/ui/screens/SignUpScreen.js +0 -229
- package/lib/commonjs/ui/screens/SignUpScreen.js.map +0 -1
- package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js +0 -135
- package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js.map +0 -1
- package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js +0 -165
- package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js.map +0 -1
- package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js +0 -159
- package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js.map +0 -1
- package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js +0 -144
- package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js.map +0 -1
- package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js +0 -358
- package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js.map +0 -1
- package/lib/commonjs/ui/screens/steps/SignInTotpStep.js +0 -188
- package/lib/commonjs/ui/screens/steps/SignInTotpStep.js.map +0 -1
- package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js +0 -509
- package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js.map +0 -1
- package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js +0 -200
- package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js.map +0 -1
- package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js +0 -185
- package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js.map +0 -1
- package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js +0 -138
- package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js.map +0 -1
- package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js +0 -150
- package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js.map +0 -1
- package/lib/module/package.json +0 -1
- package/lib/module/ui/components/internal/TextField.js +0 -660
- package/lib/module/ui/components/internal/TextField.js.map +0 -1
- package/lib/module/ui/navigation/OxyRouter.js +0 -209
- package/lib/module/ui/navigation/OxyRouter.js.map +0 -1
- package/lib/module/ui/navigation/types.js +0 -22
- package/lib/module/ui/navigation/types.js.map +0 -1
- package/lib/module/ui/screens/AccountManagementDemo.js +0 -295
- package/lib/module/ui/screens/AccountManagementDemo.js.map +0 -1
- package/lib/module/ui/screens/RecoverAccountScreen.js +0 -133
- package/lib/module/ui/screens/RecoverAccountScreen.js.map +0 -1
- package/lib/module/ui/screens/SignInScreen.js +0 -265
- package/lib/module/ui/screens/SignInScreen.js.map +0 -1
- package/lib/module/ui/screens/SignUpScreen.js +0 -224
- package/lib/module/ui/screens/SignUpScreen.js.map +0 -1
- package/lib/module/ui/screens/steps/RecoverRequestStep.js +0 -130
- package/lib/module/ui/screens/steps/RecoverRequestStep.js.map +0 -1
- package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js +0 -160
- package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js.map +0 -1
- package/lib/module/ui/screens/steps/RecoverSuccessStep.js +0 -154
- package/lib/module/ui/screens/steps/RecoverSuccessStep.js.map +0 -1
- package/lib/module/ui/screens/steps/RecoverVerifyStep.js +0 -139
- package/lib/module/ui/screens/steps/RecoverVerifyStep.js.map +0 -1
- package/lib/module/ui/screens/steps/SignInPasswordStep.js +0 -353
- package/lib/module/ui/screens/steps/SignInPasswordStep.js.map +0 -1
- package/lib/module/ui/screens/steps/SignInTotpStep.js +0 -183
- package/lib/module/ui/screens/steps/SignInTotpStep.js.map +0 -1
- package/lib/module/ui/screens/steps/SignInUsernameStep.js +0 -504
- package/lib/module/ui/screens/steps/SignInUsernameStep.js.map +0 -1
- package/lib/module/ui/screens/steps/SignUpIdentityStep.js +0 -195
- package/lib/module/ui/screens/steps/SignUpIdentityStep.js.map +0 -1
- package/lib/module/ui/screens/steps/SignUpSecurityStep.js +0 -180
- package/lib/module/ui/screens/steps/SignUpSecurityStep.js.map +0 -1
- package/lib/module/ui/screens/steps/SignUpSummaryStep.js +0 -133
- package/lib/module/ui/screens/steps/SignUpSummaryStep.js.map +0 -1
- package/lib/module/ui/screens/steps/SignUpWelcomeStep.js +0 -145
- package/lib/module/ui/screens/steps/SignUpWelcomeStep.js.map +0 -1
- package/lib/typescript/ui/components/internal/TextField.d.ts +0 -41
- package/lib/typescript/ui/components/internal/TextField.d.ts.map +0 -1
- package/lib/typescript/ui/navigation/OxyRouter.d.ts +0 -7
- package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +0 -1
- package/lib/typescript/ui/navigation/types.d.ts +0 -141
- package/lib/typescript/ui/navigation/types.d.ts.map +0 -1
- package/lib/typescript/ui/screens/AccountManagementDemo.d.ts +0 -8
- package/lib/typescript/ui/screens/AccountManagementDemo.d.ts.map +0 -1
- package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts +0 -5
- package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts.map +0 -1
- package/lib/typescript/ui/screens/SignInScreen.d.ts +0 -5
- package/lib/typescript/ui/screens/SignInScreen.d.ts.map +0 -1
- package/lib/typescript/ui/screens/SignUpScreen.d.ts +0 -5
- package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +0 -1
- package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts +0 -24
- package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts.map +0 -1
- package/lib/typescript/ui/screens/steps/RecoverResetPasswordStep.d.ts +0 -24
- package/lib/typescript/ui/screens/steps/RecoverResetPasswordStep.d.ts.map +0 -1
- package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts +0 -19
- package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts.map +0 -1
- package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts +0 -26
- package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts.map +0 -1
- package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts +0 -30
- package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts.map +0 -1
- package/lib/typescript/ui/screens/steps/SignInTotpStep.d.ts +0 -19
- package/lib/typescript/ui/screens/steps/SignInTotpStep.d.ts.map +0 -1
- package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts +0 -28
- package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts.map +0 -1
- package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts +0 -26
- package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts.map +0 -1
- package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts +0 -27
- package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts.map +0 -1
- package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts +0 -17
- package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts.map +0 -1
- package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts +0 -14
- package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts.map +0 -1
- package/src/ui/components/internal/TextField.tsx +0 -808
- package/src/ui/navigation/OxyRouter.tsx +0 -216
- package/src/ui/navigation/types.ts +0 -164
- package/src/ui/screens/AccountManagementDemo.tsx +0 -297
- package/src/ui/screens/RecoverAccountScreen.tsx +0 -141
- package/src/ui/screens/SignInScreen.tsx +0 -297
- package/src/ui/screens/SignUpScreen.tsx +0 -239
- package/src/ui/screens/steps/RecoverRequestStep.tsx +0 -143
- package/src/ui/screens/steps/RecoverResetPasswordStep.tsx +0 -162
- package/src/ui/screens/steps/RecoverSuccessStep.tsx +0 -148
- package/src/ui/screens/steps/RecoverVerifyStep.tsx +0 -154
- package/src/ui/screens/steps/SignInPasswordStep.tsx +0 -343
- package/src/ui/screens/steps/SignInTotpStep.tsx +0 -163
- package/src/ui/screens/steps/SignInUsernameStep.tsx +0 -560
- package/src/ui/screens/steps/SignUpIdentityStep.tsx +0 -217
- package/src/ui/screens/steps/SignUpSecurityStep.tsx +0 -207
- package/src/ui/screens/steps/SignUpSummaryStep.tsx +0 -155
- package/src/ui/screens/steps/SignUpWelcomeStep.tsx +0 -127
|
@@ -6,74 +6,93 @@ import {
|
|
|
6
6
|
StyleSheet,
|
|
7
7
|
ScrollView,
|
|
8
8
|
ActivityIndicator,
|
|
9
|
-
Platform,
|
|
10
9
|
RefreshControl,
|
|
11
|
-
Dimensions,
|
|
12
|
-
Modal,
|
|
13
10
|
TextInput,
|
|
14
|
-
Image,
|
|
11
|
+
Image,
|
|
15
12
|
Animated,
|
|
16
13
|
Easing,
|
|
17
14
|
Alert,
|
|
18
15
|
} from 'react-native';
|
|
19
16
|
import { Image as ExpoImage } from 'expo-image';
|
|
20
|
-
import type {
|
|
21
|
-
import { useOxy } from '../context/OxyContext';
|
|
22
|
-
import { fontFamilies } from '../styles/fonts';
|
|
17
|
+
import type { FileManagementScreenProps } from '../types/fileManagement';
|
|
23
18
|
import { toast } from '../../lib/sonner';
|
|
24
19
|
import { Ionicons } from '@expo/vector-icons';
|
|
20
|
+
// @ts-ignore - MaterialCommunityIcons is available at runtime
|
|
21
|
+
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
|
25
22
|
import type { FileMetadata } from '../../models/interfaces';
|
|
26
23
|
import { useFileStore, useFiles, useUploading as useUploadingStore, useUploadAggregateProgress, useDeleting as useDeletingStore } from '../stores/fileStore';
|
|
27
24
|
import Header from '../components/Header';
|
|
28
25
|
import JustifiedPhotoGrid from '../components/photogrid/JustifiedPhotoGrid';
|
|
29
26
|
import { GroupedSection } from '../components';
|
|
27
|
+
import { useThemeStyles } from '../hooks/useThemeStyles';
|
|
28
|
+
import { useColorScheme } from '../hooks/use-color-scheme';
|
|
29
|
+
import { normalizeTheme } from '../utils/themeUtils';
|
|
30
|
+
import { useOxy } from '../context/OxyContext';
|
|
31
|
+
import {
|
|
32
|
+
confirmAction,
|
|
33
|
+
convertDocumentPickerAssetToFile,
|
|
34
|
+
formatFileSize,
|
|
35
|
+
getFileIcon,
|
|
36
|
+
getSafeDownloadUrl,
|
|
37
|
+
uploadFileRaw
|
|
38
|
+
} from '../utils/fileManagement';
|
|
39
|
+
import { FileViewer } from '../components/fileManagement/FileViewer';
|
|
40
|
+
import { FileDetailsModal } from '../components/fileManagement/FileDetailsModal';
|
|
41
|
+
import { UploadPreview } from '../components/fileManagement/UploadPreview';
|
|
42
|
+
import { fileManagementStyles } from '../components/fileManagement/styles';
|
|
43
|
+
import type { OnConfirmFileSelection } from '../types/fileManagement';
|
|
44
|
+
|
|
45
|
+
// Animated button component for smooth transitions
|
|
46
|
+
const AnimatedButton: React.FC<{
|
|
47
|
+
isSelected: boolean;
|
|
48
|
+
onPress: () => void;
|
|
49
|
+
icon: string;
|
|
50
|
+
primaryColor: string;
|
|
51
|
+
textColor: string;
|
|
52
|
+
style: any;
|
|
53
|
+
}> = ({ isSelected, onPress, icon, primaryColor, textColor, style }) => {
|
|
54
|
+
const animatedValue = useRef(new Animated.Value(isSelected ? 1 : 0)).current;
|
|
30
55
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// Initial selected file IDs for multi-select
|
|
45
|
-
initialSelectedIds?: string[];
|
|
46
|
-
maxSelection?: number;
|
|
47
|
-
disabledMimeTypes?: string[];
|
|
48
|
-
/**
|
|
49
|
-
* What to do after a single selection (non-multiSelect) is made.
|
|
50
|
-
* 'close' (default) will dismiss the bottom sheet via onClose.
|
|
51
|
-
* 'back' will navigate back to the previous screen (e.g., return to AccountSettings without closing sheet).
|
|
52
|
-
* 'none' will keep the picker open (caller can manually close or navigate).
|
|
53
|
-
*/
|
|
54
|
-
afterSelect?: 'close' | 'back' | 'none';
|
|
55
|
-
allowUploadInSelectMode?: boolean;
|
|
56
|
-
/**
|
|
57
|
-
* Default visibility for uploaded files in this screen
|
|
58
|
-
* Useful for third-party apps that want files to be public (e.g., GIF selector)
|
|
59
|
-
*/
|
|
60
|
-
defaultVisibility?: 'private' | 'public' | 'unlisted';
|
|
61
|
-
/**
|
|
62
|
-
* Link context for tracking file usage by third-party apps
|
|
63
|
-
* When provided, selected files will be linked to this entity
|
|
64
|
-
*/
|
|
65
|
-
linkContext?: {
|
|
66
|
-
app: string; // App identifier (e.g., 'chat-app', 'post-composer')
|
|
67
|
-
entityType: string; // Type of entity (e.g., 'message', 'post', 'profile')
|
|
68
|
-
entityId: string; // Unique ID of the entity using this file
|
|
69
|
-
webhookUrl?: string; // Optional webhook URL to receive file events
|
|
70
|
-
};
|
|
71
|
-
}
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
Animated.timing(animatedValue, {
|
|
58
|
+
toValue: isSelected ? 1 : 0,
|
|
59
|
+
duration: 200,
|
|
60
|
+
easing: Easing.out(Easing.ease),
|
|
61
|
+
useNativeDriver: false,
|
|
62
|
+
}).start();
|
|
63
|
+
}, [isSelected, animatedValue]);
|
|
64
|
+
|
|
65
|
+
const backgroundColor = animatedValue.interpolate({
|
|
66
|
+
inputRange: [0, 1],
|
|
67
|
+
outputRange: ['transparent', primaryColor],
|
|
68
|
+
});
|
|
72
69
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
70
|
+
const iconColor = animatedValue.interpolate({
|
|
71
|
+
inputRange: [0, 1],
|
|
72
|
+
outputRange: [textColor, '#FFFFFF'],
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<TouchableOpacity onPress={onPress} activeOpacity={0.7}>
|
|
77
|
+
<Animated.View
|
|
78
|
+
style={[
|
|
79
|
+
style,
|
|
80
|
+
{
|
|
81
|
+
backgroundColor,
|
|
82
|
+
},
|
|
83
|
+
]}
|
|
84
|
+
>
|
|
85
|
+
<Animated.View>
|
|
86
|
+
<MaterialCommunityIcons
|
|
87
|
+
name={icon as any}
|
|
88
|
+
size={16}
|
|
89
|
+
color={isSelected ? '#FFFFFF' : textColor}
|
|
90
|
+
/>
|
|
91
|
+
</Animated.View>
|
|
92
|
+
</Animated.View>
|
|
93
|
+
</TouchableOpacity>
|
|
94
|
+
);
|
|
95
|
+
};
|
|
77
96
|
|
|
78
97
|
const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
79
98
|
onClose,
|
|
@@ -94,8 +113,11 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
94
113
|
defaultVisibility = 'private',
|
|
95
114
|
linkContext,
|
|
96
115
|
}) => {
|
|
116
|
+
// Use useOxy() hook for OxyContext values
|
|
97
117
|
const { user, oxyServices } = useOxy();
|
|
98
118
|
const files = useFiles();
|
|
119
|
+
// Ensure containerWidth is a number (TypeScript guard)
|
|
120
|
+
const safeContainerWidth: number = typeof containerWidth === 'number' ? containerWidth : 400;
|
|
99
121
|
const uploading = useUploadingStore();
|
|
100
122
|
const uploadProgress = useUploadAggregateProgress();
|
|
101
123
|
const deleting = useDeletingStore();
|
|
@@ -109,6 +131,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
109
131
|
const [fileContent, setFileContent] = useState<string | null>(null);
|
|
110
132
|
const [loadingFileContent, setLoadingFileContent] = useState(false);
|
|
111
133
|
const [showFileDetailsInViewer, setShowFileDetailsInViewer] = useState(false);
|
|
134
|
+
const [isPickingDocument, setIsPickingDocument] = useState(false);
|
|
112
135
|
const [viewMode, setViewMode] = useState<'all' | 'photos' | 'videos' | 'documents' | 'audio'>('all');
|
|
113
136
|
const [searchQuery, setSearchQuery] = useState('');
|
|
114
137
|
const [sortBy, setSortBy] = useState<'date' | 'size' | 'name' | 'type'>('date');
|
|
@@ -123,7 +146,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
123
146
|
} else if (viewMode === 'videos') {
|
|
124
147
|
filteredByMode = files.filter(file => file.contentType.startsWith('video/'));
|
|
125
148
|
} else if (viewMode === 'documents') {
|
|
126
|
-
filteredByMode = files.filter(file =>
|
|
149
|
+
filteredByMode = files.filter(file =>
|
|
127
150
|
file.contentType.includes('pdf') ||
|
|
128
151
|
file.contentType.includes('document') ||
|
|
129
152
|
file.contentType.includes('text') ||
|
|
@@ -136,7 +159,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
136
159
|
} else if (viewMode === 'audio') {
|
|
137
160
|
filteredByMode = files.filter(file => file.contentType.startsWith('audio/'));
|
|
138
161
|
}
|
|
139
|
-
|
|
162
|
+
|
|
140
163
|
let filtered = filteredByMode;
|
|
141
164
|
if (searchQuery.trim()) {
|
|
142
165
|
const query = searchQuery.toLowerCase();
|
|
@@ -146,7 +169,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
146
169
|
(file.metadata?.description && file.metadata.description.toLowerCase().includes(query))
|
|
147
170
|
);
|
|
148
171
|
}
|
|
149
|
-
|
|
172
|
+
|
|
150
173
|
// Sort files
|
|
151
174
|
const sorted = [...filtered].sort((a, b) => {
|
|
152
175
|
let comparison = 0;
|
|
@@ -163,13 +186,11 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
163
186
|
}
|
|
164
187
|
return sortOrder === 'asc' ? comparison : -comparison;
|
|
165
188
|
});
|
|
166
|
-
|
|
189
|
+
|
|
167
190
|
return sorted;
|
|
168
191
|
}, [files, searchQuery, viewMode, sortBy, sortOrder]);
|
|
169
|
-
const [isDragging, setIsDragging] = useState(false);
|
|
170
192
|
const [photoDimensions, setPhotoDimensions] = useState<{ [key: string]: { width: number, height: number } }>({});
|
|
171
193
|
const [loadingDimensions, setLoadingDimensions] = useState(false);
|
|
172
|
-
const [hoveredPreview, setHoveredPreview] = useState<string | null>(null);
|
|
173
194
|
const uploadStartRef = useRef<number | null>(null);
|
|
174
195
|
const MIN_BANNER_MS = 600;
|
|
175
196
|
// Selection state
|
|
@@ -178,7 +199,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
178
199
|
const scrollViewRef = useRef<ScrollView>(null);
|
|
179
200
|
const photoScrollViewRef = useRef<ScrollView>(null);
|
|
180
201
|
const itemRefs = useRef<Map<string, number>>(new Map()); // Track item positions
|
|
181
|
-
const containerRef = useRef<View>(null);
|
|
202
|
+
const containerRef = useRef<View>(null);
|
|
182
203
|
useEffect(() => {
|
|
183
204
|
if (initialSelectedIds && initialSelectedIds.length) {
|
|
184
205
|
setSelectedIds(new Set(initialSelectedIds));
|
|
@@ -205,7 +226,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
205
226
|
// Continue anyway - selection shouldn't fail if visibility update fails
|
|
206
227
|
}
|
|
207
228
|
}
|
|
208
|
-
|
|
229
|
+
|
|
209
230
|
// Track the selected file for scrolling
|
|
210
231
|
setLastSelectedFileId(file.id);
|
|
211
232
|
|
|
@@ -303,56 +324,22 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
303
324
|
}, []);
|
|
304
325
|
|
|
305
326
|
// Helper to safely request a thumbnail variant only for image mime types.
|
|
306
|
-
|
|
307
|
-
const getSafeDownloadUrl = useCallback(
|
|
327
|
+
const getSafeDownloadUrlCallback = useCallback(
|
|
308
328
|
(file: FileMetadata, variant: string = 'thumb') => {
|
|
309
|
-
|
|
310
|
-
const isVideo = file.contentType.startsWith('video/');
|
|
311
|
-
|
|
312
|
-
// Prefer explicit variant key if variants metadata present
|
|
313
|
-
if (file.variants && file.variants.length > 0) {
|
|
314
|
-
// For videos, try 'poster' regardless of requested variant
|
|
315
|
-
if (isVideo) {
|
|
316
|
-
const poster = file.variants.find(v => v.type === 'poster');
|
|
317
|
-
if (poster) return oxyServices.getFileDownloadUrl(file.id, 'poster');
|
|
318
|
-
}
|
|
319
|
-
if (isImage) {
|
|
320
|
-
const desired = file.variants.find(v => v.type === variant);
|
|
321
|
-
if (desired) return oxyServices.getFileDownloadUrl(file.id, variant);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (isImage) {
|
|
326
|
-
return oxyServices.getFileDownloadUrl(file.id, variant);
|
|
327
|
-
}
|
|
328
|
-
if (isVideo) {
|
|
329
|
-
// Fallback to poster if backend supports implicit generation
|
|
330
|
-
try {
|
|
331
|
-
return oxyServices.getFileDownloadUrl(file.id, 'poster');
|
|
332
|
-
} catch {
|
|
333
|
-
return oxyServices.getFileDownloadUrl(file.id);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
// Other mime types: no variant
|
|
337
|
-
return oxyServices.getFileDownloadUrl(file.id);
|
|
329
|
+
return getSafeDownloadUrl(file, variant, (fileId: string, variant?: string) => oxyServices.getFileDownloadUrl(fileId, variant));
|
|
338
330
|
},
|
|
339
331
|
[oxyServices]
|
|
340
332
|
);
|
|
341
333
|
|
|
342
|
-
//
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
primaryColor: '#007AFF',
|
|
352
|
-
dangerColor: '#FF3B30',
|
|
353
|
-
successColor: '#34C759',
|
|
354
|
-
};
|
|
355
|
-
}, [theme]);
|
|
334
|
+
// Use centralized theme styles hook for consistency
|
|
335
|
+
const colorScheme = useColorScheme();
|
|
336
|
+
const normalizedTheme = normalizeTheme(theme);
|
|
337
|
+
const baseThemeStyles = useThemeStyles(normalizedTheme, colorScheme);
|
|
338
|
+
// FileManagementScreen uses a slightly different light background
|
|
339
|
+
const themeStyles = useMemo(() => ({
|
|
340
|
+
...baseThemeStyles,
|
|
341
|
+
backgroundColor: baseThemeStyles.isDarkTheme ? baseThemeStyles.backgroundColor : '#f2f2f2',
|
|
342
|
+
}), [baseThemeStyles]);
|
|
356
343
|
|
|
357
344
|
// Extract commonly used theme variables
|
|
358
345
|
const backgroundColor = themeStyles.backgroundColor;
|
|
@@ -425,7 +412,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
425
412
|
|
|
426
413
|
// (removed effect; filteredFiles is memoized)
|
|
427
414
|
|
|
428
|
-
// Load photo dimensions for justified grid
|
|
415
|
+
// Load photo dimensions for justified grid - unified approach using Image.getSize
|
|
429
416
|
const loadPhotoDimensions = useCallback(async (photos: FileMetadata[]) => {
|
|
430
417
|
if (photos.length === 0) return;
|
|
431
418
|
|
|
@@ -445,46 +432,25 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
445
432
|
await Promise.all(
|
|
446
433
|
photosToLoad.map(async (photo) => {
|
|
447
434
|
try {
|
|
448
|
-
const downloadUrl =
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
height: img.naturalHeight
|
|
457
|
-
};
|
|
435
|
+
const downloadUrl = getSafeDownloadUrlCallback(photo, 'thumb');
|
|
436
|
+
|
|
437
|
+
// Unified approach using Image.getSize (works on all platforms)
|
|
438
|
+
await new Promise<void>((resolve) => {
|
|
439
|
+
Image.getSize(
|
|
440
|
+
downloadUrl,
|
|
441
|
+
(width: number, height: number) => {
|
|
442
|
+
newDimensions[photo.id] = { width, height };
|
|
458
443
|
hasNewDimensions = true;
|
|
459
444
|
resolve();
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// Fallback dimensions
|
|
445
|
+
},
|
|
446
|
+
() => {
|
|
447
|
+
// Fallback dimensions
|
|
463
448
|
newDimensions[photo.id] = { width: 1, height: 1 };
|
|
464
449
|
hasNewDimensions = true;
|
|
465
450
|
resolve();
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
} else {
|
|
470
|
-
// For mobile, use Image.getSize from react-native
|
|
471
|
-
await new Promise<void>((resolve) => {
|
|
472
|
-
Image.getSize(
|
|
473
|
-
downloadUrl,
|
|
474
|
-
(width: number, height: number) => {
|
|
475
|
-
newDimensions[photo.id] = { width, height };
|
|
476
|
-
hasNewDimensions = true;
|
|
477
|
-
resolve();
|
|
478
|
-
},
|
|
479
|
-
() => {
|
|
480
|
-
// Fallback dimensions
|
|
481
|
-
newDimensions[photo.id] = { width: 1, height: 1 };
|
|
482
|
-
hasNewDimensions = true;
|
|
483
|
-
resolve();
|
|
484
|
-
}
|
|
485
|
-
);
|
|
486
|
-
});
|
|
487
|
-
}
|
|
451
|
+
}
|
|
452
|
+
);
|
|
453
|
+
});
|
|
488
454
|
} catch (error) {
|
|
489
455
|
// Fallback dimensions for any errors
|
|
490
456
|
newDimensions[photo.id] = { width: 1, height: 1 };
|
|
@@ -501,7 +467,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
501
467
|
} finally {
|
|
502
468
|
setLoadingDimensions(false);
|
|
503
469
|
}
|
|
504
|
-
}, [
|
|
470
|
+
}, [getSafeDownloadUrlCallback, photoDimensions]);
|
|
505
471
|
|
|
506
472
|
// Create justified rows from photos with responsive algorithm
|
|
507
473
|
const createJustifiedRows = useCallback((photos: FileMetadata[], containerWidth: number) => {
|
|
@@ -518,26 +484,38 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
518
484
|
return rows;
|
|
519
485
|
}, []);
|
|
520
486
|
|
|
521
|
-
const processFileUploads = async (selectedFiles: File[]) => {
|
|
522
|
-
if (selectedFiles.length === 0) return;
|
|
523
|
-
if (!targetUserId) return; // Guard clause to ensure userId is defined
|
|
487
|
+
const processFileUploads = async (selectedFiles: File[]): Promise<FileMetadata[]> => {
|
|
488
|
+
if (selectedFiles.length === 0) return [];
|
|
489
|
+
if (!targetUserId) return []; // Guard clause to ensure userId is defined
|
|
490
|
+
const uploadedFiles: FileMetadata[] = [];
|
|
524
491
|
try {
|
|
525
492
|
storeSetUploadProgress({ current: 0, total: selectedFiles.length });
|
|
526
493
|
const maxSize = 50 * 1024 * 1024; // 50MB
|
|
527
494
|
const oversizedFiles = selectedFiles.filter(file => file.size > maxSize);
|
|
528
495
|
if (oversizedFiles.length > 0) {
|
|
529
|
-
const fileList = oversizedFiles.map(f => f.name).join('
|
|
530
|
-
|
|
531
|
-
return;
|
|
496
|
+
const fileList = oversizedFiles.map(f => f.name).join(', ');
|
|
497
|
+
toast.error(`The following files are too large (max 50MB): ${fileList}`);
|
|
498
|
+
return [];
|
|
532
499
|
}
|
|
533
500
|
let successCount = 0;
|
|
534
501
|
let failureCount = 0;
|
|
535
502
|
const errors: string[] = [];
|
|
536
503
|
for (let i = 0; i < selectedFiles.length; i++) {
|
|
537
504
|
storeSetUploadProgress({ current: i + 1, total: selectedFiles.length });
|
|
505
|
+
const raw = selectedFiles[i];
|
|
506
|
+
const fileName = raw.name || `file-${i + 1}`;
|
|
507
|
+
const optimisticId = `temp-${Date.now()}-${i}-${Math.random().toString(36).substr(2, 9)}`; // Unique ID per file
|
|
508
|
+
|
|
538
509
|
try {
|
|
539
|
-
|
|
540
|
-
|
|
510
|
+
// Validate file before upload
|
|
511
|
+
if (!raw || !raw.name || raw.size === undefined || raw.size <= 0) {
|
|
512
|
+
const errorMsg = `Invalid file: ${fileName}`;
|
|
513
|
+
console.error('Upload validation failed:', { file: raw, error: errorMsg });
|
|
514
|
+
failureCount++;
|
|
515
|
+
errors.push(`${fileName}: Invalid file (missing name or size)`);
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
|
|
541
519
|
const optimisticFile: FileMetadata = {
|
|
542
520
|
id: optimisticId,
|
|
543
521
|
filename: raw.name,
|
|
@@ -549,7 +527,9 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
549
527
|
variants: [],
|
|
550
528
|
};
|
|
551
529
|
useFileStore.getState().addFile(optimisticFile, { prepend: true });
|
|
530
|
+
|
|
552
531
|
const result = await uploadFileRaw(raw, targetUserId, oxyServices, defaultVisibility);
|
|
532
|
+
|
|
553
533
|
// Attempt to refresh file list incrementally – fetch single file metadata if API allows
|
|
554
534
|
if (result?.file || result?.files?.[0]) {
|
|
555
535
|
const f = result.file || result.files[0];
|
|
@@ -566,22 +546,43 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
566
546
|
// Remove optimistic then add real
|
|
567
547
|
useFileStore.getState().removeFile(optimisticId);
|
|
568
548
|
useFileStore.getState().addFile(merged, { prepend: true });
|
|
549
|
+
uploadedFiles.push(merged);
|
|
550
|
+
successCount++;
|
|
569
551
|
} else {
|
|
570
552
|
// Fallback: will reconcile on later list refresh
|
|
571
553
|
useFileStore.getState().updateFile(optimisticId, { metadata: { uploading: false } as any });
|
|
554
|
+
console.warn('Upload completed but no file data returned:', { fileName, result });
|
|
555
|
+
// Still count as success if upload didn't throw
|
|
556
|
+
successCount++;
|
|
572
557
|
}
|
|
573
|
-
successCount++;
|
|
574
558
|
} catch (error: any) {
|
|
575
559
|
failureCount++;
|
|
576
|
-
|
|
560
|
+
const errorMessage = error.message || error.toString() || 'Upload failed';
|
|
561
|
+
const fullError = `${fileName}: ${errorMessage}`;
|
|
562
|
+
errors.push(fullError);
|
|
563
|
+
console.error('File upload failed:', {
|
|
564
|
+
fileName,
|
|
565
|
+
fileSize: raw.size,
|
|
566
|
+
fileType: raw.type,
|
|
567
|
+
error: errorMessage,
|
|
568
|
+
stack: error.stack
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
// Remove optimistic file on error (use the same optimisticId from above)
|
|
572
|
+
useFileStore.getState().removeFile(optimisticId);
|
|
577
573
|
}
|
|
578
574
|
}
|
|
575
|
+
|
|
576
|
+
// Show success/error messages
|
|
579
577
|
if (successCount > 0) {
|
|
580
578
|
toast.success(`${successCount} file(s) uploaded successfully`);
|
|
581
579
|
}
|
|
582
580
|
if (failureCount > 0) {
|
|
583
|
-
|
|
584
|
-
|
|
581
|
+
// Show detailed error message with first few errors
|
|
582
|
+
const errorDetails = errors.length > 0
|
|
583
|
+
? `\n${errors.slice(0, 3).join('\n')}${errors.length > 3 ? `\n...and ${errors.length - 3} more` : ''}`
|
|
584
|
+
: '';
|
|
585
|
+
toast.error(`${failureCount} file(s) failed to upload${errorDetails}`);
|
|
585
586
|
}
|
|
586
587
|
// Silent background refresh to ensure metadata/variants updated
|
|
587
588
|
setTimeout(() => { loadFiles('silent'); }, 1200);
|
|
@@ -590,6 +591,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
590
591
|
} finally {
|
|
591
592
|
storeSetUploadProgress(null);
|
|
592
593
|
}
|
|
594
|
+
return uploadedFiles;
|
|
593
595
|
};
|
|
594
596
|
|
|
595
597
|
const handleFileSelection = useCallback(async (selectedFiles: File[] | any[]) => {
|
|
@@ -597,16 +599,61 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
597
599
|
const processedFiles: Array<{ file: File | Blob; preview?: string; size: number; name: string; type: string }> = [];
|
|
598
600
|
|
|
599
601
|
for (const file of selectedFiles) {
|
|
602
|
+
// Validate file has required properties
|
|
603
|
+
if (!file) {
|
|
604
|
+
console.error('Invalid file: file is null or undefined');
|
|
605
|
+
toast.error('Invalid file: file is missing');
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (!file.name || typeof file.name !== 'string') {
|
|
610
|
+
console.error('Invalid file: missing or invalid name property', file);
|
|
611
|
+
toast.error('Invalid file: missing file name');
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (file.size === undefined || file.size === null || isNaN(file.size)) {
|
|
616
|
+
console.error('Invalid file: missing or invalid size property', file);
|
|
617
|
+
toast.error(`Invalid file "${file.name || 'unknown'}": missing file size`);
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
if (file.size <= 0) {
|
|
622
|
+
console.error('Invalid file: file size is zero or negative', file);
|
|
623
|
+
toast.error(`File "${file.name}" is empty`);
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
|
|
600
627
|
// Validate file size
|
|
601
628
|
if (file.size > MAX_FILE_SIZE) {
|
|
602
629
|
toast.error(`"${file.name}" is too large. Maximum file size is ${formatFileSize(MAX_FILE_SIZE)}`);
|
|
603
630
|
continue;
|
|
604
631
|
}
|
|
605
632
|
|
|
606
|
-
//
|
|
633
|
+
// Ensure file has a type property
|
|
634
|
+
const fileType = file.type || 'application/octet-stream';
|
|
635
|
+
|
|
636
|
+
// Generate preview for images - unified approach
|
|
607
637
|
let preview: string | undefined;
|
|
608
|
-
if (
|
|
609
|
-
|
|
638
|
+
if (fileType.startsWith('image/')) {
|
|
639
|
+
// Try to use file URI from expo-document-picker if available (works on all platforms)
|
|
640
|
+
const fileUri = (file as any).uri;
|
|
641
|
+
if (fileUri && typeof fileUri === 'string' &&
|
|
642
|
+
(fileUri.startsWith('file://') || fileUri.startsWith('content://') ||
|
|
643
|
+
fileUri.startsWith('http://') || fileUri.startsWith('https://') ||
|
|
644
|
+
fileUri.startsWith('blob:'))) {
|
|
645
|
+
preview = fileUri;
|
|
646
|
+
} else {
|
|
647
|
+
// Fallback: create blob URL if possible (works on web)
|
|
648
|
+
try {
|
|
649
|
+
if (file instanceof File || file instanceof Blob) {
|
|
650
|
+
preview = URL.createObjectURL(file);
|
|
651
|
+
}
|
|
652
|
+
} catch (error: any) {
|
|
653
|
+
console.warn('Failed to create preview URL:', error);
|
|
654
|
+
// Preview is optional, continue without it
|
|
655
|
+
}
|
|
656
|
+
}
|
|
610
657
|
}
|
|
611
658
|
|
|
612
659
|
processedFiles.push({
|
|
@@ -614,11 +661,14 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
614
661
|
preview,
|
|
615
662
|
size: file.size,
|
|
616
663
|
name: file.name,
|
|
617
|
-
type:
|
|
664
|
+
type: fileType
|
|
618
665
|
});
|
|
619
666
|
}
|
|
620
667
|
|
|
621
|
-
if (processedFiles.length === 0)
|
|
668
|
+
if (processedFiles.length === 0) {
|
|
669
|
+
toast.error('No valid files to upload');
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
622
672
|
|
|
623
673
|
// Show preview modal for user to review files before upload
|
|
624
674
|
setPendingFiles(processedFiles);
|
|
@@ -636,8 +686,8 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
636
686
|
try {
|
|
637
687
|
const filesToUpload = pendingFiles.map(pf => pf.file as File);
|
|
638
688
|
storeSetUploadProgress({ current: 0, total: filesToUpload.length });
|
|
639
|
-
await processFileUploads(filesToUpload);
|
|
640
|
-
|
|
689
|
+
const uploadedFiles = await processFileUploads(filesToUpload);
|
|
690
|
+
|
|
641
691
|
// Cleanup preview URLs
|
|
642
692
|
pendingFiles.forEach(pf => {
|
|
643
693
|
if (pf.preview) {
|
|
@@ -645,6 +695,31 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
645
695
|
}
|
|
646
696
|
});
|
|
647
697
|
setPendingFiles([]);
|
|
698
|
+
|
|
699
|
+
// If in selectMode, automatically select the uploaded file(s)
|
|
700
|
+
if (selectMode && uploadedFiles.length > 0) {
|
|
701
|
+
// Wait a bit for the file store to update and ensure file is available
|
|
702
|
+
setTimeout(() => {
|
|
703
|
+
const fileToSelect = uploadedFiles[0];
|
|
704
|
+
if (!multiSelect && fileToSelect) {
|
|
705
|
+
// Single select mode - directly call onSelect callback
|
|
706
|
+
onSelect?.(fileToSelect);
|
|
707
|
+
if (afterSelect === 'back') {
|
|
708
|
+
goBack?.();
|
|
709
|
+
} else if (afterSelect === 'close') {
|
|
710
|
+
onClose?.();
|
|
711
|
+
}
|
|
712
|
+
} else if (multiSelect) {
|
|
713
|
+
// Multi-select mode - add all uploaded files to selection
|
|
714
|
+
uploadedFiles.forEach(file => {
|
|
715
|
+
if (!selectedIds.has(file.id)) {
|
|
716
|
+
setSelectedIds(prev => new Set(prev).add(file.id));
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
}, 500);
|
|
721
|
+
}
|
|
722
|
+
|
|
648
723
|
endUpload();
|
|
649
724
|
} catch (error: any) {
|
|
650
725
|
toast.error(error.message || 'Failed to upload files');
|
|
@@ -675,88 +750,124 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
675
750
|
}
|
|
676
751
|
};
|
|
677
752
|
|
|
753
|
+
/**
|
|
754
|
+
* Handle file upload - opens document picker and processes selected files
|
|
755
|
+
* Expo 54 compatible - works on web, iOS, and Android
|
|
756
|
+
*/
|
|
678
757
|
const handleFileUpload = async () => {
|
|
758
|
+
// Prevent concurrent document picker calls
|
|
759
|
+
if (isPickingDocument) {
|
|
760
|
+
toast.error('Please wait for the current file selection to complete');
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
|
|
679
764
|
try {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
input.multiple = true;
|
|
685
|
-
input.accept = '*/*';
|
|
686
|
-
|
|
687
|
-
const cancellationTimer = setTimeout(() => {
|
|
688
|
-
const state = useFileStore.getState();
|
|
689
|
-
if (state.uploading && uploadStartRef.current && !state.uploadProgress) {
|
|
690
|
-
endUpload();
|
|
691
|
-
}
|
|
692
|
-
}, 1500);
|
|
693
|
-
|
|
694
|
-
input.onchange = async (e: any) => {
|
|
695
|
-
clearTimeout(cancellationTimer);
|
|
696
|
-
const selectedFiles = Array.from(e.target.files || []) as File[];
|
|
697
|
-
if (selectedFiles.length === 0) {
|
|
698
|
-
endUpload();
|
|
699
|
-
return;
|
|
700
|
-
}
|
|
701
|
-
await handleFileSelection(selectedFiles);
|
|
702
|
-
};
|
|
765
|
+
setIsPickingDocument(true);
|
|
766
|
+
|
|
767
|
+
// Dynamically import expo-document-picker (Expo 54 supports it on all platforms)
|
|
768
|
+
const DocumentPicker = await import('expo-document-picker').catch(() => null);
|
|
703
769
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
// Dynamically import to avoid breaking if not installed
|
|
709
|
-
const DocumentPicker = await import('expo-document-picker').catch(() => null);
|
|
710
|
-
|
|
711
|
-
if (!DocumentPicker) {
|
|
712
|
-
toast.error('File picker not available. Please install expo-document-picker');
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
770
|
+
if (!DocumentPicker || !DocumentPicker.getDocumentAsync) {
|
|
771
|
+
toast.error('File picker not available. Please install expo-document-picker');
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
715
774
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
775
|
+
// Use getDocumentAsync directly - it will handle platform availability
|
|
776
|
+
const result = await DocumentPicker.getDocumentAsync({
|
|
777
|
+
type: '*/*',
|
|
778
|
+
multiple: true,
|
|
779
|
+
copyToCacheDirectory: true,
|
|
780
|
+
});
|
|
721
781
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
782
|
+
if (result.canceled) {
|
|
783
|
+
setIsPickingDocument(false);
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
if (!result.assets || result.assets.length === 0) {
|
|
788
|
+
setIsPickingDocument(false);
|
|
789
|
+
toast.error('No files were selected');
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// Convert expo document picker results to File-like objects
|
|
794
|
+
// According to Expo 54 docs, expo-document-picker returns assets with:
|
|
795
|
+
// - uri: file URI (file://, content://, or blob URL)
|
|
796
|
+
// - name: file name
|
|
797
|
+
// - size: file size in bytes
|
|
798
|
+
// - mimeType: MIME type of the file
|
|
799
|
+
// - file: (optional) native File object (usually only on web)
|
|
800
|
+
const files: File[] = [];
|
|
801
|
+
const errors: string[] = [];
|
|
725
802
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
803
|
+
// Process files in parallel for better performance
|
|
804
|
+
// This allows multiple files to be converted simultaneously
|
|
805
|
+
const conversionPromises = result.assets.map((doc, index) =>
|
|
806
|
+
convertDocumentPickerAssetToFile(doc, index)
|
|
807
|
+
.then((file) => {
|
|
808
|
+
if (file) {
|
|
809
|
+
// Validate file has required properties before adding
|
|
810
|
+
if (!file.name || file.size === undefined) {
|
|
811
|
+
errors.push(`File "${doc.name || 'file'}" is invalid: missing required properties`);
|
|
812
|
+
return null;
|
|
813
|
+
}
|
|
814
|
+
return file;
|
|
738
815
|
}
|
|
739
|
-
|
|
816
|
+
return null;
|
|
817
|
+
})
|
|
818
|
+
.catch((error: any) => {
|
|
819
|
+
errors.push(`File "${doc.name || 'file'}": ${error.message || 'Failed to process'}`);
|
|
820
|
+
return null;
|
|
821
|
+
})
|
|
822
|
+
);
|
|
740
823
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
} else {
|
|
748
|
-
toast.error(error.message || 'Failed to select files');
|
|
749
|
-
}
|
|
824
|
+
const convertedFiles = await Promise.all(conversionPromises);
|
|
825
|
+
|
|
826
|
+
// Filter out null values
|
|
827
|
+
for (const file of convertedFiles) {
|
|
828
|
+
if (file) {
|
|
829
|
+
files.push(file);
|
|
750
830
|
}
|
|
751
831
|
}
|
|
832
|
+
|
|
833
|
+
// Show errors if any
|
|
834
|
+
if (errors.length > 0) {
|
|
835
|
+
const errorMessage = errors.slice(0, 3).join('\n') + (errors.length > 3 ? `\n...and ${errors.length - 3} more` : '');
|
|
836
|
+
toast.error(`Failed to load some files:\n${errorMessage}`);
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
// Process successfully converted files
|
|
840
|
+
if (files.length > 0) {
|
|
841
|
+
await handleFileSelection(files);
|
|
842
|
+
} else {
|
|
843
|
+
// Files were selected but none could be converted
|
|
844
|
+
toast.error('No files could be processed. Please try selecting files again.');
|
|
845
|
+
}
|
|
752
846
|
} catch (error: any) {
|
|
753
|
-
|
|
847
|
+
console.error('File upload error:', error);
|
|
848
|
+
if (error.message?.includes('expo-document-picker') || error.message?.includes('Different document picking in progress')) {
|
|
849
|
+
if (error.message?.includes('Different document picking in progress')) {
|
|
850
|
+
toast.error('Please wait for the current file selection to complete');
|
|
851
|
+
} else {
|
|
852
|
+
toast.error('File picker not available. Please install expo-document-picker');
|
|
853
|
+
}
|
|
854
|
+
} else {
|
|
855
|
+
toast.error(error.message || 'Failed to select files');
|
|
856
|
+
}
|
|
857
|
+
} finally {
|
|
858
|
+
// Always reset the picking state, even if there was an error
|
|
859
|
+
setIsPickingDocument(false);
|
|
754
860
|
}
|
|
755
861
|
};
|
|
756
862
|
|
|
757
863
|
const handleFileDelete = async (fileId: string, filename: string) => {
|
|
758
|
-
// Use
|
|
759
|
-
const confirmed =
|
|
864
|
+
// Use platform-aware confirmation dialog
|
|
865
|
+
const confirmed = await confirmAction(
|
|
866
|
+
`Are you sure you want to delete "${filename}"? This action cannot be undone.`,
|
|
867
|
+
'Delete File',
|
|
868
|
+
'Delete',
|
|
869
|
+
'Cancel'
|
|
870
|
+
);
|
|
760
871
|
|
|
761
872
|
if (!confirmed) {
|
|
762
873
|
return;
|
|
@@ -792,17 +903,20 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
792
903
|
|
|
793
904
|
const handleBulkDelete = useCallback(async () => {
|
|
794
905
|
if (selectedIds.size === 0) return;
|
|
795
|
-
|
|
906
|
+
|
|
796
907
|
const fileMap: Record<string, FileMetadata> = {};
|
|
797
908
|
files.forEach(f => { fileMap[f.id] = f; });
|
|
798
909
|
const selectedFiles = Array.from(selectedIds).map(id => fileMap[id]).filter(Boolean);
|
|
799
|
-
|
|
800
|
-
const confirmed =
|
|
801
|
-
`Are you sure you want to delete ${selectedFiles.length} file(s)? This action cannot be undone
|
|
910
|
+
|
|
911
|
+
const confirmed = await confirmAction(
|
|
912
|
+
`Are you sure you want to delete ${selectedFiles.length} file(s)? This action cannot be undone.`,
|
|
913
|
+
'Delete Files',
|
|
914
|
+
'Delete',
|
|
915
|
+
'Cancel'
|
|
802
916
|
);
|
|
803
|
-
|
|
917
|
+
|
|
804
918
|
if (!confirmed) return;
|
|
805
|
-
|
|
919
|
+
|
|
806
920
|
try {
|
|
807
921
|
const deletePromises = Array.from(selectedIds).map(async (fileId) => {
|
|
808
922
|
try {
|
|
@@ -813,18 +927,18 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
813
927
|
return { success: false, fileId, error };
|
|
814
928
|
}
|
|
815
929
|
});
|
|
816
|
-
|
|
930
|
+
|
|
817
931
|
const results = await Promise.allSettled(deletePromises);
|
|
818
932
|
const successful = results.filter(r => r.status === 'fulfilled' && r.value.success).length;
|
|
819
933
|
const failed = results.length - successful;
|
|
820
|
-
|
|
934
|
+
|
|
821
935
|
if (successful > 0) {
|
|
822
936
|
toast.success(`${successful} file(s) deleted successfully`);
|
|
823
937
|
}
|
|
824
938
|
if (failed > 0) {
|
|
825
939
|
toast.error(`${failed} file(s) failed to delete`);
|
|
826
940
|
}
|
|
827
|
-
|
|
941
|
+
|
|
828
942
|
setSelectedIds(new Set());
|
|
829
943
|
setTimeout(() => loadFiles('silent'), 800);
|
|
830
944
|
} catch (error: any) {
|
|
@@ -834,7 +948,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
834
948
|
|
|
835
949
|
const handleBulkVisibilityChange = useCallback(async (visibility: 'private' | 'public' | 'unlisted') => {
|
|
836
950
|
if (selectedIds.size === 0) return;
|
|
837
|
-
|
|
951
|
+
|
|
838
952
|
try {
|
|
839
953
|
const updatePromises = Array.from(selectedIds).map(async (fileId) => {
|
|
840
954
|
try {
|
|
@@ -844,11 +958,11 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
844
958
|
return { success: false, fileId, error };
|
|
845
959
|
}
|
|
846
960
|
});
|
|
847
|
-
|
|
961
|
+
|
|
848
962
|
const results = await Promise.allSettled(updatePromises);
|
|
849
963
|
const successful = results.filter(r => r.status === 'fulfilled' && r.value.success).length;
|
|
850
964
|
const failed = results.length - successful;
|
|
851
|
-
|
|
965
|
+
|
|
852
966
|
if (successful > 0) {
|
|
853
967
|
toast.success(`${successful} file(s) visibility updated to ${visibility}`);
|
|
854
968
|
// Update file metadata in store
|
|
@@ -861,87 +975,24 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
861
975
|
if (failed > 0) {
|
|
862
976
|
toast.error(`${failed} file(s) failed to update visibility`);
|
|
863
977
|
}
|
|
864
|
-
|
|
978
|
+
|
|
865
979
|
setTimeout(() => loadFiles('silent'), 800);
|
|
866
980
|
} catch (error: any) {
|
|
867
981
|
toast.error(error.message || 'Failed to update visibility');
|
|
868
982
|
}
|
|
869
983
|
}, [selectedIds, oxyServices, files, loadFiles]);
|
|
870
984
|
|
|
871
|
-
//
|
|
872
|
-
useEffect(() => {
|
|
873
|
-
if (Platform.OS !== 'web' || user?.id !== targetUserId) return;
|
|
874
|
-
|
|
875
|
-
let dragCounter = 0; // Track drag enter/leave to handle nested elements
|
|
876
|
-
|
|
877
|
-
const onDragEnter = (e: DragEvent) => {
|
|
878
|
-
dragCounter++;
|
|
879
|
-
if (e?.dataTransfer?.types?.includes('Files')) {
|
|
880
|
-
e.preventDefault();
|
|
881
|
-
e.stopPropagation();
|
|
882
|
-
setIsDragging(true);
|
|
883
|
-
}
|
|
884
|
-
};
|
|
885
|
-
|
|
886
|
-
const onDragOver = (e: DragEvent) => {
|
|
887
|
-
if (e?.dataTransfer?.types?.includes('Files')) {
|
|
888
|
-
e.preventDefault();
|
|
889
|
-
e.stopPropagation();
|
|
890
|
-
// Keep dragging state true while over document
|
|
891
|
-
setIsDragging(true);
|
|
892
|
-
}
|
|
893
|
-
};
|
|
894
|
-
|
|
895
|
-
const onDrop = async (e: DragEvent) => {
|
|
896
|
-
dragCounter = 0;
|
|
897
|
-
setIsDragging(false);
|
|
898
|
-
|
|
899
|
-
if (e?.dataTransfer?.files?.length) {
|
|
900
|
-
e.preventDefault();
|
|
901
|
-
e.stopPropagation();
|
|
902
|
-
|
|
903
|
-
try {
|
|
904
|
-
const files = Array.from(e.dataTransfer.files) as File[];
|
|
905
|
-
if (files.length > 0) {
|
|
906
|
-
await handleFileSelection(files);
|
|
907
|
-
}
|
|
908
|
-
} catch (error: any) {
|
|
909
|
-
toast.error(error.message || 'Failed to upload files');
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
};
|
|
913
|
-
|
|
914
|
-
const onDragLeave = (e: DragEvent) => {
|
|
915
|
-
dragCounter--;
|
|
916
|
-
// Only hide drag overlay if we're actually leaving the document (drag counter reaches 0)
|
|
917
|
-
if (dragCounter === 0) {
|
|
918
|
-
setIsDragging(false);
|
|
919
|
-
}
|
|
920
|
-
};
|
|
921
|
-
|
|
922
|
-
// Attach to document for global drag detection
|
|
923
|
-
document.addEventListener('dragenter', onDragEnter, false);
|
|
924
|
-
document.addEventListener('dragover', onDragOver, false);
|
|
925
|
-
document.addEventListener('drop', onDrop, false);
|
|
926
|
-
document.addEventListener('dragleave', onDragLeave, false);
|
|
927
|
-
|
|
928
|
-
return () => {
|
|
929
|
-
document.removeEventListener('dragenter', onDragEnter, false);
|
|
930
|
-
document.removeEventListener('dragover', onDragOver, false);
|
|
931
|
-
document.removeEventListener('drop', onDrop, false);
|
|
932
|
-
document.removeEventListener('dragleave', onDragLeave, false);
|
|
933
|
-
};
|
|
934
|
-
}, [user?.id, targetUserId, handleFileSelection]);
|
|
935
|
-
|
|
936
|
-
|
|
985
|
+
// Unified download function - works on all platforms
|
|
937
986
|
const handleFileDownload = async (fileId: string, filename: string) => {
|
|
938
987
|
try {
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
988
|
+
// Try to use the download URL with a simple approach
|
|
989
|
+
// On web, this creates a download link. On mobile, it opens the URL.
|
|
990
|
+
const downloadUrl = oxyServices.getFileDownloadUrl(fileId);
|
|
942
991
|
|
|
992
|
+
// For web platforms, use link download
|
|
993
|
+
if (typeof window !== 'undefined' && window.document) {
|
|
943
994
|
try {
|
|
944
|
-
//
|
|
995
|
+
// Try simple link download first
|
|
945
996
|
const link = document.createElement('a');
|
|
946
997
|
link.href = downloadUrl;
|
|
947
998
|
link.download = filename;
|
|
@@ -949,13 +1000,11 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
949
1000
|
document.body.appendChild(link);
|
|
950
1001
|
link.click();
|
|
951
1002
|
document.body.removeChild(link);
|
|
952
|
-
|
|
953
1003
|
toast.success('File download started');
|
|
954
1004
|
} catch (linkError) {
|
|
955
|
-
|
|
956
|
-
// Method 2: Fallback to authenticated download
|
|
1005
|
+
// Fallback to authenticated download
|
|
957
1006
|
const blob = await oxyServices.getFileContentAsBlob(fileId);
|
|
958
|
-
const url =
|
|
1007
|
+
const url = URL.createObjectURL(blob);
|
|
959
1008
|
|
|
960
1009
|
const link = document.createElement('a');
|
|
961
1010
|
link.href = url;
|
|
@@ -965,36 +1014,20 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
965
1014
|
document.body.removeChild(link);
|
|
966
1015
|
|
|
967
1016
|
// Clean up the blob URL
|
|
968
|
-
|
|
969
|
-
|
|
1017
|
+
URL.revokeObjectURL(url);
|
|
970
1018
|
toast.success('File downloaded successfully');
|
|
971
1019
|
}
|
|
972
1020
|
} else {
|
|
973
|
-
|
|
1021
|
+
// For mobile, open the URL (user can save from browser)
|
|
1022
|
+
// Note: This is a simplified approach - for full mobile support,
|
|
1023
|
+
// consider using expo-file-system or react-native-fs
|
|
1024
|
+
toast.info('Please use your browser to download the file');
|
|
974
1025
|
}
|
|
975
1026
|
} catch (error: any) {
|
|
976
1027
|
toast.error(error.message || 'Failed to download file');
|
|
977
1028
|
}
|
|
978
1029
|
};
|
|
979
1030
|
|
|
980
|
-
const formatFileSize = (bytes: number): string => {
|
|
981
|
-
if (bytes === 0) return '0 Bytes';
|
|
982
|
-
const k = 1024;
|
|
983
|
-
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
984
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
985
|
-
return Number.parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
986
|
-
};
|
|
987
|
-
|
|
988
|
-
const getFileIcon = (contentType: string): string => {
|
|
989
|
-
if (contentType.startsWith('image/')) return 'image';
|
|
990
|
-
if (contentType.startsWith('video/')) return 'videocam';
|
|
991
|
-
if (contentType.startsWith('audio/')) return 'musical-notes';
|
|
992
|
-
if (contentType.includes('pdf')) return 'document-text';
|
|
993
|
-
if (contentType.includes('word') || contentType.includes('doc')) return 'document';
|
|
994
|
-
if (contentType.includes('excel') || contentType.includes('sheet')) return 'grid';
|
|
995
|
-
if (contentType.includes('zip') || contentType.includes('archive')) return 'archive';
|
|
996
|
-
return 'document-outline';
|
|
997
|
-
};
|
|
998
1031
|
|
|
999
1032
|
const handleFileOpen = async (file: FileMetadata) => {
|
|
1000
1033
|
if (selectMode) {
|
|
@@ -1061,24 +1094,24 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1061
1094
|
};
|
|
1062
1095
|
|
|
1063
1096
|
const renderSimplePhotoItem = useCallback((photo: FileMetadata, index: number) => {
|
|
1064
|
-
const downloadUrl =
|
|
1097
|
+
const downloadUrl = getSafeDownloadUrlCallback(photo, 'thumb');
|
|
1065
1098
|
|
|
1066
1099
|
// Calculate photo item width based on actual container size from bottom sheet
|
|
1067
1100
|
let itemsPerRow = 3; // Default for mobile
|
|
1068
|
-
if (
|
|
1069
|
-
else if (
|
|
1101
|
+
if (safeContainerWidth > 768) itemsPerRow = 4; // Desktop/tablet
|
|
1102
|
+
else if (safeContainerWidth > 480) itemsPerRow = 3; // Large mobile
|
|
1070
1103
|
|
|
1071
1104
|
// Account for the photoScrollContainer padding (16px on each side = 32px total)
|
|
1072
1105
|
const scrollContainerPadding = 32; // Total horizontal padding from photoScrollContainer
|
|
1073
1106
|
const gaps = (itemsPerRow - 1) * 4; // Gap between items (4px)
|
|
1074
|
-
const availableWidth =
|
|
1107
|
+
const availableWidth = safeContainerWidth - scrollContainerPadding;
|
|
1075
1108
|
const itemWidth = (availableWidth - gaps) / itemsPerRow;
|
|
1076
1109
|
|
|
1077
1110
|
return (
|
|
1078
1111
|
<TouchableOpacity
|
|
1079
1112
|
key={photo.id}
|
|
1080
1113
|
style={[
|
|
1081
|
-
|
|
1114
|
+
fileManagementStyles.simplePhotoItem,
|
|
1082
1115
|
{
|
|
1083
1116
|
width: itemWidth,
|
|
1084
1117
|
height: itemWidth,
|
|
@@ -1089,10 +1122,10 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1089
1122
|
onPress={() => handleFileOpen(photo)}
|
|
1090
1123
|
activeOpacity={0.8}
|
|
1091
1124
|
>
|
|
1092
|
-
<View style={
|
|
1125
|
+
<View style={fileManagementStyles.simplePhotoContainer}>
|
|
1093
1126
|
<ExpoImage
|
|
1094
1127
|
source={{ uri: downloadUrl }}
|
|
1095
|
-
style={
|
|
1128
|
+
style={fileManagementStyles.simplePhotoImage}
|
|
1096
1129
|
contentFit="cover"
|
|
1097
1130
|
transition={120}
|
|
1098
1131
|
cachePolicy="memory-disk"
|
|
@@ -1102,23 +1135,23 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1102
1135
|
accessibilityLabel={photo.filename}
|
|
1103
1136
|
/>
|
|
1104
1137
|
{selectMode && (
|
|
1105
|
-
<View style={
|
|
1138
|
+
<View style={fileManagementStyles.selectionBadge}>
|
|
1106
1139
|
<Ionicons name={selectedIds.has(photo.id) ? 'checkmark-circle' : 'ellipse-outline'} size={20} color={selectedIds.has(photo.id) ? themeStyles.primaryColor : themeStyles.textColor} />
|
|
1107
1140
|
</View>
|
|
1108
1141
|
)}
|
|
1109
1142
|
</View>
|
|
1110
1143
|
</TouchableOpacity>
|
|
1111
1144
|
);
|
|
1112
|
-
}, [oxyServices,
|
|
1145
|
+
}, [oxyServices, safeContainerWidth, selectMode, selectedIds, themeStyles.primaryColor, themeStyles.textColor]);
|
|
1113
1146
|
|
|
1114
1147
|
const renderJustifiedPhotoItem = useCallback((photo: FileMetadata, width: number, height: number, isLast: boolean) => {
|
|
1115
|
-
const downloadUrl =
|
|
1148
|
+
const downloadUrl = getSafeDownloadUrlCallback(photo, 'thumb');
|
|
1116
1149
|
|
|
1117
1150
|
return (
|
|
1118
1151
|
<TouchableOpacity
|
|
1119
1152
|
key={photo.id}
|
|
1120
1153
|
style={[
|
|
1121
|
-
|
|
1154
|
+
fileManagementStyles.justifiedPhotoItem,
|
|
1122
1155
|
{
|
|
1123
1156
|
width,
|
|
1124
1157
|
height,
|
|
@@ -1129,10 +1162,10 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1129
1162
|
onPress={() => handleFileOpen(photo)}
|
|
1130
1163
|
activeOpacity={0.8}
|
|
1131
1164
|
>
|
|
1132
|
-
<View style={
|
|
1165
|
+
<View style={fileManagementStyles.justifiedPhotoContainer}>
|
|
1133
1166
|
<ExpoImage
|
|
1134
1167
|
source={{ uri: downloadUrl }}
|
|
1135
|
-
style={
|
|
1168
|
+
style={fileManagementStyles.justifiedPhotoImage}
|
|
1136
1169
|
contentFit="cover"
|
|
1137
1170
|
transition={120}
|
|
1138
1171
|
cachePolicy="memory-disk"
|
|
@@ -1142,7 +1175,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1142
1175
|
accessibilityLabel={photo.filename}
|
|
1143
1176
|
/>
|
|
1144
1177
|
{selectMode && (
|
|
1145
|
-
<View style={
|
|
1178
|
+
<View style={fileManagementStyles.selectionBadge}>
|
|
1146
1179
|
<Ionicons name={selectedIds.has(photo.id) ? 'checkmark-circle' : 'ellipse-outline'} size={20} color={selectedIds.has(photo.id) ? themeStyles.primaryColor : themeStyles.textColor} />
|
|
1147
1180
|
</View>
|
|
1148
1181
|
)}
|
|
@@ -1173,26 +1206,20 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1173
1206
|
return (
|
|
1174
1207
|
<View
|
|
1175
1208
|
key={file.id}
|
|
1176
|
-
style={[
|
|
1209
|
+
style={[fileManagementStyles.fileItem, { backgroundColor: themeStyles.secondaryBackgroundColor, borderColor }, selectMode && selectedIds.has(file.id) && { borderColor: themeStyles.primaryColor, borderWidth: 2 }]}
|
|
1177
1210
|
>
|
|
1178
1211
|
<TouchableOpacity
|
|
1179
|
-
style={
|
|
1212
|
+
style={fileManagementStyles.fileContent}
|
|
1180
1213
|
onPress={() => handleFileOpen(file)}
|
|
1181
1214
|
>
|
|
1182
1215
|
{/* Preview Thumbnail */}
|
|
1183
|
-
<View style={
|
|
1216
|
+
<View style={fileManagementStyles.filePreviewContainer}>
|
|
1184
1217
|
{hasPreview ? (
|
|
1185
|
-
<View
|
|
1186
|
-
style={styles.filePreview}
|
|
1187
|
-
{...(Platform.OS === 'web' && {
|
|
1188
|
-
onMouseEnter: () => setHoveredPreview(file.id),
|
|
1189
|
-
onMouseLeave: () => setHoveredPreview(null),
|
|
1190
|
-
})}
|
|
1191
|
-
>
|
|
1218
|
+
<View style={fileManagementStyles.filePreview}>
|
|
1192
1219
|
{isImage && (
|
|
1193
1220
|
<ExpoImage
|
|
1194
|
-
source={{ uri:
|
|
1195
|
-
style={
|
|
1221
|
+
source={{ uri: getSafeDownloadUrlCallback(file, 'thumb') }}
|
|
1222
|
+
style={fileManagementStyles.previewImage}
|
|
1196
1223
|
contentFit="cover"
|
|
1197
1224
|
transition={120}
|
|
1198
1225
|
cachePolicy="memory-disk"
|
|
@@ -1203,16 +1230,16 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1203
1230
|
/>
|
|
1204
1231
|
)}
|
|
1205
1232
|
{isPDF && (
|
|
1206
|
-
<View style={
|
|
1233
|
+
<View style={fileManagementStyles.pdfPreview}>
|
|
1207
1234
|
<Ionicons name="document" size={32} color={themeStyles.primaryColor} />
|
|
1208
|
-
<Text style={[
|
|
1235
|
+
<Text style={[fileManagementStyles.pdfLabel, { color: themeStyles.primaryColor }]}>PDF</Text>
|
|
1209
1236
|
</View>
|
|
1210
1237
|
)}
|
|
1211
1238
|
{isVideo && (
|
|
1212
|
-
<View style={
|
|
1239
|
+
<View style={fileManagementStyles.videoPreviewWrapper}>
|
|
1213
1240
|
<ExpoImage
|
|
1214
|
-
source={{ uri:
|
|
1215
|
-
style={
|
|
1241
|
+
source={{ uri: getSafeDownloadUrlCallback(file, 'thumb') }}
|
|
1242
|
+
style={fileManagementStyles.videoPosterImage}
|
|
1216
1243
|
contentFit="cover"
|
|
1217
1244
|
transition={120}
|
|
1218
1245
|
cachePolicy="memory-disk"
|
|
@@ -1221,15 +1248,14 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1221
1248
|
}}
|
|
1222
1249
|
accessibilityLabel={file.filename + ' video thumbnail'}
|
|
1223
1250
|
/>
|
|
1224
|
-
<View style={
|
|
1251
|
+
<View style={fileManagementStyles.videoOverlay}>
|
|
1225
1252
|
<Ionicons name="play" size={24} color="#FFFFFF" />
|
|
1226
1253
|
</View>
|
|
1227
1254
|
</View>
|
|
1228
1255
|
)}
|
|
1229
1256
|
{/* Fallback icon (hidden by default for images) */}
|
|
1230
1257
|
<View
|
|
1231
|
-
style={[
|
|
1232
|
-
{...(Platform.OS === 'web' && { 'data-fallback': 'true' })}
|
|
1258
|
+
style={[fileManagementStyles.fallbackIcon, { display: isImage ? 'none' : 'flex' }]}
|
|
1233
1259
|
>
|
|
1234
1260
|
<Ionicons
|
|
1235
1261
|
name={getFileIcon(file.contentType) as any}
|
|
@@ -1238,20 +1264,14 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1238
1264
|
/>
|
|
1239
1265
|
</View>
|
|
1240
1266
|
|
|
1241
|
-
{/* Preview overlay for hover effect */}
|
|
1242
|
-
{!selectMode && Platform.OS === 'web' && hoveredPreview === file.id && isImage && (
|
|
1243
|
-
<View style={styles.previewOverlay}>
|
|
1244
|
-
<Ionicons name="eye" size={24} color="#FFFFFF" />
|
|
1245
|
-
</View>
|
|
1246
|
-
)}
|
|
1247
1267
|
{selectMode && (
|
|
1248
|
-
<View style={
|
|
1268
|
+
<View style={fileManagementStyles.selectionBadge}>
|
|
1249
1269
|
<Ionicons name={selectedIds.has(file.id) ? 'checkmark-circle' : 'ellipse-outline'} size={22} color={selectedIds.has(file.id) ? themeStyles.primaryColor : themeStyles.textColor} />
|
|
1250
1270
|
</View>
|
|
1251
1271
|
)}
|
|
1252
1272
|
</View>
|
|
1253
1273
|
) : (
|
|
1254
|
-
<View style={
|
|
1274
|
+
<View style={fileManagementStyles.fileIconContainer}>
|
|
1255
1275
|
<Ionicons
|
|
1256
1276
|
name={getFileIcon(file.contentType) as any}
|
|
1257
1277
|
size={32}
|
|
@@ -1261,16 +1281,16 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1261
1281
|
)}
|
|
1262
1282
|
</View>
|
|
1263
1283
|
|
|
1264
|
-
<View style={
|
|
1265
|
-
<Text style={[
|
|
1284
|
+
<View style={fileManagementStyles.fileInfo}>
|
|
1285
|
+
<Text style={[fileManagementStyles.fileName, { color: themeStyles.textColor }]} numberOfLines={1}>
|
|
1266
1286
|
{file.filename}
|
|
1267
1287
|
</Text>
|
|
1268
|
-
<Text style={[
|
|
1288
|
+
<Text style={[fileManagementStyles.fileDetails, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1269
1289
|
{formatFileSize(file.length)} • {new Date(file.uploadDate).toLocaleDateString()}
|
|
1270
1290
|
</Text>
|
|
1271
1291
|
{file.metadata?.description && (
|
|
1272
1292
|
<Text
|
|
1273
|
-
style={[
|
|
1293
|
+
style={[fileManagementStyles.fileDescription, { color: themeStyles.isDarkTheme ? '#AAAAAA' : '#888888' }]}
|
|
1274
1294
|
numberOfLines={2}
|
|
1275
1295
|
>
|
|
1276
1296
|
{file.metadata.description}
|
|
@@ -1280,11 +1300,11 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1280
1300
|
</TouchableOpacity>
|
|
1281
1301
|
|
|
1282
1302
|
{!selectMode && (
|
|
1283
|
-
<View style={
|
|
1303
|
+
<View style={fileManagementStyles.fileActions}>
|
|
1284
1304
|
{/* Preview button for supported files */}
|
|
1285
1305
|
{hasPreview && (
|
|
1286
1306
|
<TouchableOpacity
|
|
1287
|
-
style={[
|
|
1307
|
+
style={[fileManagementStyles.actionButton, { backgroundColor: themeStyles.isDarkTheme ? '#333333' : '#F0F0F0' }]}
|
|
1288
1308
|
onPress={() => handleFileOpen(file)}
|
|
1289
1309
|
>
|
|
1290
1310
|
<Ionicons name="eye" size={20} color={themeStyles.primaryColor} />
|
|
@@ -1292,7 +1312,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1292
1312
|
)}
|
|
1293
1313
|
|
|
1294
1314
|
<TouchableOpacity
|
|
1295
|
-
style={[
|
|
1315
|
+
style={[fileManagementStyles.actionButton, { backgroundColor: themeStyles.isDarkTheme ? '#333333' : '#F0F0F0' }]}
|
|
1296
1316
|
onPress={() => handleFileDownload(file.id, file.filename)}
|
|
1297
1317
|
>
|
|
1298
1318
|
<Ionicons name="download" size={20} color={themeStyles.primaryColor} />
|
|
@@ -1300,7 +1320,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1300
1320
|
|
|
1301
1321
|
{/* Always show delete button for debugging */}
|
|
1302
1322
|
<TouchableOpacity
|
|
1303
|
-
style={[
|
|
1323
|
+
style={[fileManagementStyles.actionButton, { backgroundColor: themeStyles.isDarkTheme ? '#400000' : '#FFEBEE' }]}
|
|
1304
1324
|
onPress={() => {
|
|
1305
1325
|
handleFileDelete(file.id, file.filename);
|
|
1306
1326
|
}}
|
|
@@ -1322,86 +1342,133 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1322
1342
|
const groupedFileItems = useMemo(() => {
|
|
1323
1343
|
// filteredFiles is already sorted, so just use it directly
|
|
1324
1344
|
const sortedFiles = filteredFiles;
|
|
1325
|
-
|
|
1345
|
+
|
|
1326
1346
|
// Store file positions for scrolling
|
|
1327
1347
|
sortedFiles.forEach((file, index) => {
|
|
1328
1348
|
itemRefs.current.set(file.id, index);
|
|
1329
1349
|
});
|
|
1330
|
-
|
|
1350
|
+
|
|
1331
1351
|
return sortedFiles.map((file) => {
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1352
|
+
const isImage = file.contentType.startsWith('image/');
|
|
1353
|
+
const isPDF = file.contentType.includes('pdf');
|
|
1354
|
+
const isVideo = file.contentType.startsWith('video/');
|
|
1355
|
+
const hasPreview = isImage || isPDF || isVideo;
|
|
1356
|
+
const isSelected = selectedIds.has(file.id);
|
|
1357
|
+
|
|
1358
|
+
// Create customIcon for preview thumbnails (36x36 to match GroupedItem iconContainer)
|
|
1359
|
+
let customIcon: React.ReactNode | undefined;
|
|
1360
|
+
if (hasPreview) {
|
|
1361
|
+
if (isImage) {
|
|
1362
|
+
customIcon = (
|
|
1363
|
+
<View style={{ width: 36, height: 36, borderRadius: 18, overflow: 'hidden' }}>
|
|
1364
|
+
<ExpoImage
|
|
1365
|
+
source={{ uri: getSafeDownloadUrlCallback(file, 'thumb') }}
|
|
1366
|
+
style={{ width: 36, height: 36 }}
|
|
1367
|
+
contentFit="cover"
|
|
1368
|
+
transition={120}
|
|
1369
|
+
cachePolicy="memory-disk"
|
|
1370
|
+
onError={() => {
|
|
1371
|
+
// Image preview failed to load - will fallback to icon
|
|
1372
|
+
}}
|
|
1373
|
+
accessibilityLabel={file.filename}
|
|
1374
|
+
/>
|
|
1375
|
+
</View>
|
|
1376
|
+
);
|
|
1377
|
+
} else if (isVideo) {
|
|
1378
|
+
customIcon = (
|
|
1379
|
+
<View style={{ width: 36, height: 36, borderRadius: 18, overflow: 'hidden', backgroundColor: '#000000', position: 'relative' }}>
|
|
1380
|
+
<ExpoImage
|
|
1381
|
+
source={{ uri: getSafeDownloadUrlCallback(file, 'thumb') }}
|
|
1382
|
+
style={{ width: 36, height: 36 }}
|
|
1383
|
+
contentFit="cover"
|
|
1384
|
+
transition={120}
|
|
1385
|
+
cachePolicy="memory-disk"
|
|
1386
|
+
onError={(_: any) => {
|
|
1387
|
+
// If thumbnail not available, we still show icon overlay
|
|
1388
|
+
}}
|
|
1389
|
+
accessibilityLabel={file.filename + ' video thumbnail'}
|
|
1390
|
+
/>
|
|
1391
|
+
<View style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, alignItems: 'center', justifyContent: 'center', backgroundColor: 'rgba(0,0,0,0.25)' }}>
|
|
1392
|
+
<Ionicons name="play" size={16} color="#FFFFFF" />
|
|
1393
|
+
</View>
|
|
1394
|
+
</View>
|
|
1395
|
+
);
|
|
1396
|
+
} else if (isPDF) {
|
|
1397
|
+
customIcon = (
|
|
1398
|
+
<View style={{ width: 36, height: 36, borderRadius: 18, alignItems: 'center', justifyContent: 'center', backgroundColor: '#FF6B6B20' }}>
|
|
1399
|
+
<Ionicons name="document" size={20} color={themeStyles.primaryColor} />
|
|
1400
|
+
</View>
|
|
1401
|
+
);
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
return {
|
|
1406
|
+
id: file.id,
|
|
1407
|
+
customIcon: customIcon,
|
|
1408
|
+
icon: !hasPreview ? getFileIcon(file.contentType) : undefined,
|
|
1409
|
+
iconColor: themeStyles.primaryColor,
|
|
1410
|
+
title: file.filename,
|
|
1411
|
+
subtitle: `${formatFileSize(file.length)} • ${new Date(file.uploadDate).toLocaleDateString()}`,
|
|
1412
|
+
theme: theme as 'light' | 'dark',
|
|
1413
|
+
onPress: () => {
|
|
1414
|
+
// Support selection in regular mode with long press or if already selecting
|
|
1415
|
+
if (!selectMode && selectedIds.size > 0) {
|
|
1416
|
+
// If already in selection mode (some files selected), toggle selection
|
|
1417
|
+
toggleSelect(file);
|
|
1418
|
+
} else {
|
|
1419
|
+
handleFileOpen(file);
|
|
1420
|
+
}
|
|
1421
|
+
},
|
|
1422
|
+
onLongPress: !selectMode ? () => {
|
|
1423
|
+
// Enable selection mode on long press
|
|
1424
|
+
if (selectedIds.size === 0) {
|
|
1425
|
+
setSelectedIds(new Set([file.id]));
|
|
1426
|
+
} else {
|
|
1427
|
+
toggleSelect(file);
|
|
1428
|
+
}
|
|
1429
|
+
} : undefined,
|
|
1430
|
+
showChevron: false,
|
|
1431
|
+
dense: true,
|
|
1432
|
+
multiRow: !!file.metadata?.description,
|
|
1433
|
+
selected: (selectMode || selectedIds.size > 0) && isSelected,
|
|
1434
|
+
// Hide action buttons when selecting (in selectMode or bulk operations mode)
|
|
1435
|
+
customContent: (!selectMode && selectedIds.size === 0) ? (
|
|
1436
|
+
<View style={fileManagementStyles.groupedActions}>
|
|
1437
|
+
{(isImage || isVideo || file.contentType.includes('pdf')) && (
|
|
1384
1438
|
<TouchableOpacity
|
|
1385
|
-
style={[
|
|
1386
|
-
onPress={() =>
|
|
1387
|
-
disabled={deleting === file.id}
|
|
1439
|
+
style={[fileManagementStyles.groupedActionBtn, { backgroundColor: themeStyles.isDarkTheme ? '#333333' : '#F0F0F0' }]}
|
|
1440
|
+
onPress={() => handleFileOpen(file)}
|
|
1388
1441
|
>
|
|
1389
|
-
{
|
|
1390
|
-
<ActivityIndicator size="small" color={themeStyles.dangerColor} />
|
|
1391
|
-
) : (
|
|
1392
|
-
<Ionicons name="trash" size={18} color={themeStyles.dangerColor} />
|
|
1393
|
-
)}
|
|
1442
|
+
<Ionicons name="eye" size={18} color={themeStyles.primaryColor} />
|
|
1394
1443
|
</TouchableOpacity>
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1444
|
+
)}
|
|
1445
|
+
<TouchableOpacity
|
|
1446
|
+
style={[fileManagementStyles.groupedActionBtn, { backgroundColor: themeStyles.isDarkTheme ? '#333333' : '#F0F0F0' }]}
|
|
1447
|
+
onPress={() => handleFileDownload(file.id, file.filename)}
|
|
1448
|
+
>
|
|
1449
|
+
<Ionicons name="download" size={18} color={themeStyles.primaryColor} />
|
|
1450
|
+
</TouchableOpacity>
|
|
1451
|
+
<TouchableOpacity
|
|
1452
|
+
style={[fileManagementStyles.groupedActionBtn, { backgroundColor: themeStyles.isDarkTheme ? '#400000' : '#FFEBEE' }]}
|
|
1453
|
+
onPress={() => handleFileDelete(file.id, file.filename)}
|
|
1454
|
+
disabled={deleting === file.id}
|
|
1455
|
+
>
|
|
1456
|
+
{deleting === file.id ? (
|
|
1457
|
+
<ActivityIndicator size="small" color={themeStyles.dangerColor} />
|
|
1458
|
+
) : (
|
|
1459
|
+
<Ionicons name="trash" size={18} color={themeStyles.dangerColor} />
|
|
1460
|
+
)}
|
|
1461
|
+
</TouchableOpacity>
|
|
1462
|
+
</View>
|
|
1463
|
+
) : undefined,
|
|
1464
|
+
customContentBelow: file.metadata?.description ? (
|
|
1465
|
+
<Text style={[fileManagementStyles.groupedDescription, { color: themeStyles.isDarkTheme ? '#AAAAAA' : '#666666' }]} numberOfLines={2}>
|
|
1466
|
+
{file.metadata.description}
|
|
1467
|
+
</Text>
|
|
1468
|
+
) : undefined,
|
|
1469
|
+
} as any;
|
|
1470
|
+
});
|
|
1471
|
+
}, [filteredFiles, theme, themeStyles, deleting, handleFileDownload, handleFileDelete, handleFileOpen, getSafeDownloadUrlCallback, selectMode, selectedIds]);
|
|
1405
1472
|
|
|
1406
1473
|
// Scroll to selected file after selection
|
|
1407
1474
|
useEffect(() => {
|
|
@@ -1409,7 +1476,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1409
1476
|
if (viewMode === 'all' && scrollViewRef.current) {
|
|
1410
1477
|
// Find the index of the selected file
|
|
1411
1478
|
const itemIndex = itemRefs.current.get(lastSelectedFileId);
|
|
1412
|
-
|
|
1479
|
+
|
|
1413
1480
|
if (itemIndex !== undefined && itemIndex >= 0) {
|
|
1414
1481
|
// Estimate item height (GroupedItem with dense mode is approximately 60-70px)
|
|
1415
1482
|
// Account for description rows which add extra height
|
|
@@ -1417,7 +1484,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1417
1484
|
const descriptionHeight = 30; // Approximate height for description
|
|
1418
1485
|
// Use filteredFiles which is already sorted according to user's selection
|
|
1419
1486
|
const sortedFiles = filteredFiles;
|
|
1420
|
-
|
|
1487
|
+
|
|
1421
1488
|
// Calculate total height up to this item
|
|
1422
1489
|
let scrollPosition = 0;
|
|
1423
1490
|
for (let i = 0; i <= itemIndex && i < sortedFiles.length; i++) {
|
|
@@ -1427,11 +1494,11 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1427
1494
|
scrollPosition += descriptionHeight;
|
|
1428
1495
|
}
|
|
1429
1496
|
}
|
|
1430
|
-
|
|
1497
|
+
|
|
1431
1498
|
// Add header, controls, search, and stats height (approximately 250px)
|
|
1432
1499
|
const headerHeight = 250;
|
|
1433
1500
|
const finalScrollPosition = headerHeight + scrollPosition - 150; // Offset to show item near top
|
|
1434
|
-
|
|
1501
|
+
|
|
1435
1502
|
// Use requestAnimationFrame to ensure DOM is updated before scrolling
|
|
1436
1503
|
requestAnimationFrame(() => {
|
|
1437
1504
|
requestAnimationFrame(() => {
|
|
@@ -1446,24 +1513,24 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1446
1513
|
// For photo grid, find the photo index
|
|
1447
1514
|
const photos = filteredFiles.filter(file => file.contentType.startsWith('image/'));
|
|
1448
1515
|
const photoIndex = photos.findIndex(p => p.id === lastSelectedFileId);
|
|
1449
|
-
|
|
1516
|
+
|
|
1450
1517
|
if (photoIndex >= 0) {
|
|
1451
1518
|
// Estimate photo item height based on grid layout
|
|
1452
1519
|
// Calculate items per row
|
|
1453
1520
|
let itemsPerRow = 3;
|
|
1454
|
-
if (
|
|
1455
|
-
else if (
|
|
1456
|
-
|
|
1521
|
+
if (safeContainerWidth > 768) itemsPerRow = 6;
|
|
1522
|
+
else if (safeContainerWidth > 480) itemsPerRow = 4;
|
|
1523
|
+
|
|
1457
1524
|
const scrollContainerPadding = 32;
|
|
1458
1525
|
const gaps = (itemsPerRow - 1) * 4;
|
|
1459
|
-
const availableWidth =
|
|
1526
|
+
const availableWidth = safeContainerWidth - scrollContainerPadding;
|
|
1460
1527
|
const itemWidth = (availableWidth - gaps) / itemsPerRow;
|
|
1461
|
-
|
|
1528
|
+
|
|
1462
1529
|
// Calculate row and approximate scroll position
|
|
1463
1530
|
const row = Math.floor(photoIndex / itemsPerRow);
|
|
1464
1531
|
const headerHeight = 250;
|
|
1465
1532
|
const finalScrollPosition = headerHeight + (row * (itemWidth + 4)) - 150;
|
|
1466
|
-
|
|
1533
|
+
|
|
1467
1534
|
// Use requestAnimationFrame to ensure DOM is updated before scrolling
|
|
1468
1535
|
requestAnimationFrame(() => {
|
|
1469
1536
|
requestAnimationFrame(() => {
|
|
@@ -1476,7 +1543,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1476
1543
|
}
|
|
1477
1544
|
}
|
|
1478
1545
|
}
|
|
1479
|
-
}, [lastSelectedFileId, selectMode, viewMode, filteredFiles,
|
|
1546
|
+
}, [lastSelectedFileId, selectMode, viewMode, filteredFiles, safeContainerWidth]);
|
|
1480
1547
|
|
|
1481
1548
|
// Clear selected file ID after scroll animation completes
|
|
1482
1549
|
useEffect(() => {
|
|
@@ -1484,30 +1551,30 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1484
1551
|
const timeoutId = setTimeout(() => {
|
|
1485
1552
|
setLastSelectedFileId(null);
|
|
1486
1553
|
}, 600); // Allow time for scroll animation to complete
|
|
1487
|
-
|
|
1554
|
+
|
|
1488
1555
|
return () => clearTimeout(timeoutId);
|
|
1489
1556
|
}
|
|
1490
1557
|
}, [lastSelectedFileId]);
|
|
1491
1558
|
|
|
1492
1559
|
const renderPhotoItem = (photo: FileMetadata, index: number) => {
|
|
1493
|
-
const downloadUrl =
|
|
1560
|
+
const downloadUrl = getSafeDownloadUrlCallback(photo, 'thumb');
|
|
1494
1561
|
|
|
1495
1562
|
// Calculate photo item width based on actual container size from bottom sheet
|
|
1496
1563
|
let itemsPerRow = 3; // Default for mobile
|
|
1497
|
-
if (
|
|
1498
|
-
else if (
|
|
1564
|
+
if (safeContainerWidth > 768) itemsPerRow = 6; // Tablet/Desktop
|
|
1565
|
+
else if (safeContainerWidth > 480) itemsPerRow = 4; // Large mobile
|
|
1499
1566
|
|
|
1500
1567
|
// Account for the photoScrollContainer padding (16px on each side = 32px total)
|
|
1501
1568
|
const scrollContainerPadding = 32; // Total horizontal padding from photoScrollContainer
|
|
1502
1569
|
const gaps = (itemsPerRow - 1) * 4; // Gap between items
|
|
1503
|
-
const availableWidth =
|
|
1570
|
+
const availableWidth = safeContainerWidth - scrollContainerPadding;
|
|
1504
1571
|
const itemWidth = (availableWidth - gaps) / itemsPerRow;
|
|
1505
1572
|
|
|
1506
1573
|
return (
|
|
1507
1574
|
<TouchableOpacity
|
|
1508
1575
|
key={photo.id}
|
|
1509
1576
|
style={[
|
|
1510
|
-
|
|
1577
|
+
fileManagementStyles.photoItem,
|
|
1511
1578
|
{
|
|
1512
1579
|
width: itemWidth,
|
|
1513
1580
|
height: itemWidth,
|
|
@@ -1516,10 +1583,10 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1516
1583
|
onPress={() => handleFileOpen(photo)}
|
|
1517
1584
|
activeOpacity={0.8}
|
|
1518
1585
|
>
|
|
1519
|
-
<View style={
|
|
1586
|
+
<View style={fileManagementStyles.photoContainer}>
|
|
1520
1587
|
<ExpoImage
|
|
1521
1588
|
source={{ uri: downloadUrl }}
|
|
1522
|
-
style={
|
|
1589
|
+
style={fileManagementStyles.photoImage}
|
|
1523
1590
|
contentFit="cover"
|
|
1524
1591
|
transition={120}
|
|
1525
1592
|
cachePolicy="memory-disk"
|
|
@@ -1538,26 +1605,28 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1538
1605
|
|
|
1539
1606
|
if (photos.length === 0) {
|
|
1540
1607
|
return (
|
|
1541
|
-
<View style={
|
|
1608
|
+
<View style={fileManagementStyles.emptyState}>
|
|
1542
1609
|
<Ionicons name="images-outline" size={64} color={themeStyles.isDarkTheme ? '#666666' : '#CCCCCC'} />
|
|
1543
|
-
<Text style={[
|
|
1544
|
-
<Text style={[
|
|
1610
|
+
<Text style={[fileManagementStyles.emptyStateTitle, { color: themeStyles.textColor }]}>No Photos Yet</Text>
|
|
1611
|
+
<Text style={[fileManagementStyles.emptyStateDescription, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}> {
|
|
1545
1612
|
user?.id === targetUserId
|
|
1546
|
-
? `Upload photos to get started. You can select multiple photos at once
|
|
1613
|
+
? `Upload photos to get started. You can select multiple photos at once.`
|
|
1547
1614
|
: "This user hasn't uploaded any photos yet"
|
|
1548
1615
|
} </Text>
|
|
1549
1616
|
{user?.id === targetUserId && (
|
|
1550
1617
|
<TouchableOpacity
|
|
1551
|
-
style={[
|
|
1618
|
+
style={[fileManagementStyles.emptyStateButton, { backgroundColor: themeStyles.primaryColor }]}
|
|
1552
1619
|
onPress={handleFileUpload}
|
|
1553
|
-
disabled={uploading}
|
|
1620
|
+
disabled={uploading || isPickingDocument}
|
|
1554
1621
|
>
|
|
1555
1622
|
{uploading ? (
|
|
1556
1623
|
<ActivityIndicator size="small" color="#FFFFFF" />
|
|
1624
|
+
) : isPickingDocument ? (
|
|
1625
|
+
<ActivityIndicator size="small" color="#FFFFFF" />
|
|
1557
1626
|
) : (
|
|
1558
1627
|
<>
|
|
1559
1628
|
<Ionicons name="cloud-upload" size={20} color="#FFFFFF" />
|
|
1560
|
-
<Text style={
|
|
1629
|
+
<Text style={fileManagementStyles.emptyStateButtonText}>Upload Photos</Text>
|
|
1561
1630
|
</>
|
|
1562
1631
|
)}
|
|
1563
1632
|
</TouchableOpacity>
|
|
@@ -1569,8 +1638,8 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1569
1638
|
return (
|
|
1570
1639
|
<ScrollView
|
|
1571
1640
|
ref={photoScrollViewRef}
|
|
1572
|
-
style={
|
|
1573
|
-
contentContainerStyle={
|
|
1641
|
+
style={fileManagementStyles.scrollView}
|
|
1642
|
+
contentContainerStyle={fileManagementStyles.photoScrollContainer}
|
|
1574
1643
|
refreshControl={
|
|
1575
1644
|
<RefreshControl
|
|
1576
1645
|
refreshing={refreshing}
|
|
@@ -1589,9 +1658,9 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1589
1658
|
scrollEventThrottle={250}
|
|
1590
1659
|
>
|
|
1591
1660
|
{loadingDimensions && (
|
|
1592
|
-
<View style={
|
|
1661
|
+
<View style={fileManagementStyles.dimensionsLoadingIndicator}>
|
|
1593
1662
|
<ActivityIndicator size="small" color={themeStyles.primaryColor} />
|
|
1594
|
-
<Text style={[
|
|
1663
|
+
<Text style={[fileManagementStyles.dimensionsLoadingText, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>Loading photo layout...</Text>
|
|
1595
1664
|
</View>
|
|
1596
1665
|
)}
|
|
1597
1666
|
|
|
@@ -1603,7 +1672,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1603
1672
|
renderJustifiedPhotoItem={renderJustifiedPhotoItem}
|
|
1604
1673
|
renderSimplePhotoItem={renderPhotoItem}
|
|
1605
1674
|
textColor={themeStyles.textColor}
|
|
1606
|
-
containerWidth={
|
|
1675
|
+
containerWidth={safeContainerWidth}
|
|
1607
1676
|
/>
|
|
1608
1677
|
</ScrollView>
|
|
1609
1678
|
);
|
|
@@ -1622,417 +1691,37 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1622
1691
|
createJustifiedRows,
|
|
1623
1692
|
renderJustifiedPhotoItem,
|
|
1624
1693
|
renderPhotoItem,
|
|
1625
|
-
|
|
1694
|
+
safeContainerWidth
|
|
1626
1695
|
]);
|
|
1627
1696
|
|
|
1628
1697
|
// Inline justified grid removed (moved to components/photogrid/JustifiedPhotoGrid.tsx)
|
|
1629
1698
|
|
|
1630
|
-
const renderFileDetailsModal = () => {
|
|
1631
|
-
const backgroundColor = themeStyles.backgroundColor;
|
|
1632
|
-
const borderColor = themeStyles.borderColor;
|
|
1633
|
-
|
|
1634
|
-
return (
|
|
1635
|
-
<Modal
|
|
1636
|
-
visible={showFileDetails}
|
|
1637
|
-
animationType="slide"
|
|
1638
|
-
presentationStyle="pageSheet"
|
|
1639
|
-
onRequestClose={() => setShowFileDetails(false)}
|
|
1640
|
-
>
|
|
1641
|
-
<View style={[styles.modalContainer, { backgroundColor }]}>
|
|
1642
|
-
<View style={[styles.modalHeader, { borderBottomColor: borderColor }]}>
|
|
1643
|
-
<TouchableOpacity
|
|
1644
|
-
style={styles.modalCloseButton}
|
|
1645
|
-
onPress={() => setShowFileDetails(false)}
|
|
1646
|
-
>
|
|
1647
|
-
<Ionicons name="close" size={24} color={themeStyles.textColor} />
|
|
1648
|
-
</TouchableOpacity>
|
|
1649
|
-
<Text style={[styles.modalTitle, { color: themeStyles.textColor }]}>File Details</Text>
|
|
1650
|
-
<View style={styles.modalPlaceholder} />
|
|
1651
|
-
</View>
|
|
1652
|
-
|
|
1653
|
-
{selectedFile && (
|
|
1654
|
-
<ScrollView style={styles.modalContent}>
|
|
1655
|
-
<View style={[styles.fileDetailCard, { backgroundColor: themeStyles.secondaryBackgroundColor, borderColor }]}>
|
|
1656
|
-
<View style={styles.fileDetailIcon}>
|
|
1657
|
-
<Ionicons
|
|
1658
|
-
name={getFileIcon(selectedFile.contentType) as any}
|
|
1659
|
-
size={64}
|
|
1660
|
-
color={themeStyles.primaryColor}
|
|
1661
|
-
/>
|
|
1662
|
-
</View>
|
|
1663
|
-
|
|
1664
|
-
<Text style={[styles.fileDetailName, { color: themeStyles.textColor }]}>
|
|
1665
|
-
{selectedFile.filename}
|
|
1666
|
-
</Text>
|
|
1667
|
-
|
|
1668
|
-
<View style={styles.fileDetailInfo}>
|
|
1669
|
-
<View style={styles.detailRow}>
|
|
1670
|
-
<Text style={[styles.detailLabel, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1671
|
-
Size:
|
|
1672
|
-
</Text>
|
|
1673
|
-
<Text style={[styles.detailValue, { color: themeStyles.textColor }]}>
|
|
1674
|
-
{formatFileSize(selectedFile.length)}
|
|
1675
|
-
</Text>
|
|
1676
|
-
</View>
|
|
1677
|
-
|
|
1678
|
-
<View style={styles.detailRow}>
|
|
1679
|
-
<Text style={[styles.detailLabel, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1680
|
-
Type:
|
|
1681
|
-
</Text>
|
|
1682
|
-
<Text style={[styles.detailValue, { color: themeStyles.textColor }]}>
|
|
1683
|
-
{selectedFile.contentType}
|
|
1684
|
-
</Text>
|
|
1685
|
-
</View>
|
|
1686
|
-
|
|
1687
|
-
<View style={styles.detailRow}>
|
|
1688
|
-
<Text style={[styles.detailLabel, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1689
|
-
Uploaded:
|
|
1690
|
-
</Text>
|
|
1691
|
-
<Text style={[styles.detailValue, { color: themeStyles.textColor }]}>
|
|
1692
|
-
{new Date(selectedFile.uploadDate).toLocaleString()}
|
|
1693
|
-
</Text>
|
|
1694
|
-
</View>
|
|
1695
|
-
|
|
1696
|
-
{selectedFile.metadata?.description && (
|
|
1697
|
-
<View style={styles.detailRow}>
|
|
1698
|
-
<Text style={[styles.detailLabel, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1699
|
-
Description:
|
|
1700
|
-
</Text>
|
|
1701
|
-
<Text style={[styles.detailValue, { color: themeStyles.textColor }]}>
|
|
1702
|
-
{selectedFile.metadata.description}
|
|
1703
|
-
</Text>
|
|
1704
|
-
</View>
|
|
1705
|
-
)}
|
|
1706
|
-
</View>
|
|
1707
|
-
|
|
1708
|
-
<View style={styles.modalActions}>
|
|
1709
|
-
<TouchableOpacity
|
|
1710
|
-
style={[styles.modalActionButton, { backgroundColor: themeStyles.primaryColor }]}
|
|
1711
|
-
onPress={() => {
|
|
1712
|
-
handleFileDownload(selectedFile.id, selectedFile.filename);
|
|
1713
|
-
setShowFileDetails(false);
|
|
1714
|
-
}}
|
|
1715
|
-
>
|
|
1716
|
-
<Ionicons name="download" size={20} color="#FFFFFF" />
|
|
1717
|
-
<Text style={styles.modalActionText}>Download</Text>
|
|
1718
|
-
</TouchableOpacity>
|
|
1719
|
-
|
|
1720
|
-
{(user?.id === targetUserId) && (
|
|
1721
|
-
<TouchableOpacity
|
|
1722
|
-
style={[styles.modalActionButton, { backgroundColor: themeStyles.dangerColor }]}
|
|
1723
|
-
onPress={() => {
|
|
1724
|
-
setShowFileDetails(false);
|
|
1725
|
-
handleFileDelete(selectedFile.id, selectedFile.filename);
|
|
1726
|
-
}}
|
|
1727
|
-
>
|
|
1728
|
-
<Ionicons name="trash" size={20} color="#FFFFFF" />
|
|
1729
|
-
<Text style={styles.modalActionText}>Delete</Text>
|
|
1730
|
-
</TouchableOpacity>
|
|
1731
|
-
)}
|
|
1732
|
-
</View>
|
|
1733
|
-
</View>
|
|
1734
|
-
</ScrollView>
|
|
1735
|
-
)}
|
|
1736
|
-
</View>
|
|
1737
|
-
</Modal>
|
|
1738
|
-
);
|
|
1739
|
-
};
|
|
1740
|
-
|
|
1741
|
-
const renderFileViewer = () => {
|
|
1742
|
-
if (!openedFile) return null;
|
|
1743
|
-
|
|
1744
|
-
const backgroundColor = themeStyles.backgroundColor;
|
|
1745
|
-
const borderColor = themeStyles.borderColor;
|
|
1746
|
-
|
|
1747
|
-
const isImage = openedFile.contentType.startsWith('image/');
|
|
1748
|
-
const isText = openedFile.contentType.startsWith('text/') ||
|
|
1749
|
-
openedFile.contentType.includes('json') ||
|
|
1750
|
-
openedFile.contentType.includes('xml') ||
|
|
1751
|
-
openedFile.contentType.includes('javascript') ||
|
|
1752
|
-
openedFile.contentType.includes('typescript');
|
|
1753
|
-
const isPDF = openedFile.contentType.includes('pdf');
|
|
1754
|
-
const isVideo = openedFile.contentType.startsWith('video/');
|
|
1755
|
-
const isAudio = openedFile.contentType.startsWith('audio/');
|
|
1756
|
-
|
|
1757
|
-
return (
|
|
1758
|
-
<View style={[styles.fileViewerContainer, { backgroundColor }]}>
|
|
1759
|
-
{/* File Viewer Header */}
|
|
1760
|
-
<View style={[styles.fileViewerHeader, { borderBottomColor: borderColor }]}>
|
|
1761
|
-
<TouchableOpacity
|
|
1762
|
-
style={styles.backButton}
|
|
1763
|
-
onPress={handleCloseFile}
|
|
1764
|
-
>
|
|
1765
|
-
<Ionicons name="arrow-back" size={24} color={themeStyles.textColor} />
|
|
1766
|
-
</TouchableOpacity>
|
|
1767
|
-
<View style={styles.fileViewerTitleContainer}>
|
|
1768
|
-
<Text style={[styles.fileViewerTitle, { color: themeStyles.textColor }]} numberOfLines={1}>
|
|
1769
|
-
{openedFile.filename}
|
|
1770
|
-
</Text>
|
|
1771
|
-
<Text style={[styles.fileViewerSubtitle, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1772
|
-
{formatFileSize(openedFile.length)} • {openedFile.contentType}
|
|
1773
|
-
</Text>
|
|
1774
|
-
</View>
|
|
1775
|
-
<View style={styles.fileViewerActions}>
|
|
1776
|
-
<TouchableOpacity
|
|
1777
|
-
style={[styles.actionButton, { backgroundColor: themeStyles.isDarkTheme ? '#333333' : '#F0F0F0' }]}
|
|
1778
|
-
onPress={() => handleFileDownload(openedFile.id, openedFile.filename)}
|
|
1779
|
-
>
|
|
1780
|
-
<Ionicons name="download" size={20} color={themeStyles.primaryColor} />
|
|
1781
|
-
</TouchableOpacity>
|
|
1782
|
-
<TouchableOpacity
|
|
1783
|
-
style={[
|
|
1784
|
-
styles.actionButton,
|
|
1785
|
-
{
|
|
1786
|
-
backgroundColor: showFileDetailsInViewer
|
|
1787
|
-
? themeStyles.primaryColor
|
|
1788
|
-
: (themeStyles.isDarkTheme ? '#333333' : '#F0F0F0')
|
|
1789
|
-
}
|
|
1790
|
-
]}
|
|
1791
|
-
onPress={() => setShowFileDetailsInViewer(!showFileDetailsInViewer)}
|
|
1792
|
-
>
|
|
1793
|
-
<Ionicons
|
|
1794
|
-
name={showFileDetailsInViewer ? "chevron-up" : "information-circle"}
|
|
1795
|
-
size={20}
|
|
1796
|
-
color={showFileDetailsInViewer ? "#FFFFFF" : themeStyles.primaryColor}
|
|
1797
|
-
/>
|
|
1798
|
-
</TouchableOpacity>
|
|
1799
|
-
</View>
|
|
1800
|
-
</View>
|
|
1801
|
-
|
|
1802
|
-
{/* File Details Section */}
|
|
1803
|
-
{showFileDetailsInViewer && (
|
|
1804
|
-
<View style={[styles.fileDetailsSection, { backgroundColor: themeStyles.secondaryBackgroundColor, borderColor }]}>
|
|
1805
|
-
<View style={styles.fileDetailsSectionHeader}>
|
|
1806
|
-
<Text style={[styles.fileDetailsSectionTitle, { color: themeStyles.textColor }]}>
|
|
1807
|
-
File Details
|
|
1808
|
-
</Text>
|
|
1809
|
-
<TouchableOpacity
|
|
1810
|
-
style={styles.fileDetailsSectionToggle}
|
|
1811
|
-
onPress={() => setShowFileDetailsInViewer(false)}
|
|
1812
|
-
>
|
|
1813
|
-
<Ionicons name="chevron-up" size={20} color={themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'} />
|
|
1814
|
-
</TouchableOpacity>
|
|
1815
|
-
</View>
|
|
1816
|
-
|
|
1817
|
-
<View style={styles.fileDetailInfo}>
|
|
1818
|
-
<View style={styles.detailRow}>
|
|
1819
|
-
<Text style={[styles.detailLabel, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1820
|
-
File Name:
|
|
1821
|
-
</Text>
|
|
1822
|
-
<Text style={[styles.detailValue, { color: themeStyles.textColor }]}>
|
|
1823
|
-
{openedFile.filename}
|
|
1824
|
-
</Text>
|
|
1825
|
-
</View>
|
|
1826
|
-
|
|
1827
|
-
<View style={styles.detailRow}>
|
|
1828
|
-
<Text style={[styles.detailLabel, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1829
|
-
Size:
|
|
1830
|
-
</Text>
|
|
1831
|
-
<Text style={[styles.detailValue, { color: themeStyles.textColor }]}>
|
|
1832
|
-
{formatFileSize(openedFile.length)}
|
|
1833
|
-
</Text>
|
|
1834
|
-
</View>
|
|
1835
|
-
|
|
1836
|
-
<View style={styles.detailRow}>
|
|
1837
|
-
<Text style={[styles.detailLabel, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1838
|
-
Type:
|
|
1839
|
-
</Text>
|
|
1840
|
-
<Text style={[styles.detailValue, { color: themeStyles.textColor }]}>
|
|
1841
|
-
{openedFile.contentType}
|
|
1842
|
-
</Text>
|
|
1843
|
-
</View>
|
|
1844
|
-
|
|
1845
|
-
<View style={styles.detailRow}>
|
|
1846
|
-
<Text style={[styles.detailLabel, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1847
|
-
Uploaded:
|
|
1848
|
-
</Text>
|
|
1849
|
-
<Text style={[styles.detailValue, { color: themeStyles.textColor }]}>
|
|
1850
|
-
{new Date(openedFile.uploadDate).toLocaleString()}
|
|
1851
|
-
</Text>
|
|
1852
|
-
</View>
|
|
1853
|
-
|
|
1854
|
-
{openedFile.metadata?.description && (
|
|
1855
|
-
<View style={styles.detailRow}>
|
|
1856
|
-
<Text style={[styles.detailLabel, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1857
|
-
Description:
|
|
1858
|
-
</Text>
|
|
1859
|
-
<Text style={[styles.detailValue, { color: themeStyles.textColor }]}>
|
|
1860
|
-
{openedFile.metadata.description}
|
|
1861
|
-
</Text>
|
|
1862
|
-
</View>
|
|
1863
|
-
)}
|
|
1864
|
-
|
|
1865
|
-
<View style={styles.detailRow}>
|
|
1866
|
-
<Text style={[styles.detailLabel, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1867
|
-
File ID:
|
|
1868
|
-
</Text>
|
|
1869
|
-
<Text style={[styles.detailValue, { color: themeStyles.textColor, fontSize: 12, fontFamily: Platform.OS === 'web' ? 'monospace' : 'Courier' }]}>
|
|
1870
|
-
{openedFile.id}
|
|
1871
|
-
</Text>
|
|
1872
|
-
</View>
|
|
1873
|
-
</View>
|
|
1874
|
-
|
|
1875
|
-
<View style={styles.fileDetailsActions}>
|
|
1876
|
-
<TouchableOpacity
|
|
1877
|
-
style={[styles.fileDetailsActionButton, { backgroundColor: themeStyles.primaryColor }]}
|
|
1878
|
-
onPress={() => handleFileDownload(openedFile.id, openedFile.filename)}
|
|
1879
|
-
>
|
|
1880
|
-
<Ionicons name="download" size={16} color="#FFFFFF" />
|
|
1881
|
-
<Text style={styles.fileDetailsActionText}>Download</Text>
|
|
1882
|
-
</TouchableOpacity>
|
|
1883
|
-
|
|
1884
|
-
{(user?.id === targetUserId) && (
|
|
1885
|
-
<TouchableOpacity
|
|
1886
|
-
style={[styles.fileDetailsActionButton, { backgroundColor: themeStyles.dangerColor }]}
|
|
1887
|
-
onPress={() => {
|
|
1888
|
-
handleCloseFile();
|
|
1889
|
-
handleFileDelete(openedFile.id, openedFile.filename);
|
|
1890
|
-
}}
|
|
1891
|
-
>
|
|
1892
|
-
<Ionicons name="trash" size={16} color="#FFFFFF" />
|
|
1893
|
-
<Text style={styles.fileDetailsActionText}>Delete</Text>
|
|
1894
|
-
</TouchableOpacity>
|
|
1895
|
-
)}
|
|
1896
|
-
</View>
|
|
1897
|
-
</View>
|
|
1898
|
-
)}
|
|
1899
1699
|
|
|
1900
|
-
{/* File Content */}
|
|
1901
|
-
<ScrollView
|
|
1902
|
-
style={[
|
|
1903
|
-
styles.fileViewerContent,
|
|
1904
|
-
showFileDetailsInViewer && styles.fileViewerContentWithDetails
|
|
1905
|
-
]}
|
|
1906
|
-
contentContainerStyle={styles.fileViewerContentContainer}
|
|
1907
|
-
>
|
|
1908
|
-
{loadingFileContent ? (
|
|
1909
|
-
<View style={styles.fileViewerLoading}>
|
|
1910
|
-
<ActivityIndicator size="large" color={themeStyles.primaryColor} />
|
|
1911
|
-
<Text style={[styles.fileViewerLoadingText, { color: themeStyles.textColor }]}>
|
|
1912
|
-
Loading file content...
|
|
1913
|
-
</Text>
|
|
1914
|
-
</View>
|
|
1915
|
-
) : isImage && fileContent ? (
|
|
1916
|
-
<View style={styles.imageContainer}>
|
|
1917
|
-
<ExpoImage
|
|
1918
|
-
source={{ uri: fileContent }}
|
|
1919
|
-
style={{ width: '100%', height: 400, borderRadius: 8 }}
|
|
1920
|
-
contentFit="contain"
|
|
1921
|
-
transition={120}
|
|
1922
|
-
cachePolicy="memory-disk"
|
|
1923
|
-
onError={() => {
|
|
1924
|
-
// Image failed to load
|
|
1925
|
-
}}
|
|
1926
|
-
accessibilityLabel={openedFile.filename}
|
|
1927
|
-
/>
|
|
1928
|
-
</View>
|
|
1929
|
-
) : isText && fileContent ? (
|
|
1930
|
-
<View style={[styles.textContainer, { backgroundColor: themeStyles.secondaryBackgroundColor, borderColor }]}>
|
|
1931
|
-
<ScrollView style={{ flex: 1 }} nestedScrollEnabled>
|
|
1932
|
-
<Text style={[styles.textContent, { color: themeStyles.textColor }]}>
|
|
1933
|
-
{fileContent}
|
|
1934
|
-
</Text>
|
|
1935
|
-
</ScrollView>
|
|
1936
|
-
</View>
|
|
1937
|
-
) : isPDF && fileContent && Platform.OS === 'web' ? (
|
|
1938
|
-
<View style={styles.pdfContainer}>
|
|
1939
|
-
<iframe
|
|
1940
|
-
src={fileContent}
|
|
1941
|
-
width="100%"
|
|
1942
|
-
height="600px"
|
|
1943
|
-
style={{ border: 'none', borderRadius: 8 }}
|
|
1944
|
-
title={openedFile.filename}
|
|
1945
|
-
/>
|
|
1946
|
-
</View>
|
|
1947
|
-
) : isVideo && fileContent ? (
|
|
1948
|
-
<View style={styles.mediaContainer}>
|
|
1949
|
-
{Platform.OS === 'web' ? (
|
|
1950
|
-
<video
|
|
1951
|
-
controls
|
|
1952
|
-
style={{
|
|
1953
|
-
width: '100%',
|
|
1954
|
-
maxHeight: '70vh',
|
|
1955
|
-
borderRadius: 8,
|
|
1956
|
-
}}
|
|
1957
|
-
>
|
|
1958
|
-
<source src={fileContent} type={openedFile.contentType} />
|
|
1959
|
-
Your browser does not support the video tag.
|
|
1960
|
-
</video>
|
|
1961
|
-
) : (
|
|
1962
|
-
<Text style={[styles.unsupportedText, { color: themeStyles.textColor }]}>
|
|
1963
|
-
Video playback not supported on mobile
|
|
1964
|
-
</Text>
|
|
1965
|
-
)}
|
|
1966
|
-
</View>
|
|
1967
|
-
) : isAudio && fileContent ? (
|
|
1968
|
-
<View style={styles.mediaContainer}>
|
|
1969
|
-
{Platform.OS === 'web' ? (
|
|
1970
|
-
<audio
|
|
1971
|
-
controls
|
|
1972
|
-
style={{
|
|
1973
|
-
width: '100%',
|
|
1974
|
-
borderRadius: 8,
|
|
1975
|
-
}}
|
|
1976
|
-
>
|
|
1977
|
-
<source src={fileContent} type={openedFile.contentType} />
|
|
1978
|
-
Your browser does not support the audio tag.
|
|
1979
|
-
</audio>
|
|
1980
|
-
) : (
|
|
1981
|
-
<Text style={[styles.unsupportedText, { color: themeStyles.textColor }]}>
|
|
1982
|
-
Audio playback not supported on mobile
|
|
1983
|
-
</Text>
|
|
1984
|
-
)}
|
|
1985
|
-
</View>
|
|
1986
|
-
) : (
|
|
1987
|
-
<View style={styles.unsupportedFileContainer}>
|
|
1988
|
-
<Ionicons
|
|
1989
|
-
name={getFileIcon(openedFile.contentType) as any}
|
|
1990
|
-
size={64}
|
|
1991
|
-
color={themeStyles.isDarkTheme ? '#666666' : '#CCCCCC'}
|
|
1992
|
-
/>
|
|
1993
|
-
<Text style={[styles.unsupportedFileTitle, { color: themeStyles.textColor }]}>
|
|
1994
|
-
Preview Not Available
|
|
1995
|
-
</Text>
|
|
1996
|
-
<Text style={[styles.unsupportedFileDescription, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
1997
|
-
This file type cannot be previewed in the browser.{'\n'}
|
|
1998
|
-
Download the file to view its contents.
|
|
1999
|
-
</Text>
|
|
2000
|
-
<TouchableOpacity
|
|
2001
|
-
style={[styles.downloadButtonLarge, { backgroundColor: themeStyles.primaryColor }]}
|
|
2002
|
-
onPress={() => handleFileDownload(openedFile.id, openedFile.filename)}
|
|
2003
|
-
>
|
|
2004
|
-
<Ionicons name="download" size={20} color="#FFFFFF" />
|
|
2005
|
-
<Text style={styles.downloadButtonText}>Download File</Text>
|
|
2006
|
-
</TouchableOpacity>
|
|
2007
|
-
</View>
|
|
2008
|
-
)}
|
|
2009
|
-
</ScrollView>
|
|
2010
|
-
</View>
|
|
2011
|
-
);
|
|
2012
|
-
};
|
|
2013
1700
|
|
|
2014
1701
|
const renderEmptyState = () => (
|
|
2015
|
-
<View style={
|
|
1702
|
+
<View style={fileManagementStyles.emptyState}>
|
|
2016
1703
|
<Ionicons name="folder-open-outline" size={64} color={themeStyles.isDarkTheme ? '#666666' : '#CCCCCC'} />
|
|
2017
|
-
<Text style={[
|
|
2018
|
-
<Text style={[
|
|
1704
|
+
<Text style={[fileManagementStyles.emptyStateTitle, { color: themeStyles.textColor }]}>No Files Yet</Text>
|
|
1705
|
+
<Text style={[fileManagementStyles.emptyStateDescription, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
2019
1706
|
{user?.id === targetUserId
|
|
2020
|
-
? `Upload files to get started. You can select multiple files at once
|
|
1707
|
+
? `Upload files to get started. You can select multiple files at once.`
|
|
2021
1708
|
: "This user hasn't uploaded any files yet"
|
|
2022
1709
|
}
|
|
2023
1710
|
</Text>
|
|
2024
1711
|
{user?.id === targetUserId && (
|
|
2025
1712
|
<TouchableOpacity
|
|
2026
|
-
style={[
|
|
1713
|
+
style={[fileManagementStyles.emptyStateButton, { backgroundColor: themeStyles.primaryColor }]}
|
|
2027
1714
|
onPress={handleFileUpload}
|
|
2028
|
-
disabled={uploading}
|
|
1715
|
+
disabled={uploading || isPickingDocument}
|
|
2029
1716
|
>
|
|
2030
1717
|
{uploading ? (
|
|
2031
1718
|
<ActivityIndicator size="small" color="#FFFFFF" />
|
|
1719
|
+
) : isPickingDocument ? (
|
|
1720
|
+
<ActivityIndicator size="small" color="#FFFFFF" />
|
|
2032
1721
|
) : (
|
|
2033
1722
|
<>
|
|
2034
1723
|
<Ionicons name="cloud-upload" size={20} color="#FFFFFF" />
|
|
2035
|
-
<Text style={
|
|
1724
|
+
<Text style={fileManagementStyles.emptyStateButtonText}>Upload Files</Text>
|
|
2036
1725
|
</>
|
|
2037
1726
|
)}
|
|
2038
1727
|
</TouchableOpacity>
|
|
@@ -2043,7 +1732,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2043
1732
|
// Professional Skeleton Loading Component with Advanced Shimmer Effect
|
|
2044
1733
|
const SkeletonLoader = React.memo(() => {
|
|
2045
1734
|
const shimmerAnim = useRef(new Animated.Value(0)).current;
|
|
2046
|
-
const skeletonContainerWidth =
|
|
1735
|
+
const skeletonContainerWidth = safeContainerWidth;
|
|
2047
1736
|
|
|
2048
1737
|
useEffect(() => {
|
|
2049
1738
|
const shimmer = Animated.loop(
|
|
@@ -2070,7 +1759,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2070
1759
|
outputRange: [-skeletonContainerWidth * 2 + delay, skeletonContainerWidth * 2 + delay],
|
|
2071
1760
|
});
|
|
2072
1761
|
|
|
2073
|
-
|
|
1762
|
+
return (
|
|
2074
1763
|
<View
|
|
2075
1764
|
style={[
|
|
2076
1765
|
{
|
|
@@ -2110,8 +1799,8 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2110
1799
|
style={{
|
|
2111
1800
|
width: skeletonContainerWidth,
|
|
2112
1801
|
height: '100%',
|
|
2113
|
-
backgroundColor: themeStyles.isDarkTheme
|
|
2114
|
-
? 'rgba(255, 255, 255, 0.08)'
|
|
1802
|
+
backgroundColor: themeStyles.isDarkTheme
|
|
1803
|
+
? 'rgba(255, 255, 255, 0.08)'
|
|
2115
1804
|
: 'rgba(255, 255, 255, 0.8)',
|
|
2116
1805
|
shadowColor: themeStyles.isDarkTheme ? '#000' : '#FFF',
|
|
2117
1806
|
shadowOffset: { width: 0, height: 0 },
|
|
@@ -2120,8 +1809,8 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2120
1809
|
}}
|
|
2121
1810
|
/>
|
|
2122
1811
|
</Animated.View>
|
|
2123
|
-
|
|
2124
|
-
|
|
1812
|
+
</View>
|
|
1813
|
+
);
|
|
2125
1814
|
};
|
|
2126
1815
|
|
|
2127
1816
|
// Skeleton file item matching GroupedSection structure
|
|
@@ -2141,18 +1830,18 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2141
1830
|
>
|
|
2142
1831
|
{/* Icon/Image skeleton */}
|
|
2143
1832
|
<SkeletonBox width={44} height={44} borderRadius={8} delay={index * 50} />
|
|
2144
|
-
|
|
1833
|
+
|
|
2145
1834
|
{/* Content skeleton */}
|
|
2146
1835
|
<View style={{ flex: 1, marginLeft: 12, justifyContent: 'center' }}>
|
|
2147
|
-
<SkeletonBox
|
|
2148
|
-
width={index % 3 === 0 ? '85%' : index % 3 === 1 ? '70%' : '90%'}
|
|
2149
|
-
height={16}
|
|
2150
|
-
style={{ marginBottom: 8 }}
|
|
1836
|
+
<SkeletonBox
|
|
1837
|
+
width={index % 3 === 0 ? '85%' : index % 3 === 1 ? '70%' : '90%'}
|
|
1838
|
+
height={16}
|
|
1839
|
+
style={{ marginBottom: 8 }}
|
|
2151
1840
|
delay={index * 50 + 20}
|
|
2152
1841
|
/>
|
|
2153
|
-
<SkeletonBox
|
|
2154
|
-
width={index % 2 === 0 ? '50%' : '60%'}
|
|
2155
|
-
height={12}
|
|
1842
|
+
<SkeletonBox
|
|
1843
|
+
width={index % 2 === 0 ? '50%' : '60%'}
|
|
1844
|
+
height={12}
|
|
2156
1845
|
delay={index * 50 + 40}
|
|
2157
1846
|
/>
|
|
2158
1847
|
</View>
|
|
@@ -2160,11 +1849,11 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2160
1849
|
);
|
|
2161
1850
|
|
|
2162
1851
|
return (
|
|
2163
|
-
<View style={[
|
|
1852
|
+
<View style={[fileManagementStyles.container, { backgroundColor }]}>
|
|
2164
1853
|
{/* Header Skeleton */}
|
|
2165
|
-
<View style={[
|
|
1854
|
+
<View style={[fileManagementStyles.header, { borderBottomColor: themeStyles.borderColor, borderBottomWidth: StyleSheet.hairlineWidth }]}>
|
|
2166
1855
|
<SkeletonBox width={44} height={44} borderRadius={12} />
|
|
2167
|
-
<View style={[
|
|
1856
|
+
<View style={[fileManagementStyles.headerTitleContainer, { flex: 1 }]}>
|
|
2168
1857
|
<SkeletonBox width={140} height={20} style={{ marginBottom: 6 }} />
|
|
2169
1858
|
<SkeletonBox width={100} height={14} />
|
|
2170
1859
|
</View>
|
|
@@ -2172,28 +1861,24 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2172
1861
|
</View>
|
|
2173
1862
|
|
|
2174
1863
|
{/* Controls Bar Skeleton */}
|
|
2175
|
-
<View style={
|
|
1864
|
+
<View style={fileManagementStyles.controlsBar}>
|
|
2176
1865
|
<SkeletonBox width={100} height={36} borderRadius={18} />
|
|
2177
1866
|
<SkeletonBox width={44} height={44} borderRadius={22} />
|
|
2178
1867
|
</View>
|
|
2179
1868
|
|
|
2180
1869
|
{/* Search Bar Skeleton */}
|
|
2181
|
-
<View style={[
|
|
2182
|
-
backgroundColor: themeStyles.
|
|
2183
|
-
borderColor: themeStyles.borderColor,
|
|
2184
|
-
borderWidth: StyleSheet.hairlineWidth,
|
|
1870
|
+
<View style={[fileManagementStyles.searchContainer, {
|
|
1871
|
+
backgroundColor: themeStyles.colors.card,
|
|
2185
1872
|
}]}>
|
|
2186
1873
|
<SkeletonBox width="100%" height={44} borderRadius={12} />
|
|
2187
1874
|
</View>
|
|
2188
1875
|
|
|
2189
1876
|
{/* Stats Container Skeleton */}
|
|
2190
|
-
<View style={[
|
|
2191
|
-
backgroundColor: themeStyles.
|
|
2192
|
-
borderColor: themeStyles.borderColor,
|
|
2193
|
-
borderWidth: StyleSheet.hairlineWidth,
|
|
1877
|
+
<View style={[fileManagementStyles.statsContainer, {
|
|
1878
|
+
backgroundColor: themeStyles.colors.card,
|
|
2194
1879
|
}]}>
|
|
2195
1880
|
{[1, 2, 3].map((i) => (
|
|
2196
|
-
<View key={i} style={
|
|
1881
|
+
<View key={i} style={fileManagementStyles.statItem}>
|
|
2197
1882
|
<SkeletonBox width={50} height={20} style={{ marginBottom: 4 }} delay={i * 30} />
|
|
2198
1883
|
<SkeletonBox width={40} height={14} delay={i * 30 + 15} />
|
|
2199
1884
|
</View>
|
|
@@ -2201,16 +1886,15 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2201
1886
|
</View>
|
|
2202
1887
|
|
|
2203
1888
|
{/* File List Skeleton - Matching GroupedSection */}
|
|
2204
|
-
<ScrollView
|
|
2205
|
-
style={
|
|
2206
|
-
contentContainerStyle={
|
|
1889
|
+
<ScrollView
|
|
1890
|
+
style={fileManagementStyles.scrollView}
|
|
1891
|
+
contentContainerStyle={fileManagementStyles.scrollContainer}
|
|
2207
1892
|
showsVerticalScrollIndicator={false}
|
|
2208
1893
|
>
|
|
2209
1894
|
<View style={{
|
|
2210
|
-
backgroundColor: themeStyles.
|
|
2211
|
-
borderRadius:
|
|
1895
|
+
backgroundColor: themeStyles.colors.card,
|
|
1896
|
+
borderRadius: 18,
|
|
2212
1897
|
overflow: 'hidden',
|
|
2213
|
-
marginHorizontal: 16,
|
|
2214
1898
|
marginTop: 8,
|
|
2215
1899
|
}}>
|
|
2216
1900
|
{[1, 2, 3, 4, 5, 6, 7, 8].map((i) => (
|
|
@@ -2230,20 +1914,59 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2230
1914
|
if (!selectMode && openedFile) {
|
|
2231
1915
|
return (
|
|
2232
1916
|
<>
|
|
2233
|
-
|
|
2234
|
-
|
|
1917
|
+
<FileViewer
|
|
1918
|
+
file={openedFile}
|
|
1919
|
+
fileContent={fileContent}
|
|
1920
|
+
loadingFileContent={loadingFileContent}
|
|
1921
|
+
showFileDetailsInViewer={showFileDetailsInViewer}
|
|
1922
|
+
onToggleDetails={() => setShowFileDetailsInViewer(!showFileDetailsInViewer)}
|
|
1923
|
+
onClose={handleCloseFile}
|
|
1924
|
+
onDownload={handleFileDownload}
|
|
1925
|
+
onDelete={handleFileDelete}
|
|
1926
|
+
themeStyles={themeStyles}
|
|
1927
|
+
isOwner={user?.id === targetUserId}
|
|
1928
|
+
/>
|
|
1929
|
+
<FileDetailsModal
|
|
1930
|
+
visible={showFileDetails}
|
|
1931
|
+
file={selectedFile}
|
|
1932
|
+
onClose={() => setShowFileDetails(false)}
|
|
1933
|
+
onDownload={handleFileDownload}
|
|
1934
|
+
onDelete={handleFileDelete}
|
|
1935
|
+
themeStyles={themeStyles}
|
|
1936
|
+
isOwner={user?.id === targetUserId}
|
|
1937
|
+
/>
|
|
2235
1938
|
</>
|
|
2236
1939
|
);
|
|
2237
1940
|
}
|
|
2238
1941
|
|
|
1942
|
+
// If upload preview is showing, render it inline instead of the file list
|
|
1943
|
+
if (showUploadPreview) {
|
|
1944
|
+
return (
|
|
1945
|
+
<View style={fileManagementStyles.container}>
|
|
1946
|
+
<Header
|
|
1947
|
+
title="Review Files"
|
|
1948
|
+
subtitle={`${pendingFiles.length} file${pendingFiles.length !== 1 ? 's' : ''} ready to upload`}
|
|
1949
|
+
onBack={handleCancelUpload}
|
|
1950
|
+
showBackButton
|
|
1951
|
+
variant="minimal"
|
|
1952
|
+
elevation="none"
|
|
1953
|
+
titleAlignment="left"
|
|
1954
|
+
/>
|
|
1955
|
+
<UploadPreview
|
|
1956
|
+
visible={true}
|
|
1957
|
+
pendingFiles={pendingFiles}
|
|
1958
|
+
onConfirm={handleConfirmUpload}
|
|
1959
|
+
onCancel={handleCancelUpload}
|
|
1960
|
+
onRemoveFile={removePendingFile}
|
|
1961
|
+
themeStyles={themeStyles}
|
|
1962
|
+
inline={true}
|
|
1963
|
+
/>
|
|
1964
|
+
</View>
|
|
1965
|
+
);
|
|
1966
|
+
}
|
|
1967
|
+
|
|
2239
1968
|
return (
|
|
2240
|
-
<View
|
|
2241
|
-
ref={containerRef}
|
|
2242
|
-
style={[
|
|
2243
|
-
styles.container,
|
|
2244
|
-
isDragging && Platform.OS === 'web' && styles.dragOverlay
|
|
2245
|
-
]}
|
|
2246
|
-
>
|
|
1969
|
+
<View style={fileManagementStyles.container}>
|
|
2247
1970
|
<Header
|
|
2248
1971
|
title={selectMode ? (multiSelect ? `${selectedIds.size}${maxSelection ? '/' + maxSelection : ''} Selected` : 'Select a File') : (viewMode === 'photos' ? 'Photos' : 'File Management')}
|
|
2249
1972
|
subtitle={selectMode ? (multiSelect ? `${filteredFiles.length} available` : 'Tap to select') : `${filteredFiles.length} ${filteredFiles.length === 1 ? 'item' : 'items'}`}
|
|
@@ -2292,98 +2015,70 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2292
2015
|
}
|
|
2293
2016
|
] : undefined}
|
|
2294
2017
|
onBack={onClose || goBack}
|
|
2295
|
-
|
|
2018
|
+
|
|
2296
2019
|
showBackButton
|
|
2297
2020
|
variant="minimal"
|
|
2298
2021
|
elevation="none"
|
|
2299
2022
|
titleAlignment="left"
|
|
2300
2023
|
/>
|
|
2301
2024
|
|
|
2302
|
-
<View style={
|
|
2303
|
-
<ScrollView
|
|
2304
|
-
horizontal
|
|
2025
|
+
<View style={fileManagementStyles.controlsBar}>
|
|
2026
|
+
<ScrollView
|
|
2027
|
+
horizontal
|
|
2305
2028
|
showsHorizontalScrollIndicator={false}
|
|
2306
|
-
style={
|
|
2029
|
+
style={fileManagementStyles.viewModeScroll}
|
|
2307
2030
|
>
|
|
2308
2031
|
<View style={[
|
|
2309
|
-
|
|
2032
|
+
fileManagementStyles.viewModeToggle,
|
|
2310
2033
|
{
|
|
2311
|
-
backgroundColor: themeStyles.
|
|
2312
|
-
borderWidth: 1,
|
|
2313
|
-
borderColor: themeStyles.isDarkTheme ? '#2A2A2A' : '#E8E9EA',
|
|
2034
|
+
backgroundColor: themeStyles.colors.card,
|
|
2314
2035
|
}
|
|
2315
2036
|
]}>
|
|
2316
|
-
<
|
|
2317
|
-
|
|
2318
|
-
styles.viewModeButton,
|
|
2319
|
-
viewMode === 'all' && { backgroundColor: themeStyles.primaryColor }
|
|
2320
|
-
]}
|
|
2037
|
+
<AnimatedButton
|
|
2038
|
+
isSelected={viewMode === 'all'}
|
|
2321
2039
|
onPress={() => setViewMode('all')}
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
<TouchableOpacity
|
|
2330
|
-
style={[
|
|
2331
|
-
styles.viewModeButton,
|
|
2332
|
-
viewMode === 'photos' && { backgroundColor: themeStyles.primaryColor }
|
|
2333
|
-
]}
|
|
2040
|
+
icon={viewMode === 'all' ? 'folder' : 'folder-outline'}
|
|
2041
|
+
primaryColor={themeStyles.primaryColor}
|
|
2042
|
+
textColor={themeStyles.textColor}
|
|
2043
|
+
style={fileManagementStyles.viewModeButton}
|
|
2044
|
+
/>
|
|
2045
|
+
<AnimatedButton
|
|
2046
|
+
isSelected={viewMode === 'photos'}
|
|
2334
2047
|
onPress={() => setViewMode('photos')}
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
<TouchableOpacity
|
|
2343
|
-
style={[
|
|
2344
|
-
styles.viewModeButton,
|
|
2345
|
-
viewMode === 'videos' && { backgroundColor: themeStyles.primaryColor }
|
|
2346
|
-
]}
|
|
2048
|
+
icon={viewMode === 'photos' ? 'image-multiple' : 'image-multiple-outline'}
|
|
2049
|
+
primaryColor={themeStyles.primaryColor}
|
|
2050
|
+
textColor={themeStyles.textColor}
|
|
2051
|
+
style={fileManagementStyles.viewModeButton}
|
|
2052
|
+
/>
|
|
2053
|
+
<AnimatedButton
|
|
2054
|
+
isSelected={viewMode === 'videos'}
|
|
2347
2055
|
onPress={() => setViewMode('videos')}
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
<TouchableOpacity
|
|
2356
|
-
style={[
|
|
2357
|
-
styles.viewModeButton,
|
|
2358
|
-
viewMode === 'documents' && { backgroundColor: themeStyles.primaryColor }
|
|
2359
|
-
]}
|
|
2056
|
+
icon={viewMode === 'videos' ? 'video' : 'video-outline'}
|
|
2057
|
+
primaryColor={themeStyles.primaryColor}
|
|
2058
|
+
textColor={themeStyles.textColor}
|
|
2059
|
+
style={fileManagementStyles.viewModeButton}
|
|
2060
|
+
/>
|
|
2061
|
+
<AnimatedButton
|
|
2062
|
+
isSelected={viewMode === 'documents'}
|
|
2360
2063
|
onPress={() => setViewMode('documents')}
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
<TouchableOpacity
|
|
2369
|
-
style={[
|
|
2370
|
-
styles.viewModeButton,
|
|
2371
|
-
viewMode === 'audio' && { backgroundColor: themeStyles.primaryColor }
|
|
2372
|
-
]}
|
|
2064
|
+
icon={viewMode === 'documents' ? 'file-document' : 'file-document-outline'}
|
|
2065
|
+
primaryColor={themeStyles.primaryColor}
|
|
2066
|
+
textColor={themeStyles.textColor}
|
|
2067
|
+
style={fileManagementStyles.viewModeButton}
|
|
2068
|
+
/>
|
|
2069
|
+
<AnimatedButton
|
|
2070
|
+
isSelected={viewMode === 'audio'}
|
|
2373
2071
|
onPress={() => setViewMode('audio')}
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
/>
|
|
2380
|
-
</TouchableOpacity>
|
|
2072
|
+
icon={viewMode === 'audio' ? 'music-note' : 'music-note-outline'}
|
|
2073
|
+
primaryColor={themeStyles.primaryColor}
|
|
2074
|
+
textColor={themeStyles.textColor}
|
|
2075
|
+
style={fileManagementStyles.viewModeButton}
|
|
2076
|
+
/>
|
|
2381
2077
|
</View>
|
|
2382
2078
|
</ScrollView>
|
|
2383
2079
|
<TouchableOpacity
|
|
2384
|
-
style={[
|
|
2385
|
-
backgroundColor: themeStyles.
|
|
2386
|
-
borderColor: themeStyles.isDarkTheme ? '#2A2A2A' : '#E8E9EA',
|
|
2080
|
+
style={[fileManagementStyles.sortButton, {
|
|
2081
|
+
backgroundColor: themeStyles.colors.card,
|
|
2387
2082
|
}]}
|
|
2388
2083
|
onPress={() => {
|
|
2389
2084
|
// Cycle through sort options: date -> size -> name -> type -> date
|
|
@@ -2397,37 +2092,38 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2397
2092
|
}
|
|
2398
2093
|
}}
|
|
2399
2094
|
>
|
|
2400
|
-
<
|
|
2401
|
-
name={sortOrder === 'asc' ? 'arrow-up' : 'arrow-down'}
|
|
2402
|
-
size={18}
|
|
2403
|
-
color={themeStyles.textColor}
|
|
2404
|
-
/>
|
|
2405
|
-
<Ionicons
|
|
2095
|
+
<MaterialCommunityIcons
|
|
2406
2096
|
name={
|
|
2407
2097
|
sortBy === 'date' ? 'calendar' :
|
|
2408
|
-
|
|
2409
|
-
|
|
2098
|
+
sortBy === 'size' ? 'sort-numeric-variant' :
|
|
2099
|
+
sortBy === 'name' ? 'sort-alphabetical-variant' : 'file-document-outline'
|
|
2410
2100
|
}
|
|
2411
2101
|
size={16}
|
|
2412
2102
|
color={themeStyles.textColor}
|
|
2413
|
-
|
|
2103
|
+
/>
|
|
2104
|
+
<MaterialCommunityIcons
|
|
2105
|
+
name={sortOrder === 'asc' ? 'arrow-up' : 'arrow-down'}
|
|
2106
|
+
size={14}
|
|
2107
|
+
color={themeStyles.colors.secondaryText}
|
|
2414
2108
|
/>
|
|
2415
2109
|
</TouchableOpacity>
|
|
2416
2110
|
{user?.id === targetUserId && (!selectMode || (selectMode && allowUploadInSelectMode)) && (
|
|
2417
2111
|
<TouchableOpacity
|
|
2418
|
-
style={[
|
|
2112
|
+
style={[fileManagementStyles.uploadButton, { backgroundColor: themeStyles.primaryColor }]}
|
|
2419
2113
|
onPress={handleFileUpload}
|
|
2420
|
-
disabled={uploading}
|
|
2114
|
+
disabled={uploading || isPickingDocument}
|
|
2421
2115
|
>
|
|
2422
2116
|
{uploading ? (
|
|
2423
|
-
<View style={
|
|
2117
|
+
<View style={fileManagementStyles.uploadProgress}>
|
|
2424
2118
|
<ActivityIndicator size="small" color="#FFFFFF" />
|
|
2425
2119
|
{uploadProgress && (
|
|
2426
|
-
<Text style={
|
|
2120
|
+
<Text style={fileManagementStyles.uploadProgressText}>
|
|
2427
2121
|
{uploadProgress.current}/{uploadProgress.total}
|
|
2428
2122
|
</Text>
|
|
2429
2123
|
)}
|
|
2430
2124
|
</View>
|
|
2125
|
+
) : isPickingDocument ? (
|
|
2126
|
+
<ActivityIndicator size="small" color="#FFFFFF" />
|
|
2431
2127
|
) : (
|
|
2432
2128
|
<Ionicons name="add" size={22} color="#FFFFFF" />
|
|
2433
2129
|
)}
|
|
@@ -2438,26 +2134,25 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2438
2134
|
{/* Search Bar */}
|
|
2439
2135
|
{files.length > 0 && (viewMode === 'all' || files.some(f => f.contentType.startsWith('image/'))) && (
|
|
2440
2136
|
<View style={[
|
|
2441
|
-
|
|
2137
|
+
fileManagementStyles.searchContainer,
|
|
2442
2138
|
{
|
|
2443
|
-
backgroundColor: themeStyles.
|
|
2444
|
-
borderColor: themeStyles.isDarkTheme ? '#3A3A3A' : '#E8E9EA',
|
|
2139
|
+
backgroundColor: themeStyles.colors.card,
|
|
2445
2140
|
}
|
|
2446
2141
|
]}>
|
|
2447
|
-
<Ionicons name="search" size={22} color={themeStyles.
|
|
2142
|
+
<Ionicons name="search" size={22} color={themeStyles.colors.icon} />
|
|
2448
2143
|
<TextInput
|
|
2449
|
-
style={[
|
|
2144
|
+
style={[fileManagementStyles.searchInput, { color: themeStyles.textColor }]}
|
|
2450
2145
|
placeholder={viewMode === 'photos' ? 'Search photos...' : 'Search files...'}
|
|
2451
|
-
placeholderTextColor={themeStyles.
|
|
2146
|
+
placeholderTextColor={themeStyles.colors.secondaryText}
|
|
2452
2147
|
value={searchQuery}
|
|
2453
2148
|
onChangeText={setSearchQuery}
|
|
2454
2149
|
/>
|
|
2455
2150
|
{searchQuery.length > 0 && (
|
|
2456
2151
|
<TouchableOpacity
|
|
2457
2152
|
onPress={() => setSearchQuery('')}
|
|
2458
|
-
style={
|
|
2153
|
+
style={fileManagementStyles.searchClearButton}
|
|
2459
2154
|
>
|
|
2460
|
-
<Ionicons name="close-circle" size={22} color={themeStyles.
|
|
2155
|
+
<Ionicons name="close-circle" size={22} color={themeStyles.colors.icon} />
|
|
2461
2156
|
</TouchableOpacity>
|
|
2462
2157
|
)}
|
|
2463
2158
|
</View>
|
|
@@ -2466,30 +2161,29 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2466
2161
|
{/* File Stats */}
|
|
2467
2162
|
{files.length > 0 && (
|
|
2468
2163
|
<View style={[
|
|
2469
|
-
|
|
2164
|
+
fileManagementStyles.statsContainer,
|
|
2470
2165
|
{
|
|
2471
|
-
backgroundColor: themeStyles.
|
|
2472
|
-
borderColor: themeStyles.isDarkTheme ? '#3A3A3A' : '#E8E9EA',
|
|
2166
|
+
backgroundColor: themeStyles.colors.card,
|
|
2473
2167
|
}
|
|
2474
2168
|
]}>
|
|
2475
|
-
<View style={
|
|
2476
|
-
<Text style={[
|
|
2477
|
-
<Text style={[
|
|
2169
|
+
<View style={fileManagementStyles.statItem}>
|
|
2170
|
+
<Text style={[fileManagementStyles.statValue, { color: themeStyles.textColor }]}>{filteredFiles.length}</Text>
|
|
2171
|
+
<Text style={[fileManagementStyles.statLabel, { color: themeStyles.colors.secondaryText }]}>
|
|
2478
2172
|
{searchQuery.length > 0 ? 'Found' : (filteredFiles.length === 1 ? (viewMode === 'photos' ? 'Photo' : 'File') : (viewMode === 'photos' ? 'Photos' : 'Files'))}
|
|
2479
2173
|
</Text>
|
|
2480
2174
|
</View>
|
|
2481
|
-
<View style={
|
|
2482
|
-
<Text style={[
|
|
2175
|
+
<View style={fileManagementStyles.statItem}>
|
|
2176
|
+
<Text style={[fileManagementStyles.statValue, { color: themeStyles.textColor }]}>
|
|
2483
2177
|
{formatFileSize(filteredFiles.reduce((total, file) => total + file.length, 0))}
|
|
2484
2178
|
</Text>
|
|
2485
|
-
<Text style={[
|
|
2179
|
+
<Text style={[fileManagementStyles.statLabel, { color: themeStyles.colors.secondaryText }]}>
|
|
2486
2180
|
{searchQuery.length > 0 ? 'Size' : 'Total Size'}
|
|
2487
2181
|
</Text>
|
|
2488
2182
|
</View>
|
|
2489
2183
|
{searchQuery.length > 0 && (
|
|
2490
|
-
<View style={
|
|
2491
|
-
<Text style={[
|
|
2492
|
-
<Text style={[
|
|
2184
|
+
<View style={fileManagementStyles.statItem}>
|
|
2185
|
+
<Text style={[fileManagementStyles.statValue, { color: themeStyles.textColor }]}>{files.length}</Text>
|
|
2186
|
+
<Text style={[fileManagementStyles.statLabel, { color: themeStyles.colors.secondaryText }]}>
|
|
2493
2187
|
Total
|
|
2494
2188
|
</Text>
|
|
2495
2189
|
</View>
|
|
@@ -2503,8 +2197,8 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2503
2197
|
) : (
|
|
2504
2198
|
<ScrollView
|
|
2505
2199
|
ref={scrollViewRef}
|
|
2506
|
-
style={
|
|
2507
|
-
contentContainerStyle={
|
|
2200
|
+
style={fileManagementStyles.scrollView}
|
|
2201
|
+
contentContainerStyle={fileManagementStyles.scrollContainer}
|
|
2508
2202
|
refreshControl={
|
|
2509
2203
|
<RefreshControl
|
|
2510
2204
|
refreshing={refreshing}
|
|
@@ -2522,27 +2216,27 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2522
2216
|
scrollEventThrottle={250}
|
|
2523
2217
|
>
|
|
2524
2218
|
{filteredFiles.length === 0 && searchQuery.length > 0 ? (
|
|
2525
|
-
<View style={
|
|
2219
|
+
<View style={fileManagementStyles.emptyState}>
|
|
2526
2220
|
<Ionicons name="search" size={64} color={themeStyles.isDarkTheme ? '#666666' : '#CCCCCC'} />
|
|
2527
|
-
<Text style={[
|
|
2528
|
-
<Text style={[
|
|
2221
|
+
<Text style={[fileManagementStyles.emptyStateTitle, { color: themeStyles.textColor }]}>No Results Found</Text>
|
|
2222
|
+
<Text style={[fileManagementStyles.emptyStateDescription, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
2529
2223
|
No files match your search for "{searchQuery}"
|
|
2530
2224
|
</Text>
|
|
2531
2225
|
<TouchableOpacity
|
|
2532
|
-
style={[
|
|
2226
|
+
style={[fileManagementStyles.emptyStateButton, { backgroundColor: themeStyles.primaryColor }]}
|
|
2533
2227
|
onPress={() => setSearchQuery('')}
|
|
2534
2228
|
>
|
|
2535
2229
|
<Ionicons name="refresh" size={20} color="#FFFFFF" />
|
|
2536
|
-
<Text style={
|
|
2230
|
+
<Text style={fileManagementStyles.emptyStateButtonText}>Clear Search</Text>
|
|
2537
2231
|
</TouchableOpacity>
|
|
2538
2232
|
</View>
|
|
2539
2233
|
) : filteredFiles.length === 0 ? renderEmptyState() : (
|
|
2540
2234
|
<>
|
|
2541
|
-
<GroupedSection items={groupedFileItems}
|
|
2235
|
+
<GroupedSection items={groupedFileItems} />
|
|
2542
2236
|
{paging.loadingMore && (
|
|
2543
|
-
<View style={
|
|
2237
|
+
<View style={fileManagementStyles.loadingMoreBar}>
|
|
2544
2238
|
<ActivityIndicator size="small" color={themeStyles.primaryColor} />
|
|
2545
|
-
<Text style={[
|
|
2239
|
+
<Text style={[fileManagementStyles.loadingMoreText, { color: themeStyles.textColor }]}>Loading more...</Text>
|
|
2546
2240
|
</View>
|
|
2547
2241
|
)}
|
|
2548
2242
|
</>
|
|
@@ -2550,1008 +2244,52 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
2550
2244
|
</ScrollView>
|
|
2551
2245
|
)}
|
|
2552
2246
|
|
|
2553
|
-
{!selectMode &&
|
|
2247
|
+
{!selectMode && (
|
|
2248
|
+
<FileDetailsModal
|
|
2249
|
+
visible={showFileDetails}
|
|
2250
|
+
file={selectedFile}
|
|
2251
|
+
onClose={() => setShowFileDetails(false)}
|
|
2252
|
+
onDownload={handleFileDownload}
|
|
2253
|
+
onDelete={handleFileDelete}
|
|
2254
|
+
themeStyles={themeStyles}
|
|
2255
|
+
isOwner={user?.id === targetUserId}
|
|
2256
|
+
/>
|
|
2257
|
+
)}
|
|
2554
2258
|
|
|
2555
|
-
{/* Uploading banner overlay */}
|
|
2259
|
+
{/* Uploading banner overlay with progress */}
|
|
2556
2260
|
{!selectMode && uploading && (
|
|
2557
|
-
<View style={[
|
|
2558
|
-
<View style={[
|
|
2261
|
+
<View style={[fileManagementStyles.uploadBannerContainer, { pointerEvents: 'none' }]}>
|
|
2262
|
+
<View style={[fileManagementStyles.uploadBanner, { backgroundColor: themeStyles.isDarkTheme ? '#222831EE' : '#FFFFFFEE', borderColor: themeStyles.borderColor }]}>
|
|
2559
2263
|
<Ionicons name="cloud-upload" size={18} color={themeStyles.primaryColor} />
|
|
2560
|
-
<
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2264
|
+
<View style={fileManagementStyles.uploadBannerContent}>
|
|
2265
|
+
<Text style={[fileManagementStyles.uploadBannerText, { color: themeStyles.textColor }]}>
|
|
2266
|
+
Uploading{uploadProgress ? ` ${uploadProgress.current}/${uploadProgress.total}` : '...'}
|
|
2267
|
+
</Text>
|
|
2268
|
+
{uploadProgress && uploadProgress.total > 0 && (
|
|
2269
|
+
<View style={[fileManagementStyles.uploadProgressBarContainer, { backgroundColor: themeStyles.isDarkTheme ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)' }]}>
|
|
2270
|
+
<View
|
|
2271
|
+
style={[
|
|
2272
|
+
fileManagementStyles.uploadProgressBar,
|
|
2273
|
+
{
|
|
2274
|
+
width: `${(uploadProgress.current / uploadProgress.total) * 100}%`,
|
|
2275
|
+
backgroundColor: themeStyles.primaryColor
|
|
2276
|
+
}
|
|
2277
|
+
]}
|
|
2278
|
+
/>
|
|
2279
|
+
</View>
|
|
2280
|
+
)}
|
|
2565
2281
|
</View>
|
|
2282
|
+
<ActivityIndicator size="small" color={themeStyles.primaryColor} />
|
|
2566
2283
|
</View>
|
|
2567
2284
|
</View>
|
|
2568
2285
|
)}
|
|
2569
2286
|
|
|
2570
2287
|
{/* Selection bar removed; actions are now in header */}
|
|
2571
2288
|
{/* Global loadingMore bar removed; now inline in scroll areas */}
|
|
2572
|
-
|
|
2573
|
-
{/* Drag and Drop Overlay - Enhanced */}
|
|
2574
|
-
{isDragging && Platform.OS === 'web' && (
|
|
2575
|
-
<View style={styles.dragDropOverlay}>
|
|
2576
|
-
<View style={[styles.dragDropContent, {
|
|
2577
|
-
backgroundColor: themeStyles.isDarkTheme ? 'rgba(30, 30, 30, 0.98)' : 'rgba(255, 255, 255, 0.98)',
|
|
2578
|
-
borderColor: themeStyles.primaryColor,
|
|
2579
|
-
}]}>
|
|
2580
|
-
<View style={[styles.dragDropIconContainer, { backgroundColor: `${themeStyles.primaryColor}15` }]}>
|
|
2581
|
-
<Ionicons name="cloud-upload" size={64} color={themeStyles.primaryColor} />
|
|
2582
|
-
</View>
|
|
2583
|
-
<Text style={[styles.dragDropTitle, { color: themeStyles.primaryColor }]}>
|
|
2584
|
-
Drop files to upload
|
|
2585
|
-
</Text>
|
|
2586
|
-
<Text style={[styles.dragDropSubtitle, { color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666' }]}>
|
|
2587
|
-
Release to upload multiple files
|
|
2588
|
-
</Text>
|
|
2589
|
-
</View>
|
|
2590
|
-
</View>
|
|
2591
|
-
)}
|
|
2592
2289
|
</View>
|
|
2593
2290
|
);
|
|
2594
2291
|
};
|
|
2595
2292
|
|
|
2596
|
-
|
|
2597
|
-
container: {
|
|
2598
|
-
flex: 1,
|
|
2599
|
-
},
|
|
2600
|
-
selectionBadge: {
|
|
2601
|
-
position: 'absolute',
|
|
2602
|
-
top: 4,
|
|
2603
|
-
right: 4,
|
|
2604
|
-
backgroundColor: 'rgba(0,0,0,0.4)',
|
|
2605
|
-
borderRadius: 12,
|
|
2606
|
-
padding: 2,
|
|
2607
|
-
},
|
|
2608
|
-
selectionBar: {
|
|
2609
|
-
position: 'absolute',
|
|
2610
|
-
left: 0,
|
|
2611
|
-
right: 0,
|
|
2612
|
-
bottom: 0,
|
|
2613
|
-
flexDirection: 'row',
|
|
2614
|
-
justifyContent: 'space-between',
|
|
2615
|
-
padding: 12,
|
|
2616
|
-
backgroundColor: 'rgba(0,0,0,0.55)',
|
|
2617
|
-
gap: 12,
|
|
2618
|
-
},
|
|
2619
|
-
selectionBarButton: {
|
|
2620
|
-
flex: 1,
|
|
2621
|
-
paddingVertical: 14,
|
|
2622
|
-
borderRadius: 10,
|
|
2623
|
-
alignItems: 'center',
|
|
2624
|
-
justifyContent: 'center',
|
|
2625
|
-
},
|
|
2626
|
-
selectionBarButtonText: {
|
|
2627
|
-
color: '#FFFFFF',
|
|
2628
|
-
fontSize: 15,
|
|
2629
|
-
fontWeight: '600',
|
|
2630
|
-
},
|
|
2631
|
-
loadingMoreBar: {
|
|
2632
|
-
flexDirection: 'row',
|
|
2633
|
-
alignItems: 'center',
|
|
2634
|
-
justifyContent: 'center',
|
|
2635
|
-
paddingVertical: 12,
|
|
2636
|
-
gap: 8,
|
|
2637
|
-
},
|
|
2638
|
-
loadingMoreText: {
|
|
2639
|
-
fontSize: 13,
|
|
2640
|
-
fontWeight: '500',
|
|
2641
|
-
},
|
|
2642
|
-
dragOverlay: {
|
|
2643
|
-
backgroundColor: 'rgba(0, 122, 255, 0.06)',
|
|
2644
|
-
borderWidth: 1,
|
|
2645
|
-
borderColor: '#66AFFF',
|
|
2646
|
-
borderStyle: 'dashed',
|
|
2647
|
-
},
|
|
2648
|
-
centerContent: {
|
|
2649
|
-
justifyContent: 'center',
|
|
2650
|
-
alignItems: 'center',
|
|
2651
|
-
},
|
|
2652
|
-
header: {
|
|
2653
|
-
flexDirection: 'row',
|
|
2654
|
-
alignItems: 'center',
|
|
2655
|
-
justifyContent: 'space-between',
|
|
2656
|
-
paddingHorizontal: 16,
|
|
2657
|
-
paddingVertical: 12,
|
|
2658
|
-
borderBottomWidth: 1,
|
|
2659
|
-
position: 'relative',
|
|
2660
|
-
},
|
|
2661
|
-
backButton: {
|
|
2662
|
-
padding: 12,
|
|
2663
|
-
borderRadius: 12,
|
|
2664
|
-
alignItems: 'center',
|
|
2665
|
-
justifyContent: 'center',
|
|
2666
|
-
minWidth: 44,
|
|
2667
|
-
minHeight: 44,
|
|
2668
|
-
},
|
|
2669
|
-
headerTitleContainer: {
|
|
2670
|
-
flex: 1,
|
|
2671
|
-
alignItems: 'center',
|
|
2672
|
-
justifyContent: 'center',
|
|
2673
|
-
marginHorizontal: 16,
|
|
2674
|
-
},
|
|
2675
|
-
headerTitle: {
|
|
2676
|
-
fontSize: 22,
|
|
2677
|
-
fontWeight: '700',
|
|
2678
|
-
fontFamily: fontFamilies.phuduBold,
|
|
2679
|
-
letterSpacing: -0.5,
|
|
2680
|
-
lineHeight: 28,
|
|
2681
|
-
},
|
|
2682
|
-
headerSubtitle: {
|
|
2683
|
-
fontSize: 13,
|
|
2684
|
-
fontWeight: '500',
|
|
2685
|
-
fontFamily: fontFamilies.phuduMedium,
|
|
2686
|
-
marginTop: 2,
|
|
2687
|
-
letterSpacing: 0.2,
|
|
2688
|
-
},
|
|
2689
|
-
uploadButton: {
|
|
2690
|
-
width: 44,
|
|
2691
|
-
height: 44,
|
|
2692
|
-
borderRadius: 22,
|
|
2693
|
-
alignItems: 'center',
|
|
2694
|
-
justifyContent: 'center',
|
|
2695
|
-
},
|
|
2696
|
-
uploadProgress: {
|
|
2697
|
-
alignItems: 'center',
|
|
2698
|
-
justifyContent: 'center',
|
|
2699
|
-
},
|
|
2700
|
-
uploadProgressText: {
|
|
2701
|
-
color: '#FFFFFF',
|
|
2702
|
-
fontSize: 10,
|
|
2703
|
-
fontWeight: '600',
|
|
2704
|
-
marginTop: 2,
|
|
2705
|
-
},
|
|
2706
|
-
uploadBannerContainer: {
|
|
2707
|
-
position: 'absolute',
|
|
2708
|
-
top: 72, // below header
|
|
2709
|
-
left: 0,
|
|
2710
|
-
right: 0,
|
|
2711
|
-
alignItems: 'center',
|
|
2712
|
-
zIndex: 50,
|
|
2713
|
-
},
|
|
2714
|
-
uploadBanner: {
|
|
2715
|
-
flexDirection: 'row',
|
|
2716
|
-
alignItems: 'center',
|
|
2717
|
-
paddingHorizontal: 14,
|
|
2718
|
-
paddingVertical: 8,
|
|
2719
|
-
borderRadius: 24,
|
|
2720
|
-
gap: 8,
|
|
2721
|
-
borderWidth: 1,
|
|
2722
|
-
shadowColor: '#000',
|
|
2723
|
-
shadowOpacity: 0.1,
|
|
2724
|
-
shadowRadius: 6,
|
|
2725
|
-
shadowOffset: { width: 0, height: 2 },
|
|
2726
|
-
elevation: 2,
|
|
2727
|
-
},
|
|
2728
|
-
uploadBannerText: {
|
|
2729
|
-
fontSize: 13,
|
|
2730
|
-
fontWeight: '500',
|
|
2731
|
-
},
|
|
2732
|
-
uploadBannerDots: {
|
|
2733
|
-
flexDirection: 'row',
|
|
2734
|
-
gap: 4,
|
|
2735
|
-
marginLeft: 2,
|
|
2736
|
-
},
|
|
2737
|
-
dot: {
|
|
2738
|
-
width: 6,
|
|
2739
|
-
height: 6,
|
|
2740
|
-
borderRadius: 3,
|
|
2741
|
-
backgroundColor: '#007AFF',
|
|
2742
|
-
},
|
|
2743
|
-
searchContainer: {
|
|
2744
|
-
flexDirection: 'row',
|
|
2745
|
-
alignItems: 'center',
|
|
2746
|
-
paddingHorizontal: 14,
|
|
2747
|
-
paddingVertical: 10,
|
|
2748
|
-
marginHorizontal: 16,
|
|
2749
|
-
marginTop: 12,
|
|
2750
|
-
borderRadius: 10,
|
|
2751
|
-
borderWidth: 1,
|
|
2752
|
-
gap: 10,
|
|
2753
|
-
},
|
|
2754
|
-
searchInput: {
|
|
2755
|
-
flex: 1,
|
|
2756
|
-
fontSize: 16,
|
|
2757
|
-
fontFamily: fontFamilies.phudu,
|
|
2758
|
-
lineHeight: 20,
|
|
2759
|
-
},
|
|
2760
|
-
searchClearButton: {
|
|
2761
|
-
padding: 4,
|
|
2762
|
-
borderRadius: 12,
|
|
2763
|
-
alignItems: 'center',
|
|
2764
|
-
justifyContent: 'center',
|
|
2765
|
-
},
|
|
2766
|
-
searchIcon: {
|
|
2767
|
-
marginRight: 8,
|
|
2768
|
-
},
|
|
2769
|
-
statsContainer: {
|
|
2770
|
-
flexDirection: 'row',
|
|
2771
|
-
paddingHorizontal: 14,
|
|
2772
|
-
paddingVertical: 10,
|
|
2773
|
-
marginHorizontal: 16,
|
|
2774
|
-
marginTop: 12,
|
|
2775
|
-
borderRadius: 10,
|
|
2776
|
-
borderWidth: 1,
|
|
2777
|
-
},
|
|
2778
|
-
statItem: {
|
|
2779
|
-
flex: 1,
|
|
2780
|
-
alignItems: 'center',
|
|
2781
|
-
paddingVertical: 4,
|
|
2782
|
-
},
|
|
2783
|
-
statValue: {
|
|
2784
|
-
fontSize: 20,
|
|
2785
|
-
fontWeight: '800',
|
|
2786
|
-
fontFamily: fontFamilies.phuduBold,
|
|
2787
|
-
letterSpacing: -0.5,
|
|
2788
|
-
lineHeight: 24,
|
|
2789
|
-
},
|
|
2790
|
-
statLabel: {
|
|
2791
|
-
fontSize: 12,
|
|
2792
|
-
fontWeight: '500',
|
|
2793
|
-
fontFamily: fontFamilies.phuduMedium,
|
|
2794
|
-
marginTop: 2,
|
|
2795
|
-
letterSpacing: 0.2,
|
|
2796
|
-
},
|
|
2797
|
-
scrollView: {
|
|
2798
|
-
flex: 1,
|
|
2799
|
-
backgroundColor: '#e5f1ff',
|
|
2800
|
-
},
|
|
2801
|
-
scrollContainer: {
|
|
2802
|
-
padding: 12,
|
|
2803
|
-
},
|
|
2804
|
-
fileItem: {
|
|
2805
|
-
flexDirection: 'row',
|
|
2806
|
-
alignItems: 'center',
|
|
2807
|
-
padding: 10,
|
|
2808
|
-
marginBottom: 8,
|
|
2809
|
-
borderRadius: 10,
|
|
2810
|
-
borderWidth: 1,
|
|
2811
|
-
},
|
|
2812
|
-
fileContent: {
|
|
2813
|
-
flexDirection: 'row',
|
|
2814
|
-
alignItems: 'center',
|
|
2815
|
-
flex: 1,
|
|
2816
|
-
},
|
|
2817
|
-
fileIconContainer: {
|
|
2818
|
-
width: 50,
|
|
2819
|
-
height: 50,
|
|
2820
|
-
alignItems: 'center',
|
|
2821
|
-
justifyContent: 'center',
|
|
2822
|
-
marginRight: 12,
|
|
2823
|
-
},
|
|
2824
|
-
filePreviewContainer: {
|
|
2825
|
-
width: 52,
|
|
2826
|
-
height: 52,
|
|
2827
|
-
marginRight: 10,
|
|
2828
|
-
},
|
|
2829
|
-
filePreview: {
|
|
2830
|
-
width: '100%',
|
|
2831
|
-
height: '100%',
|
|
2832
|
-
borderRadius: 8,
|
|
2833
|
-
backgroundColor: 'transparent',
|
|
2834
|
-
alignItems: 'center',
|
|
2835
|
-
justifyContent: 'center',
|
|
2836
|
-
overflow: 'hidden',
|
|
2837
|
-
position: 'relative',
|
|
2838
|
-
},
|
|
2839
|
-
previewImage: {
|
|
2840
|
-
width: '100%',
|
|
2841
|
-
height: '100%',
|
|
2842
|
-
borderRadius: 8,
|
|
2843
|
-
},
|
|
2844
|
-
pdfPreview: {
|
|
2845
|
-
alignItems: 'center',
|
|
2846
|
-
justifyContent: 'center',
|
|
2847
|
-
width: '100%',
|
|
2848
|
-
height: '100%',
|
|
2849
|
-
backgroundColor: '#FF6B6B20',
|
|
2850
|
-
},
|
|
2851
|
-
pdfLabel: {
|
|
2852
|
-
fontSize: 8,
|
|
2853
|
-
fontWeight: 'bold',
|
|
2854
|
-
marginTop: 2,
|
|
2855
|
-
},
|
|
2856
|
-
videoPreview: {
|
|
2857
|
-
alignItems: 'center',
|
|
2858
|
-
justifyContent: 'center',
|
|
2859
|
-
width: '100%',
|
|
2860
|
-
height: '100%',
|
|
2861
|
-
backgroundColor: '#4ECDC420',
|
|
2862
|
-
},
|
|
2863
|
-
videoLabel: {
|
|
2864
|
-
fontSize: 8,
|
|
2865
|
-
fontWeight: 'bold',
|
|
2866
|
-
marginTop: 2,
|
|
2867
|
-
},
|
|
2868
|
-
fallbackIcon: {
|
|
2869
|
-
position: 'absolute',
|
|
2870
|
-
top: 0,
|
|
2871
|
-
left: 0,
|
|
2872
|
-
right: 0,
|
|
2873
|
-
bottom: 0,
|
|
2874
|
-
alignItems: 'center',
|
|
2875
|
-
justifyContent: 'center',
|
|
2876
|
-
backgroundColor: 'transparent',
|
|
2877
|
-
borderRadius: 8,
|
|
2878
|
-
},
|
|
2879
|
-
previewOverlay: {
|
|
2880
|
-
position: 'absolute',
|
|
2881
|
-
top: 0,
|
|
2882
|
-
left: 0,
|
|
2883
|
-
right: 0,
|
|
2884
|
-
bottom: 0,
|
|
2885
|
-
backgroundColor: 'rgba(0, 0, 0, 0.25)',
|
|
2886
|
-
alignItems: 'center',
|
|
2887
|
-
justifyContent: 'center',
|
|
2888
|
-
borderRadius: 8,
|
|
2889
|
-
},
|
|
2890
|
-
groupedActions: {
|
|
2891
|
-
flexDirection: 'row',
|
|
2892
|
-
alignItems: 'center',
|
|
2893
|
-
gap: 6,
|
|
2894
|
-
marginLeft: 12,
|
|
2895
|
-
},
|
|
2896
|
-
groupedActionBtn: {
|
|
2897
|
-
width: 34,
|
|
2898
|
-
height: 34,
|
|
2899
|
-
borderRadius: 8,
|
|
2900
|
-
alignItems: 'center',
|
|
2901
|
-
justifyContent: 'center',
|
|
2902
|
-
},
|
|
2903
|
-
groupedDescription: {
|
|
2904
|
-
fontSize: 12,
|
|
2905
|
-
lineHeight: 16,
|
|
2906
|
-
marginTop: 6,
|
|
2907
|
-
},
|
|
2908
|
-
videoPreviewWrapper: {
|
|
2909
|
-
width: '100%',
|
|
2910
|
-
height: '100%',
|
|
2911
|
-
borderRadius: 8,
|
|
2912
|
-
overflow: 'hidden',
|
|
2913
|
-
backgroundColor: '#000000',
|
|
2914
|
-
alignItems: 'center',
|
|
2915
|
-
justifyContent: 'center',
|
|
2916
|
-
},
|
|
2917
|
-
videoPosterImage: {
|
|
2918
|
-
position: 'absolute',
|
|
2919
|
-
top: 0,
|
|
2920
|
-
left: 0,
|
|
2921
|
-
right: 0,
|
|
2922
|
-
bottom: 0,
|
|
2923
|
-
width: '100%',
|
|
2924
|
-
height: '100%',
|
|
2925
|
-
},
|
|
2926
|
-
videoOverlay: {
|
|
2927
|
-
position: 'absolute',
|
|
2928
|
-
top: 0,
|
|
2929
|
-
left: 0,
|
|
2930
|
-
right: 0,
|
|
2931
|
-
bottom: 0,
|
|
2932
|
-
alignItems: 'center',
|
|
2933
|
-
justifyContent: 'center',
|
|
2934
|
-
backgroundColor: 'rgba(0,0,0,0.25)',
|
|
2935
|
-
},
|
|
2936
|
-
fileInfo: {
|
|
2937
|
-
flex: 1,
|
|
2938
|
-
},
|
|
2939
|
-
fileName: {
|
|
2940
|
-
fontSize: 16,
|
|
2941
|
-
fontWeight: '600',
|
|
2942
|
-
marginBottom: 4,
|
|
2943
|
-
},
|
|
2944
|
-
fileDetails: {
|
|
2945
|
-
fontSize: 14,
|
|
2946
|
-
marginBottom: 2,
|
|
2947
|
-
},
|
|
2948
|
-
fileDescription: {
|
|
2949
|
-
fontSize: 12,
|
|
2950
|
-
fontStyle: 'italic',
|
|
2951
|
-
},
|
|
2952
|
-
fileActions: {
|
|
2953
|
-
flexDirection: 'row',
|
|
2954
|
-
gap: 8,
|
|
2955
|
-
},
|
|
2956
|
-
actionButton: {
|
|
2957
|
-
width: 36,
|
|
2958
|
-
height: 36,
|
|
2959
|
-
borderRadius: 18,
|
|
2960
|
-
alignItems: 'center',
|
|
2961
|
-
justifyContent: 'center',
|
|
2962
|
-
borderWidth: 1,
|
|
2963
|
-
borderColor: '#E0E0E0',
|
|
2964
|
-
backgroundColor: 'transparent',
|
|
2965
|
-
},
|
|
2966
|
-
emptyState: {
|
|
2967
|
-
alignItems: 'center',
|
|
2968
|
-
paddingVertical: 40,
|
|
2969
|
-
paddingHorizontal: 24,
|
|
2970
|
-
},
|
|
2971
|
-
emptyStateTitle: {
|
|
2972
|
-
fontSize: 24,
|
|
2973
|
-
fontWeight: 'bold',
|
|
2974
|
-
fontFamily: fontFamilies.phuduBold,
|
|
2975
|
-
marginTop: 16,
|
|
2976
|
-
marginBottom: 8,
|
|
2977
|
-
},
|
|
2978
|
-
emptyStateDescription: {
|
|
2979
|
-
fontSize: 16,
|
|
2980
|
-
textAlign: 'center',
|
|
2981
|
-
lineHeight: 24,
|
|
2982
|
-
marginBottom: 32,
|
|
2983
|
-
},
|
|
2984
|
-
emptyStateButton: {
|
|
2985
|
-
flexDirection: 'row',
|
|
2986
|
-
alignItems: 'center',
|
|
2987
|
-
paddingHorizontal: 24,
|
|
2988
|
-
paddingVertical: 12,
|
|
2989
|
-
borderRadius: 24,
|
|
2990
|
-
gap: 8,
|
|
2991
|
-
},
|
|
2992
|
-
emptyStateButtonText: {
|
|
2993
|
-
color: '#FFFFFF',
|
|
2994
|
-
fontSize: 16,
|
|
2995
|
-
fontWeight: '600',
|
|
2996
|
-
},
|
|
2997
|
-
loadingText: {
|
|
2998
|
-
fontSize: 16,
|
|
2999
|
-
marginTop: 16,
|
|
3000
|
-
},
|
|
3001
|
-
|
|
3002
|
-
// Modal styles
|
|
3003
|
-
modalContainer: {
|
|
3004
|
-
flex: 1,
|
|
3005
|
-
},
|
|
3006
|
-
modalHeader: {
|
|
3007
|
-
flexDirection: 'row',
|
|
3008
|
-
alignItems: 'center',
|
|
3009
|
-
justifyContent: 'space-between',
|
|
3010
|
-
paddingHorizontal: 16,
|
|
3011
|
-
paddingVertical: 12,
|
|
3012
|
-
borderBottomWidth: 1,
|
|
3013
|
-
},
|
|
3014
|
-
modalCloseButton: {
|
|
3015
|
-
padding: 8,
|
|
3016
|
-
},
|
|
3017
|
-
modalTitle: {
|
|
3018
|
-
fontSize: 18,
|
|
3019
|
-
fontWeight: '600',
|
|
3020
|
-
fontFamily: fontFamilies.phuduSemiBold,
|
|
3021
|
-
},
|
|
3022
|
-
modalPlaceholder: {
|
|
3023
|
-
width: 40,
|
|
3024
|
-
},
|
|
3025
|
-
modalContent: {
|
|
3026
|
-
flex: 1,
|
|
3027
|
-
padding: 16,
|
|
3028
|
-
},
|
|
3029
|
-
fileDetailCard: {
|
|
3030
|
-
padding: 18,
|
|
3031
|
-
borderRadius: 14,
|
|
3032
|
-
borderWidth: 1,
|
|
3033
|
-
alignItems: 'center',
|
|
3034
|
-
},
|
|
3035
|
-
fileDetailIcon: {
|
|
3036
|
-
marginBottom: 16,
|
|
3037
|
-
},
|
|
3038
|
-
fileDetailName: {
|
|
3039
|
-
fontSize: 20,
|
|
3040
|
-
fontWeight: 'bold',
|
|
3041
|
-
fontFamily: fontFamilies.phuduBold,
|
|
3042
|
-
textAlign: 'center',
|
|
3043
|
-
marginBottom: 24,
|
|
3044
|
-
},
|
|
3045
|
-
fileDetailInfo: {
|
|
3046
|
-
width: '100%',
|
|
3047
|
-
marginBottom: 32,
|
|
3048
|
-
},
|
|
3049
|
-
detailRow: {
|
|
3050
|
-
flexDirection: 'row',
|
|
3051
|
-
justifyContent: 'space-between',
|
|
3052
|
-
alignItems: 'flex-start',
|
|
3053
|
-
marginBottom: 12,
|
|
3054
|
-
flexWrap: 'wrap',
|
|
3055
|
-
},
|
|
3056
|
-
detailLabel: {
|
|
3057
|
-
fontSize: 16,
|
|
3058
|
-
fontWeight: '500',
|
|
3059
|
-
flex: 1,
|
|
3060
|
-
minWidth: 100,
|
|
3061
|
-
},
|
|
3062
|
-
detailValue: {
|
|
3063
|
-
fontSize: 16,
|
|
3064
|
-
flex: 2,
|
|
3065
|
-
textAlign: 'right',
|
|
3066
|
-
},
|
|
3067
|
-
modalActions: {
|
|
3068
|
-
flexDirection: 'row',
|
|
3069
|
-
gap: 12,
|
|
3070
|
-
width: '100%',
|
|
3071
|
-
},
|
|
3072
|
-
modalActionButton: {
|
|
3073
|
-
flex: 1,
|
|
3074
|
-
flexDirection: 'row',
|
|
3075
|
-
alignItems: 'center',
|
|
3076
|
-
justifyContent: 'center',
|
|
3077
|
-
paddingVertical: 16,
|
|
3078
|
-
borderRadius: 12,
|
|
3079
|
-
gap: 8,
|
|
3080
|
-
},
|
|
3081
|
-
modalActionText: {
|
|
3082
|
-
color: '#FFFFFF',
|
|
3083
|
-
fontSize: 16,
|
|
3084
|
-
fontWeight: '600',
|
|
3085
|
-
},
|
|
3086
|
-
|
|
3087
|
-
// Drag and Drop styles - Enhanced
|
|
3088
|
-
dragDropOverlay: {
|
|
3089
|
-
position: 'absolute',
|
|
3090
|
-
top: 0,
|
|
3091
|
-
left: 0,
|
|
3092
|
-
right: 0,
|
|
3093
|
-
bottom: 0,
|
|
3094
|
-
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
|
3095
|
-
justifyContent: 'center',
|
|
3096
|
-
alignItems: 'center',
|
|
3097
|
-
zIndex: 1000,
|
|
3098
|
-
},
|
|
3099
|
-
dragDropContent: {
|
|
3100
|
-
alignItems: 'center',
|
|
3101
|
-
padding: 32,
|
|
3102
|
-
borderRadius: 20,
|
|
3103
|
-
borderWidth: 3,
|
|
3104
|
-
borderStyle: 'dashed',
|
|
3105
|
-
minWidth: 280,
|
|
3106
|
-
shadowColor: '#000',
|
|
3107
|
-
shadowOpacity: 0.3,
|
|
3108
|
-
shadowRadius: 20,
|
|
3109
|
-
shadowOffset: { width: 0, height: 10 },
|
|
3110
|
-
elevation: 10,
|
|
3111
|
-
},
|
|
3112
|
-
dragDropIconContainer: {
|
|
3113
|
-
padding: 24,
|
|
3114
|
-
borderRadius: 50,
|
|
3115
|
-
marginBottom: 16,
|
|
3116
|
-
},
|
|
3117
|
-
dragDropTitle: {
|
|
3118
|
-
fontSize: 24,
|
|
3119
|
-
fontWeight: '700',
|
|
3120
|
-
fontFamily: fontFamilies.phuduBold,
|
|
3121
|
-
marginBottom: 8,
|
|
3122
|
-
},
|
|
3123
|
-
dragDropSubtitle: {
|
|
3124
|
-
fontSize: 16,
|
|
3125
|
-
fontWeight: '500',
|
|
3126
|
-
fontFamily: fontFamilies.phuduMedium,
|
|
3127
|
-
},
|
|
3128
|
-
// Upload Preview Modal styles
|
|
3129
|
-
uploadPreviewContainer: {
|
|
3130
|
-
flex: 1,
|
|
3131
|
-
},
|
|
3132
|
-
uploadPreviewHeader: {
|
|
3133
|
-
flexDirection: 'row',
|
|
3134
|
-
alignItems: 'center',
|
|
3135
|
-
justifyContent: 'space-between',
|
|
3136
|
-
paddingHorizontal: 16,
|
|
3137
|
-
paddingVertical: 16,
|
|
3138
|
-
borderBottomWidth: 1,
|
|
3139
|
-
},
|
|
3140
|
-
uploadPreviewTitle: {
|
|
3141
|
-
fontSize: 20,
|
|
3142
|
-
fontWeight: '700',
|
|
3143
|
-
fontFamily: fontFamilies.phuduBold,
|
|
3144
|
-
},
|
|
3145
|
-
uploadPreviewList: {
|
|
3146
|
-
flex: 1,
|
|
3147
|
-
padding: 16,
|
|
3148
|
-
},
|
|
3149
|
-
uploadPreviewItem: {
|
|
3150
|
-
flexDirection: 'row',
|
|
3151
|
-
alignItems: 'center',
|
|
3152
|
-
padding: 12,
|
|
3153
|
-
borderRadius: 12,
|
|
3154
|
-
borderWidth: 1,
|
|
3155
|
-
marginBottom: 12,
|
|
3156
|
-
gap: 12,
|
|
3157
|
-
},
|
|
3158
|
-
uploadPreviewThumbnail: {
|
|
3159
|
-
width: 60,
|
|
3160
|
-
height: 60,
|
|
3161
|
-
borderRadius: 8,
|
|
3162
|
-
},
|
|
3163
|
-
uploadPreviewIconContainer: {
|
|
3164
|
-
width: 60,
|
|
3165
|
-
height: 60,
|
|
3166
|
-
borderRadius: 8,
|
|
3167
|
-
alignItems: 'center',
|
|
3168
|
-
justifyContent: 'center',
|
|
3169
|
-
},
|
|
3170
|
-
uploadPreviewInfo: {
|
|
3171
|
-
flex: 1,
|
|
3172
|
-
minWidth: 0,
|
|
3173
|
-
},
|
|
3174
|
-
uploadPreviewName: {
|
|
3175
|
-
fontSize: 16,
|
|
3176
|
-
fontWeight: '600',
|
|
3177
|
-
fontFamily: fontFamilies.phuduSemiBold,
|
|
3178
|
-
marginBottom: 4,
|
|
3179
|
-
},
|
|
3180
|
-
uploadPreviewMeta: {
|
|
3181
|
-
fontSize: 13,
|
|
3182
|
-
fontFamily: fontFamilies.phudu,
|
|
3183
|
-
},
|
|
3184
|
-
uploadPreviewRemove: {
|
|
3185
|
-
padding: 4,
|
|
3186
|
-
},
|
|
3187
|
-
uploadPreviewFooter: {
|
|
3188
|
-
padding: 16,
|
|
3189
|
-
borderTopWidth: 1,
|
|
3190
|
-
},
|
|
3191
|
-
uploadPreviewStats: {
|
|
3192
|
-
flexDirection: 'row',
|
|
3193
|
-
justifyContent: 'space-between',
|
|
3194
|
-
marginBottom: 16,
|
|
3195
|
-
},
|
|
3196
|
-
uploadPreviewStatsText: {
|
|
3197
|
-
fontSize: 15,
|
|
3198
|
-
fontWeight: '600',
|
|
3199
|
-
fontFamily: fontFamilies.phuduSemiBold,
|
|
3200
|
-
},
|
|
3201
|
-
uploadPreviewActions: {
|
|
3202
|
-
flexDirection: 'row',
|
|
3203
|
-
gap: 12,
|
|
3204
|
-
},
|
|
3205
|
-
uploadPreviewCancelButton: {
|
|
3206
|
-
flex: 1,
|
|
3207
|
-
paddingVertical: 14,
|
|
3208
|
-
borderRadius: 12,
|
|
3209
|
-
borderWidth: 1,
|
|
3210
|
-
alignItems: 'center',
|
|
3211
|
-
justifyContent: 'center',
|
|
3212
|
-
},
|
|
3213
|
-
uploadPreviewCancelText: {
|
|
3214
|
-
fontSize: 16,
|
|
3215
|
-
fontWeight: '600',
|
|
3216
|
-
fontFamily: fontFamilies.phuduSemiBold,
|
|
3217
|
-
},
|
|
3218
|
-
uploadPreviewConfirmButton: {
|
|
3219
|
-
flex: 2,
|
|
3220
|
-
flexDirection: 'row',
|
|
3221
|
-
alignItems: 'center',
|
|
3222
|
-
justifyContent: 'center',
|
|
3223
|
-
paddingVertical: 14,
|
|
3224
|
-
borderRadius: 12,
|
|
3225
|
-
gap: 8,
|
|
3226
|
-
},
|
|
3227
|
-
uploadPreviewConfirmText: {
|
|
3228
|
-
color: '#FFFFFF',
|
|
3229
|
-
fontSize: 16,
|
|
3230
|
-
fontWeight: '600',
|
|
3231
|
-
fontFamily: fontFamilies.phuduSemiBold,
|
|
3232
|
-
},
|
|
3233
|
-
|
|
3234
|
-
// File Viewer styles
|
|
3235
|
-
fileViewerContainer: {
|
|
3236
|
-
flex: 1,
|
|
3237
|
-
},
|
|
3238
|
-
fileViewerHeader: {
|
|
3239
|
-
flexDirection: 'row',
|
|
3240
|
-
alignItems: 'center',
|
|
3241
|
-
paddingHorizontal: 16,
|
|
3242
|
-
paddingVertical: 12,
|
|
3243
|
-
borderBottomWidth: 1,
|
|
3244
|
-
},
|
|
3245
|
-
fileViewerTitleContainer: {
|
|
3246
|
-
flex: 1,
|
|
3247
|
-
marginHorizontal: 16,
|
|
3248
|
-
},
|
|
3249
|
-
fileViewerTitle: {
|
|
3250
|
-
fontSize: 18,
|
|
3251
|
-
fontWeight: '600',
|
|
3252
|
-
fontFamily: fontFamilies.phuduSemiBold,
|
|
3253
|
-
marginBottom: 2,
|
|
3254
|
-
},
|
|
3255
|
-
fileViewerSubtitle: {
|
|
3256
|
-
fontSize: 14,
|
|
3257
|
-
},
|
|
3258
|
-
fileViewerActions: {
|
|
3259
|
-
flexDirection: 'row',
|
|
3260
|
-
gap: 8,
|
|
3261
|
-
},
|
|
3262
|
-
fileViewerContent: {
|
|
3263
|
-
flex: 1,
|
|
3264
|
-
},
|
|
3265
|
-
fileViewerContentWithDetails: {
|
|
3266
|
-
paddingBottom: 20,
|
|
3267
|
-
},
|
|
3268
|
-
fileViewerContentContainer: {
|
|
3269
|
-
flexGrow: 1,
|
|
3270
|
-
padding: 14,
|
|
3271
|
-
},
|
|
3272
|
-
fileViewerLoading: {
|
|
3273
|
-
flex: 1,
|
|
3274
|
-
justifyContent: 'center',
|
|
3275
|
-
alignItems: 'center',
|
|
3276
|
-
},
|
|
3277
|
-
fileViewerLoadingText: {
|
|
3278
|
-
fontSize: 16,
|
|
3279
|
-
marginTop: 16,
|
|
3280
|
-
},
|
|
3281
|
-
imageContainer: {
|
|
3282
|
-
alignItems: 'center',
|
|
3283
|
-
justifyContent: 'center',
|
|
3284
|
-
flex: 1,
|
|
3285
|
-
},
|
|
3286
|
-
textContainer: {
|
|
3287
|
-
flex: 1,
|
|
3288
|
-
borderRadius: 10,
|
|
3289
|
-
borderWidth: 1,
|
|
3290
|
-
padding: 12,
|
|
3291
|
-
minHeight: 180,
|
|
3292
|
-
maxHeight: '80%',
|
|
3293
|
-
},
|
|
3294
|
-
textContent: {
|
|
3295
|
-
fontSize: 14,
|
|
3296
|
-
fontFamily: Platform.OS === 'web' ? 'monospace' : 'Courier',
|
|
3297
|
-
lineHeight: 20,
|
|
3298
|
-
},
|
|
3299
|
-
unsupportedFileContainer: {
|
|
3300
|
-
flex: 1,
|
|
3301
|
-
justifyContent: 'center',
|
|
3302
|
-
alignItems: 'center',
|
|
3303
|
-
paddingVertical: 40,
|
|
3304
|
-
paddingHorizontal: 24,
|
|
3305
|
-
},
|
|
3306
|
-
unsupportedFileTitle: {
|
|
3307
|
-
fontSize: 24,
|
|
3308
|
-
fontWeight: 'bold',
|
|
3309
|
-
fontFamily: fontFamilies.phuduBold,
|
|
3310
|
-
marginTop: 16,
|
|
3311
|
-
marginBottom: 8,
|
|
3312
|
-
textAlign: 'center',
|
|
3313
|
-
},
|
|
3314
|
-
unsupportedFileDescription: {
|
|
3315
|
-
fontSize: 16,
|
|
3316
|
-
textAlign: 'center',
|
|
3317
|
-
lineHeight: 24,
|
|
3318
|
-
marginBottom: 32,
|
|
3319
|
-
},
|
|
3320
|
-
downloadButtonLarge: {
|
|
3321
|
-
flexDirection: 'row',
|
|
3322
|
-
alignItems: 'center',
|
|
3323
|
-
paddingHorizontal: 18,
|
|
3324
|
-
paddingVertical: 12,
|
|
3325
|
-
borderRadius: 20,
|
|
3326
|
-
gap: 8,
|
|
3327
|
-
},
|
|
3328
|
-
downloadButtonText: {
|
|
3329
|
-
color: '#FFFFFF',
|
|
3330
|
-
fontSize: 16,
|
|
3331
|
-
fontWeight: '600',
|
|
3332
|
-
},
|
|
3333
|
-
pdfContainer: {
|
|
3334
|
-
flex: 1,
|
|
3335
|
-
alignItems: 'center',
|
|
3336
|
-
justifyContent: 'center',
|
|
3337
|
-
},
|
|
3338
|
-
mediaContainer: {
|
|
3339
|
-
flex: 1,
|
|
3340
|
-
alignItems: 'center',
|
|
3341
|
-
justifyContent: 'center',
|
|
3342
|
-
padding: 20,
|
|
3343
|
-
},
|
|
3344
|
-
unsupportedText: {
|
|
3345
|
-
fontSize: 16,
|
|
3346
|
-
textAlign: 'center',
|
|
3347
|
-
fontStyle: 'italic',
|
|
3348
|
-
},
|
|
3349
|
-
|
|
3350
|
-
// File Details in Viewer styles
|
|
3351
|
-
fileDetailsSection: {
|
|
3352
|
-
margin: 12,
|
|
3353
|
-
marginTop: 0,
|
|
3354
|
-
padding: 14,
|
|
3355
|
-
borderRadius: 10,
|
|
3356
|
-
borderWidth: 1,
|
|
3357
|
-
},
|
|
3358
|
-
fileDetailsSectionTitle: {
|
|
3359
|
-
fontSize: 18,
|
|
3360
|
-
fontWeight: '600',
|
|
3361
|
-
fontFamily: fontFamilies.phuduSemiBold,
|
|
3362
|
-
flex: 1,
|
|
3363
|
-
},
|
|
3364
|
-
fileDetailsSectionHeader: {
|
|
3365
|
-
flexDirection: 'row',
|
|
3366
|
-
alignItems: 'center',
|
|
3367
|
-
justifyContent: 'space-between',
|
|
3368
|
-
marginBottom: 16,
|
|
3369
|
-
},
|
|
3370
|
-
fileDetailsSectionToggle: {
|
|
3371
|
-
padding: 4,
|
|
3372
|
-
},
|
|
3373
|
-
fileDetailsActions: {
|
|
3374
|
-
flexDirection: 'row',
|
|
3375
|
-
gap: 12,
|
|
3376
|
-
marginTop: 16,
|
|
3377
|
-
},
|
|
3378
|
-
fileDetailsActionButton: {
|
|
3379
|
-
flex: 1,
|
|
3380
|
-
flexDirection: 'row',
|
|
3381
|
-
alignItems: 'center',
|
|
3382
|
-
justifyContent: 'center',
|
|
3383
|
-
paddingVertical: 12,
|
|
3384
|
-
borderRadius: 8,
|
|
3385
|
-
gap: 6,
|
|
3386
|
-
},
|
|
3387
|
-
fileDetailsActionText: {
|
|
3388
|
-
color: '#FFFFFF',
|
|
3389
|
-
fontSize: 14,
|
|
3390
|
-
fontWeight: '600',
|
|
3391
|
-
},
|
|
3392
|
-
|
|
3393
|
-
// Header styles
|
|
3394
|
-
headerActions: {
|
|
3395
|
-
flexDirection: 'row',
|
|
3396
|
-
alignItems: 'center',
|
|
3397
|
-
gap: 16,
|
|
3398
|
-
},
|
|
3399
|
-
controlsBar: {
|
|
3400
|
-
flexDirection: 'row',
|
|
3401
|
-
alignItems: 'center',
|
|
3402
|
-
justifyContent: 'space-between',
|
|
3403
|
-
paddingHorizontal: 16,
|
|
3404
|
-
paddingTop: 8,
|
|
3405
|
-
paddingBottom: 4,
|
|
3406
|
-
gap: 12,
|
|
3407
|
-
},
|
|
3408
|
-
viewModeScroll: {
|
|
3409
|
-
flex: 1,
|
|
3410
|
-
maxWidth: '80%',
|
|
3411
|
-
},
|
|
3412
|
-
viewModeToggle: {
|
|
3413
|
-
flexDirection: 'row',
|
|
3414
|
-
borderRadius: 24,
|
|
3415
|
-
padding: 3,
|
|
3416
|
-
overflow: 'hidden',
|
|
3417
|
-
},
|
|
3418
|
-
viewModeButton: {
|
|
3419
|
-
paddingHorizontal: 14,
|
|
3420
|
-
paddingVertical: 10,
|
|
3421
|
-
borderRadius: 20,
|
|
3422
|
-
minWidth: 44,
|
|
3423
|
-
alignItems: 'center',
|
|
3424
|
-
justifyContent: 'center',
|
|
3425
|
-
marginHorizontal: 1,
|
|
3426
|
-
},
|
|
3427
|
-
sortButton: {
|
|
3428
|
-
flexDirection: 'row',
|
|
3429
|
-
alignItems: 'center',
|
|
3430
|
-
justifyContent: 'center',
|
|
3431
|
-
paddingHorizontal: 12,
|
|
3432
|
-
paddingVertical: 10,
|
|
3433
|
-
borderRadius: 20,
|
|
3434
|
-
borderWidth: 1,
|
|
3435
|
-
minWidth: 44,
|
|
3436
|
-
},
|
|
3437
|
-
|
|
3438
|
-
// Photo Grid styles
|
|
3439
|
-
photoScrollContainer: {
|
|
3440
|
-
padding: 10,
|
|
3441
|
-
},
|
|
3442
|
-
photoDateSection: {
|
|
3443
|
-
marginBottom: 16,
|
|
3444
|
-
},
|
|
3445
|
-
photoDateHeader: {
|
|
3446
|
-
fontSize: 16,
|
|
3447
|
-
fontWeight: '600',
|
|
3448
|
-
fontFamily: fontFamilies.phuduSemiBold,
|
|
3449
|
-
marginBottom: 8,
|
|
3450
|
-
paddingHorizontal: 2,
|
|
3451
|
-
},
|
|
3452
|
-
photoGrid: {
|
|
3453
|
-
flexDirection: 'row',
|
|
3454
|
-
flexWrap: 'wrap',
|
|
3455
|
-
gap: 4,
|
|
3456
|
-
justifyContent: 'flex-start',
|
|
3457
|
-
},
|
|
3458
|
-
photoItem: {
|
|
3459
|
-
borderRadius: 8,
|
|
3460
|
-
overflow: 'hidden',
|
|
3461
|
-
},
|
|
3462
|
-
photoContainer: {
|
|
3463
|
-
width: '100%',
|
|
3464
|
-
height: '100%',
|
|
3465
|
-
position: 'relative',
|
|
3466
|
-
borderRadius: 8,
|
|
3467
|
-
overflow: 'hidden',
|
|
3468
|
-
},
|
|
3469
|
-
photoImage: {
|
|
3470
|
-
width: '100%',
|
|
3471
|
-
height: '100%',
|
|
3472
|
-
},
|
|
3473
|
-
|
|
3474
|
-
// Justified Grid styles
|
|
3475
|
-
dimensionsLoadingIndicator: {
|
|
3476
|
-
flexDirection: 'row',
|
|
3477
|
-
alignItems: 'center',
|
|
3478
|
-
justifyContent: 'center',
|
|
3479
|
-
paddingVertical: 16,
|
|
3480
|
-
gap: 8,
|
|
3481
|
-
},
|
|
3482
|
-
dimensionsLoadingText: {
|
|
3483
|
-
fontSize: 14,
|
|
3484
|
-
fontStyle: 'italic',
|
|
3485
|
-
},
|
|
3486
|
-
justifiedPhotoGrid: {
|
|
3487
|
-
gap: 4,
|
|
3488
|
-
},
|
|
3489
|
-
justifiedPhotoRow: {
|
|
3490
|
-
flexDirection: 'row',
|
|
3491
|
-
},
|
|
3492
|
-
justifiedPhotoItem: {
|
|
3493
|
-
borderRadius: 6,
|
|
3494
|
-
overflow: 'hidden',
|
|
3495
|
-
position: 'relative',
|
|
3496
|
-
},
|
|
3497
|
-
justifiedPhotoContainer: {
|
|
3498
|
-
width: '100%',
|
|
3499
|
-
height: '100%',
|
|
3500
|
-
position: 'relative',
|
|
3501
|
-
borderRadius: 6,
|
|
3502
|
-
overflow: 'hidden',
|
|
3503
|
-
backgroundColor: 'transparent',
|
|
3504
|
-
},
|
|
3505
|
-
justifiedPhotoImage: {
|
|
3506
|
-
width: '100%',
|
|
3507
|
-
height: '100%',
|
|
3508
|
-
borderRadius: 6,
|
|
3509
|
-
},
|
|
3510
|
-
|
|
3511
|
-
// Simple Photo Grid styles
|
|
3512
|
-
simplePhotoItem: {
|
|
3513
|
-
borderRadius: 8,
|
|
3514
|
-
overflow: 'hidden',
|
|
3515
|
-
backgroundColor: 'transparent',
|
|
3516
|
-
},
|
|
3517
|
-
simplePhotoContainer: {
|
|
3518
|
-
width: '100%',
|
|
3519
|
-
height: '100%',
|
|
3520
|
-
position: 'relative',
|
|
3521
|
-
borderRadius: 8,
|
|
3522
|
-
overflow: 'hidden',
|
|
3523
|
-
},
|
|
3524
|
-
simplePhotoImage: {
|
|
3525
|
-
width: '100%',
|
|
3526
|
-
height: '100%',
|
|
3527
|
-
borderRadius: 8,
|
|
3528
|
-
},
|
|
3529
|
-
|
|
3530
|
-
// Loading skeleton styles
|
|
3531
|
-
photoSkeletonGrid: {
|
|
3532
|
-
flexDirection: 'row',
|
|
3533
|
-
flexWrap: 'wrap',
|
|
3534
|
-
gap: 4,
|
|
3535
|
-
marginTop: 20,
|
|
3536
|
-
},
|
|
3537
|
-
photoSkeletonItem: {
|
|
3538
|
-
width: '32%',
|
|
3539
|
-
aspectRatio: 1,
|
|
3540
|
-
borderRadius: 8,
|
|
3541
|
-
marginBottom: 4,
|
|
3542
|
-
},
|
|
3543
|
-
skeletonFileItem: {
|
|
3544
|
-
flexDirection: 'row',
|
|
3545
|
-
alignItems: 'center',
|
|
3546
|
-
paddingHorizontal: 16,
|
|
3547
|
-
paddingVertical: 12,
|
|
3548
|
-
borderBottomWidth: 1,
|
|
3549
|
-
gap: 12,
|
|
3550
|
-
},
|
|
3551
|
-
skeletonFileInfo: {
|
|
3552
|
-
flex: 1,
|
|
3553
|
-
justifyContent: 'center',
|
|
3554
|
-
},
|
|
3555
|
-
});
|
|
2293
|
+
// Styles have been moved to components/fileManagement/styles.ts
|
|
3556
2294
|
|
|
3557
2295
|
export default FileManagementScreen;
|