@oxyhq/services 22.9.0 → 22.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/index.js +24 -5
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/components/AvatarCameraBadge.js +42 -0
- package/lib/commonjs/ui/components/AvatarCameraBadge.js.map +1 -0
- package/lib/commonjs/ui/components/{OxyAccountDialog.js → OxyAccountDialogScreen.js} +55 -133
- package/lib/commonjs/ui/components/OxyAccountDialogScreen.js.map +1 -0
- package/lib/commonjs/ui/components/OxyAuthChooser.js +657 -88
- package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
- package/lib/commonjs/ui/components/OxyConsentScreen.js +1 -1
- package/lib/commonjs/ui/components/ProfileButton.js +15 -1
- package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileSummaryCard.js +3 -23
- package/lib/commonjs/ui/components/ProfileSummaryCard.js.map +1 -1
- package/lib/commonjs/ui/components/RequireOxyAuth.js +1 -1
- package/lib/commonjs/ui/components/SurfaceHeaderAction.js +63 -0
- package/lib/commonjs/ui/components/SurfaceHeaderAction.js.map +1 -0
- package/lib/commonjs/ui/components/SurfaceScreen.js +91 -8
- package/lib/commonjs/ui/components/SurfaceScreen.js.map +1 -1
- package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js +46 -29
- package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
- package/lib/commonjs/ui/components/modals/DeleteAccountModal.js +47 -23
- package/lib/commonjs/ui/components/modals/DeleteAccountModal.js.map +1 -1
- package/lib/commonjs/ui/components/oxyAuthChooserStyles.js +81 -19
- package/lib/commonjs/ui/components/oxyAuthChooserStyles.js.map +1 -1
- package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js +83 -23
- package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
- package/lib/commonjs/ui/components/surfaces/ActionSheetSurface.js +83 -0
- package/lib/commonjs/ui/components/surfaces/ActionSheetSurface.js.map +1 -0
- package/lib/commonjs/ui/context/OxyContext.js +79 -29
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/queryKeys.js +18 -1
- package/lib/commonjs/ui/hooks/queries/queryKeys.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useFileQueries.js +129 -0
- package/lib/commonjs/ui/hooks/queries/useFileQueries.js.map +1 -0
- package/lib/commonjs/ui/hooks/useAvatarPicker.js +38 -55
- package/lib/commonjs/ui/hooks/useAvatarPicker.js.map +1 -1
- package/lib/commonjs/ui/hooks/useReduceMotion.js +57 -0
- package/lib/commonjs/ui/hooks/useReduceMotion.js.map +1 -0
- package/lib/commonjs/ui/hooks/useSurfaceHeader.js +46 -0
- package/lib/commonjs/ui/hooks/useSurfaceHeader.js.map +1 -0
- package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +1 -1
- package/lib/commonjs/ui/navigation/accountDialogManager.js +36 -2
- package/lib/commonjs/ui/navigation/accountDialogManager.js.map +1 -1
- package/lib/commonjs/ui/navigation/bottomSheetManager.js +5 -6
- package/lib/commonjs/ui/navigation/bottomSheetManager.js.map +1 -1
- package/lib/commonjs/ui/navigation/routes.js +4 -3
- package/lib/commonjs/ui/navigation/routes.js.map +1 -1
- package/lib/commonjs/ui/navigation/surfaceBackBridge.js +68 -0
- package/lib/commonjs/ui/navigation/surfaceBackBridge.js.map +1 -0
- package/lib/commonjs/ui/navigation/surfaceNavStack.js +62 -15
- package/lib/commonjs/ui/navigation/surfaceNavStack.js.map +1 -1
- package/lib/commonjs/ui/navigation/surfaceRegistry.js +84 -19
- package/lib/commonjs/ui/navigation/surfaceRegistry.js.map +1 -1
- package/lib/commonjs/ui/navigation/surfaces.js +139 -25
- package/lib/commonjs/ui/navigation/surfaces.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountMembersScreen.js +214 -283
- package/lib/commonjs/ui/screens/AccountMembersScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +88 -118
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountVerificationScreen.js +22 -36
- package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AppInfoScreen.js +219 -226
- package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AvatarCropScreen.js +287 -289
- package/lib/commonjs/ui/screens/AvatarCropScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ChangeAvatarScreen.js +301 -0
- package/lib/commonjs/ui/screens/ChangeAvatarScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/ConnectedAppsScreen.js +24 -39
- package/lib/commonjs/ui/screens/ConnectedAppsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/CreateAccountScreen.js +136 -158
- package/lib/commonjs/ui/screens/CreateAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +29 -36
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/EditProfileScreen.js +101 -109
- package/lib/commonjs/ui/screens/EditProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FAQScreen.js +10 -15
- package/lib/commonjs/ui/screens/FAQScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FeedbackScreen.js +8 -16
- package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +403 -627
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/HelpSupportScreen.js +62 -69
- package/lib/commonjs/ui/screens/HelpSupportScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/HistoryViewScreen.js +63 -79
- package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +69 -98
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LearnMoreUsernamesScreen.js +8 -14
- package/lib/commonjs/ui/screens/LearnMoreUsernamesScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +77 -94
- package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ManageAccountScreen.js +99 -134
- package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/NotificationsScreen.js +69 -76
- package/lib/commonjs/ui/screens/NotificationsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +3 -8
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PreferencesScreen.js +67 -74
- package/lib/commonjs/ui/screens/PreferencesScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +55 -91
- package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +291 -304
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +100 -114
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SavesCollectionsScreen.js +38 -45
- package/lib/commonjs/ui/screens/SavesCollectionsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SearchSettingsScreen.js +44 -57
- package/lib/commonjs/ui/screens/SearchSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/UserLinksScreen.js +24 -31
- package/lib/commonjs/ui/screens/UserLinksScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/UserListScreen.js +14 -24
- package/lib/commonjs/ui/screens/UserListScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +16 -48
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/fileManagement/FileLibraryError.js +63 -0
- package/lib/commonjs/ui/screens/fileManagement/FileLibraryError.js.map +1 -0
- package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js +54 -41
- package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
- package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js +44 -81
- package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustAboutScreen.js +66 -75
- package/lib/commonjs/ui/screens/trust/TrustAboutScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js +111 -139
- package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustFAQScreen.js +13 -20
- package/lib/commonjs/ui/screens/trust/TrustFAQScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js +14 -27
- package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js +68 -85
- package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js +28 -36
- package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js.map +1 -1
- package/lib/commonjs/ui/stores/resetSessionScopedStores.js +8 -3
- package/lib/commonjs/ui/stores/resetSessionScopedStores.js.map +1 -1
- package/lib/commonjs/ui/utils/avatarUtils.js +11 -2
- package/lib/commonjs/ui/utils/avatarUtils.js.map +1 -1
- package/lib/commonjs/ui/utils/fileManagement.js +0 -79
- package/lib/commonjs/ui/utils/fileManagement.js.map +1 -1
- package/lib/module/index.js +12 -5
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/components/AvatarCameraBadge.js +40 -0
- package/lib/module/ui/components/AvatarCameraBadge.js.map +1 -0
- package/lib/module/ui/components/{OxyAccountDialog.js → OxyAccountDialogScreen.js} +57 -135
- package/lib/module/ui/components/OxyAccountDialogScreen.js.map +1 -0
- package/lib/module/ui/components/OxyAuthChooser.js +659 -91
- package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
- package/lib/module/ui/components/OxyConsentScreen.js +1 -1
- package/lib/module/ui/components/ProfileButton.js +16 -2
- package/lib/module/ui/components/ProfileButton.js.map +1 -1
- package/lib/module/ui/components/ProfileSummaryCard.js +2 -23
- package/lib/module/ui/components/ProfileSummaryCard.js.map +1 -1
- package/lib/module/ui/components/RequireOxyAuth.js +1 -1
- package/lib/module/ui/components/SurfaceHeaderAction.js +58 -0
- package/lib/module/ui/components/SurfaceHeaderAction.js.map +1 -0
- package/lib/module/ui/components/SurfaceScreen.js +93 -10
- package/lib/module/ui/components/SurfaceScreen.js.map +1 -1
- package/lib/module/ui/components/fileManagement/FileDetailsModal.js +46 -29
- package/lib/module/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
- package/lib/module/ui/components/modals/DeleteAccountModal.js +46 -23
- package/lib/module/ui/components/modals/DeleteAccountModal.js.map +1 -1
- package/lib/module/ui/components/oxyAuthChooserStyles.js +81 -19
- package/lib/module/ui/components/oxyAuthChooserStyles.js.map +1 -1
- package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js +83 -25
- package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
- package/lib/module/ui/components/surfaces/ActionSheetSurface.js +78 -0
- package/lib/module/ui/components/surfaces/ActionSheetSurface.js.map +1 -0
- package/lib/module/ui/context/OxyContext.js +80 -30
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/queries/queryKeys.js +16 -0
- package/lib/module/ui/hooks/queries/queryKeys.js.map +1 -1
- package/lib/module/ui/hooks/queries/useFileQueries.js +120 -0
- package/lib/module/ui/hooks/queries/useFileQueries.js.map +1 -0
- package/lib/module/ui/hooks/useAvatarPicker.js +38 -55
- package/lib/module/ui/hooks/useAvatarPicker.js.map +1 -1
- package/lib/module/ui/hooks/useReduceMotion.js +53 -0
- package/lib/module/ui/hooks/useReduceMotion.js.map +1 -0
- package/lib/module/ui/hooks/useSurfaceHeader.js +42 -0
- package/lib/module/ui/hooks/useSurfaceHeader.js.map +1 -0
- package/lib/module/ui/hooks/useSwitchableAccounts.js +1 -1
- package/lib/module/ui/navigation/accountDialogManager.js +34 -2
- package/lib/module/ui/navigation/accountDialogManager.js.map +1 -1
- package/lib/module/ui/navigation/bottomSheetManager.js +6 -7
- package/lib/module/ui/navigation/bottomSheetManager.js.map +1 -1
- package/lib/module/ui/navigation/routes.js +4 -3
- package/lib/module/ui/navigation/routes.js.map +1 -1
- package/lib/module/ui/navigation/surfaceBackBridge.js +63 -0
- package/lib/module/ui/navigation/surfaceBackBridge.js.map +1 -0
- package/lib/module/ui/navigation/surfaceNavStack.js +62 -15
- package/lib/module/ui/navigation/surfaceNavStack.js.map +1 -1
- package/lib/module/ui/navigation/surfaceRegistry.js +84 -19
- package/lib/module/ui/navigation/surfaceRegistry.js.map +1 -1
- package/lib/module/ui/navigation/surfaces.js +138 -26
- package/lib/module/ui/navigation/surfaces.js.map +1 -1
- package/lib/module/ui/screens/AccountMembersScreen.js +218 -286
- package/lib/module/ui/screens/AccountMembersScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +92 -121
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountVerificationScreen.js +25 -38
- package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
- package/lib/module/ui/screens/AppInfoScreen.js +220 -227
- package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/module/ui/screens/AvatarCropScreen.js +289 -291
- package/lib/module/ui/screens/AvatarCropScreen.js.map +1 -1
- package/lib/module/ui/screens/ChangeAvatarScreen.js +298 -0
- package/lib/module/ui/screens/ChangeAvatarScreen.js.map +1 -0
- package/lib/module/ui/screens/ConnectedAppsScreen.js +26 -40
- package/lib/module/ui/screens/ConnectedAppsScreen.js.map +1 -1
- package/lib/module/ui/screens/CreateAccountScreen.js +139 -160
- package/lib/module/ui/screens/CreateAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/EditProfileFieldScreen.js +32 -38
- package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/module/ui/screens/EditProfileScreen.js +102 -110
- package/lib/module/ui/screens/EditProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/FAQScreen.js +11 -15
- package/lib/module/ui/screens/FAQScreen.js.map +1 -1
- package/lib/module/ui/screens/FeedbackScreen.js +10 -17
- package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +408 -631
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/HelpSupportScreen.js +64 -70
- package/lib/module/ui/screens/HelpSupportScreen.js.map +1 -1
- package/lib/module/ui/screens/HistoryViewScreen.js +65 -81
- package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js +71 -99
- package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/module/ui/screens/LearnMoreUsernamesScreen.js +10 -15
- package/lib/module/ui/screens/LearnMoreUsernamesScreen.js.map +1 -1
- package/lib/module/ui/screens/LegalDocumentsScreen.js +78 -94
- package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -1
- package/lib/module/ui/screens/ManageAccountScreen.js +102 -137
- package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/NotificationsScreen.js +71 -77
- package/lib/module/ui/screens/NotificationsScreen.js.map +1 -1
- package/lib/module/ui/screens/PaymentGatewayScreen.js +4 -9
- package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/module/ui/screens/PreferencesScreen.js +69 -75
- package/lib/module/ui/screens/PreferencesScreen.js.map +1 -1
- package/lib/module/ui/screens/PremiumSubscriptionScreen.js +58 -93
- package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
- package/lib/module/ui/screens/PrivacySettingsScreen.js +293 -305
- package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +102 -116
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/SavesCollectionsScreen.js +40 -46
- package/lib/module/ui/screens/SavesCollectionsScreen.js.map +1 -1
- package/lib/module/ui/screens/SearchSettingsScreen.js +46 -58
- package/lib/module/ui/screens/SearchSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/UserLinksScreen.js +26 -32
- package/lib/module/ui/screens/UserLinksScreen.js.map +1 -1
- package/lib/module/ui/screens/UserListScreen.js +14 -24
- package/lib/module/ui/screens/UserListScreen.js.map +1 -1
- package/lib/module/ui/screens/WelcomeNewUserScreen.js +17 -49
- package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/module/ui/screens/fileManagement/FileLibraryError.js +59 -0
- package/lib/module/ui/screens/fileManagement/FileLibraryError.js.map +1 -0
- package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js +54 -42
- package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
- package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js +45 -81
- package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustAboutScreen.js +67 -75
- package/lib/module/ui/screens/trust/TrustAboutScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustCenterScreen.js +112 -139
- package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustFAQScreen.js +15 -21
- package/lib/module/ui/screens/trust/TrustFAQScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js +14 -26
- package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustRewardsScreen.js +69 -85
- package/lib/module/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustRulesScreen.js +30 -37
- package/lib/module/ui/screens/trust/TrustRulesScreen.js.map +1 -1
- package/lib/module/ui/stores/resetSessionScopedStores.js +8 -3
- package/lib/module/ui/stores/resetSessionScopedStores.js.map +1 -1
- package/lib/module/ui/utils/avatarUtils.js +11 -2
- package/lib/module/ui/utils/avatarUtils.js.map +1 -1
- package/lib/module/ui/utils/fileManagement.js +0 -78
- package/lib/module/ui/utils/fileManagement.js.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +2 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/AvatarCameraBadge.d.ts +4 -0
- package/lib/typescript/commonjs/ui/components/AvatarCameraBadge.d.ts.map +1 -0
- package/lib/typescript/{module/ui/components/OxyAccountDialog.d.ts → commonjs/ui/components/OxyAccountDialogScreen.d.ts} +5 -4
- package/lib/typescript/commonjs/ui/components/OxyAccountDialogScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts +3 -3
- package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +2 -2
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileSummaryCard.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/RequireOxyAuth.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/SurfaceHeaderAction.d.ts +16 -0
- package/lib/typescript/commonjs/ui/components/SurfaceHeaderAction.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/SurfaceScreen.d.ts +3 -4
- package/lib/typescript/commonjs/ui/components/SurfaceScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts +14 -4
- package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/modals/DeleteAccountModal.d.ts +17 -2
- package/lib/typescript/commonjs/ui/components/modals/DeleteAccountModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/oxyAuthChooserStyles.d.ts +75 -13
- package/lib/typescript/commonjs/ui/components/oxyAuthChooserStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/photogrid/JustifiedPhotoGrid.d.ts +10 -8
- package/lib/typescript/commonjs/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/surfaces/ActionSheetSurface.d.ts +38 -0
- package/lib/typescript/commonjs/ui/components/surfaces/ActionSheetSurface.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/queryKeys.d.ts +9 -0
- package/lib/typescript/commonjs/ui/hooks/queries/queryKeys.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/useFileQueries.d.ts +50 -0
- package/lib/typescript/commonjs/ui/hooks/queries/useFileQueries.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts +17 -16
- package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useReduceMotion.d.ts +14 -0
- package/lib/typescript/commonjs/ui/hooks/useReduceMotion.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts +31 -0
- package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts +1 -1
- package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts +27 -2
- package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/bottomSheetManager.d.ts +4 -5
- package/lib/typescript/commonjs/ui/navigation/bottomSheetManager.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/surfaceBackBridge.d.ts +16 -0
- package/lib/typescript/commonjs/ui/navigation/surfaceBackBridge.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/navigation/surfaceNavStack.d.ts +21 -0
- package/lib/typescript/commonjs/ui/navigation/surfaceNavStack.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/surfaceRegistry.d.ts +101 -23
- package/lib/typescript/commonjs/ui/navigation/surfaceRegistry.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/surfaces.d.ts +42 -11
- package/lib/typescript/commonjs/ui/navigation/surfaces.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AccountMembersScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AccountVerificationScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AppInfoScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AvatarCropScreen.d.ts +18 -9
- package/lib/typescript/commonjs/ui/screens/AvatarCropScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ChangeAvatarScreen.d.ts +34 -0
- package/lib/typescript/commonjs/ui/screens/ChangeAvatarScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/CreateAccountScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/EditProfileScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/FAQScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/FeedbackScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/HelpSupportScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/HistoryViewScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/LearnMoreUsernamesScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/LegalDocumentsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts +1 -1
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/NotificationsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/PreferencesScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ProfileScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/SearchSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/UserLinksScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/UserListScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/FileLibraryError.d.ts +23 -0
- package/lib/typescript/commonjs/ui/screens/fileManagement/FileLibraryError.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts +4 -0
- package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +10 -2
- package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustAboutScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustCenterScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustFAQScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustRewardsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/stores/resetSessionScopedStores.d.ts +8 -1
- package/lib/typescript/commonjs/ui/stores/resetSessionScopedStores.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/types/navigation.d.ts +10 -0
- package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts +0 -48
- package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +2 -0
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/AvatarCameraBadge.d.ts +4 -0
- package/lib/typescript/module/ui/components/AvatarCameraBadge.d.ts.map +1 -0
- package/lib/typescript/{commonjs/ui/components/OxyAccountDialog.d.ts → module/ui/components/OxyAccountDialogScreen.d.ts} +5 -4
- package/lib/typescript/module/ui/components/OxyAccountDialogScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts +3 -3
- package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ProfileButton.d.ts +2 -2
- package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ProfileSummaryCard.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/RequireOxyAuth.d.ts +1 -1
- package/lib/typescript/module/ui/components/SurfaceHeaderAction.d.ts +16 -0
- package/lib/typescript/module/ui/components/SurfaceHeaderAction.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/SurfaceScreen.d.ts +3 -4
- package/lib/typescript/module/ui/components/SurfaceScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts +14 -4
- package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/modals/DeleteAccountModal.d.ts +17 -2
- package/lib/typescript/module/ui/components/modals/DeleteAccountModal.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/oxyAuthChooserStyles.d.ts +75 -13
- package/lib/typescript/module/ui/components/oxyAuthChooserStyles.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/photogrid/JustifiedPhotoGrid.d.ts +10 -8
- package/lib/typescript/module/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/surfaces/ActionSheetSurface.d.ts +38 -0
- package/lib/typescript/module/ui/components/surfaces/ActionSheetSurface.d.ts.map +1 -0
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/queryKeys.d.ts +9 -0
- package/lib/typescript/module/ui/hooks/queries/queryKeys.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/useFileQueries.d.ts +50 -0
- package/lib/typescript/module/ui/hooks/queries/useFileQueries.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts +17 -16
- package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useReduceMotion.d.ts +14 -0
- package/lib/typescript/module/ui/hooks/useReduceMotion.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts +31 -0
- package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts +1 -1
- package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts +27 -2
- package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/bottomSheetManager.d.ts +4 -5
- package/lib/typescript/module/ui/navigation/bottomSheetManager.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/surfaceBackBridge.d.ts +16 -0
- package/lib/typescript/module/ui/navigation/surfaceBackBridge.d.ts.map +1 -0
- package/lib/typescript/module/ui/navigation/surfaceNavStack.d.ts +21 -0
- package/lib/typescript/module/ui/navigation/surfaceNavStack.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/surfaceRegistry.d.ts +101 -23
- package/lib/typescript/module/ui/navigation/surfaceRegistry.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/surfaces.d.ts +42 -11
- package/lib/typescript/module/ui/navigation/surfaces.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AccountMembersScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AccountVerificationScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AppInfoScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts +18 -9
- package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ChangeAvatarScreen.d.ts +34 -0
- package/lib/typescript/module/ui/screens/ChangeAvatarScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/CreateAccountScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/EditProfileScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FAQScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FeedbackScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/HelpSupportScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/HistoryViewScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/LearnMoreUsernamesScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/LegalDocumentsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/NotificationsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/PreferencesScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ProfileScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/SearchSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/UserLinksScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/UserListScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/FileLibraryError.d.ts +23 -0
- package/lib/typescript/module/ui/screens/fileManagement/FileLibraryError.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts +4 -0
- package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +10 -2
- package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustAboutScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustCenterScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustFAQScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustRewardsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/stores/resetSessionScopedStores.d.ts +8 -1
- package/lib/typescript/module/ui/stores/resetSessionScopedStores.d.ts.map +1 -1
- package/lib/typescript/module/ui/types/navigation.d.ts +10 -0
- package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/avatarUtils.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/fileManagement.d.ts +0 -48
- package/lib/typescript/module/ui/utils/fileManagement.d.ts.map +1 -1
- package/package.json +9 -5
- package/src/index.ts +12 -5
- package/src/ui/components/AvatarCameraBadge.tsx +35 -0
- package/src/ui/components/{OxyAccountDialog.tsx → OxyAccountDialogScreen.tsx} +50 -116
- package/src/ui/components/OxyAuthChooser.tsx +743 -86
- package/src/ui/components/OxyConsentScreen.tsx +1 -1
- package/src/ui/components/ProfileButton.tsx +18 -3
- package/src/ui/components/ProfileSummaryCard.tsx +2 -25
- package/src/ui/components/RequireOxyAuth.tsx +1 -1
- package/src/ui/components/SurfaceHeaderAction.tsx +60 -0
- package/src/ui/components/SurfaceScreen.tsx +108 -14
- package/src/ui/components/fileManagement/FileDetailsModal.tsx +50 -36
- package/src/ui/components/modals/DeleteAccountModal.tsx +47 -26
- package/src/ui/components/oxyAuthChooserStyles.ts +78 -16
- package/src/ui/components/photogrid/JustifiedPhotoGrid.tsx +158 -84
- package/src/ui/components/photogrid/__tests__/chunkPhotos.test.ts +51 -0
- package/src/ui/components/surfaces/ActionSheetSurface.tsx +98 -0
- package/src/ui/context/OxyContext.tsx +79 -25
- package/src/ui/hooks/queries/queryKeys.ts +15 -0
- package/src/ui/hooks/queries/useFileQueries.ts +162 -0
- package/src/ui/hooks/useAvatarPicker.ts +46 -74
- package/src/ui/hooks/useReduceMotion.ts +58 -0
- package/src/ui/hooks/useSurfaceHeader.ts +57 -0
- package/src/ui/hooks/useSwitchableAccounts.ts +1 -1
- package/src/ui/navigation/__tests__/getSurfaceConfig.test.ts +55 -7
- package/src/ui/navigation/__tests__/surfaceNavStack.test.ts +149 -0
- package/src/ui/navigation/accountDialogManager.ts +42 -2
- package/src/ui/navigation/bottomSheetManager.ts +6 -7
- package/src/ui/navigation/routes.ts +6 -4
- package/src/ui/navigation/surfaceBackBridge.ts +69 -0
- package/src/ui/navigation/surfaceNavStack.ts +72 -9
- package/src/ui/navigation/surfaceRegistry.ts +164 -24
- package/src/ui/navigation/surfaces.ts +137 -30
- package/src/ui/screens/AccountMembersScreen.tsx +39 -100
- package/src/ui/screens/AccountSettingsScreen.tsx +32 -54
- package/src/ui/screens/AccountVerificationScreen.tsx +23 -51
- package/src/ui/screens/AppInfoScreen.tsx +6 -13
- package/src/ui/screens/AvatarCropScreen.tsx +340 -311
- package/src/ui/screens/ChangeAvatarScreen.tsx +359 -0
- package/src/ui/screens/ConnectedAppsScreen.tsx +39 -60
- package/src/ui/screens/CreateAccountScreen.tsx +13 -39
- package/src/ui/screens/EditProfileFieldScreen.tsx +30 -48
- package/src/ui/screens/EditProfileScreen.tsx +7 -16
- package/src/ui/screens/FAQScreen.tsx +9 -13
- package/src/ui/screens/FeedbackScreen.tsx +8 -22
- package/src/ui/screens/FileManagementScreen.tsx +370 -610
- package/src/ui/screens/HelpSupportScreen.tsx +7 -13
- package/src/ui/screens/HistoryViewScreen.tsx +26 -31
- package/src/ui/screens/LanguageSelectorScreen.tsx +12 -46
- package/src/ui/screens/LearnMoreUsernamesScreen.tsx +8 -16
- package/src/ui/screens/LegalDocumentsScreen.tsx +7 -22
- package/src/ui/screens/ManageAccountScreen.tsx +96 -165
- package/src/ui/screens/NotificationsScreen.tsx +7 -13
- package/src/ui/screens/PaymentGatewayScreen.tsx +3 -10
- package/src/ui/screens/PreferencesScreen.tsx +7 -13
- package/src/ui/screens/PremiumSubscriptionScreen.tsx +52 -90
- package/src/ui/screens/PrivacySettingsScreen.tsx +9 -21
- package/src/ui/screens/ProfileScreen.tsx +9 -11
- package/src/ui/screens/SavesCollectionsScreen.tsx +7 -13
- package/src/ui/screens/SearchSettingsScreen.tsx +9 -21
- package/src/ui/screens/UserLinksScreen.tsx +7 -14
- package/src/ui/screens/UserListScreen.tsx +2 -5
- package/src/ui/screens/WelcomeNewUserScreen.tsx +18 -48
- package/src/ui/screens/fileManagement/FileLibraryError.tsx +56 -0
- package/src/ui/screens/fileManagement/PhotoPickerSection.tsx +56 -46
- package/src/ui/screens/fileManagement/hooks/useFileUploadState.ts +55 -71
- package/src/ui/screens/trust/TrustAboutScreen.tsx +10 -17
- package/src/ui/screens/trust/TrustCenterScreen.tsx +9 -28
- package/src/ui/screens/trust/TrustFAQScreen.tsx +15 -18
- package/src/ui/screens/trust/TrustLeaderboardScreen.tsx +3 -5
- package/src/ui/screens/trust/TrustRewardsScreen.tsx +11 -26
- package/src/ui/screens/trust/TrustRulesScreen.tsx +10 -13
- package/src/ui/stores/resetSessionScopedStores.ts +8 -3
- package/src/ui/types/navigation.ts +10 -0
- package/src/ui/utils/avatarUtils.ts +11 -2
- package/src/ui/utils/fileManagement.ts +1 -101
- package/lib/commonjs/ui/components/Header.js +0 -305
- package/lib/commonjs/ui/components/Header.js.map +0 -1
- package/lib/commonjs/ui/components/OxyAccountDialog.js.map +0 -1
- package/lib/commonjs/ui/stores/fileStore.js +0 -153
- package/lib/commonjs/ui/stores/fileStore.js.map +0 -1
- package/lib/module/ui/components/Header.js +0 -299
- package/lib/module/ui/components/Header.js.map +0 -1
- package/lib/module/ui/components/OxyAccountDialog.js.map +0 -1
- package/lib/module/ui/stores/fileStore.js +0 -145
- package/lib/module/ui/stores/fileStore.js.map +0 -1
- package/lib/typescript/commonjs/ui/components/Header.d.ts +0 -33
- package/lib/typescript/commonjs/ui/components/Header.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/stores/fileStore.d.ts +0 -31
- package/lib/typescript/commonjs/ui/stores/fileStore.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/Header.d.ts +0 -33
- package/lib/typescript/module/ui/components/Header.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts.map +0 -1
- package/lib/typescript/module/ui/stores/fileStore.d.ts +0 -31
- package/lib/typescript/module/ui/stores/fileStore.d.ts.map +0 -1
- package/src/ui/components/Header.tsx +0 -224
- package/src/ui/stores/fileStore.ts +0 -118
|
@@ -5,11 +5,17 @@
|
|
|
5
5
|
* but before the avatar is uploaded. Inspired by iOS Photos, Google Photos and
|
|
6
6
|
* Instagram crop tools.
|
|
7
7
|
*
|
|
8
|
+
* Reached ONLY by navigating within a `ChangeAvatar` surface, so the panel
|
|
9
|
+
* morphs from the source list into the editor. The surface owns the chrome: this
|
|
10
|
+
* screen declares its title and its "Use photo" action through `useSurfaceHeader`
|
|
11
|
+
* and renders no bar of its own — the nav bar's back arrow is Cancel, and it
|
|
12
|
+
* returns to the source list.
|
|
13
|
+
*
|
|
8
14
|
* Architecture:
|
|
9
|
-
* -
|
|
10
|
-
*
|
|
11
|
-
* - Circular viewport with white ring
|
|
12
|
-
*
|
|
15
|
+
* - A dark crop stage, independent of theme, so photos always read well, inset
|
|
16
|
+
* inside the surface's own themed panel.
|
|
17
|
+
* - Circular viewport with white ring and a 3x3 rule-of-thirds grid that
|
|
18
|
+
* appears during gestures and fades after 800ms.
|
|
13
19
|
* - Floating zoom chip during pinch.
|
|
14
20
|
* - Pan + pinch via Gesture Handler, transform driven by Reanimated.
|
|
15
21
|
* - Reduced-motion aware entrance animation.
|
|
@@ -21,13 +27,12 @@
|
|
|
21
27
|
*/
|
|
22
28
|
|
|
23
29
|
import type React from 'react';
|
|
24
|
-
import { useCallback,
|
|
30
|
+
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
25
31
|
import {
|
|
26
32
|
View,
|
|
27
33
|
Text,
|
|
28
34
|
StyleSheet,
|
|
29
35
|
ActivityIndicator,
|
|
30
|
-
TouchableOpacity,
|
|
31
36
|
Image,
|
|
32
37
|
Platform,
|
|
33
38
|
AccessibilityInfo,
|
|
@@ -43,10 +48,14 @@ import Animated, {
|
|
|
43
48
|
withSpring,
|
|
44
49
|
withTiming,
|
|
45
50
|
} from 'react-native-reanimated';
|
|
46
|
-
import {
|
|
51
|
+
import { useQuery, keepPreviousData } from '@tanstack/react-query';
|
|
47
52
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
53
|
+
import { Button } from '@oxyhq/bloom/button';
|
|
48
54
|
import { logger } from '@oxyhq/core';
|
|
55
|
+
import { useOxy } from '../context/OxyContext';
|
|
49
56
|
import { useI18n } from '../hooks/useI18n';
|
|
57
|
+
import { useReduceMotion } from '../hooks/useReduceMotion';
|
|
58
|
+
import { useSurfaceHeader } from '../hooks/useSurfaceHeader';
|
|
50
59
|
import { toast } from '@oxyhq/bloom';
|
|
51
60
|
import type { BaseScreenProps } from '../types/navigation';
|
|
52
61
|
|
|
@@ -66,16 +75,19 @@ export interface AvatarCropResult {
|
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
export interface AvatarCropScreenProps extends BaseScreenProps {
|
|
69
|
-
/** URI of the source image to crop. */
|
|
78
|
+
/** URI of the source image to crop (device / camera sources pass this). */
|
|
70
79
|
imageUri?: string;
|
|
80
|
+
/**
|
|
81
|
+
* ID of an existing Oxy file to crop (the "My Oxy files" source passes this
|
|
82
|
+
* instead of a URL). Its download URL is usually private, so it is resolved
|
|
83
|
+
* HERE — showing this screen's own loading state on the dark canvas — rather
|
|
84
|
+
* than in the source list, which would otherwise linger for the round-trip.
|
|
85
|
+
*/
|
|
86
|
+
imageFileId?: string;
|
|
71
87
|
/** Natural width of the source image (optional — measured if absent). */
|
|
72
88
|
sourceWidth?: number;
|
|
73
89
|
/** Natural height of the source image (optional — measured if absent). */
|
|
74
90
|
sourceHeight?: number;
|
|
75
|
-
/** Called with the cropped file once the user confirms. */
|
|
76
|
-
onConfirm?: (result: AvatarCropResult) => void | Promise<void>;
|
|
77
|
-
/** Called if the user cancels without confirming. */
|
|
78
|
-
onCancel?: () => void;
|
|
79
91
|
}
|
|
80
92
|
|
|
81
93
|
/** Side length (in dp) of the crop viewport. The output is always 512x512px. */
|
|
@@ -83,14 +95,20 @@ const VIEWPORT_SIZE = 320;
|
|
|
83
95
|
const OUTPUT_SIZE = 512;
|
|
84
96
|
const MIN_SCALE = 1;
|
|
85
97
|
const MAX_SCALE = 4;
|
|
98
|
+
/** Zoom increment per +/- button press (web, where there is no pinch). */
|
|
99
|
+
const ZOOM_STEP = 0.5;
|
|
100
|
+
/** Tween duration for a button-driven zoom (collapses to 0 under reduce-motion). */
|
|
101
|
+
const ZOOM_BUTTON_DURATION_MS = 180;
|
|
86
102
|
/** Duration (ms) that the rule-of-thirds grid lingers after a gesture ends. */
|
|
87
103
|
const GRID_FADE_DELAY_MS = 800;
|
|
88
104
|
const GRID_FADE_DURATION_MS = 220;
|
|
89
105
|
/** Duration the zoom chip stays visible after a pinch ends. */
|
|
90
106
|
const ZOOM_CHIP_FADE_DELAY_MS = 600;
|
|
91
107
|
const ZOOM_CHIP_FADE_DURATION_MS = 200;
|
|
92
|
-
/**
|
|
108
|
+
/** Stage color is fixed independent of theme so the photo always reads well. */
|
|
93
109
|
const CANVAS_BG = '#000000';
|
|
110
|
+
/** Corner radius of the dark stage block inside the surface's themed panel. */
|
|
111
|
+
const STAGE_RADIUS = 24;
|
|
94
112
|
const RING_COLOR = '#ffffff';
|
|
95
113
|
const RING_WIDTH = 2;
|
|
96
114
|
const REMOTE_HTTP_URI_PATTERN = /^https?:\/\//i;
|
|
@@ -123,6 +141,28 @@ interface ImageNaturalSize {
|
|
|
123
141
|
height: number;
|
|
124
142
|
}
|
|
125
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Measure an image's intrinsic size via `Image.getSize`, wrapped as a Promise so
|
|
146
|
+
* it can be a React Query `queryFn` (no component state / effects). Rejects on a
|
|
147
|
+
* platform failure or degenerate dimensions so the query surfaces `isError`.
|
|
148
|
+
* Mirrors the `measurePhotoDimensions` helper the photo grid uses.
|
|
149
|
+
*/
|
|
150
|
+
function measureImageSize(uri: string): Promise<ImageNaturalSize> {
|
|
151
|
+
return new Promise<ImageNaturalSize>((resolve, reject) => {
|
|
152
|
+
Image.getSize(
|
|
153
|
+
uri,
|
|
154
|
+
(width, height) => {
|
|
155
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
|
|
156
|
+
reject(new Error('Image reported invalid dimensions'));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
resolve({ width, height });
|
|
160
|
+
},
|
|
161
|
+
() => reject(new Error('Image measurement failed')),
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
126
166
|
/**
|
|
127
167
|
* Lazy-loaded reference to the expo-image-manipulator module. The module is an
|
|
128
168
|
* optional peer dep, so we resolve it on demand and surface a clean error
|
|
@@ -296,28 +336,84 @@ async function hapticSelection(): Promise<void> {
|
|
|
296
336
|
}
|
|
297
337
|
|
|
298
338
|
const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
|
|
339
|
+
dismiss,
|
|
299
340
|
goBack,
|
|
300
|
-
onClose,
|
|
301
341
|
imageUri,
|
|
342
|
+
imageFileId,
|
|
302
343
|
sourceWidth,
|
|
303
344
|
sourceHeight,
|
|
304
|
-
onConfirm,
|
|
305
|
-
onCancel,
|
|
306
345
|
}) => {
|
|
307
346
|
const theme = useTheme();
|
|
308
347
|
const { t } = useI18n();
|
|
309
|
-
const
|
|
348
|
+
const { oxyServices } = useOxy();
|
|
349
|
+
// Reactive OS reduce-motion preference (useSyncExternalStore, no effect). Pins
|
|
350
|
+
// the entrance spring off. Declared before `entrance` so its initial rest value
|
|
351
|
+
// is correct under reduce-motion.
|
|
352
|
+
const reduceMotion = useReduceMotion();
|
|
353
|
+
|
|
354
|
+
// The "My Oxy files" source hands us a file ID instead of a ready URL. Its
|
|
355
|
+
// download URL is usually private, so it must be resolved through the SDK
|
|
356
|
+
// (which throws on failure). Resolving it HERE — not in the source list — is
|
|
357
|
+
// what keeps the list from lingering on screen for the round-trip: this screen
|
|
358
|
+
// shows its own spinner on the dark canvas while the URL resolves. A React
|
|
359
|
+
// Query read (not an effect) so it stays declarative and cached.
|
|
360
|
+
const shouldResolveFile = !imageUri && !!imageFileId;
|
|
361
|
+
const sourceQuery = useQuery({
|
|
362
|
+
queryKey: ['avatarCropSource', imageFileId],
|
|
363
|
+
enabled: shouldResolveFile,
|
|
364
|
+
staleTime: Number.POSITIVE_INFINITY,
|
|
365
|
+
retry: false,
|
|
366
|
+
queryFn: async () => {
|
|
367
|
+
if (!imageFileId) {
|
|
368
|
+
throw new Error('No file id to resolve for cropping');
|
|
369
|
+
}
|
|
370
|
+
const resolved = await oxyServices.assetGetUrl(imageFileId);
|
|
371
|
+
if (!resolved?.url) {
|
|
372
|
+
throw new Error('No download URL returned for the selected image');
|
|
373
|
+
}
|
|
374
|
+
return resolved.url;
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// The URL the cropper actually loads: the passed `imageUri`, else the URL the
|
|
379
|
+
// file-ID query resolved. While it resolves, `effectiveUri` is undefined and
|
|
380
|
+
// the stage shows its own spinner (never the empty state).
|
|
381
|
+
const effectiveUri = imageUri ?? sourceQuery.data;
|
|
382
|
+
const isResolvingSource = shouldResolveFile && !sourceQuery.data && !sourceQuery.isError;
|
|
383
|
+
const sourceErrorMessage = sourceQuery.isError
|
|
384
|
+
? t('changeAvatar.errors.loadImageFailed') || 'Could not load the selected image'
|
|
385
|
+
: null;
|
|
386
|
+
|
|
387
|
+
// Natural size of the source image. Known up front (device/camera sources pass
|
|
388
|
+
// the dimensions) OR measured lazily from `effectiveUri` via a React Query read
|
|
389
|
+
// (no effect) — the same Image.getSize→useQuery pattern the photo grid uses.
|
|
390
|
+
const hasPassedDimensions = !!(sourceWidth && sourceHeight);
|
|
391
|
+
const measureQuery = useQuery({
|
|
392
|
+
queryKey: ['avatarCropMeasure', effectiveUri],
|
|
393
|
+
enabled: !!effectiveUri && !hasPassedDimensions,
|
|
394
|
+
queryFn: () => {
|
|
395
|
+
if (!effectiveUri) {
|
|
396
|
+
throw new Error('No image to measure');
|
|
397
|
+
}
|
|
398
|
+
return measureImageSize(effectiveUri);
|
|
399
|
+
},
|
|
400
|
+
staleTime: Number.POSITIVE_INFINITY,
|
|
401
|
+
retry: false,
|
|
402
|
+
placeholderData: keepPreviousData,
|
|
403
|
+
});
|
|
404
|
+
const naturalSize = useMemo<ImageNaturalSize | null>(() => {
|
|
405
|
+
if (sourceWidth && sourceHeight) return { width: sourceWidth, height: sourceHeight };
|
|
406
|
+
return measureQuery.data ?? null;
|
|
407
|
+
}, [sourceWidth, sourceHeight, measureQuery.data]);
|
|
408
|
+
/** Measurement failed (bad dimensions / getSize error) — surfaced via the empty UI. */
|
|
409
|
+
const measureErrorMessage = measureQuery.isError
|
|
410
|
+
? t('editProfile.toasts.cropMeasureFailed') || 'Could not measure the image'
|
|
411
|
+
: null;
|
|
310
412
|
|
|
311
|
-
// Natural size of the source image. May be known up front (passed in) or
|
|
312
|
-
// measured lazily via Image.getSize once the image loads.
|
|
313
|
-
const [naturalSize, setNaturalSize] = useState<ImageNaturalSize | null>(
|
|
314
|
-
sourceWidth && sourceHeight ? { width: sourceWidth, height: sourceHeight } : null,
|
|
315
|
-
);
|
|
316
413
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
317
414
|
const [zoomLabel, setZoomLabel] = useState('1.0');
|
|
318
415
|
/** True when scale != MIN_SCALE OR translate != 0 — used to reveal the reset link. */
|
|
319
416
|
const [isModified, setIsModified] = useState(false);
|
|
320
|
-
const [reduceMotion, setReduceMotion] = useState(false);
|
|
321
417
|
|
|
322
418
|
// Shared values for the active gesture transform.
|
|
323
419
|
const scale = useSharedValue(MIN_SCALE);
|
|
@@ -361,112 +457,24 @@ const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
|
|
|
361
457
|
return { width: VIEWPORT_SIZE, height: VIEWPORT_SIZE / ratio };
|
|
362
458
|
}, [naturalSize]);
|
|
363
459
|
|
|
364
|
-
//
|
|
365
|
-
//
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
const
|
|
371
|
-
(
|
|
372
|
-
if (
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
logger.debug('Measuring image', { component: LOG_COMPONENT });
|
|
379
|
-
Image.getSize(
|
|
380
|
-
uri,
|
|
381
|
-
(w, h) => {
|
|
382
|
-
logger.debug('Image measured', { component: LOG_COMPONENT }, { width: w, height: h });
|
|
383
|
-
if (!Number.isFinite(w) || !Number.isFinite(h) || w <= 0 || h <= 0) {
|
|
384
|
-
const message = t('editProfile.toasts.cropMeasureFailed') ||
|
|
385
|
-
'Could not measure the image';
|
|
386
|
-
setMeasureError(message);
|
|
387
|
-
toast.error(message);
|
|
388
|
-
measuringUriRef.current = null;
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
setMeasureError(null);
|
|
392
|
-
setNaturalSize({ width: w, height: h });
|
|
393
|
-
},
|
|
394
|
-
() => {
|
|
395
|
-
logger.error(
|
|
396
|
-
'Image.getSize failed',
|
|
397
|
-
new Error('Image measurement failed'),
|
|
398
|
-
{ component: LOG_COMPONENT },
|
|
399
|
-
);
|
|
400
|
-
const message = t('editProfile.toasts.cropMeasureFailed') ||
|
|
401
|
-
'Could not measure the image';
|
|
402
|
-
setMeasureError(message);
|
|
403
|
-
toast.error(message);
|
|
404
|
-
measuringUriRef.current = null;
|
|
405
|
-
},
|
|
406
|
-
);
|
|
460
|
+
// Entrance pulse, driven from the crop frame's ref callback (fires on mount)
|
|
461
|
+
// rather than an effect — the media-cleanup `startEntrance` pattern. Reduce
|
|
462
|
+
// motion pins the frame at rest; otherwise it springs in from 0.95→1. The
|
|
463
|
+
// callback depends on `reduceMotion`, so if that preference resolves/flips the
|
|
464
|
+
// callback re-runs with the node and re-pins (snap to 1) — matching the old
|
|
465
|
+
// effect that snapped the entrance to rest when reduce-motion turned on.
|
|
466
|
+
const startEntrance = useCallback(
|
|
467
|
+
(node: unknown): void => {
|
|
468
|
+
if (!node) return; // unmount
|
|
469
|
+
if (reduceMotion) {
|
|
470
|
+
entrance.value = 1;
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
entrance.value = withSpring(1, { damping: 14, stiffness: 180, mass: 0.9 });
|
|
407
474
|
},
|
|
408
|
-
[
|
|
475
|
+
[entrance, reduceMotion],
|
|
409
476
|
);
|
|
410
477
|
|
|
411
|
-
// Kick off measurement once per imageUri. Using useEffect (not a render-body
|
|
412
|
-
// side effect) so the call is scheduled exactly when the URI changes,
|
|
413
|
-
// rather than being re-fired on every parent re-render.
|
|
414
|
-
useEffect(() => {
|
|
415
|
-
if (!imageUri) return;
|
|
416
|
-
if (sourceWidth && sourceHeight) return;
|
|
417
|
-
if (naturalSize) return;
|
|
418
|
-
handleImageMeasured(imageUri);
|
|
419
|
-
}, [handleImageMeasured, imageUri, naturalSize, sourceHeight, sourceWidth]);
|
|
420
|
-
|
|
421
|
-
// Dev-only one-time mount breadcrumb. `logger.debug` is dev-gated so
|
|
422
|
-
// this is a no-op in production releases; we additionally avoid logging
|
|
423
|
-
// the full `imageUri` to prevent leaking on-device file paths into any
|
|
424
|
-
// breadcrumb sink that picks up debug output.
|
|
425
|
-
useEffect(() => {
|
|
426
|
-
logger.debug(
|
|
427
|
-
'mount',
|
|
428
|
-
{ component: LOG_COMPONENT },
|
|
429
|
-
{
|
|
430
|
-
hasImageUri: !!imageUri,
|
|
431
|
-
hasSourceDimensions: !!(sourceWidth && sourceHeight),
|
|
432
|
-
},
|
|
433
|
-
);
|
|
434
|
-
}, [imageUri, sourceHeight, sourceWidth]);
|
|
435
|
-
|
|
436
|
-
// Detect reduce-motion preference once on mount + subscribe to changes.
|
|
437
|
-
useEffect(() => {
|
|
438
|
-
let cancelled = false;
|
|
439
|
-
AccessibilityInfo.isReduceMotionEnabled()
|
|
440
|
-
.then((enabled) => {
|
|
441
|
-
if (cancelled) return;
|
|
442
|
-
setReduceMotion(enabled);
|
|
443
|
-
if (enabled) {
|
|
444
|
-
entrance.value = 1;
|
|
445
|
-
}
|
|
446
|
-
})
|
|
447
|
-
.catch(() => {
|
|
448
|
-
// Best-effort — fall back to motion enabled.
|
|
449
|
-
});
|
|
450
|
-
const sub = AccessibilityInfo.addEventListener('reduceMotionChanged', (enabled) => {
|
|
451
|
-
setReduceMotion(enabled);
|
|
452
|
-
if (enabled) entrance.value = 1;
|
|
453
|
-
});
|
|
454
|
-
return () => {
|
|
455
|
-
cancelled = true;
|
|
456
|
-
sub.remove();
|
|
457
|
-
};
|
|
458
|
-
}, [entrance]);
|
|
459
|
-
|
|
460
|
-
// Play the entrance pulse exactly once when motion is allowed.
|
|
461
|
-
useEffect(() => {
|
|
462
|
-
if (reduceMotion) return;
|
|
463
|
-
entrance.value = withSpring(1, {
|
|
464
|
-
damping: 14,
|
|
465
|
-
stiffness: 180,
|
|
466
|
-
mass: 0.9,
|
|
467
|
-
});
|
|
468
|
-
}, [entrance, reduceMotion]);
|
|
469
|
-
|
|
470
478
|
const commitTransform = useCallback((s: number, tx: number, ty: number) => {
|
|
471
479
|
committedScale.current = s;
|
|
472
480
|
committedTranslateX.current = tx;
|
|
@@ -635,17 +643,29 @@ const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
|
|
|
635
643
|
[panGesture, pinchGesture],
|
|
636
644
|
);
|
|
637
645
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
646
|
+
// Deps list every shared value the mapper reads so it re-runs on web (RN-Web
|
|
647
|
+
// has no worklets plugin — a mapper omitting its driver SVs freezes at the
|
|
648
|
+
// first frame, which would leave the button-driven zoom stuck). Native
|
|
649
|
+
// auto-tracks and ignores the extra deps, so this is safe cross-platform.
|
|
650
|
+
const imageAnimatedStyle = useAnimatedStyle(
|
|
651
|
+
() => ({
|
|
652
|
+
transform: [
|
|
653
|
+
{ translateX: translateX.value },
|
|
654
|
+
{ translateY: translateY.value },
|
|
655
|
+
{ scale: scale.value },
|
|
656
|
+
],
|
|
657
|
+
}),
|
|
658
|
+
[translateX, translateY, scale],
|
|
659
|
+
);
|
|
645
660
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
661
|
+
// `[entrance]` in deps so the ref-callback-driven entrance spring ticks on
|
|
662
|
+
// RN-Web (no worklets plugin); native auto-tracks and ignores the extra dep.
|
|
663
|
+
const cropFrameAnimatedStyle = useAnimatedStyle(
|
|
664
|
+
() => ({
|
|
665
|
+
transform: [{ scale: entrance.value }],
|
|
666
|
+
}),
|
|
667
|
+
[entrance],
|
|
668
|
+
);
|
|
649
669
|
|
|
650
670
|
const gridAnimatedStyle = useAnimatedStyle(() => ({
|
|
651
671
|
opacity: gridOpacity.value,
|
|
@@ -667,6 +687,61 @@ const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
|
|
|
667
687
|
);
|
|
668
688
|
}, [commitTransform, reduceMotion, scale, t, translateX, translateY]);
|
|
669
689
|
|
|
690
|
+
/**
|
|
691
|
+
* Web zoom controls. A desktop pointer has no pinch, so the +/- buttons drive
|
|
692
|
+
* the SAME `scale` shared value the pinch gesture does — clamped to the same
|
|
693
|
+
* bounds, with translation re-clamped through the shared {@link clampTranslation}
|
|
694
|
+
* helper so the image never leaves the viewport. Native keeps pinch (the
|
|
695
|
+
* buttons are hidden there). Reduced motion collapses the tween to an instant
|
|
696
|
+
* set. Reads the committed transform (refs) at press time, never during render.
|
|
697
|
+
*/
|
|
698
|
+
const applyZoom = useCallback(
|
|
699
|
+
(direction: 1 | -1) => {
|
|
700
|
+
if (!baseFit || isProcessing) return;
|
|
701
|
+
const current = committedScale.current;
|
|
702
|
+
const target = Math.min(
|
|
703
|
+
MAX_SCALE,
|
|
704
|
+
Math.max(MIN_SCALE, current + direction * ZOOM_STEP),
|
|
705
|
+
);
|
|
706
|
+
if (Math.abs(target - current) < 0.001) {
|
|
707
|
+
// Already at the bound — a soft selection tick, no transform change.
|
|
708
|
+
void hapticSelection();
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
const clamped = clampTranslation(
|
|
712
|
+
committedTranslateX.current,
|
|
713
|
+
committedTranslateY.current,
|
|
714
|
+
target,
|
|
715
|
+
baseFit.width,
|
|
716
|
+
baseFit.height,
|
|
717
|
+
);
|
|
718
|
+
const duration = reduceMotion ? 0 : ZOOM_BUTTON_DURATION_MS;
|
|
719
|
+
scale.value = withTiming(target, { duration });
|
|
720
|
+
translateX.value = withTiming(clamped.tx, { duration });
|
|
721
|
+
translateY.value = withTiming(clamped.ty, { duration });
|
|
722
|
+
commitTransform(target, clamped.tx, clamped.ty);
|
|
723
|
+
void hapticImpact('light');
|
|
724
|
+
// Mirror the pinch's transient chrome so the buttons feel identical.
|
|
725
|
+
showGrid();
|
|
726
|
+
hideGrid();
|
|
727
|
+
showZoomChip();
|
|
728
|
+
hideZoomChip();
|
|
729
|
+
},
|
|
730
|
+
[
|
|
731
|
+
baseFit,
|
|
732
|
+
commitTransform,
|
|
733
|
+
hideGrid,
|
|
734
|
+
hideZoomChip,
|
|
735
|
+
isProcessing,
|
|
736
|
+
reduceMotion,
|
|
737
|
+
scale,
|
|
738
|
+
showGrid,
|
|
739
|
+
showZoomChip,
|
|
740
|
+
translateX,
|
|
741
|
+
translateY,
|
|
742
|
+
],
|
|
743
|
+
);
|
|
744
|
+
|
|
670
745
|
/**
|
|
671
746
|
* Convert the on-screen transform into pixel-space crop coordinates
|
|
672
747
|
* relative to the source image, then invoke expo-image-manipulator to
|
|
@@ -686,7 +761,7 @@ const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
|
|
|
686
761
|
committedTranslateY: committedTranslateY.current,
|
|
687
762
|
},
|
|
688
763
|
);
|
|
689
|
-
if (!
|
|
764
|
+
if (!effectiveUri || !baseFit || !naturalSize) {
|
|
690
765
|
toast.error(
|
|
691
766
|
t('editProfile.toasts.cropNotReady') || 'Image not ready yet',
|
|
692
767
|
);
|
|
@@ -738,7 +813,7 @@ const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
|
|
|
738
813
|
},
|
|
739
814
|
);
|
|
740
815
|
|
|
741
|
-
const preparedImage = await prepareImageForManipulator(
|
|
816
|
+
const preparedImage = await prepareImageForManipulator(effectiveUri);
|
|
742
817
|
preparedImageCleanup = preparedImage.cleanup;
|
|
743
818
|
const result = await manipulateAsync(
|
|
744
819
|
preparedImage.uri,
|
|
@@ -765,16 +840,15 @@ const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
|
|
|
765
840
|
|
|
766
841
|
void hapticNotification('success');
|
|
767
842
|
|
|
768
|
-
|
|
843
|
+
// Resolve the surface's present() promise with the cropped JPEG and
|
|
844
|
+
// close it. The awaiting caller (`useAvatarPicker`) handles the
|
|
845
|
+
// upload + any success toast.
|
|
846
|
+
dismiss?.({
|
|
769
847
|
uri: result.uri,
|
|
770
848
|
width: result.width,
|
|
771
849
|
height: result.height,
|
|
772
850
|
mime: 'image/jpeg',
|
|
773
851
|
});
|
|
774
|
-
|
|
775
|
-
// Close the sheet on success. The caller is responsible for any
|
|
776
|
-
// success toast (uploads typically toast their own outcome).
|
|
777
|
-
onClose?.();
|
|
778
852
|
} catch (err) {
|
|
779
853
|
const normalizedError = normalizeCropError(err);
|
|
780
854
|
logger.error('handleConfirm failed', normalizedError, { component: LOG_COMPONENT });
|
|
@@ -786,87 +860,59 @@ const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
|
|
|
786
860
|
preparedImageCleanup?.();
|
|
787
861
|
setIsProcessing(false);
|
|
788
862
|
}
|
|
789
|
-
}, [baseFit,
|
|
863
|
+
}, [baseFit, effectiveUri, naturalSize, dismiss, t]);
|
|
790
864
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
865
|
+
/**
|
|
866
|
+
* The surface's primary action, mounted into the Dialog nav bar's right slot
|
|
867
|
+
* (which is why it must stay referentially stable). While processing it keeps
|
|
868
|
+
* its width and shows a spinner; the a11y label carries the "Saving…" state
|
|
869
|
+
* the visible label can no longer show.
|
|
870
|
+
*/
|
|
871
|
+
const doneAction = useMemo(
|
|
872
|
+
() => (
|
|
873
|
+
<Button
|
|
874
|
+
variant="primary"
|
|
875
|
+
size="small"
|
|
876
|
+
onPress={() => void handleConfirm()}
|
|
877
|
+
disabled={isProcessing || !baseFit}
|
|
878
|
+
loading={isProcessing}
|
|
879
|
+
accessibilityLabel={
|
|
880
|
+
isProcessing ? t('editProfile.crop.saving') : t('editProfile.crop.confirm')
|
|
881
|
+
}
|
|
882
|
+
>
|
|
883
|
+
{t('editProfile.crop.confirm')}
|
|
884
|
+
</Button>
|
|
885
|
+
),
|
|
886
|
+
[baseFit, handleConfirm, isProcessing, t],
|
|
887
|
+
);
|
|
795
888
|
|
|
796
|
-
|
|
797
|
-
|
|
889
|
+
// No bar of our own: the surface owns the chrome. `goBack` pops back to the
|
|
890
|
+
// ChangeAvatar source list (and dismisses the surface if this is somehow the
|
|
891
|
+
// root frame), which is exactly Cancel.
|
|
892
|
+
useSurfaceHeader({
|
|
893
|
+
title: t('editProfile.crop.title'),
|
|
894
|
+
largeTitle: false,
|
|
895
|
+
right: doneAction,
|
|
896
|
+
onBack: goBack,
|
|
897
|
+
});
|
|
798
898
|
|
|
799
899
|
const styles = useMemo(
|
|
800
900
|
() =>
|
|
801
901
|
StyleSheet.create({
|
|
802
902
|
container: {
|
|
803
|
-
|
|
804
|
-
backgroundColor: CANVAS_BG,
|
|
805
|
-
},
|
|
806
|
-
topBar: {
|
|
807
|
-
paddingTop: topInset,
|
|
808
|
-
paddingHorizontal: 12,
|
|
809
|
-
paddingBottom: 10,
|
|
810
|
-
flexDirection: 'row',
|
|
811
|
-
alignItems: 'center',
|
|
812
|
-
justifyContent: 'space-between',
|
|
813
|
-
backgroundColor: 'rgba(0,0,0,0.6)',
|
|
814
|
-
zIndex: 10,
|
|
815
|
-
},
|
|
816
|
-
topBarTitleWrap: {
|
|
817
|
-
flex: 1,
|
|
818
|
-
alignItems: 'center',
|
|
819
|
-
justifyContent: 'center',
|
|
820
|
-
paddingHorizontal: 4,
|
|
821
|
-
},
|
|
822
|
-
topBarTitle: {
|
|
823
|
-
color: '#ffffff',
|
|
824
|
-
fontSize: 17,
|
|
825
|
-
letterSpacing: -0.2,
|
|
826
|
-
...(Platform.OS === 'web' ? { fontWeight: '600' as const } : null),
|
|
827
|
-
},
|
|
828
|
-
cancelBtn: {
|
|
829
|
-
minWidth: 64,
|
|
830
|
-
paddingHorizontal: 10,
|
|
831
|
-
paddingVertical: 8,
|
|
832
|
-
borderRadius: 18,
|
|
833
|
-
alignItems: 'flex-start',
|
|
834
|
-
justifyContent: 'center',
|
|
835
|
-
},
|
|
836
|
-
cancelLabel: {
|
|
837
|
-
color: '#ffffff',
|
|
838
|
-
fontSize: 15,
|
|
839
|
-
opacity: 0.85,
|
|
840
|
-
},
|
|
841
|
-
doneBtn: {
|
|
842
|
-
minWidth: 76,
|
|
843
|
-
paddingHorizontal: 14,
|
|
844
|
-
paddingVertical: 8,
|
|
845
|
-
borderRadius: 18,
|
|
846
|
-
alignItems: 'center',
|
|
847
|
-
justifyContent: 'center',
|
|
848
|
-
backgroundColor: theme.colors.primary,
|
|
849
|
-
},
|
|
850
|
-
doneBtnDisabled: {
|
|
851
|
-
opacity: 0.5,
|
|
852
|
-
},
|
|
853
|
-
doneLabel: {
|
|
854
|
-
color: '#ffffff',
|
|
855
|
-
fontSize: 15,
|
|
856
|
-
letterSpacing: -0.1,
|
|
857
|
-
...(Platform.OS === 'web' ? { fontWeight: '600' as const } : null),
|
|
858
|
-
},
|
|
859
|
-
doneLabelLoading: {
|
|
860
|
-
flexDirection: 'row',
|
|
861
|
-
alignItems: 'center',
|
|
862
|
-
justifyContent: 'center',
|
|
863
|
-
gap: 8,
|
|
903
|
+
backgroundColor: theme.colors.background,
|
|
864
904
|
},
|
|
865
905
|
stage: {
|
|
866
|
-
|
|
906
|
+
backgroundColor: CANVAS_BG,
|
|
907
|
+
borderRadius: STAGE_RADIUS,
|
|
908
|
+
overflow: 'hidden',
|
|
909
|
+
// Top padding clears the zoom chip, which floats 44dp above
|
|
910
|
+
// the crop frame and would otherwise be clipped by `overflow`.
|
|
911
|
+
paddingTop: 60,
|
|
912
|
+
paddingBottom: 28,
|
|
913
|
+
paddingHorizontal: 16,
|
|
867
914
|
alignItems: 'center',
|
|
868
915
|
justifyContent: 'center',
|
|
869
|
-
paddingHorizontal: 16,
|
|
870
916
|
},
|
|
871
917
|
cropFrame: {
|
|
872
918
|
width: VIEWPORT_SIZE,
|
|
@@ -951,17 +997,14 @@ const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
|
|
|
951
997
|
letterSpacing: 0.2,
|
|
952
998
|
},
|
|
953
999
|
helperBlock: {
|
|
954
|
-
|
|
955
|
-
paddingTop: 24,
|
|
956
|
-
paddingBottom: bottomInset,
|
|
1000
|
+
paddingTop: 16,
|
|
957
1001
|
alignItems: 'center',
|
|
958
|
-
|
|
959
|
-
gap: 10,
|
|
1002
|
+
gap: 8,
|
|
960
1003
|
},
|
|
961
1004
|
helper: {
|
|
962
1005
|
fontSize: 13,
|
|
963
1006
|
lineHeight: 18,
|
|
964
|
-
color:
|
|
1007
|
+
color: theme.colors.textSecondary,
|
|
965
1008
|
textAlign: 'center',
|
|
966
1009
|
maxWidth: 320,
|
|
967
1010
|
},
|
|
@@ -971,55 +1014,50 @@ const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
|
|
|
971
1014
|
},
|
|
972
1015
|
resetLinkText: {
|
|
973
1016
|
fontSize: 13,
|
|
974
|
-
color:
|
|
975
|
-
opacity: 0.85,
|
|
1017
|
+
color: theme.colors.primary,
|
|
976
1018
|
textDecorationLine: 'underline',
|
|
977
1019
|
},
|
|
978
1020
|
emptyState: {
|
|
979
|
-
flex: 1,
|
|
980
1021
|
alignItems: 'center',
|
|
981
1022
|
justifyContent: 'center',
|
|
982
|
-
|
|
1023
|
+
paddingVertical: 48,
|
|
983
1024
|
},
|
|
984
1025
|
emptyLabel: {
|
|
985
1026
|
fontSize: 14,
|
|
986
|
-
color:
|
|
1027
|
+
color: theme.colors.textSecondary,
|
|
987
1028
|
textAlign: 'center',
|
|
988
1029
|
},
|
|
989
1030
|
}),
|
|
990
|
-
[baseFit,
|
|
1031
|
+
[baseFit, theme],
|
|
991
1032
|
);
|
|
992
1033
|
|
|
993
1034
|
// Reset link reveal — only show when the image is not at the default
|
|
994
1035
|
// transform. Use derived display state to avoid mounting/unmounting jank.
|
|
995
1036
|
const resetLinkOpacity = isModified ? 1 : 0;
|
|
996
1037
|
|
|
997
|
-
//
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1038
|
+
// Zoom-button state is derived from `zoomLabel` (reactive state, set on every
|
|
1039
|
+
// commit) rather than the committed-scale ref, so it stays correct across
|
|
1040
|
+
// renders without reading mutable state during render. The +/- pair is web-only
|
|
1041
|
+
// (native has pinch).
|
|
1042
|
+
const currentZoom = Number.parseFloat(zoomLabel) || MIN_SCALE;
|
|
1043
|
+
const canZoomOut = currentZoom > MIN_SCALE + 0.001;
|
|
1044
|
+
const canZoomIn = currentZoom < MAX_SCALE - 0.001;
|
|
1045
|
+
const showZoomControls = Platform.OS === 'web';
|
|
1046
|
+
const zoomOutDisabled = !canZoomOut || !baseFit || isProcessing;
|
|
1047
|
+
const zoomInDisabled = !canZoomIn || !baseFit || isProcessing;
|
|
1048
|
+
|
|
1049
|
+
// No source at all (and none resolving), a resolution failure, or a
|
|
1050
|
+
// measurement failure — render a minimal empty state. While a file ID is still
|
|
1051
|
+
// resolving, fall THROUGH to the stage so its own spinner shows, not this.
|
|
1052
|
+
// The surface's nav bar (back = cancel) is the only chrome needed here.
|
|
1053
|
+
if ((!effectiveUri && !isResolvingSource) || sourceErrorMessage || measureErrorMessage) {
|
|
1054
|
+
const emptyMessage = sourceErrorMessage
|
|
1055
|
+
? sourceErrorMessage
|
|
1056
|
+
: measureErrorMessage
|
|
1057
|
+
? measureErrorMessage
|
|
1058
|
+
: t('editProfile.crop.noImage');
|
|
1002
1059
|
return (
|
|
1003
|
-
<View style={styles.container}>
|
|
1004
|
-
<View style={styles.topBar}>
|
|
1005
|
-
<TouchableOpacity
|
|
1006
|
-
accessibilityLabel={t('editProfile.crop.cancel') || 'Cancel'}
|
|
1007
|
-
accessibilityRole="button"
|
|
1008
|
-
style={styles.cancelBtn}
|
|
1009
|
-
onPress={handleCancel}
|
|
1010
|
-
activeOpacity={0.6}
|
|
1011
|
-
>
|
|
1012
|
-
<Text style={styles.cancelLabel}>
|
|
1013
|
-
{t('editProfile.crop.cancel') || 'Cancel'}
|
|
1014
|
-
</Text>
|
|
1015
|
-
</TouchableOpacity>
|
|
1016
|
-
<View style={styles.topBarTitleWrap}>
|
|
1017
|
-
<Text style={styles.topBarTitle}>
|
|
1018
|
-
{t('editProfile.crop.title') || 'Crop avatar'}
|
|
1019
|
-
</Text>
|
|
1020
|
-
</View>
|
|
1021
|
-
<View style={styles.cancelBtn} />
|
|
1022
|
-
</View>
|
|
1060
|
+
<View style={styles.container} className="px-screen-margin pb-space-24">
|
|
1023
1061
|
<View style={styles.emptyState}>
|
|
1024
1062
|
<Text style={styles.emptyLabel}>{emptyMessage}</Text>
|
|
1025
1063
|
</View>
|
|
@@ -1028,67 +1066,20 @@ const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
|
|
|
1028
1066
|
}
|
|
1029
1067
|
|
|
1030
1068
|
return (
|
|
1031
|
-
<View style={styles.container}>
|
|
1032
|
-
<View style={styles.topBar}>
|
|
1033
|
-
<TouchableOpacity
|
|
1034
|
-
accessibilityLabel={t('editProfile.crop.cancel') || 'Cancel'}
|
|
1035
|
-
accessibilityRole="button"
|
|
1036
|
-
style={styles.cancelBtn}
|
|
1037
|
-
onPress={handleCancel}
|
|
1038
|
-
disabled={isProcessing}
|
|
1039
|
-
activeOpacity={0.6}
|
|
1040
|
-
>
|
|
1041
|
-
<Text style={styles.cancelLabel}>
|
|
1042
|
-
{t('editProfile.crop.cancel') || 'Cancel'}
|
|
1043
|
-
</Text>
|
|
1044
|
-
</TouchableOpacity>
|
|
1045
|
-
<View style={styles.topBarTitleWrap}>
|
|
1046
|
-
<Text style={styles.topBarTitle} numberOfLines={1}>
|
|
1047
|
-
{t('editProfile.crop.title') || 'Crop avatar'}
|
|
1048
|
-
</Text>
|
|
1049
|
-
</View>
|
|
1050
|
-
<TouchableOpacity
|
|
1051
|
-
accessibilityLabel={t('editProfile.crop.confirm') || 'Use photo'}
|
|
1052
|
-
accessibilityRole="button"
|
|
1053
|
-
accessibilityState={{ disabled: isProcessing || !baseFit, busy: isProcessing }}
|
|
1054
|
-
style={[
|
|
1055
|
-
styles.doneBtn,
|
|
1056
|
-
(isProcessing || !baseFit) && styles.doneBtnDisabled,
|
|
1057
|
-
]}
|
|
1058
|
-
onPress={handleConfirm}
|
|
1059
|
-
disabled={isProcessing || !baseFit}
|
|
1060
|
-
activeOpacity={0.85}
|
|
1061
|
-
>
|
|
1062
|
-
{isProcessing ? (
|
|
1063
|
-
<View style={styles.doneLabelLoading}>
|
|
1064
|
-
<ActivityIndicator size="small" color="#ffffff" />
|
|
1065
|
-
<Text style={styles.doneLabel}>
|
|
1066
|
-
{t('editProfile.crop.saving') || 'Saving…'}
|
|
1067
|
-
</Text>
|
|
1068
|
-
</View>
|
|
1069
|
-
) : (
|
|
1070
|
-
<Text style={styles.doneLabel}>
|
|
1071
|
-
{t('editProfile.crop.confirm') || 'Use photo'}
|
|
1072
|
-
</Text>
|
|
1073
|
-
)}
|
|
1074
|
-
</TouchableOpacity>
|
|
1075
|
-
</View>
|
|
1076
|
-
|
|
1069
|
+
<View style={styles.container} className="px-screen-margin pb-space-24">
|
|
1077
1070
|
<View style={styles.stage}>
|
|
1078
1071
|
<Animated.View
|
|
1072
|
+
ref={startEntrance}
|
|
1079
1073
|
style={[styles.cropFrame, cropFrameAnimatedStyle]}
|
|
1080
1074
|
accessible
|
|
1081
1075
|
accessibilityRole="image"
|
|
1082
|
-
accessibilityLabel={
|
|
1083
|
-
t('editProfile.crop.a11yImage') ||
|
|
1084
|
-
'Crop preview. Pinch to zoom and drag to reposition the image.'
|
|
1085
|
-
}
|
|
1076
|
+
accessibilityLabel={t('editProfile.crop.a11yImage')}
|
|
1086
1077
|
>
|
|
1087
1078
|
<GestureDetector gesture={composedGesture}>
|
|
1088
1079
|
<View style={styles.viewport}>
|
|
1089
|
-
{baseFit ? (
|
|
1080
|
+
{baseFit && effectiveUri ? (
|
|
1090
1081
|
<Animated.Image
|
|
1091
|
-
source={{ uri:
|
|
1082
|
+
source={{ uri: effectiveUri }}
|
|
1092
1083
|
style={[styles.image, imageAnimatedStyle]}
|
|
1093
1084
|
resizeMode="cover"
|
|
1094
1085
|
/>
|
|
@@ -1118,28 +1109,66 @@ const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
|
|
|
1118
1109
|
style={[styles.zoomChip, zoomChipAnimatedStyle]}
|
|
1119
1110
|
>
|
|
1120
1111
|
<Text style={styles.zoomChipText}>
|
|
1121
|
-
{t('editProfile.crop.zoom', { value: zoomLabel })
|
|
1112
|
+
{t('editProfile.crop.zoom', { value: zoomLabel })}
|
|
1122
1113
|
</Text>
|
|
1123
1114
|
</Animated.View>
|
|
1124
1115
|
</Animated.View>
|
|
1116
|
+
|
|
1117
|
+
{/* Web-only +/- zoom controls (a desktop pointer has no pinch).
|
|
1118
|
+
Styled with NativeWind to match the translucent zoom-chip
|
|
1119
|
+
aesthetic; the full-width row is `box-none` so only the pill
|
|
1120
|
+
takes pointer events and the rest of the circle stays pannable. */}
|
|
1121
|
+
{showZoomControls ? (
|
|
1122
|
+
<View
|
|
1123
|
+
className="absolute bottom-4 left-0 right-0 items-center"
|
|
1124
|
+
pointerEvents="box-none"
|
|
1125
|
+
>
|
|
1126
|
+
<View className="flex-row overflow-hidden rounded-full bg-black/70">
|
|
1127
|
+
<Pressable
|
|
1128
|
+
accessibilityRole="button"
|
|
1129
|
+
accessibilityLabel={t('editProfile.crop.zoomOut')}
|
|
1130
|
+
accessibilityState={{ disabled: zoomOutDisabled }}
|
|
1131
|
+
disabled={zoomOutDisabled}
|
|
1132
|
+
onPress={() => applyZoom(-1)}
|
|
1133
|
+
className={`h-10 w-[52px] items-center justify-center active:bg-white/10${
|
|
1134
|
+
zoomOutDisabled ? ' opacity-40' : ''
|
|
1135
|
+
}`}
|
|
1136
|
+
>
|
|
1137
|
+
<Text className="text-white text-[22px] font-medium leading-[24px]">
|
|
1138
|
+
{'−'}
|
|
1139
|
+
</Text>
|
|
1140
|
+
</Pressable>
|
|
1141
|
+
<View className="w-px self-stretch bg-white/25" />
|
|
1142
|
+
<Pressable
|
|
1143
|
+
accessibilityRole="button"
|
|
1144
|
+
accessibilityLabel={t('editProfile.crop.zoomIn')}
|
|
1145
|
+
accessibilityState={{ disabled: zoomInDisabled }}
|
|
1146
|
+
disabled={zoomInDisabled}
|
|
1147
|
+
onPress={() => applyZoom(1)}
|
|
1148
|
+
className={`h-10 w-[52px] items-center justify-center active:bg-white/10${
|
|
1149
|
+
zoomInDisabled ? ' opacity-40' : ''
|
|
1150
|
+
}`}
|
|
1151
|
+
>
|
|
1152
|
+
<Text className="text-white text-[22px] font-medium leading-[24px]">
|
|
1153
|
+
{'+'}
|
|
1154
|
+
</Text>
|
|
1155
|
+
</Pressable>
|
|
1156
|
+
</View>
|
|
1157
|
+
</View>
|
|
1158
|
+
) : null}
|
|
1125
1159
|
</View>
|
|
1126
1160
|
|
|
1127
1161
|
<View style={styles.helperBlock}>
|
|
1128
|
-
<Text style={styles.helper}>
|
|
1129
|
-
{t('editProfile.crop.helper') ||
|
|
1130
|
-
'The cropped circle is what will appear on your profile. Pinch to zoom, drag to position.'}
|
|
1131
|
-
</Text>
|
|
1162
|
+
<Text style={styles.helper}>{t('editProfile.crop.helper')}</Text>
|
|
1132
1163
|
<Pressable
|
|
1133
|
-
accessibilityLabel={t('editProfile.crop.a11yReset')
|
|
1164
|
+
accessibilityLabel={t('editProfile.crop.a11yReset')}
|
|
1134
1165
|
accessibilityRole="button"
|
|
1135
1166
|
accessibilityState={{ disabled: !isModified || isProcessing }}
|
|
1136
1167
|
onPress={resetTransform}
|
|
1137
1168
|
disabled={!isModified || isProcessing}
|
|
1138
1169
|
style={[styles.resetLink, { opacity: isProcessing ? 0.3 : resetLinkOpacity }]}
|
|
1139
1170
|
>
|
|
1140
|
-
<Text style={styles.resetLinkText}>
|
|
1141
|
-
{t('editProfile.crop.resetToCenter') || 'Reset to center'}
|
|
1142
|
-
</Text>
|
|
1171
|
+
<Text style={styles.resetLinkText}>{t('editProfile.crop.resetToCenter')}</Text>
|
|
1143
1172
|
</Pressable>
|
|
1144
1173
|
</View>
|
|
1145
1174
|
</View>
|