@oxyhq/services 6.9.46 → 6.10.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.
Files changed (812) hide show
  1. package/lib/commonjs/index.js +36 -13
  2. package/lib/commonjs/index.js.map +1 -1
  3. package/lib/commonjs/ui/client.js +0 -20
  4. package/lib/commonjs/ui/client.js.map +1 -1
  5. package/lib/commonjs/ui/components/ActingAsBanner.js +0 -4
  6. package/lib/commonjs/ui/components/ActingAsBanner.js.map +1 -1
  7. package/lib/commonjs/ui/components/ActivityIndicator.js +1 -1
  8. package/lib/commonjs/ui/components/ActivityIndicator.js.map +1 -1
  9. package/lib/commonjs/ui/components/Avatar.js +0 -2
  10. package/lib/commonjs/ui/components/Avatar.js.map +1 -1
  11. package/lib/commonjs/ui/components/BottomSheet.js +33 -398
  12. package/lib/commonjs/ui/components/BottomSheet.js.map +1 -1
  13. package/lib/commonjs/ui/components/BottomSheetRouter.js +8 -0
  14. package/lib/commonjs/ui/components/BottomSheetRouter.js.map +1 -1
  15. package/lib/commonjs/ui/components/FollowButton.js +3 -5
  16. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  17. package/lib/commonjs/ui/components/Header.js +0 -5
  18. package/lib/commonjs/ui/components/Header.js.map +1 -1
  19. package/lib/commonjs/ui/components/Icon.js +6 -7
  20. package/lib/commonjs/ui/components/Icon.js.map +1 -1
  21. package/lib/commonjs/ui/components/IconButton/IconButton.js +1 -5
  22. package/lib/commonjs/ui/components/IconButton/IconButton.js.map +1 -1
  23. package/lib/commonjs/ui/components/OxyPayButton.js +0 -2
  24. package/lib/commonjs/ui/components/OxyPayButton.js.map +1 -1
  25. package/lib/commonjs/ui/components/OxyProvider.js +100 -37
  26. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  27. package/lib/commonjs/ui/components/OxySignInButton.js +23 -9
  28. package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
  29. package/lib/commonjs/ui/components/ProfileCard.js +11 -8
  30. package/lib/commonjs/ui/components/ProfileCard.js.map +1 -1
  31. package/lib/commonjs/ui/components/QuickActions.js +2 -2
  32. package/lib/commonjs/ui/components/QuickActions.js.map +1 -1
  33. package/lib/commonjs/ui/components/SignInModal.js +139 -284
  34. package/lib/commonjs/ui/components/SignInModal.js.map +1 -1
  35. package/lib/commonjs/ui/components/StepBasedScreen.js +0 -2
  36. package/lib/commonjs/ui/components/StepBasedScreen.js.map +1 -1
  37. package/lib/commonjs/ui/components/TextField.js +0 -1
  38. package/lib/commonjs/ui/components/TextField.js.map +1 -1
  39. package/lib/commonjs/ui/components/TouchableRipple/TouchableRipple.native.js +1 -1
  40. package/lib/commonjs/ui/components/TouchableRipple/TouchableRipple.native.js.map +1 -1
  41. package/lib/commonjs/ui/components/feedback/feedbackStyles.js +0 -2
  42. package/lib/commonjs/ui/components/feedback/feedbackStyles.js.map +1 -1
  43. package/lib/commonjs/ui/components/fileManagement/AnimatedButton.js +0 -2
  44. package/lib/commonjs/ui/components/fileManagement/AnimatedButton.js.map +1 -1
  45. package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js +80 -76
  46. package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
  47. package/lib/commonjs/ui/components/fileManagement/FileViewer.js +6 -8
  48. package/lib/commonjs/ui/components/fileManagement/FileViewer.js.map +1 -1
  49. package/lib/commonjs/ui/components/fileManagement/UploadPreview.js +18 -23
  50. package/lib/commonjs/ui/components/fileManagement/UploadPreview.js.map +1 -1
  51. package/lib/commonjs/ui/components/fileManagement/styles.js +213 -25
  52. package/lib/commonjs/ui/components/fileManagement/styles.js.map +1 -1
  53. package/lib/commonjs/ui/components/logo/LogoIcon.js +63 -0
  54. package/lib/commonjs/ui/components/logo/LogoIcon.js.map +1 -0
  55. package/lib/commonjs/ui/components/logo/LogoText.js +50 -0
  56. package/lib/commonjs/ui/components/logo/LogoText.js.map +1 -0
  57. package/lib/commonjs/ui/components/modals/DeleteAccountModal.js +54 -88
  58. package/lib/commonjs/ui/components/modals/DeleteAccountModal.js.map +1 -1
  59. package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js +2 -2
  60. package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js.map +1 -1
  61. package/lib/commonjs/ui/components/payment/PaymentReviewStep.js +1 -1
  62. package/lib/commonjs/ui/components/payment/PaymentReviewStep.js.map +1 -1
  63. package/lib/commonjs/ui/components/payment/PaymentSuccessStep.js +1 -1
  64. package/lib/commonjs/ui/components/payment/PaymentSuccessStep.js.map +1 -1
  65. package/lib/commonjs/ui/components/payment/paymentStyles.js +2 -10
  66. package/lib/commonjs/ui/components/payment/paymentStyles.js.map +1 -1
  67. package/lib/commonjs/ui/components/styles/overlay.js +7 -9
  68. package/lib/commonjs/ui/components/styles/overlay.js.map +1 -1
  69. package/lib/commonjs/ui/components/theming.js +0 -1
  70. package/lib/commonjs/ui/components/theming.js.map +1 -1
  71. package/lib/commonjs/ui/context/OxyContext.js +34 -21
  72. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  73. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +1 -3
  74. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  75. package/lib/commonjs/ui/hooks/index.js +32 -12
  76. package/lib/commonjs/ui/hooks/index.js.map +1 -1
  77. package/lib/commonjs/ui/hooks/mutations/mutationFactory.js +10 -5
  78. package/lib/commonjs/ui/hooks/mutations/mutationFactory.js.map +1 -1
  79. package/lib/commonjs/ui/hooks/mutations/mutationKeys.js +34 -0
  80. package/lib/commonjs/ui/hooks/mutations/mutationKeys.js.map +1 -0
  81. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +235 -57
  82. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  83. package/lib/commonjs/ui/hooks/mutations/useServicesMutations.js +17 -13
  84. package/lib/commonjs/ui/hooks/mutations/useServicesMutations.js.map +1 -1
  85. package/lib/commonjs/ui/hooks/queries/index.js +6 -0
  86. package/lib/commonjs/ui/hooks/queries/index.js.map +1 -1
  87. package/lib/commonjs/ui/hooks/queries/queryKeys.js +2 -1
  88. package/lib/commonjs/ui/hooks/queries/queryKeys.js.map +1 -1
  89. package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +80 -3
  90. package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -1
  91. package/lib/commonjs/ui/hooks/queries/useSecurityQueries.js +36 -1
  92. package/lib/commonjs/ui/hooks/queries/useSecurityQueries.js.map +1 -1
  93. package/lib/commonjs/ui/hooks/queryClient.js +168 -70
  94. package/lib/commonjs/ui/hooks/queryClient.js.map +1 -1
  95. package/lib/commonjs/ui/hooks/useAsyncAction.js +7 -7
  96. package/lib/commonjs/ui/hooks/useAsyncAction.js.map +1 -1
  97. package/lib/commonjs/ui/hooks/useAuth.js +0 -8
  98. package/lib/commonjs/ui/hooks/useAuth.js.map +1 -1
  99. package/lib/commonjs/ui/hooks/useAvatarPicker.js +71 -20
  100. package/lib/commonjs/ui/hooks/useAvatarPicker.js.map +1 -1
  101. package/lib/commonjs/ui/hooks/useFileDownloadUrl.js +12 -41
  102. package/lib/commonjs/ui/hooks/useFileDownloadUrl.js.map +1 -1
  103. package/lib/commonjs/ui/hooks/useMutationStatus.js +86 -0
  104. package/lib/commonjs/ui/hooks/useMutationStatus.js.map +1 -0
  105. package/lib/commonjs/ui/hooks/useOnlineStatus.js +33 -0
  106. package/lib/commonjs/ui/hooks/useOnlineStatus.js.map +1 -0
  107. package/lib/commonjs/ui/hooks/useSessionSocket.js +101 -130
  108. package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
  109. package/lib/commonjs/ui/hooks/useSettingToggle.js +4 -4
  110. package/lib/commonjs/ui/hooks/useSettingToggle.js.map +1 -1
  111. package/lib/commonjs/ui/index.js +1 -11
  112. package/lib/commonjs/ui/index.js.map +1 -1
  113. package/lib/commonjs/ui/navigation/routes.js +55 -3
  114. package/lib/commonjs/ui/navigation/routes.js.map +1 -1
  115. package/lib/commonjs/ui/screens/AccountCenterScreen.js +16 -16
  116. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  117. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +108 -123
  118. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  119. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +20 -19
  120. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  121. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +204 -161
  122. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  123. package/lib/commonjs/ui/screens/AccountVerificationScreen.js +18 -18
  124. package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
  125. package/lib/commonjs/ui/screens/AppInfoScreen.js +22 -23
  126. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
  127. package/lib/commonjs/ui/screens/AvatarCropScreen.js +939 -0
  128. package/lib/commonjs/ui/screens/AvatarCropScreen.js.map +1 -0
  129. package/lib/commonjs/ui/screens/CreateManagedAccountScreen.js +13 -20
  130. package/lib/commonjs/ui/screens/CreateManagedAccountScreen.js.map +1 -1
  131. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +10 -13
  132. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
  133. package/lib/commonjs/ui/screens/FAQScreen.js +4 -4
  134. package/lib/commonjs/ui/screens/FAQScreen.js.map +1 -1
  135. package/lib/commonjs/ui/screens/FeedbackScreen.js +17 -15
  136. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  137. package/lib/commonjs/ui/screens/FileManagementScreen.js +797 -159
  138. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  139. package/lib/commonjs/ui/screens/HelpSupportScreen.js +8 -9
  140. package/lib/commonjs/ui/screens/HelpSupportScreen.js.map +1 -1
  141. package/lib/commonjs/ui/screens/HistoryViewScreen.js +29 -21
  142. package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
  143. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +3 -5
  144. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
  145. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +5 -5
  146. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -1
  147. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +2 -2
  148. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +75 -73
  149. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  150. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +32 -21
  151. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
  152. package/lib/commonjs/ui/screens/ProfileScreen.js +4 -3
  153. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  154. package/lib/commonjs/ui/screens/SavesCollectionsScreen.js +3 -3
  155. package/lib/commonjs/ui/screens/SavesCollectionsScreen.js.map +1 -1
  156. package/lib/commonjs/ui/screens/SessionManagementScreen.js +57 -56
  157. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
  158. package/lib/commonjs/ui/screens/UserLinksScreen.js +2 -3
  159. package/lib/commonjs/ui/screens/UserLinksScreen.js.map +1 -1
  160. package/lib/commonjs/ui/screens/UserListScreen.js +39 -22
  161. package/lib/commonjs/ui/screens/UserListScreen.js.map +1 -1
  162. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +18 -21
  163. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  164. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +0 -3
  165. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
  166. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +6 -10
  167. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  168. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +1 -1
  169. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
  170. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +6 -6
  171. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  172. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +13 -19
  173. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  174. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +5 -5
  175. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  176. package/lib/commonjs/ui/server.js +0 -5
  177. package/lib/commonjs/ui/server.js.map +1 -1
  178. package/lib/commonjs/ui/styles/authStyles.js +0 -5
  179. package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
  180. package/lib/commonjs/ui/styles/index.js +0 -11
  181. package/lib/commonjs/ui/styles/index.js.map +1 -1
  182. package/lib/commonjs/ui/styles/spacing.js +1 -42
  183. package/lib/commonjs/ui/styles/spacing.js.map +1 -1
  184. package/lib/commonjs/ui/styles/theme.js +0 -4
  185. package/lib/commonjs/ui/styles/theme.js.map +1 -1
  186. package/lib/commonjs/ui/utils/fileManagement.js +58 -39
  187. package/lib/commonjs/ui/utils/fileManagement.js.map +1 -1
  188. package/lib/commonjs/ui/utils/sessionHelpers.js +3 -1
  189. package/lib/commonjs/ui/utils/sessionHelpers.js.map +1 -1
  190. package/lib/commonjs/ui/utils/userUtils.js +33 -16
  191. package/lib/commonjs/ui/utils/userUtils.js.map +1 -1
  192. package/lib/module/index.js +9 -5
  193. package/lib/module/index.js.map +1 -1
  194. package/lib/module/ui/client.js +0 -6
  195. package/lib/module/ui/client.js.map +1 -1
  196. package/lib/module/ui/components/ActingAsBanner.js +0 -4
  197. package/lib/module/ui/components/ActingAsBanner.js.map +1 -1
  198. package/lib/module/ui/components/ActivityIndicator.js +1 -1
  199. package/lib/module/ui/components/ActivityIndicator.js.map +1 -1
  200. package/lib/module/ui/components/Avatar.js +0 -2
  201. package/lib/module/ui/components/Avatar.js.map +1 -1
  202. package/lib/module/ui/components/BottomSheet.js +35 -400
  203. package/lib/module/ui/components/BottomSheet.js.map +1 -1
  204. package/lib/module/ui/components/BottomSheetRouter.js +9 -1
  205. package/lib/module/ui/components/BottomSheetRouter.js.map +1 -1
  206. package/lib/module/ui/components/FollowButton.js +2 -4
  207. package/lib/module/ui/components/FollowButton.js.map +1 -1
  208. package/lib/module/ui/components/Header.js +0 -5
  209. package/lib/module/ui/components/Header.js.map +1 -1
  210. package/lib/module/ui/components/Icon.js +6 -7
  211. package/lib/module/ui/components/Icon.js.map +1 -1
  212. package/lib/module/ui/components/IconButton/IconButton.js +1 -5
  213. package/lib/module/ui/components/IconButton/IconButton.js.map +1 -1
  214. package/lib/module/ui/components/OxyPayButton.js +0 -2
  215. package/lib/module/ui/components/OxyPayButton.js.map +1 -1
  216. package/lib/module/ui/components/OxyProvider.js +103 -40
  217. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  218. package/lib/module/ui/components/OxySignInButton.js +23 -9
  219. package/lib/module/ui/components/OxySignInButton.js.map +1 -1
  220. package/lib/module/ui/components/ProfileCard.js +11 -8
  221. package/lib/module/ui/components/ProfileCard.js.map +1 -1
  222. package/lib/module/ui/components/QuickActions.js +2 -2
  223. package/lib/module/ui/components/QuickActions.js.map +1 -1
  224. package/lib/module/ui/components/SignInModal.js +137 -284
  225. package/lib/module/ui/components/SignInModal.js.map +1 -1
  226. package/lib/module/ui/components/StepBasedScreen.js +0 -2
  227. package/lib/module/ui/components/StepBasedScreen.js.map +1 -1
  228. package/lib/module/ui/components/TextField.js +0 -1
  229. package/lib/module/ui/components/TextField.js.map +1 -1
  230. package/lib/module/ui/components/TouchableRipple/TouchableRipple.native.js +1 -1
  231. package/lib/module/ui/components/TouchableRipple/TouchableRipple.native.js.map +1 -1
  232. package/lib/module/ui/components/feedback/feedbackStyles.js +0 -2
  233. package/lib/module/ui/components/feedback/feedbackStyles.js.map +1 -1
  234. package/lib/module/ui/components/fileManagement/AnimatedButton.js +0 -1
  235. package/lib/module/ui/components/fileManagement/AnimatedButton.js.map +1 -1
  236. package/lib/module/ui/components/fileManagement/FileDetailsModal.js +80 -75
  237. package/lib/module/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
  238. package/lib/module/ui/components/fileManagement/FileViewer.js +6 -7
  239. package/lib/module/ui/components/fileManagement/FileViewer.js.map +1 -1
  240. package/lib/module/ui/components/fileManagement/UploadPreview.js +18 -22
  241. package/lib/module/ui/components/fileManagement/UploadPreview.js.map +1 -1
  242. package/lib/module/ui/components/fileManagement/styles.js +212 -24
  243. package/lib/module/ui/components/fileManagement/styles.js.map +1 -1
  244. package/lib/module/ui/components/logo/LogoIcon.js +56 -0
  245. package/lib/module/ui/components/logo/LogoIcon.js.map +1 -0
  246. package/lib/module/ui/components/logo/LogoText.js +43 -0
  247. package/lib/module/ui/components/logo/LogoText.js.map +1 -0
  248. package/lib/module/ui/components/modals/DeleteAccountModal.js +55 -88
  249. package/lib/module/ui/components/modals/DeleteAccountModal.js.map +1 -1
  250. package/lib/module/ui/components/payment/PaymentDetailsStep.js +1 -1
  251. package/lib/module/ui/components/payment/PaymentDetailsStep.js.map +1 -1
  252. package/lib/module/ui/components/payment/PaymentReviewStep.js +1 -1
  253. package/lib/module/ui/components/payment/PaymentReviewStep.js.map +1 -1
  254. package/lib/module/ui/components/payment/PaymentSuccessStep.js +1 -1
  255. package/lib/module/ui/components/payment/PaymentSuccessStep.js.map +1 -1
  256. package/lib/module/ui/components/payment/paymentStyles.js +2 -10
  257. package/lib/module/ui/components/payment/paymentStyles.js.map +1 -1
  258. package/lib/module/ui/components/styles/overlay.js +8 -8
  259. package/lib/module/ui/components/styles/overlay.js.map +1 -1
  260. package/lib/module/ui/components/theming.js +0 -1
  261. package/lib/module/ui/components/theming.js.map +1 -1
  262. package/lib/module/ui/context/OxyContext.js +32 -19
  263. package/lib/module/ui/context/OxyContext.js.map +1 -1
  264. package/lib/module/ui/context/hooks/useAuthOperations.js +1 -3
  265. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  266. package/lib/module/ui/hooks/index.js +5 -3
  267. package/lib/module/ui/hooks/index.js.map +1 -1
  268. package/lib/module/ui/hooks/mutations/mutationFactory.js +6 -1
  269. package/lib/module/ui/hooks/mutations/mutationFactory.js.map +1 -1
  270. package/lib/module/ui/hooks/mutations/mutationKeys.js +30 -0
  271. package/lib/module/ui/hooks/mutations/mutationKeys.js.map +1 -0
  272. package/lib/module/ui/hooks/mutations/useAccountMutations.js +231 -52
  273. package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  274. package/lib/module/ui/hooks/mutations/useServicesMutations.js +9 -5
  275. package/lib/module/ui/hooks/mutations/useServicesMutations.js.map +1 -1
  276. package/lib/module/ui/hooks/queries/index.js +1 -1
  277. package/lib/module/ui/hooks/queries/index.js.map +1 -1
  278. package/lib/module/ui/hooks/queries/queryKeys.js +2 -1
  279. package/lib/module/ui/hooks/queries/queryKeys.js.map +1 -1
  280. package/lib/module/ui/hooks/queries/useAccountQueries.js +80 -3
  281. package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -1
  282. package/lib/module/ui/hooks/queries/useSecurityQueries.js +35 -1
  283. package/lib/module/ui/hooks/queries/useSecurityQueries.js.map +1 -1
  284. package/lib/module/ui/hooks/queryClient.js +166 -68
  285. package/lib/module/ui/hooks/queryClient.js.map +1 -1
  286. package/lib/module/ui/hooks/useAsyncAction.js +3 -3
  287. package/lib/module/ui/hooks/useAsyncAction.js.map +1 -1
  288. package/lib/module/ui/hooks/useAuth.js +0 -3
  289. package/lib/module/ui/hooks/useAuth.js.map +1 -1
  290. package/lib/module/ui/hooks/useAvatarPicker.js +73 -22
  291. package/lib/module/ui/hooks/useAvatarPicker.js.map +1 -1
  292. package/lib/module/ui/hooks/useFileDownloadUrl.js +11 -39
  293. package/lib/module/ui/hooks/useFileDownloadUrl.js.map +1 -1
  294. package/lib/module/ui/hooks/useMutationStatus.js +82 -0
  295. package/lib/module/ui/hooks/useMutationStatus.js.map +1 -0
  296. package/lib/module/ui/hooks/useOnlineStatus.js +29 -0
  297. package/lib/module/ui/hooks/useOnlineStatus.js.map +1 -0
  298. package/lib/module/ui/hooks/useSessionSocket.js +101 -130
  299. package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
  300. package/lib/module/ui/hooks/useSettingToggle.js +1 -1
  301. package/lib/module/ui/hooks/useSettingToggle.js.map +1 -1
  302. package/lib/module/ui/index.js +1 -10
  303. package/lib/module/ui/index.js.map +1 -1
  304. package/lib/module/ui/navigation/routes.js +54 -2
  305. package/lib/module/ui/navigation/routes.js.map +1 -1
  306. package/lib/module/ui/screens/AccountCenterScreen.js +15 -14
  307. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  308. package/lib/module/ui/screens/AccountOverviewScreen.js +96 -111
  309. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  310. package/lib/module/ui/screens/AccountSettingsScreen.js +19 -18
  311. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  312. package/lib/module/ui/screens/AccountSwitcherScreen.js +189 -145
  313. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  314. package/lib/module/ui/screens/AccountVerificationScreen.js +15 -15
  315. package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
  316. package/lib/module/ui/screens/AppInfoScreen.js +14 -15
  317. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  318. package/lib/module/ui/screens/AvatarCropScreen.js +936 -0
  319. package/lib/module/ui/screens/AvatarCropScreen.js.map +1 -0
  320. package/lib/module/ui/screens/CreateManagedAccountScreen.js +11 -18
  321. package/lib/module/ui/screens/CreateManagedAccountScreen.js.map +1 -1
  322. package/lib/module/ui/screens/EditProfileFieldScreen.js +8 -11
  323. package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
  324. package/lib/module/ui/screens/FAQScreen.js +3 -3
  325. package/lib/module/ui/screens/FAQScreen.js.map +1 -1
  326. package/lib/module/ui/screens/FeedbackScreen.js +14 -12
  327. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  328. package/lib/module/ui/screens/FileManagementScreen.js +764 -125
  329. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  330. package/lib/module/ui/screens/HelpSupportScreen.js +2 -3
  331. package/lib/module/ui/screens/HelpSupportScreen.js.map +1 -1
  332. package/lib/module/ui/screens/HistoryViewScreen.js +26 -17
  333. package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
  334. package/lib/module/ui/screens/LanguageSelectorScreen.js +1 -3
  335. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
  336. package/lib/module/ui/screens/LegalDocumentsScreen.js +3 -3
  337. package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -1
  338. package/lib/module/ui/screens/PaymentGatewayScreen.js +2 -2
  339. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +60 -57
  340. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  341. package/lib/module/ui/screens/PrivacySettingsScreen.js +27 -16
  342. package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
  343. package/lib/module/ui/screens/ProfileScreen.js +4 -3
  344. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  345. package/lib/module/ui/screens/SavesCollectionsScreen.js +2 -2
  346. package/lib/module/ui/screens/SavesCollectionsScreen.js.map +1 -1
  347. package/lib/module/ui/screens/SessionManagementScreen.js +48 -47
  348. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  349. package/lib/module/ui/screens/UserLinksScreen.js +2 -3
  350. package/lib/module/ui/screens/UserLinksScreen.js.map +1 -1
  351. package/lib/module/ui/screens/UserListScreen.js +40 -23
  352. package/lib/module/ui/screens/UserListScreen.js.map +1 -1
  353. package/lib/module/ui/screens/WelcomeNewUserScreen.js +16 -19
  354. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  355. package/lib/module/ui/screens/karma/KarmaAboutScreen.js +0 -3
  356. package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
  357. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +6 -10
  358. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  359. package/lib/module/ui/screens/karma/KarmaFAQScreen.js +1 -1
  360. package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
  361. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +6 -6
  362. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  363. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +13 -19
  364. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  365. package/lib/module/ui/screens/karma/KarmaRulesScreen.js +5 -5
  366. package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  367. package/lib/module/ui/server.js +0 -4
  368. package/lib/module/ui/server.js.map +1 -1
  369. package/lib/module/ui/styles/authStyles.js +0 -5
  370. package/lib/module/ui/styles/authStyles.js.map +1 -1
  371. package/lib/module/ui/styles/index.js +0 -1
  372. package/lib/module/ui/styles/index.js.map +1 -1
  373. package/lib/module/ui/styles/spacing.js +0 -42
  374. package/lib/module/ui/styles/spacing.js.map +1 -1
  375. package/lib/module/ui/styles/theme.js +0 -4
  376. package/lib/module/ui/styles/theme.js.map +1 -1
  377. package/lib/module/ui/utils/fileManagement.js +54 -36
  378. package/lib/module/ui/utils/fileManagement.js.map +1 -1
  379. package/lib/module/ui/utils/sessionHelpers.js +3 -1
  380. package/lib/module/ui/utils/sessionHelpers.js.map +1 -1
  381. package/lib/module/ui/utils/userUtils.js +34 -16
  382. package/lib/module/ui/utils/userUtils.js.map +1 -1
  383. package/lib/typescript/commonjs/index.d.ts +7 -3
  384. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  385. package/lib/typescript/commonjs/ui/client.d.ts +0 -2
  386. package/lib/typescript/commonjs/ui/client.d.ts.map +1 -1
  387. package/lib/typescript/commonjs/ui/components/ActingAsBanner.d.ts.map +1 -1
  388. package/lib/typescript/commonjs/ui/components/Avatar.d.ts.map +1 -1
  389. package/lib/typescript/commonjs/ui/components/BottomSheet.d.ts +27 -27
  390. package/lib/typescript/commonjs/ui/components/BottomSheet.d.ts.map +1 -1
  391. package/lib/typescript/commonjs/ui/components/BottomSheetRouter.d.ts.map +1 -1
  392. package/lib/typescript/commonjs/ui/components/FollowButton.d.ts.map +1 -1
  393. package/lib/typescript/commonjs/ui/components/Header.d.ts.map +1 -1
  394. package/lib/typescript/commonjs/ui/components/Icon.d.ts +3 -2
  395. package/lib/typescript/commonjs/ui/components/Icon.d.ts.map +1 -1
  396. package/lib/typescript/commonjs/ui/components/IconButton/IconButton.d.ts.map +1 -1
  397. package/lib/typescript/commonjs/ui/components/OxyPayButton.d.ts.map +1 -1
  398. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
  399. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts.map +1 -1
  400. package/lib/typescript/commonjs/ui/components/ProfileCard.d.ts +4 -1
  401. package/lib/typescript/commonjs/ui/components/ProfileCard.d.ts.map +1 -1
  402. package/lib/typescript/commonjs/ui/components/SignInModal.d.ts.map +1 -1
  403. package/lib/typescript/commonjs/ui/components/StepBasedScreen.d.ts.map +1 -1
  404. package/lib/typescript/commonjs/ui/components/TextField/Addons/Outline.d.ts +2 -2
  405. package/lib/typescript/commonjs/ui/components/TextField/helpers.d.ts +2 -2
  406. package/lib/typescript/commonjs/ui/components/TextField/types.d.ts +0 -1
  407. package/lib/typescript/commonjs/ui/components/TextField/types.d.ts.map +1 -1
  408. package/lib/typescript/commonjs/ui/components/TextField.d.ts +1 -1
  409. package/lib/typescript/commonjs/ui/components/TextField.d.ts.map +1 -1
  410. package/lib/typescript/commonjs/ui/components/feedback/feedbackStyles.d.ts +0 -1
  411. package/lib/typescript/commonjs/ui/components/feedback/feedbackStyles.d.ts.map +1 -1
  412. package/lib/typescript/commonjs/ui/components/fileManagement/AnimatedButton.d.ts.map +1 -1
  413. package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts +1 -1
  414. package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
  415. package/lib/typescript/commonjs/ui/components/fileManagement/FileViewer.d.ts +0 -2
  416. package/lib/typescript/commonjs/ui/components/fileManagement/FileViewer.d.ts.map +1 -1
  417. package/lib/typescript/commonjs/ui/components/fileManagement/UploadPreview.d.ts +3 -2
  418. package/lib/typescript/commonjs/ui/components/fileManagement/UploadPreview.d.ts.map +1 -1
  419. package/lib/typescript/commonjs/ui/components/fileManagement/styles.d.ts +200 -17
  420. package/lib/typescript/commonjs/ui/components/fileManagement/styles.d.ts.map +1 -1
  421. package/lib/typescript/commonjs/ui/components/logo/LogoIcon.d.ts +22 -0
  422. package/lib/typescript/commonjs/ui/components/logo/LogoIcon.d.ts.map +1 -0
  423. package/lib/typescript/commonjs/ui/components/logo/LogoText.d.ts +22 -0
  424. package/lib/typescript/commonjs/ui/components/logo/LogoText.d.ts.map +1 -0
  425. package/lib/typescript/commonjs/ui/components/modals/DeleteAccountModal.d.ts +2 -2
  426. package/lib/typescript/commonjs/ui/components/modals/DeleteAccountModal.d.ts.map +1 -1
  427. package/lib/typescript/commonjs/ui/components/payment/paymentStyles.d.ts +0 -7
  428. package/lib/typescript/commonjs/ui/components/payment/paymentStyles.d.ts.map +1 -1
  429. package/lib/typescript/commonjs/ui/components/styles/overlay.d.ts +3 -1
  430. package/lib/typescript/commonjs/ui/components/styles/overlay.d.ts.map +1 -1
  431. package/lib/typescript/commonjs/ui/components/theming.d.ts.map +1 -1
  432. package/lib/typescript/commonjs/ui/components/types.d.ts.map +1 -1
  433. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  434. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  435. package/lib/typescript/commonjs/ui/hooks/index.d.ts +5 -3
  436. package/lib/typescript/commonjs/ui/hooks/index.d.ts.map +1 -1
  437. package/lib/typescript/commonjs/ui/hooks/mutations/mutationFactory.d.ts +11 -0
  438. package/lib/typescript/commonjs/ui/hooks/mutations/mutationFactory.d.ts.map +1 -1
  439. package/lib/typescript/commonjs/ui/hooks/mutations/mutationKeys.d.ts +25 -0
  440. package/lib/typescript/commonjs/ui/hooks/mutations/mutationKeys.d.ts.map +1 -0
  441. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +161 -9
  442. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  443. package/lib/typescript/commonjs/ui/hooks/mutations/useServicesMutations.d.ts.map +1 -1
  444. package/lib/typescript/commonjs/ui/hooks/queries/index.d.ts +1 -1
  445. package/lib/typescript/commonjs/ui/hooks/queries/index.d.ts.map +1 -1
  446. package/lib/typescript/commonjs/ui/hooks/queries/queryKeys.d.ts +1 -0
  447. package/lib/typescript/commonjs/ui/hooks/queries/queryKeys.d.ts.map +1 -1
  448. package/lib/typescript/commonjs/ui/hooks/queries/useAccountQueries.d.ts +22 -8
  449. package/lib/typescript/commonjs/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
  450. package/lib/typescript/commonjs/ui/hooks/queries/useSecurityQueries.d.ts +13 -3
  451. package/lib/typescript/commonjs/ui/hooks/queries/useSecurityQueries.d.ts.map +1 -1
  452. package/lib/typescript/commonjs/ui/hooks/queries/useServicesQueries.d.ts +7 -5
  453. package/lib/typescript/commonjs/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
  454. package/lib/typescript/commonjs/ui/hooks/queryClient.d.ts +57 -9
  455. package/lib/typescript/commonjs/ui/hooks/queryClient.d.ts.map +1 -1
  456. package/lib/typescript/commonjs/ui/hooks/useAssets.d.ts +1 -1
  457. package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts +0 -1
  458. package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts.map +1 -1
  459. package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts +10 -2
  460. package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts.map +1 -1
  461. package/lib/typescript/commonjs/ui/hooks/useFileDownloadUrl.d.ts +2 -6
  462. package/lib/typescript/commonjs/ui/hooks/useFileDownloadUrl.d.ts.map +1 -1
  463. package/lib/typescript/commonjs/ui/hooks/useMutationStatus.d.ts +23 -0
  464. package/lib/typescript/commonjs/ui/hooks/useMutationStatus.d.ts.map +1 -0
  465. package/lib/typescript/commonjs/ui/hooks/useOnlineStatus.d.ts +13 -0
  466. package/lib/typescript/commonjs/ui/hooks/useOnlineStatus.d.ts.map +1 -0
  467. package/lib/typescript/commonjs/ui/hooks/useSessionSocket.d.ts +1 -2
  468. package/lib/typescript/commonjs/ui/hooks/useSessionSocket.d.ts.map +1 -1
  469. package/lib/typescript/commonjs/ui/index.d.ts +1 -4
  470. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  471. package/lib/typescript/commonjs/ui/navigation/routes.d.ts +48 -2
  472. package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
  473. package/lib/typescript/commonjs/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  474. package/lib/typescript/commonjs/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  475. package/lib/typescript/commonjs/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  476. package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  477. package/lib/typescript/commonjs/ui/screens/AppInfoScreen.d.ts.map +1 -1
  478. package/lib/typescript/commonjs/ui/screens/AvatarCropScreen.d.ts +49 -0
  479. package/lib/typescript/commonjs/ui/screens/AvatarCropScreen.d.ts.map +1 -0
  480. package/lib/typescript/commonjs/ui/screens/CreateManagedAccountScreen.d.ts.map +1 -1
  481. package/lib/typescript/commonjs/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
  482. package/lib/typescript/commonjs/ui/screens/FeedbackScreen.d.ts.map +1 -1
  483. package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
  484. package/lib/typescript/commonjs/ui/screens/HelpSupportScreen.d.ts.map +1 -1
  485. package/lib/typescript/commonjs/ui/screens/HistoryViewScreen.d.ts.map +1 -1
  486. package/lib/typescript/commonjs/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
  487. package/lib/typescript/commonjs/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
  488. package/lib/typescript/commonjs/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
  489. package/lib/typescript/commonjs/ui/screens/ProfileScreen.d.ts.map +1 -1
  490. package/lib/typescript/commonjs/ui/screens/SessionManagementScreen.d.ts.map +1 -1
  491. package/lib/typescript/commonjs/ui/screens/UserLinksScreen.d.ts.map +1 -1
  492. package/lib/typescript/commonjs/ui/screens/UserListScreen.d.ts.map +1 -1
  493. package/lib/typescript/commonjs/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  494. package/lib/typescript/commonjs/ui/screens/karma/KarmaAboutScreen.d.ts.map +1 -1
  495. package/lib/typescript/commonjs/ui/screens/karma/KarmaCenterScreen.d.ts.map +1 -1
  496. package/lib/typescript/commonjs/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +1 -1
  497. package/lib/typescript/commonjs/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -1
  498. package/lib/typescript/commonjs/ui/screens/karma/KarmaRulesScreen.d.ts.map +1 -1
  499. package/lib/typescript/commonjs/ui/server.d.ts +0 -2
  500. package/lib/typescript/commonjs/ui/server.d.ts.map +1 -1
  501. package/lib/typescript/commonjs/ui/styles/authStyles.d.ts +0 -4
  502. package/lib/typescript/commonjs/ui/styles/authStyles.d.ts.map +1 -1
  503. package/lib/typescript/commonjs/ui/styles/index.d.ts +0 -1
  504. package/lib/typescript/commonjs/ui/styles/index.d.ts.map +1 -1
  505. package/lib/typescript/commonjs/ui/styles/spacing.d.ts +0 -36
  506. package/lib/typescript/commonjs/ui/styles/spacing.d.ts.map +1 -1
  507. package/lib/typescript/commonjs/ui/styles/theme.d.ts +0 -1
  508. package/lib/typescript/commonjs/ui/styles/theme.d.ts.map +1 -1
  509. package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts +39 -12
  510. package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts.map +1 -1
  511. package/lib/typescript/commonjs/ui/utils/sessionHelpers.d.ts +3 -1
  512. package/lib/typescript/commonjs/ui/utils/sessionHelpers.d.ts.map +1 -1
  513. package/lib/typescript/commonjs/ui/utils/userUtils.d.ts +19 -18
  514. package/lib/typescript/commonjs/ui/utils/userUtils.d.ts.map +1 -1
  515. package/lib/typescript/module/index.d.ts +7 -3
  516. package/lib/typescript/module/index.d.ts.map +1 -1
  517. package/lib/typescript/module/ui/client.d.ts +0 -2
  518. package/lib/typescript/module/ui/client.d.ts.map +1 -1
  519. package/lib/typescript/module/ui/components/ActingAsBanner.d.ts.map +1 -1
  520. package/lib/typescript/module/ui/components/Avatar.d.ts.map +1 -1
  521. package/lib/typescript/module/ui/components/BottomSheet.d.ts +27 -27
  522. package/lib/typescript/module/ui/components/BottomSheet.d.ts.map +1 -1
  523. package/lib/typescript/module/ui/components/BottomSheetRouter.d.ts.map +1 -1
  524. package/lib/typescript/module/ui/components/FollowButton.d.ts.map +1 -1
  525. package/lib/typescript/module/ui/components/Header.d.ts.map +1 -1
  526. package/lib/typescript/module/ui/components/Icon.d.ts +3 -2
  527. package/lib/typescript/module/ui/components/Icon.d.ts.map +1 -1
  528. package/lib/typescript/module/ui/components/IconButton/IconButton.d.ts.map +1 -1
  529. package/lib/typescript/module/ui/components/OxyPayButton.d.ts.map +1 -1
  530. package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
  531. package/lib/typescript/module/ui/components/OxySignInButton.d.ts.map +1 -1
  532. package/lib/typescript/module/ui/components/ProfileCard.d.ts +4 -1
  533. package/lib/typescript/module/ui/components/ProfileCard.d.ts.map +1 -1
  534. package/lib/typescript/module/ui/components/SignInModal.d.ts.map +1 -1
  535. package/lib/typescript/module/ui/components/StepBasedScreen.d.ts.map +1 -1
  536. package/lib/typescript/module/ui/components/TextField/Addons/Outline.d.ts +2 -2
  537. package/lib/typescript/module/ui/components/TextField/helpers.d.ts +2 -2
  538. package/lib/typescript/module/ui/components/TextField/types.d.ts +0 -1
  539. package/lib/typescript/module/ui/components/TextField/types.d.ts.map +1 -1
  540. package/lib/typescript/module/ui/components/TextField.d.ts +1 -1
  541. package/lib/typescript/module/ui/components/TextField.d.ts.map +1 -1
  542. package/lib/typescript/module/ui/components/feedback/feedbackStyles.d.ts +0 -1
  543. package/lib/typescript/module/ui/components/feedback/feedbackStyles.d.ts.map +1 -1
  544. package/lib/typescript/module/ui/components/fileManagement/AnimatedButton.d.ts.map +1 -1
  545. package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts +1 -1
  546. package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
  547. package/lib/typescript/module/ui/components/fileManagement/FileViewer.d.ts +0 -2
  548. package/lib/typescript/module/ui/components/fileManagement/FileViewer.d.ts.map +1 -1
  549. package/lib/typescript/module/ui/components/fileManagement/UploadPreview.d.ts +3 -2
  550. package/lib/typescript/module/ui/components/fileManagement/UploadPreview.d.ts.map +1 -1
  551. package/lib/typescript/module/ui/components/fileManagement/styles.d.ts +200 -17
  552. package/lib/typescript/module/ui/components/fileManagement/styles.d.ts.map +1 -1
  553. package/lib/typescript/module/ui/components/logo/LogoIcon.d.ts +22 -0
  554. package/lib/typescript/module/ui/components/logo/LogoIcon.d.ts.map +1 -0
  555. package/lib/typescript/module/ui/components/logo/LogoText.d.ts +22 -0
  556. package/lib/typescript/module/ui/components/logo/LogoText.d.ts.map +1 -0
  557. package/lib/typescript/module/ui/components/modals/DeleteAccountModal.d.ts +2 -2
  558. package/lib/typescript/module/ui/components/modals/DeleteAccountModal.d.ts.map +1 -1
  559. package/lib/typescript/module/ui/components/payment/paymentStyles.d.ts +0 -7
  560. package/lib/typescript/module/ui/components/payment/paymentStyles.d.ts.map +1 -1
  561. package/lib/typescript/module/ui/components/styles/overlay.d.ts +3 -1
  562. package/lib/typescript/module/ui/components/styles/overlay.d.ts.map +1 -1
  563. package/lib/typescript/module/ui/components/theming.d.ts.map +1 -1
  564. package/lib/typescript/module/ui/components/types.d.ts.map +1 -1
  565. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  566. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  567. package/lib/typescript/module/ui/hooks/index.d.ts +5 -3
  568. package/lib/typescript/module/ui/hooks/index.d.ts.map +1 -1
  569. package/lib/typescript/module/ui/hooks/mutations/mutationFactory.d.ts +11 -0
  570. package/lib/typescript/module/ui/hooks/mutations/mutationFactory.d.ts.map +1 -1
  571. package/lib/typescript/module/ui/hooks/mutations/mutationKeys.d.ts +25 -0
  572. package/lib/typescript/module/ui/hooks/mutations/mutationKeys.d.ts.map +1 -0
  573. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +161 -9
  574. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  575. package/lib/typescript/module/ui/hooks/mutations/useServicesMutations.d.ts.map +1 -1
  576. package/lib/typescript/module/ui/hooks/queries/index.d.ts +1 -1
  577. package/lib/typescript/module/ui/hooks/queries/index.d.ts.map +1 -1
  578. package/lib/typescript/module/ui/hooks/queries/queryKeys.d.ts +1 -0
  579. package/lib/typescript/module/ui/hooks/queries/queryKeys.d.ts.map +1 -1
  580. package/lib/typescript/module/ui/hooks/queries/useAccountQueries.d.ts +22 -8
  581. package/lib/typescript/module/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
  582. package/lib/typescript/module/ui/hooks/queries/useSecurityQueries.d.ts +13 -3
  583. package/lib/typescript/module/ui/hooks/queries/useSecurityQueries.d.ts.map +1 -1
  584. package/lib/typescript/module/ui/hooks/queries/useServicesQueries.d.ts +7 -5
  585. package/lib/typescript/module/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
  586. package/lib/typescript/module/ui/hooks/queryClient.d.ts +57 -9
  587. package/lib/typescript/module/ui/hooks/queryClient.d.ts.map +1 -1
  588. package/lib/typescript/module/ui/hooks/useAssets.d.ts +1 -1
  589. package/lib/typescript/module/ui/hooks/useAuth.d.ts +0 -1
  590. package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
  591. package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts +10 -2
  592. package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts.map +1 -1
  593. package/lib/typescript/module/ui/hooks/useFileDownloadUrl.d.ts +2 -6
  594. package/lib/typescript/module/ui/hooks/useFileDownloadUrl.d.ts.map +1 -1
  595. package/lib/typescript/module/ui/hooks/useMutationStatus.d.ts +23 -0
  596. package/lib/typescript/module/ui/hooks/useMutationStatus.d.ts.map +1 -0
  597. package/lib/typescript/module/ui/hooks/useOnlineStatus.d.ts +13 -0
  598. package/lib/typescript/module/ui/hooks/useOnlineStatus.d.ts.map +1 -0
  599. package/lib/typescript/module/ui/hooks/useSessionSocket.d.ts +1 -2
  600. package/lib/typescript/module/ui/hooks/useSessionSocket.d.ts.map +1 -1
  601. package/lib/typescript/module/ui/index.d.ts +1 -4
  602. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  603. package/lib/typescript/module/ui/navigation/routes.d.ts +48 -2
  604. package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
  605. package/lib/typescript/module/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  606. package/lib/typescript/module/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  607. package/lib/typescript/module/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  608. package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  609. package/lib/typescript/module/ui/screens/AppInfoScreen.d.ts.map +1 -1
  610. package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts +49 -0
  611. package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts.map +1 -0
  612. package/lib/typescript/module/ui/screens/CreateManagedAccountScreen.d.ts.map +1 -1
  613. package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
  614. package/lib/typescript/module/ui/screens/FeedbackScreen.d.ts.map +1 -1
  615. package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
  616. package/lib/typescript/module/ui/screens/HelpSupportScreen.d.ts.map +1 -1
  617. package/lib/typescript/module/ui/screens/HistoryViewScreen.d.ts.map +1 -1
  618. package/lib/typescript/module/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
  619. package/lib/typescript/module/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
  620. package/lib/typescript/module/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
  621. package/lib/typescript/module/ui/screens/ProfileScreen.d.ts.map +1 -1
  622. package/lib/typescript/module/ui/screens/SessionManagementScreen.d.ts.map +1 -1
  623. package/lib/typescript/module/ui/screens/UserLinksScreen.d.ts.map +1 -1
  624. package/lib/typescript/module/ui/screens/UserListScreen.d.ts.map +1 -1
  625. package/lib/typescript/module/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  626. package/lib/typescript/module/ui/screens/karma/KarmaAboutScreen.d.ts.map +1 -1
  627. package/lib/typescript/module/ui/screens/karma/KarmaCenterScreen.d.ts.map +1 -1
  628. package/lib/typescript/module/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +1 -1
  629. package/lib/typescript/module/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -1
  630. package/lib/typescript/module/ui/screens/karma/KarmaRulesScreen.d.ts.map +1 -1
  631. package/lib/typescript/module/ui/server.d.ts +0 -2
  632. package/lib/typescript/module/ui/server.d.ts.map +1 -1
  633. package/lib/typescript/module/ui/styles/authStyles.d.ts +0 -4
  634. package/lib/typescript/module/ui/styles/authStyles.d.ts.map +1 -1
  635. package/lib/typescript/module/ui/styles/index.d.ts +0 -1
  636. package/lib/typescript/module/ui/styles/index.d.ts.map +1 -1
  637. package/lib/typescript/module/ui/styles/spacing.d.ts +0 -36
  638. package/lib/typescript/module/ui/styles/spacing.d.ts.map +1 -1
  639. package/lib/typescript/module/ui/styles/theme.d.ts +0 -1
  640. package/lib/typescript/module/ui/styles/theme.d.ts.map +1 -1
  641. package/lib/typescript/module/ui/utils/fileManagement.d.ts +39 -12
  642. package/lib/typescript/module/ui/utils/fileManagement.d.ts.map +1 -1
  643. package/lib/typescript/module/ui/utils/sessionHelpers.d.ts +3 -1
  644. package/lib/typescript/module/ui/utils/sessionHelpers.d.ts.map +1 -1
  645. package/lib/typescript/module/ui/utils/userUtils.d.ts +19 -18
  646. package/lib/typescript/module/ui/utils/userUtils.d.ts.map +1 -1
  647. package/lib/typescript/types/expo-vector-icons.d.ts +7 -4
  648. package/package.json +64 -31
  649. package/src/index.ts +11 -4
  650. package/src/types/expo-vector-icons.d.ts +7 -4
  651. package/src/ui/client.ts +0 -6
  652. package/src/ui/components/ActingAsBanner.tsx +0 -4
  653. package/src/ui/components/ActivityIndicator.tsx +1 -1
  654. package/src/ui/components/Avatar.tsx +0 -2
  655. package/src/ui/components/BottomSheet.tsx +41 -440
  656. package/src/ui/components/BottomSheetRouter.tsx +12 -1
  657. package/src/ui/components/FollowButton.tsx +2 -4
  658. package/src/ui/components/Header.tsx +0 -5
  659. package/src/ui/components/Icon.tsx +12 -6
  660. package/src/ui/components/IconButton/IconButton.tsx +0 -3
  661. package/src/ui/components/OxyPayButton.tsx +0 -2
  662. package/src/ui/components/OxyProvider.tsx +127 -48
  663. package/src/ui/components/OxySignInButton.tsx +21 -9
  664. package/src/ui/components/ProfileCard.tsx +13 -10
  665. package/src/ui/components/QuickActions.tsx +2 -2
  666. package/src/ui/components/SignInModal.tsx +80 -199
  667. package/src/ui/components/StepBasedScreen.tsx +0 -2
  668. package/src/ui/components/TextField/Addons/Outline.tsx +2 -2
  669. package/src/ui/components/TextField/helpers.tsx +2 -2
  670. package/src/ui/components/TextField/types.tsx +0 -1
  671. package/src/ui/components/TextField.tsx +1 -2
  672. package/src/ui/components/TouchableRipple/TouchableRipple.native.tsx +1 -1
  673. package/src/ui/components/feedback/feedbackStyles.ts +0 -2
  674. package/src/ui/components/fileManagement/AnimatedButton.tsx +0 -1
  675. package/src/ui/components/fileManagement/FileDetailsModal.tsx +71 -65
  676. package/src/ui/components/fileManagement/FileViewer.tsx +6 -9
  677. package/src/ui/components/fileManagement/UploadPreview.tsx +21 -25
  678. package/src/ui/components/fileManagement/styles.ts +206 -18
  679. package/src/ui/components/logo/LogoIcon.tsx +70 -0
  680. package/src/ui/components/logo/LogoText.tsx +70 -0
  681. package/src/ui/components/modals/DeleteAccountModal.tsx +56 -91
  682. package/src/ui/components/payment/PaymentDetailsStep.tsx +1 -1
  683. package/src/ui/components/payment/PaymentReviewStep.tsx +1 -1
  684. package/src/ui/components/payment/PaymentSuccessStep.tsx +1 -1
  685. package/src/ui/components/payment/paymentStyles.ts +0 -8
  686. package/src/ui/components/styles/overlay.tsx +17 -8
  687. package/src/ui/components/theming.tsx +0 -1
  688. package/src/ui/components/types.tsx +3 -2
  689. package/src/ui/context/OxyContext.tsx +34 -19
  690. package/src/ui/context/hooks/useAuthOperations.ts +1 -3
  691. package/src/ui/hooks/index.ts +11 -4
  692. package/src/ui/hooks/mutations/mutationFactory.ts +16 -1
  693. package/src/ui/hooks/mutations/mutationKeys.ts +28 -0
  694. package/src/ui/hooks/mutations/useAccountMutations.ts +251 -59
  695. package/src/ui/hooks/mutations/useServicesMutations.ts +10 -4
  696. package/src/ui/hooks/queries/index.ts +1 -0
  697. package/src/ui/hooks/queries/queryKeys.ts +2 -0
  698. package/src/ui/hooks/queries/useAccountQueries.ts +83 -3
  699. package/src/ui/hooks/queries/useSecurityQueries.ts +42 -2
  700. package/src/ui/hooks/queryClient.ts +194 -69
  701. package/src/ui/hooks/useAsyncAction.ts +3 -3
  702. package/src/ui/hooks/useAuth.ts +0 -2
  703. package/src/ui/hooks/useAvatarPicker.ts +108 -27
  704. package/src/ui/hooks/useFileDownloadUrl.ts +15 -39
  705. package/src/ui/hooks/useMutationStatus.ts +111 -0
  706. package/src/ui/hooks/useOnlineStatus.ts +29 -0
  707. package/src/ui/hooks/useSessionSocket.ts +136 -126
  708. package/src/ui/hooks/useSettingToggle.ts +1 -1
  709. package/src/ui/index.ts +0 -12
  710. package/src/ui/navigation/routes.ts +93 -2
  711. package/src/ui/screens/AccountCenterScreen.tsx +15 -13
  712. package/src/ui/screens/AccountOverviewScreen.tsx +94 -104
  713. package/src/ui/screens/AccountSettingsScreen.tsx +18 -17
  714. package/src/ui/screens/AccountSwitcherScreen.tsx +331 -298
  715. package/src/ui/screens/AccountVerificationScreen.tsx +15 -15
  716. package/src/ui/screens/AppInfoScreen.tsx +8 -13
  717. package/src/ui/screens/AvatarCropScreen.tsx +1073 -0
  718. package/src/ui/screens/CreateManagedAccountScreen.tsx +5 -16
  719. package/src/ui/screens/EditProfileFieldScreen.tsx +5 -10
  720. package/src/ui/screens/FAQScreen.tsx +3 -3
  721. package/src/ui/screens/FeedbackScreen.tsx +14 -12
  722. package/src/ui/screens/FileManagementScreen.tsx +885 -124
  723. package/src/ui/screens/HelpSupportScreen.tsx +2 -3
  724. package/src/ui/screens/HistoryViewScreen.tsx +24 -9
  725. package/src/ui/screens/LanguageSelectorScreen.tsx +1 -3
  726. package/src/ui/screens/LegalDocumentsScreen.tsx +3 -3
  727. package/src/ui/screens/PaymentGatewayScreen.tsx +2 -2
  728. package/src/ui/screens/PremiumSubscriptionScreen.tsx +51 -56
  729. package/src/ui/screens/PrivacySettingsScreen.tsx +22 -20
  730. package/src/ui/screens/ProfileScreen.tsx +1 -2
  731. package/src/ui/screens/SavesCollectionsScreen.tsx +2 -2
  732. package/src/ui/screens/SessionManagementScreen.tsx +35 -47
  733. package/src/ui/screens/UserLinksScreen.tsx +1 -2
  734. package/src/ui/screens/UserListScreen.tsx +30 -19
  735. package/src/ui/screens/WelcomeNewUserScreen.tsx +14 -18
  736. package/src/ui/screens/karma/KarmaAboutScreen.tsx +0 -3
  737. package/src/ui/screens/karma/KarmaCenterScreen.tsx +4 -8
  738. package/src/ui/screens/karma/KarmaFAQScreen.tsx +1 -1
  739. package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +3 -4
  740. package/src/ui/screens/karma/KarmaRewardsScreen.tsx +13 -18
  741. package/src/ui/screens/karma/KarmaRulesScreen.tsx +3 -4
  742. package/src/ui/server.ts +0 -4
  743. package/src/ui/styles/authStyles.ts +0 -5
  744. package/src/ui/styles/index.ts +0 -1
  745. package/src/ui/styles/spacing.ts +0 -43
  746. package/src/ui/styles/theme.ts +0 -4
  747. package/src/ui/utils/fileManagement.ts +66 -38
  748. package/src/ui/utils/sessionHelpers.ts +3 -1
  749. package/src/ui/utils/userUtils.ts +45 -29
  750. package/lib/commonjs/lib/sonner-safe.js +0 -32
  751. package/lib/commonjs/lib/sonner-safe.js.map +0 -1
  752. package/lib/commonjs/lib/sonner.js +0 -19
  753. package/lib/commonjs/lib/sonner.js.map +0 -1
  754. package/lib/commonjs/lib/sonner.native.js +0 -24
  755. package/lib/commonjs/lib/sonner.native.js.map +0 -1
  756. package/lib/commonjs/lib/sonner.web.js +0 -24
  757. package/lib/commonjs/lib/sonner.web.js.map +0 -1
  758. package/lib/commonjs/ui/hooks/useThemeColors.js +0 -33
  759. package/lib/commonjs/ui/hooks/useThemeColors.js.map +0 -1
  760. package/lib/commonjs/ui/hooks/useThemeStyles.js +0 -38
  761. package/lib/commonjs/ui/hooks/useThemeStyles.js.map +0 -1
  762. package/lib/commonjs/ui/styles/fonts.js +0 -84
  763. package/lib/commonjs/ui/styles/fonts.js.map +0 -1
  764. package/lib/module/lib/sonner-safe.js +0 -29
  765. package/lib/module/lib/sonner-safe.js.map +0 -1
  766. package/lib/module/lib/sonner.js +0 -14
  767. package/lib/module/lib/sonner.js.map +0 -1
  768. package/lib/module/lib/sonner.native.js +0 -19
  769. package/lib/module/lib/sonner.native.js.map +0 -1
  770. package/lib/module/lib/sonner.web.js +0 -19
  771. package/lib/module/lib/sonner.web.js.map +0 -1
  772. package/lib/module/ui/hooks/useThemeColors.js +0 -29
  773. package/lib/module/ui/hooks/useThemeColors.js.map +0 -1
  774. package/lib/module/ui/hooks/useThemeStyles.js +0 -33
  775. package/lib/module/ui/hooks/useThemeStyles.js.map +0 -1
  776. package/lib/module/ui/styles/fonts.js +0 -81
  777. package/lib/module/ui/styles/fonts.js.map +0 -1
  778. package/lib/typescript/commonjs/lib/sonner-safe.d.ts +0 -9
  779. package/lib/typescript/commonjs/lib/sonner-safe.d.ts.map +0 -1
  780. package/lib/typescript/commonjs/lib/sonner.d.ts +0 -12
  781. package/lib/typescript/commonjs/lib/sonner.d.ts.map +0 -1
  782. package/lib/typescript/commonjs/lib/sonner.native.d.ts +0 -15
  783. package/lib/typescript/commonjs/lib/sonner.native.d.ts.map +0 -1
  784. package/lib/typescript/commonjs/lib/sonner.web.d.ts +0 -15
  785. package/lib/typescript/commonjs/lib/sonner.web.d.ts.map +0 -1
  786. package/lib/typescript/commonjs/ui/hooks/useThemeColors.d.ts +0 -87
  787. package/lib/typescript/commonjs/ui/hooks/useThemeColors.d.ts.map +0 -1
  788. package/lib/typescript/commonjs/ui/hooks/useThemeStyles.d.ts +0 -22
  789. package/lib/typescript/commonjs/ui/hooks/useThemeStyles.d.ts.map +0 -1
  790. package/lib/typescript/commonjs/ui/styles/fonts.d.ts +0 -21
  791. package/lib/typescript/commonjs/ui/styles/fonts.d.ts.map +0 -1
  792. package/lib/typescript/module/lib/sonner-safe.d.ts +0 -9
  793. package/lib/typescript/module/lib/sonner-safe.d.ts.map +0 -1
  794. package/lib/typescript/module/lib/sonner.d.ts +0 -12
  795. package/lib/typescript/module/lib/sonner.d.ts.map +0 -1
  796. package/lib/typescript/module/lib/sonner.native.d.ts +0 -15
  797. package/lib/typescript/module/lib/sonner.native.d.ts.map +0 -1
  798. package/lib/typescript/module/lib/sonner.web.d.ts +0 -15
  799. package/lib/typescript/module/lib/sonner.web.d.ts.map +0 -1
  800. package/lib/typescript/module/ui/hooks/useThemeColors.d.ts +0 -87
  801. package/lib/typescript/module/ui/hooks/useThemeColors.d.ts.map +0 -1
  802. package/lib/typescript/module/ui/hooks/useThemeStyles.d.ts +0 -22
  803. package/lib/typescript/module/ui/hooks/useThemeStyles.d.ts.map +0 -1
  804. package/lib/typescript/module/ui/styles/fonts.d.ts +0 -21
  805. package/lib/typescript/module/ui/styles/fonts.d.ts.map +0 -1
  806. package/src/lib/sonner-safe.ts +0 -31
  807. package/src/lib/sonner.native.ts +0 -28
  808. package/src/lib/sonner.ts +0 -11
  809. package/src/lib/sonner.web.ts +0 -28
  810. package/src/ui/hooks/useThemeColors.ts +0 -27
  811. package/src/ui/hooks/useThemeStyles.ts +0 -50
  812. package/src/ui/styles/fonts.ts +0 -77
@@ -0,0 +1,1073 @@
1
+ /**
2
+ * AvatarCropScreen
3
+ *
4
+ * Flagship-grade circular crop editor presented after the user picks an image
5
+ * but before the avatar is uploaded. Inspired by iOS Photos, Google Photos and
6
+ * Instagram crop tools.
7
+ *
8
+ * Architecture:
9
+ * - Full-bleed black canvas, independent of theme, so photos always read well.
10
+ * - Translucent top bar with Cancel / Title / Done (primary CTA).
11
+ * - Circular viewport with white ring, outer 50% black mask, and a 3x3
12
+ * rule-of-thirds grid that appears during gestures and fades after 800ms.
13
+ * - Floating zoom chip during pinch.
14
+ * - Pan + pinch via Gesture Handler, transform driven by Reanimated.
15
+ * - Reduced-motion aware entrance animation.
16
+ * - Haptics on milestones via dynamically imported expo-haptics (optional).
17
+ *
18
+ * `expo-image-manipulator` and `expo-haptics` are optional peer dependencies —
19
+ * loaded with `await import(...)`. A missing manipulator surfaces a clear
20
+ * error; missing haptics simply degrades silently.
21
+ */
22
+
23
+ import type React from 'react';
24
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
25
+ import {
26
+ View,
27
+ Text,
28
+ StyleSheet,
29
+ ActivityIndicator,
30
+ TouchableOpacity,
31
+ Image,
32
+ Platform,
33
+ AccessibilityInfo,
34
+ Pressable,
35
+ } from 'react-native';
36
+ import { Gesture, GestureDetector } from 'react-native-gesture-handler';
37
+ import Animated, {
38
+ Easing,
39
+ runOnJS,
40
+ useAnimatedStyle,
41
+ useSharedValue,
42
+ withDelay,
43
+ withSpring,
44
+ withTiming,
45
+ } from 'react-native-reanimated';
46
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
47
+ import { useTheme } from '@oxyhq/bloom/theme';
48
+ import { logger } from '@oxyhq/core';
49
+ import { useI18n } from '../hooks/useI18n';
50
+ import { toast } from '@oxyhq/bloom';
51
+ import type { BaseScreenProps } from '../types/navigation';
52
+
53
+ /** Component name used in `logger` context for filtered diagnostics. */
54
+ const LOG_COMPONENT = 'AvatarCropScreen';
55
+
56
+ /** Final crop result handed back to the caller. */
57
+ export interface AvatarCropResult {
58
+ /** File URI to the cropped 512x512 JPEG on disk. */
59
+ uri: string;
60
+ /** Output width (always 512). */
61
+ width: number;
62
+ /** Output height (always 512). */
63
+ height: number;
64
+ /** MIME type (always `image/jpeg`). */
65
+ mime: 'image/jpeg';
66
+ }
67
+
68
+ export interface AvatarCropScreenProps extends BaseScreenProps {
69
+ /** URI of the source image to crop. */
70
+ imageUri?: string;
71
+ /** Natural width of the source image (optional — measured if absent). */
72
+ sourceWidth?: number;
73
+ /** Natural height of the source image (optional — measured if absent). */
74
+ 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
+ }
80
+
81
+ /** Side length (in dp) of the crop viewport. The output is always 512x512px. */
82
+ const VIEWPORT_SIZE = 320;
83
+ const OUTPUT_SIZE = 512;
84
+ const MIN_SCALE = 1;
85
+ const MAX_SCALE = 4;
86
+ /** Duration (ms) that the rule-of-thirds grid lingers after a gesture ends. */
87
+ const GRID_FADE_DELAY_MS = 800;
88
+ const GRID_FADE_DURATION_MS = 220;
89
+ /** Duration the zoom chip stays visible after a pinch ends. */
90
+ const ZOOM_CHIP_FADE_DELAY_MS = 600;
91
+ const ZOOM_CHIP_FADE_DURATION_MS = 200;
92
+ /** Backdrop color is fixed independent of theme so the photo always reads well. */
93
+ const CANVAS_BG = '#000000';
94
+ const RING_COLOR = '#ffffff';
95
+ const RING_WIDTH = 2;
96
+
97
+ /**
98
+ * Clamp the translation so the image edges never leave the viewport at any
99
+ * scale. Worklet-friendly (pure function, no closures over JS state) so the
100
+ * gesture handlers can reuse it without re-creating the closure each render.
101
+ */
102
+ function clampTranslation(
103
+ tx: number,
104
+ ty: number,
105
+ s: number,
106
+ baseW: number,
107
+ baseH: number,
108
+ ): { tx: number; ty: number } {
109
+ 'worklet';
110
+ const scaledW = baseW * s;
111
+ const scaledH = baseH * s;
112
+ const maxX = Math.max(0, (scaledW - VIEWPORT_SIZE) / 2);
113
+ const maxY = Math.max(0, (scaledH - VIEWPORT_SIZE) / 2);
114
+ return {
115
+ tx: Math.min(Math.max(tx, -maxX), maxX),
116
+ ty: Math.min(Math.max(ty, -maxY), maxY),
117
+ };
118
+ }
119
+
120
+ interface ImageNaturalSize {
121
+ width: number;
122
+ height: number;
123
+ }
124
+
125
+ /**
126
+ * Lazy-loaded reference to the expo-image-manipulator module. The module is an
127
+ * optional peer dep, so we resolve it on demand and surface a clean error
128
+ * upstream if the consuming app has not installed it.
129
+ */
130
+ interface ImageManipulatorModule {
131
+ manipulateAsync: (
132
+ uri: string,
133
+ actions: Array<{
134
+ crop?: { originX: number; originY: number; width: number; height: number };
135
+ resize?: { width?: number; height?: number };
136
+ }>,
137
+ saveOptions?: { format?: 'jpeg' | 'png' | 'webp'; compress?: number },
138
+ ) => Promise<{ uri: string; width: number; height: number }>;
139
+ SaveFormat: { JPEG: 'jpeg'; PNG: 'png'; WEBP: 'webp' };
140
+ }
141
+
142
+ async function loadImageManipulator(): Promise<ImageManipulatorModule> {
143
+ try {
144
+ const mod = (await import('expo-image-manipulator')) as unknown as ImageManipulatorModule;
145
+ if (!mod || typeof mod.manipulateAsync !== 'function') {
146
+ throw new Error('expo-image-manipulator did not export manipulateAsync');
147
+ }
148
+ return mod;
149
+ } catch (err) {
150
+ const message = err instanceof Error ? err.message : String(err);
151
+ throw new Error(
152
+ `expo-image-manipulator is required for avatar cropping but is not installed: ${message}`,
153
+ );
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Haptic feedback wrapper. `expo-haptics` is an optional dependency — when not
159
+ * installed (or on web), all calls degrade silently. We resolve the module once
160
+ * and cache the promise so subsequent calls don't repeat the dynamic import.
161
+ */
162
+ type HapticImpact = 'light' | 'medium' | 'heavy';
163
+ type HapticNotification = 'success' | 'warning' | 'error';
164
+ interface HapticsModule {
165
+ impactAsync: (style: unknown) => Promise<void>;
166
+ notificationAsync: (type: unknown) => Promise<void>;
167
+ selectionAsync: () => Promise<void>;
168
+ ImpactFeedbackStyle: { Light: unknown; Medium: unknown; Heavy: unknown };
169
+ NotificationFeedbackType: { Success: unknown; Warning: unknown; Error: unknown };
170
+ }
171
+
172
+ let hapticsModulePromise: Promise<HapticsModule | null> | null = null;
173
+ function getHaptics(): Promise<HapticsModule | null> {
174
+ if (Platform.OS === 'web') return Promise.resolve(null);
175
+ if (hapticsModulePromise) return hapticsModulePromise;
176
+ hapticsModulePromise = (async () => {
177
+ try {
178
+ const mod = (await import('expo-haptics')) as unknown as HapticsModule;
179
+ if (!mod || typeof mod.impactAsync !== 'function') return null;
180
+ return mod;
181
+ } catch {
182
+ return null;
183
+ }
184
+ })();
185
+ return hapticsModulePromise;
186
+ }
187
+
188
+ async function hapticImpact(style: HapticImpact): Promise<void> {
189
+ const h = await getHaptics();
190
+ if (!h) return;
191
+ const styleEnum =
192
+ style === 'heavy'
193
+ ? h.ImpactFeedbackStyle.Heavy
194
+ : style === 'medium'
195
+ ? h.ImpactFeedbackStyle.Medium
196
+ : h.ImpactFeedbackStyle.Light;
197
+ try {
198
+ await h.impactAsync(styleEnum);
199
+ } catch {
200
+ // Silent — haptics are non-critical UX polish.
201
+ }
202
+ }
203
+
204
+ async function hapticNotification(type: HapticNotification): Promise<void> {
205
+ const h = await getHaptics();
206
+ if (!h) return;
207
+ const typeEnum =
208
+ type === 'error'
209
+ ? h.NotificationFeedbackType.Error
210
+ : type === 'warning'
211
+ ? h.NotificationFeedbackType.Warning
212
+ : h.NotificationFeedbackType.Success;
213
+ try {
214
+ await h.notificationAsync(typeEnum);
215
+ } catch {
216
+ // Silent.
217
+ }
218
+ }
219
+
220
+ async function hapticSelection(): Promise<void> {
221
+ const h = await getHaptics();
222
+ if (!h) return;
223
+ try {
224
+ await h.selectionAsync();
225
+ } catch {
226
+ // Silent.
227
+ }
228
+ }
229
+
230
+ const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
231
+ goBack,
232
+ onClose,
233
+ imageUri,
234
+ sourceWidth,
235
+ sourceHeight,
236
+ onConfirm,
237
+ onCancel,
238
+ }) => {
239
+ const theme = useTheme();
240
+ const { t } = useI18n();
241
+ const insets = useSafeAreaInsets();
242
+
243
+ // Natural size of the source image. May be known up front (passed in) or
244
+ // measured lazily via Image.getSize once the image loads.
245
+ const [naturalSize, setNaturalSize] = useState<ImageNaturalSize | null>(
246
+ sourceWidth && sourceHeight ? { width: sourceWidth, height: sourceHeight } : null,
247
+ );
248
+ const [isProcessing, setIsProcessing] = useState(false);
249
+ const [zoomLabel, setZoomLabel] = useState('1.0');
250
+ /** True when scale != MIN_SCALE OR translate != 0 — used to reveal the reset link. */
251
+ const [isModified, setIsModified] = useState(false);
252
+ const [reduceMotion, setReduceMotion] = useState(false);
253
+
254
+ // Shared values for the active gesture transform.
255
+ const scale = useSharedValue(MIN_SCALE);
256
+ const translateX = useSharedValue(0);
257
+ const translateY = useSharedValue(0);
258
+
259
+ // Entrance scale of the crop circle (pulse-in on mount).
260
+ const entrance = useSharedValue(reduceMotion ? 1 : 0.95);
261
+ /** 0..1 opacity for the rule-of-thirds grid and zoom chip. */
262
+ const gridOpacity = useSharedValue(0);
263
+ const zoomChipOpacity = useSharedValue(0);
264
+
265
+ // Refs that mirror the latest committed shared values so the JS-side
266
+ // confirm handler can read them without an extra `useSharedValue → react`
267
+ // bridge. Updated by `runOnJS(commit*)` from the gesture worklets.
268
+ const committedScale = useRef(MIN_SCALE);
269
+ const committedTranslateX = useRef(0);
270
+ const committedTranslateY = useRef(0);
271
+
272
+ // Saved start values for relative gesture math.
273
+ const savedScale = useSharedValue(MIN_SCALE);
274
+ const savedTranslateX = useSharedValue(0);
275
+ const savedTranslateY = useSharedValue(0);
276
+
277
+ // Track whether we've already announced a min/max bound during the current
278
+ // pinch so selection haptics don't fire on every frame.
279
+ const hitMinRef = useRef(false);
280
+ const hitMaxRef = useRef(false);
281
+
282
+ // The image is rendered at "cover" relative to the viewport. We compute
283
+ // `baseScale` so 1.0x means the image exactly covers the square; everything
284
+ // larger than that is user-zoom.
285
+ const baseFit = useMemo((): { width: number; height: number } | null => {
286
+ if (!naturalSize) return null;
287
+ const ratio = naturalSize.width / naturalSize.height;
288
+ // Cover: the smaller dimension matches the viewport.
289
+ if (ratio >= 1) {
290
+ // Landscape — height fills viewport
291
+ return { width: VIEWPORT_SIZE * ratio, height: VIEWPORT_SIZE };
292
+ }
293
+ return { width: VIEWPORT_SIZE, height: VIEWPORT_SIZE / ratio };
294
+ }, [naturalSize]);
295
+
296
+ // Track in-flight measurement to avoid duplicate Image.getSize calls when
297
+ // the component re-renders before the previous getSize callback fires.
298
+ const measuringUriRef = useRef<string | null>(null);
299
+ /** Failure state for measurement, surfaced to the user via the empty UI. */
300
+ const [measureError, setMeasureError] = useState<string | null>(null);
301
+
302
+ const handleImageMeasured = useCallback(
303
+ (uri: string) => {
304
+ if (measuringUriRef.current === uri) return;
305
+ measuringUriRef.current = uri;
306
+ // `logger.debug` is dev-gated upstream (no-op in production).
307
+ // We deliberately don't log the full file URI in any production
308
+ // path — only in debug builds — to avoid leaking on-device file
309
+ // paths into logcat / Sentry breadcrumbs.
310
+ logger.debug('Measuring image', { component: LOG_COMPONENT });
311
+ Image.getSize(
312
+ uri,
313
+ (w, h) => {
314
+ logger.debug('Image measured', { component: LOG_COMPONENT }, { width: w, height: h });
315
+ if (!Number.isFinite(w) || !Number.isFinite(h) || w <= 0 || h <= 0) {
316
+ const message = t('editProfile.toasts.cropMeasureFailed') ||
317
+ 'Could not measure the image';
318
+ setMeasureError(message);
319
+ toast.error(message);
320
+ measuringUriRef.current = null;
321
+ return;
322
+ }
323
+ setMeasureError(null);
324
+ setNaturalSize({ width: w, height: h });
325
+ },
326
+ (err) => {
327
+ logger.error('Image.getSize failed', err, { component: LOG_COMPONENT });
328
+ const message = t('editProfile.toasts.cropMeasureFailed') ||
329
+ 'Could not measure the image';
330
+ setMeasureError(message);
331
+ toast.error(message);
332
+ measuringUriRef.current = null;
333
+ },
334
+ );
335
+ },
336
+ [t],
337
+ );
338
+
339
+ // Kick off measurement once per imageUri. Using useEffect (not a render-body
340
+ // side effect) so the call is scheduled exactly when the URI changes,
341
+ // rather than being re-fired on every parent re-render.
342
+ useEffect(() => {
343
+ if (!imageUri) return;
344
+ if (sourceWidth && sourceHeight) return;
345
+ if (naturalSize) return;
346
+ handleImageMeasured(imageUri);
347
+ }, [handleImageMeasured, imageUri, naturalSize, sourceHeight, sourceWidth]);
348
+
349
+ // Dev-only one-time mount breadcrumb. `logger.debug` is dev-gated so
350
+ // this is a no-op in production releases; we additionally avoid logging
351
+ // the full `imageUri` to prevent leaking on-device file paths into any
352
+ // breadcrumb sink that picks up debug output.
353
+ useEffect(() => {
354
+ logger.debug(
355
+ 'mount',
356
+ { component: LOG_COMPONENT },
357
+ {
358
+ hasImageUri: !!imageUri,
359
+ hasSourceDimensions: !!(sourceWidth && sourceHeight),
360
+ },
361
+ );
362
+ }, [imageUri, sourceHeight, sourceWidth]);
363
+
364
+ // Detect reduce-motion preference once on mount + subscribe to changes.
365
+ useEffect(() => {
366
+ let cancelled = false;
367
+ AccessibilityInfo.isReduceMotionEnabled()
368
+ .then((enabled) => {
369
+ if (cancelled) return;
370
+ setReduceMotion(enabled);
371
+ if (enabled) {
372
+ entrance.value = 1;
373
+ }
374
+ })
375
+ .catch(() => {
376
+ // Best-effort — fall back to motion enabled.
377
+ });
378
+ const sub = AccessibilityInfo.addEventListener('reduceMotionChanged', (enabled) => {
379
+ setReduceMotion(enabled);
380
+ if (enabled) entrance.value = 1;
381
+ });
382
+ return () => {
383
+ cancelled = true;
384
+ sub.remove();
385
+ };
386
+ }, [entrance]);
387
+
388
+ // Play the entrance pulse exactly once when motion is allowed.
389
+ useEffect(() => {
390
+ if (reduceMotion) return;
391
+ entrance.value = withSpring(1, {
392
+ damping: 14,
393
+ stiffness: 180,
394
+ mass: 0.9,
395
+ });
396
+ }, [entrance, reduceMotion]);
397
+
398
+ const commitTransform = useCallback((s: number, tx: number, ty: number) => {
399
+ committedScale.current = s;
400
+ committedTranslateX.current = tx;
401
+ committedTranslateY.current = ty;
402
+ const modified =
403
+ Math.abs(s - MIN_SCALE) > 0.001 || Math.abs(tx) > 0.5 || Math.abs(ty) > 0.5;
404
+ setIsModified(modified);
405
+ setZoomLabel(s.toFixed(1));
406
+ }, []);
407
+
408
+ /** Show the rule-of-thirds grid; called from gesture worklets via runOnJS-free path. */
409
+ const showGrid = useCallback(() => {
410
+ gridOpacity.value = withTiming(1, { duration: 120, easing: Easing.out(Easing.quad) });
411
+ }, [gridOpacity]);
412
+
413
+ const hideGrid = useCallback(() => {
414
+ gridOpacity.value = withDelay(
415
+ GRID_FADE_DELAY_MS,
416
+ withTiming(0, { duration: GRID_FADE_DURATION_MS, easing: Easing.in(Easing.quad) }),
417
+ );
418
+ }, [gridOpacity]);
419
+
420
+ const showZoomChip = useCallback(() => {
421
+ zoomChipOpacity.value = withTiming(1, { duration: 100 });
422
+ }, [zoomChipOpacity]);
423
+
424
+ const hideZoomChip = useCallback(() => {
425
+ zoomChipOpacity.value = withDelay(
426
+ ZOOM_CHIP_FADE_DELAY_MS,
427
+ withTiming(0, { duration: ZOOM_CHIP_FADE_DURATION_MS }),
428
+ );
429
+ }, [zoomChipOpacity]);
430
+
431
+ /** Dev-only ping fired once per gesture start so we can confirm in logs. */
432
+ const logGestureStart = useCallback((kind: 'pan' | 'pinch') => {
433
+ logger.debug(`gesture start: ${kind}`, { component: LOG_COMPONENT });
434
+ }, []);
435
+
436
+ const panGesture = useMemo(
437
+ () =>
438
+ Gesture.Pan()
439
+ .minDistance(2)
440
+ .onStart(() => {
441
+ 'worklet';
442
+ savedTranslateX.value = translateX.value;
443
+ savedTranslateY.value = translateY.value;
444
+ runOnJS(showGrid)();
445
+ runOnJS(logGestureStart)('pan');
446
+ })
447
+ .onUpdate((event) => {
448
+ 'worklet';
449
+ if (!baseFit) return;
450
+ const next = clampTranslation(
451
+ savedTranslateX.value + event.translationX,
452
+ savedTranslateY.value + event.translationY,
453
+ scale.value,
454
+ baseFit.width,
455
+ baseFit.height,
456
+ );
457
+ translateX.value = next.tx;
458
+ translateY.value = next.ty;
459
+ })
460
+ .onEnd(() => {
461
+ 'worklet';
462
+ runOnJS(commitTransform)(scale.value, translateX.value, translateY.value);
463
+ runOnJS(hideGrid)();
464
+ }),
465
+ [
466
+ baseFit,
467
+ commitTransform,
468
+ hideGrid,
469
+ logGestureStart,
470
+ savedTranslateX,
471
+ savedTranslateY,
472
+ scale,
473
+ showGrid,
474
+ translateX,
475
+ translateY,
476
+ ],
477
+ );
478
+
479
+ /** Imperative helpers invoked from worklets via runOnJS. Stable refs. */
480
+ const resetPinchBounds = useCallback((): void => {
481
+ hitMinRef.current = false;
482
+ hitMaxRef.current = false;
483
+ }, []);
484
+
485
+ const updateZoomLabel = useCallback((s: number): void => {
486
+ setZoomLabel(s.toFixed(1));
487
+ }, []);
488
+
489
+ const notifyMinBoundHit = useCallback((): void => {
490
+ if (hitMinRef.current) return;
491
+ hitMinRef.current = true;
492
+ void hapticSelection();
493
+ }, []);
494
+
495
+ const notifyMaxBoundHit = useCallback((): void => {
496
+ if (hitMaxRef.current) return;
497
+ hitMaxRef.current = true;
498
+ void hapticSelection();
499
+ }, []);
500
+
501
+ const pinchGesture = useMemo(
502
+ () =>
503
+ Gesture.Pinch()
504
+ .onStart(() => {
505
+ 'worklet';
506
+ savedScale.value = scale.value;
507
+ runOnJS(showGrid)();
508
+ runOnJS(showZoomChip)();
509
+ runOnJS(resetPinchBounds)();
510
+ runOnJS(logGestureStart)('pinch');
511
+ })
512
+ .onUpdate((event) => {
513
+ 'worklet';
514
+ if (!baseFit) return;
515
+ const raw = savedScale.value * event.scale;
516
+ const nextScale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, raw));
517
+ scale.value = nextScale;
518
+ // Re-clamp translation since the bounds depend on scale.
519
+ const clamped = clampTranslation(
520
+ translateX.value,
521
+ translateY.value,
522
+ nextScale,
523
+ baseFit.width,
524
+ baseFit.height,
525
+ );
526
+ translateX.value = clamped.tx;
527
+ translateY.value = clamped.ty;
528
+ runOnJS(updateZoomLabel)(nextScale);
529
+ // Selection haptic on first frame at min/max.
530
+ if (nextScale <= MIN_SCALE + 0.001 && raw < MIN_SCALE) {
531
+ runOnJS(notifyMinBoundHit)();
532
+ } else if (nextScale >= MAX_SCALE - 0.001 && raw > MAX_SCALE) {
533
+ runOnJS(notifyMaxBoundHit)();
534
+ }
535
+ })
536
+ .onEnd(() => {
537
+ 'worklet';
538
+ runOnJS(commitTransform)(scale.value, translateX.value, translateY.value);
539
+ runOnJS(hideGrid)();
540
+ runOnJS(hideZoomChip)();
541
+ }),
542
+ [
543
+ baseFit,
544
+ commitTransform,
545
+ hideGrid,
546
+ hideZoomChip,
547
+ logGestureStart,
548
+ notifyMaxBoundHit,
549
+ notifyMinBoundHit,
550
+ resetPinchBounds,
551
+ savedScale,
552
+ scale,
553
+ showGrid,
554
+ showZoomChip,
555
+ translateX,
556
+ translateY,
557
+ updateZoomLabel,
558
+ ],
559
+ );
560
+
561
+ const composedGesture = useMemo(
562
+ () => Gesture.Simultaneous(panGesture, pinchGesture),
563
+ [panGesture, pinchGesture],
564
+ );
565
+
566
+ const imageAnimatedStyle = useAnimatedStyle(() => ({
567
+ transform: [
568
+ { translateX: translateX.value },
569
+ { translateY: translateY.value },
570
+ { scale: scale.value },
571
+ ],
572
+ }));
573
+
574
+ const cropFrameAnimatedStyle = useAnimatedStyle(() => ({
575
+ transform: [{ scale: entrance.value }],
576
+ }));
577
+
578
+ const gridAnimatedStyle = useAnimatedStyle(() => ({
579
+ opacity: gridOpacity.value,
580
+ }));
581
+
582
+ const zoomChipAnimatedStyle = useAnimatedStyle(() => ({
583
+ opacity: zoomChipOpacity.value,
584
+ }));
585
+
586
+ const resetTransform = useCallback(() => {
587
+ const duration = reduceMotion ? 0 : 220;
588
+ scale.value = withTiming(MIN_SCALE, { duration });
589
+ translateX.value = withTiming(0, { duration });
590
+ translateY.value = withTiming(0, { duration });
591
+ commitTransform(MIN_SCALE, 0, 0);
592
+ void hapticImpact('light');
593
+ AccessibilityInfo.announceForAccessibility(
594
+ t('editProfile.crop.a11yResetAnnouncement') || 'Crop reset',
595
+ );
596
+ }, [commitTransform, reduceMotion, scale, t, translateX, translateY]);
597
+
598
+ /**
599
+ * Convert the on-screen transform into pixel-space crop coordinates
600
+ * relative to the source image, then invoke expo-image-manipulator to
601
+ * crop + resize to 512x512 JPEG.
602
+ */
603
+ const handleConfirm = useCallback(async () => {
604
+ // Dev-only breadcrumb. Avoid logging `imageUri` so on-device file
605
+ // paths don't leak into breadcrumb sinks that surface debug output.
606
+ logger.debug(
607
+ 'handleConfirm start',
608
+ { component: LOG_COMPONENT },
609
+ {
610
+ hasBaseFit: !!baseFit,
611
+ hasNaturalSize: !!naturalSize,
612
+ committedScale: committedScale.current,
613
+ committedTranslateX: committedTranslateX.current,
614
+ committedTranslateY: committedTranslateY.current,
615
+ },
616
+ );
617
+ if (!imageUri || !baseFit || !naturalSize) {
618
+ toast.error(
619
+ t('editProfile.toasts.cropNotReady') || 'Image not ready yet',
620
+ );
621
+ return;
622
+ }
623
+
624
+ setIsProcessing(true);
625
+ try {
626
+ const { manipulateAsync, SaveFormat } = await loadImageManipulator();
627
+
628
+ const s = committedScale.current;
629
+ const tx = committedTranslateX.current;
630
+ const ty = committedTranslateY.current;
631
+
632
+ // Visible viewport in *displayed image* pixel space (with scale applied):
633
+ // The viewport is centered on the image origin, then offset by (-tx, -ty).
634
+ const scaledImageWidth = baseFit.width * s;
635
+ const scaledImageHeight = baseFit.height * s;
636
+
637
+ // Top-left of viewport in displayed-pixel space:
638
+ const viewportLeft = (scaledImageWidth - VIEWPORT_SIZE) / 2 - tx;
639
+ const viewportTop = (scaledImageHeight - VIEWPORT_SIZE) / 2 - ty;
640
+
641
+ // Convert to source-image pixel space:
642
+ const sourcePerDisplay = naturalSize.width / scaledImageWidth;
643
+ const cropX = Math.max(0, viewportLeft * sourcePerDisplay);
644
+ const cropY = Math.max(0, viewportTop * sourcePerDisplay);
645
+ const cropSize = Math.min(
646
+ naturalSize.width - cropX,
647
+ naturalSize.height - cropY,
648
+ VIEWPORT_SIZE * sourcePerDisplay,
649
+ );
650
+
651
+ if (!Number.isFinite(cropSize) || cropSize <= 0) {
652
+ throw new Error('Computed crop region is invalid');
653
+ }
654
+
655
+ // Dev-only crop coordinates. We log the derived crop region but
656
+ // never the input URI — paths are PII-adjacent on some platforms.
657
+ logger.debug(
658
+ 'manipulateAsync input',
659
+ { component: LOG_COMPONENT },
660
+ {
661
+ cropX,
662
+ cropY,
663
+ cropSize,
664
+ outputSize: OUTPUT_SIZE,
665
+ },
666
+ );
667
+
668
+ const result = await manipulateAsync(
669
+ imageUri,
670
+ [
671
+ {
672
+ crop: {
673
+ originX: cropX,
674
+ originY: cropY,
675
+ width: cropSize,
676
+ height: cropSize,
677
+ },
678
+ },
679
+ { resize: { width: OUTPUT_SIZE, height: OUTPUT_SIZE } },
680
+ ],
681
+ { format: SaveFormat.JPEG, compress: 0.85 },
682
+ );
683
+
684
+ // Log only the result's dimensions, never the on-disk URI.
685
+ logger.debug(
686
+ 'manipulateAsync result',
687
+ { component: LOG_COMPONENT },
688
+ { width: result.width, height: result.height },
689
+ );
690
+
691
+ void hapticNotification('success');
692
+
693
+ await onConfirm?.({
694
+ uri: result.uri,
695
+ width: result.width,
696
+ height: result.height,
697
+ mime: 'image/jpeg',
698
+ });
699
+
700
+ // Close the sheet on success. The caller is responsible for any
701
+ // success toast (uploads typically toast their own outcome).
702
+ onClose?.();
703
+ } catch (err) {
704
+ logger.error('handleConfirm failed', err, { component: LOG_COMPONENT });
705
+ const message = err instanceof Error ? err.message : undefined;
706
+ void hapticNotification('error');
707
+ toast.error(
708
+ message || t('editProfile.toasts.cropFailed') || 'Failed to crop image',
709
+ );
710
+ } finally {
711
+ setIsProcessing(false);
712
+ }
713
+ }, [baseFit, imageUri, naturalSize, onClose, onConfirm, t]);
714
+
715
+ const handleCancel = useCallback(() => {
716
+ onCancel?.();
717
+ goBack?.();
718
+ }, [goBack, onCancel]);
719
+
720
+ const topInset = Platform.OS === 'ios' ? Math.max(insets.top, 12) : Math.max(insets.top, 16);
721
+ const bottomInset = Math.max(insets.bottom, 16);
722
+
723
+ const styles = useMemo(
724
+ () =>
725
+ StyleSheet.create({
726
+ container: {
727
+ flex: 1,
728
+ backgroundColor: CANVAS_BG,
729
+ },
730
+ topBar: {
731
+ paddingTop: topInset,
732
+ paddingHorizontal: 12,
733
+ paddingBottom: 10,
734
+ flexDirection: 'row',
735
+ alignItems: 'center',
736
+ justifyContent: 'space-between',
737
+ backgroundColor: 'rgba(0,0,0,0.6)',
738
+ zIndex: 10,
739
+ },
740
+ topBarTitleWrap: {
741
+ flex: 1,
742
+ alignItems: 'center',
743
+ justifyContent: 'center',
744
+ paddingHorizontal: 4,
745
+ },
746
+ topBarTitle: {
747
+ color: '#ffffff',
748
+ fontSize: 17,
749
+ letterSpacing: -0.2,
750
+ ...(Platform.OS === 'web' ? { fontWeight: '600' as const } : null),
751
+ },
752
+ cancelBtn: {
753
+ minWidth: 64,
754
+ paddingHorizontal: 10,
755
+ paddingVertical: 8,
756
+ borderRadius: 18,
757
+ alignItems: 'flex-start',
758
+ justifyContent: 'center',
759
+ },
760
+ cancelLabel: {
761
+ color: '#ffffff',
762
+ fontSize: 15,
763
+ opacity: 0.85,
764
+ },
765
+ doneBtn: {
766
+ minWidth: 76,
767
+ paddingHorizontal: 14,
768
+ paddingVertical: 8,
769
+ borderRadius: 18,
770
+ alignItems: 'center',
771
+ justifyContent: 'center',
772
+ backgroundColor: theme.colors.primary,
773
+ },
774
+ doneBtnDisabled: {
775
+ opacity: 0.5,
776
+ },
777
+ doneLabel: {
778
+ color: '#ffffff',
779
+ fontSize: 15,
780
+ letterSpacing: -0.1,
781
+ ...(Platform.OS === 'web' ? { fontWeight: '600' as const } : null),
782
+ },
783
+ doneLabelLoading: {
784
+ flexDirection: 'row',
785
+ alignItems: 'center',
786
+ justifyContent: 'center',
787
+ gap: 8,
788
+ },
789
+ stage: {
790
+ flex: 1,
791
+ alignItems: 'center',
792
+ justifyContent: 'center',
793
+ paddingHorizontal: 16,
794
+ },
795
+ cropFrame: {
796
+ width: VIEWPORT_SIZE,
797
+ height: VIEWPORT_SIZE,
798
+ alignItems: 'center',
799
+ justifyContent: 'center',
800
+ },
801
+ viewport: {
802
+ width: VIEWPORT_SIZE,
803
+ height: VIEWPORT_SIZE,
804
+ overflow: 'hidden',
805
+ borderRadius: VIEWPORT_SIZE / 2,
806
+ backgroundColor: '#1a1a1a',
807
+ alignItems: 'center',
808
+ justifyContent: 'center',
809
+ },
810
+ image: {
811
+ width: baseFit?.width ?? VIEWPORT_SIZE,
812
+ height: baseFit?.height ?? VIEWPORT_SIZE,
813
+ },
814
+ // Outer mask: large square that overlays the canvas, with a
815
+ // round transparent cutout in the middle. We achieve this with
816
+ // four edge boxes around the circle (top/bottom/left/right) so
817
+ // there's no need for SVG. Each box is 50% black.
818
+ ringOverlay: {
819
+ position: 'absolute',
820
+ width: VIEWPORT_SIZE,
821
+ height: VIEWPORT_SIZE,
822
+ borderRadius: VIEWPORT_SIZE / 2,
823
+ borderWidth: RING_WIDTH,
824
+ borderColor: RING_COLOR,
825
+ // Subtle inner shadow approximated with a thin secondary border.
826
+ ...Platform.select({
827
+ web: {
828
+ boxShadow: 'inset 0 0 14px rgba(0,0,0,0.45)',
829
+ },
830
+ default: {},
831
+ }),
832
+ },
833
+ gridOverlay: {
834
+ position: 'absolute',
835
+ width: VIEWPORT_SIZE,
836
+ height: VIEWPORT_SIZE,
837
+ borderRadius: VIEWPORT_SIZE / 2,
838
+ overflow: 'hidden',
839
+ pointerEvents: 'none',
840
+ },
841
+ gridLineH: {
842
+ position: 'absolute',
843
+ left: 0,
844
+ right: 0,
845
+ height: StyleSheet.hairlineWidth,
846
+ backgroundColor: 'rgba(255,255,255,0.45)',
847
+ },
848
+ gridLineV: {
849
+ position: 'absolute',
850
+ top: 0,
851
+ bottom: 0,
852
+ width: StyleSheet.hairlineWidth,
853
+ backgroundColor: 'rgba(255,255,255,0.45)',
854
+ },
855
+ zoomChip: {
856
+ position: 'absolute',
857
+ top: -44,
858
+ alignSelf: 'center',
859
+ paddingHorizontal: 12,
860
+ paddingVertical: 6,
861
+ borderRadius: 999,
862
+ backgroundColor: 'rgba(0,0,0,0.7)',
863
+ minWidth: 56,
864
+ alignItems: 'center',
865
+ justifyContent: 'center',
866
+ },
867
+ zoomChipText: {
868
+ color: '#ffffff',
869
+ fontFamily: Platform.select({
870
+ ios: 'Menlo',
871
+ android: 'monospace',
872
+ default: 'ui-monospace, SFMono-Regular, Menlo, monospace',
873
+ }),
874
+ fontSize: 12,
875
+ letterSpacing: 0.2,
876
+ },
877
+ helperBlock: {
878
+ paddingHorizontal: 24,
879
+ paddingTop: 24,
880
+ paddingBottom: bottomInset,
881
+ alignItems: 'center',
882
+ justifyContent: 'flex-end',
883
+ gap: 10,
884
+ },
885
+ helper: {
886
+ fontSize: 13,
887
+ lineHeight: 18,
888
+ color: 'rgba(255,255,255,0.6)',
889
+ textAlign: 'center',
890
+ maxWidth: 320,
891
+ },
892
+ resetLink: {
893
+ paddingHorizontal: 12,
894
+ paddingVertical: 6,
895
+ },
896
+ resetLinkText: {
897
+ fontSize: 13,
898
+ color: '#ffffff',
899
+ opacity: 0.85,
900
+ textDecorationLine: 'underline',
901
+ },
902
+ emptyState: {
903
+ flex: 1,
904
+ alignItems: 'center',
905
+ justifyContent: 'center',
906
+ padding: 24,
907
+ },
908
+ emptyLabel: {
909
+ fontSize: 14,
910
+ color: 'rgba(255,255,255,0.7)',
911
+ textAlign: 'center',
912
+ },
913
+ }),
914
+ [baseFit, bottomInset, theme, topInset],
915
+ );
916
+
917
+ // Reset link reveal — only show when the image is not at the default
918
+ // transform. Use derived display state to avoid mounting/unmounting jank.
919
+ const resetLinkOpacity = isModified ? 1 : 0;
920
+
921
+ // No image supplied OR measurement failed — render a minimal empty state.
922
+ if (!imageUri || measureError) {
923
+ const emptyMessage = !imageUri
924
+ ? (t('editProfile.crop.noImage') || 'No image to crop')
925
+ : measureError;
926
+ return (
927
+ <View style={styles.container}>
928
+ <View style={styles.topBar}>
929
+ <TouchableOpacity
930
+ accessibilityLabel={t('editProfile.crop.cancel') || 'Cancel'}
931
+ accessibilityRole="button"
932
+ style={styles.cancelBtn}
933
+ onPress={handleCancel}
934
+ activeOpacity={0.6}
935
+ >
936
+ <Text style={styles.cancelLabel}>
937
+ {t('editProfile.crop.cancel') || 'Cancel'}
938
+ </Text>
939
+ </TouchableOpacity>
940
+ <View style={styles.topBarTitleWrap}>
941
+ <Text style={styles.topBarTitle}>
942
+ {t('editProfile.crop.title') || 'Crop avatar'}
943
+ </Text>
944
+ </View>
945
+ <View style={styles.cancelBtn} />
946
+ </View>
947
+ <View style={styles.emptyState}>
948
+ <Text style={styles.emptyLabel}>{emptyMessage}</Text>
949
+ </View>
950
+ </View>
951
+ );
952
+ }
953
+
954
+ return (
955
+ <View style={styles.container}>
956
+ <View style={styles.topBar}>
957
+ <TouchableOpacity
958
+ accessibilityLabel={t('editProfile.crop.cancel') || 'Cancel'}
959
+ accessibilityRole="button"
960
+ style={styles.cancelBtn}
961
+ onPress={handleCancel}
962
+ disabled={isProcessing}
963
+ activeOpacity={0.6}
964
+ >
965
+ <Text style={styles.cancelLabel}>
966
+ {t('editProfile.crop.cancel') || 'Cancel'}
967
+ </Text>
968
+ </TouchableOpacity>
969
+ <View style={styles.topBarTitleWrap}>
970
+ <Text style={styles.topBarTitle} numberOfLines={1}>
971
+ {t('editProfile.crop.title') || 'Crop avatar'}
972
+ </Text>
973
+ </View>
974
+ <TouchableOpacity
975
+ accessibilityLabel={t('editProfile.crop.confirm') || 'Use photo'}
976
+ accessibilityRole="button"
977
+ accessibilityState={{ disabled: isProcessing || !baseFit, busy: isProcessing }}
978
+ style={[
979
+ styles.doneBtn,
980
+ (isProcessing || !baseFit) && styles.doneBtnDisabled,
981
+ ]}
982
+ onPress={handleConfirm}
983
+ disabled={isProcessing || !baseFit}
984
+ activeOpacity={0.85}
985
+ >
986
+ {isProcessing ? (
987
+ <View style={styles.doneLabelLoading}>
988
+ <ActivityIndicator size="small" color="#ffffff" />
989
+ <Text style={styles.doneLabel}>
990
+ {t('editProfile.crop.saving') || 'Saving…'}
991
+ </Text>
992
+ </View>
993
+ ) : (
994
+ <Text style={styles.doneLabel}>
995
+ {t('editProfile.crop.confirm') || 'Use photo'}
996
+ </Text>
997
+ )}
998
+ </TouchableOpacity>
999
+ </View>
1000
+
1001
+ <View style={styles.stage}>
1002
+ <Animated.View
1003
+ style={[styles.cropFrame, cropFrameAnimatedStyle]}
1004
+ accessible
1005
+ accessibilityRole="image"
1006
+ accessibilityLabel={
1007
+ t('editProfile.crop.a11yImage') ||
1008
+ 'Crop preview. Pinch to zoom and drag to reposition the image.'
1009
+ }
1010
+ >
1011
+ <GestureDetector gesture={composedGesture}>
1012
+ <View style={styles.viewport}>
1013
+ {baseFit ? (
1014
+ <Animated.Image
1015
+ source={{ uri: imageUri }}
1016
+ style={[styles.image, imageAnimatedStyle]}
1017
+ resizeMode="cover"
1018
+ />
1019
+ ) : (
1020
+ <ActivityIndicator color="#ffffff" />
1021
+ )}
1022
+ </View>
1023
+ </GestureDetector>
1024
+
1025
+ {/* White ring + inner shadow around the circle. */}
1026
+ <View pointerEvents="none" style={styles.ringOverlay} />
1027
+
1028
+ {/* Rule-of-thirds grid overlay (fades in during gesture). */}
1029
+ <Animated.View
1030
+ pointerEvents="none"
1031
+ style={[styles.gridOverlay, gridAnimatedStyle]}
1032
+ >
1033
+ <View style={[styles.gridLineH, { top: VIEWPORT_SIZE / 3 }]} />
1034
+ <View style={[styles.gridLineH, { top: (VIEWPORT_SIZE * 2) / 3 }]} />
1035
+ <View style={[styles.gridLineV, { left: VIEWPORT_SIZE / 3 }]} />
1036
+ <View style={[styles.gridLineV, { left: (VIEWPORT_SIZE * 2) / 3 }]} />
1037
+ </Animated.View>
1038
+
1039
+ {/* Floating zoom chip during pinch. */}
1040
+ <Animated.View
1041
+ pointerEvents="none"
1042
+ style={[styles.zoomChip, zoomChipAnimatedStyle]}
1043
+ >
1044
+ <Text style={styles.zoomChipText}>
1045
+ {t('editProfile.crop.zoom', { value: zoomLabel }) || `${zoomLabel}×`}
1046
+ </Text>
1047
+ </Animated.View>
1048
+ </Animated.View>
1049
+ </View>
1050
+
1051
+ <View style={styles.helperBlock}>
1052
+ <Text style={styles.helper}>
1053
+ {t('editProfile.crop.helper') ||
1054
+ 'The cropped circle is what will appear on your profile. Pinch to zoom, drag to position.'}
1055
+ </Text>
1056
+ <Pressable
1057
+ accessibilityLabel={t('editProfile.crop.a11yReset') || 'Reset crop to default position'}
1058
+ accessibilityRole="button"
1059
+ accessibilityState={{ disabled: !isModified || isProcessing }}
1060
+ onPress={resetTransform}
1061
+ disabled={!isModified || isProcessing}
1062
+ style={[styles.resetLink, { opacity: isProcessing ? 0.3 : resetLinkOpacity }]}
1063
+ >
1064
+ <Text style={styles.resetLinkText}>
1065
+ {t('editProfile.crop.resetToCenter') || 'Reset to center'}
1066
+ </Text>
1067
+ </Pressable>
1068
+ </View>
1069
+ </View>
1070
+ );
1071
+ };
1072
+
1073
+ export default AvatarCropScreen;