@oxyhq/services 22.9.0 → 22.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (584) hide show
  1. package/lib/commonjs/index.js +24 -5
  2. package/lib/commonjs/index.js.map +1 -1
  3. package/lib/commonjs/ui/components/AvatarCameraBadge.js +42 -0
  4. package/lib/commonjs/ui/components/AvatarCameraBadge.js.map +1 -0
  5. package/lib/commonjs/ui/components/{OxyAccountDialog.js → OxyAccountDialogScreen.js} +55 -133
  6. package/lib/commonjs/ui/components/OxyAccountDialogScreen.js.map +1 -0
  7. package/lib/commonjs/ui/components/OxyAuthChooser.js +657 -88
  8. package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
  9. package/lib/commonjs/ui/components/OxyConsentScreen.js +1 -1
  10. package/lib/commonjs/ui/components/ProfileButton.js +15 -1
  11. package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
  12. package/lib/commonjs/ui/components/ProfileSummaryCard.js +3 -23
  13. package/lib/commonjs/ui/components/ProfileSummaryCard.js.map +1 -1
  14. package/lib/commonjs/ui/components/RequireOxyAuth.js +1 -1
  15. package/lib/commonjs/ui/components/SurfaceHeaderAction.js +63 -0
  16. package/lib/commonjs/ui/components/SurfaceHeaderAction.js.map +1 -0
  17. package/lib/commonjs/ui/components/SurfaceScreen.js +91 -8
  18. package/lib/commonjs/ui/components/SurfaceScreen.js.map +1 -1
  19. package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js +46 -29
  20. package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
  21. package/lib/commonjs/ui/components/modals/DeleteAccountModal.js +47 -23
  22. package/lib/commonjs/ui/components/modals/DeleteAccountModal.js.map +1 -1
  23. package/lib/commonjs/ui/components/oxyAuthChooserStyles.js +81 -19
  24. package/lib/commonjs/ui/components/oxyAuthChooserStyles.js.map +1 -1
  25. package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js +83 -23
  26. package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
  27. package/lib/commonjs/ui/components/surfaces/ActionSheetSurface.js +83 -0
  28. package/lib/commonjs/ui/components/surfaces/ActionSheetSurface.js.map +1 -0
  29. package/lib/commonjs/ui/context/OxyContext.js +79 -29
  30. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  31. package/lib/commonjs/ui/hooks/queries/queryKeys.js +18 -1
  32. package/lib/commonjs/ui/hooks/queries/queryKeys.js.map +1 -1
  33. package/lib/commonjs/ui/hooks/queries/useFileQueries.js +129 -0
  34. package/lib/commonjs/ui/hooks/queries/useFileQueries.js.map +1 -0
  35. package/lib/commonjs/ui/hooks/useAvatarPicker.js +38 -55
  36. package/lib/commonjs/ui/hooks/useAvatarPicker.js.map +1 -1
  37. package/lib/commonjs/ui/hooks/useReduceMotion.js +57 -0
  38. package/lib/commonjs/ui/hooks/useReduceMotion.js.map +1 -0
  39. package/lib/commonjs/ui/hooks/useSurfaceHeader.js +46 -0
  40. package/lib/commonjs/ui/hooks/useSurfaceHeader.js.map +1 -0
  41. package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +1 -1
  42. package/lib/commonjs/ui/navigation/accountDialogManager.js +36 -2
  43. package/lib/commonjs/ui/navigation/accountDialogManager.js.map +1 -1
  44. package/lib/commonjs/ui/navigation/bottomSheetManager.js +5 -6
  45. package/lib/commonjs/ui/navigation/bottomSheetManager.js.map +1 -1
  46. package/lib/commonjs/ui/navigation/routes.js +4 -3
  47. package/lib/commonjs/ui/navigation/routes.js.map +1 -1
  48. package/lib/commonjs/ui/navigation/surfaceBackBridge.js +68 -0
  49. package/lib/commonjs/ui/navigation/surfaceBackBridge.js.map +1 -0
  50. package/lib/commonjs/ui/navigation/surfaceNavStack.js +62 -15
  51. package/lib/commonjs/ui/navigation/surfaceNavStack.js.map +1 -1
  52. package/lib/commonjs/ui/navigation/surfaceRegistry.js +84 -19
  53. package/lib/commonjs/ui/navigation/surfaceRegistry.js.map +1 -1
  54. package/lib/commonjs/ui/navigation/surfaces.js +139 -25
  55. package/lib/commonjs/ui/navigation/surfaces.js.map +1 -1
  56. package/lib/commonjs/ui/screens/AccountMembersScreen.js +214 -283
  57. package/lib/commonjs/ui/screens/AccountMembersScreen.js.map +1 -1
  58. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +88 -118
  59. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  60. package/lib/commonjs/ui/screens/AccountVerificationScreen.js +22 -36
  61. package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
  62. package/lib/commonjs/ui/screens/AppInfoScreen.js +219 -226
  63. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
  64. package/lib/commonjs/ui/screens/AvatarCropScreen.js +287 -289
  65. package/lib/commonjs/ui/screens/AvatarCropScreen.js.map +1 -1
  66. package/lib/commonjs/ui/screens/ChangeAvatarScreen.js +301 -0
  67. package/lib/commonjs/ui/screens/ChangeAvatarScreen.js.map +1 -0
  68. package/lib/commonjs/ui/screens/ConnectedAppsScreen.js +24 -39
  69. package/lib/commonjs/ui/screens/ConnectedAppsScreen.js.map +1 -1
  70. package/lib/commonjs/ui/screens/CreateAccountScreen.js +136 -158
  71. package/lib/commonjs/ui/screens/CreateAccountScreen.js.map +1 -1
  72. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +29 -36
  73. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
  74. package/lib/commonjs/ui/screens/EditProfileScreen.js +101 -109
  75. package/lib/commonjs/ui/screens/EditProfileScreen.js.map +1 -1
  76. package/lib/commonjs/ui/screens/FAQScreen.js +10 -15
  77. package/lib/commonjs/ui/screens/FAQScreen.js.map +1 -1
  78. package/lib/commonjs/ui/screens/FeedbackScreen.js +8 -16
  79. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  80. package/lib/commonjs/ui/screens/FileManagementScreen.js +403 -627
  81. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  82. package/lib/commonjs/ui/screens/HelpSupportScreen.js +62 -69
  83. package/lib/commonjs/ui/screens/HelpSupportScreen.js.map +1 -1
  84. package/lib/commonjs/ui/screens/HistoryViewScreen.js +63 -79
  85. package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
  86. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +69 -98
  87. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
  88. package/lib/commonjs/ui/screens/LearnMoreUsernamesScreen.js +8 -14
  89. package/lib/commonjs/ui/screens/LearnMoreUsernamesScreen.js.map +1 -1
  90. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +77 -94
  91. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -1
  92. package/lib/commonjs/ui/screens/ManageAccountScreen.js +99 -134
  93. package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
  94. package/lib/commonjs/ui/screens/NotificationsScreen.js +69 -76
  95. package/lib/commonjs/ui/screens/NotificationsScreen.js.map +1 -1
  96. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +3 -8
  97. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
  98. package/lib/commonjs/ui/screens/PreferencesScreen.js +67 -74
  99. package/lib/commonjs/ui/screens/PreferencesScreen.js.map +1 -1
  100. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +55 -91
  101. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  102. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +291 -304
  103. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
  104. package/lib/commonjs/ui/screens/ProfileScreen.js +100 -114
  105. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  106. package/lib/commonjs/ui/screens/SavesCollectionsScreen.js +38 -45
  107. package/lib/commonjs/ui/screens/SavesCollectionsScreen.js.map +1 -1
  108. package/lib/commonjs/ui/screens/SearchSettingsScreen.js +44 -57
  109. package/lib/commonjs/ui/screens/SearchSettingsScreen.js.map +1 -1
  110. package/lib/commonjs/ui/screens/UserLinksScreen.js +24 -31
  111. package/lib/commonjs/ui/screens/UserLinksScreen.js.map +1 -1
  112. package/lib/commonjs/ui/screens/UserListScreen.js +14 -24
  113. package/lib/commonjs/ui/screens/UserListScreen.js.map +1 -1
  114. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +16 -48
  115. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  116. package/lib/commonjs/ui/screens/fileManagement/FileLibraryError.js +63 -0
  117. package/lib/commonjs/ui/screens/fileManagement/FileLibraryError.js.map +1 -0
  118. package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js +54 -41
  119. package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
  120. package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js +44 -81
  121. package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
  122. package/lib/commonjs/ui/screens/trust/TrustAboutScreen.js +66 -75
  123. package/lib/commonjs/ui/screens/trust/TrustAboutScreen.js.map +1 -1
  124. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js +111 -139
  125. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  126. package/lib/commonjs/ui/screens/trust/TrustFAQScreen.js +13 -20
  127. package/lib/commonjs/ui/screens/trust/TrustFAQScreen.js.map +1 -1
  128. package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js +14 -27
  129. package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
  130. package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js +68 -85
  131. package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
  132. package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js +28 -36
  133. package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js.map +1 -1
  134. package/lib/commonjs/ui/stores/resetSessionScopedStores.js +8 -3
  135. package/lib/commonjs/ui/stores/resetSessionScopedStores.js.map +1 -1
  136. package/lib/commonjs/ui/utils/avatarUtils.js +11 -2
  137. package/lib/commonjs/ui/utils/avatarUtils.js.map +1 -1
  138. package/lib/commonjs/ui/utils/fileManagement.js +0 -79
  139. package/lib/commonjs/ui/utils/fileManagement.js.map +1 -1
  140. package/lib/module/index.js +12 -5
  141. package/lib/module/index.js.map +1 -1
  142. package/lib/module/ui/components/AvatarCameraBadge.js +40 -0
  143. package/lib/module/ui/components/AvatarCameraBadge.js.map +1 -0
  144. package/lib/module/ui/components/{OxyAccountDialog.js → OxyAccountDialogScreen.js} +57 -135
  145. package/lib/module/ui/components/OxyAccountDialogScreen.js.map +1 -0
  146. package/lib/module/ui/components/OxyAuthChooser.js +659 -91
  147. package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
  148. package/lib/module/ui/components/OxyConsentScreen.js +1 -1
  149. package/lib/module/ui/components/ProfileButton.js +16 -2
  150. package/lib/module/ui/components/ProfileButton.js.map +1 -1
  151. package/lib/module/ui/components/ProfileSummaryCard.js +2 -23
  152. package/lib/module/ui/components/ProfileSummaryCard.js.map +1 -1
  153. package/lib/module/ui/components/RequireOxyAuth.js +1 -1
  154. package/lib/module/ui/components/SurfaceHeaderAction.js +58 -0
  155. package/lib/module/ui/components/SurfaceHeaderAction.js.map +1 -0
  156. package/lib/module/ui/components/SurfaceScreen.js +93 -10
  157. package/lib/module/ui/components/SurfaceScreen.js.map +1 -1
  158. package/lib/module/ui/components/fileManagement/FileDetailsModal.js +46 -29
  159. package/lib/module/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
  160. package/lib/module/ui/components/modals/DeleteAccountModal.js +46 -23
  161. package/lib/module/ui/components/modals/DeleteAccountModal.js.map +1 -1
  162. package/lib/module/ui/components/oxyAuthChooserStyles.js +81 -19
  163. package/lib/module/ui/components/oxyAuthChooserStyles.js.map +1 -1
  164. package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js +83 -25
  165. package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
  166. package/lib/module/ui/components/surfaces/ActionSheetSurface.js +78 -0
  167. package/lib/module/ui/components/surfaces/ActionSheetSurface.js.map +1 -0
  168. package/lib/module/ui/context/OxyContext.js +80 -30
  169. package/lib/module/ui/context/OxyContext.js.map +1 -1
  170. package/lib/module/ui/hooks/queries/queryKeys.js +16 -0
  171. package/lib/module/ui/hooks/queries/queryKeys.js.map +1 -1
  172. package/lib/module/ui/hooks/queries/useFileQueries.js +120 -0
  173. package/lib/module/ui/hooks/queries/useFileQueries.js.map +1 -0
  174. package/lib/module/ui/hooks/useAvatarPicker.js +38 -55
  175. package/lib/module/ui/hooks/useAvatarPicker.js.map +1 -1
  176. package/lib/module/ui/hooks/useReduceMotion.js +53 -0
  177. package/lib/module/ui/hooks/useReduceMotion.js.map +1 -0
  178. package/lib/module/ui/hooks/useSurfaceHeader.js +42 -0
  179. package/lib/module/ui/hooks/useSurfaceHeader.js.map +1 -0
  180. package/lib/module/ui/hooks/useSwitchableAccounts.js +1 -1
  181. package/lib/module/ui/navigation/accountDialogManager.js +34 -2
  182. package/lib/module/ui/navigation/accountDialogManager.js.map +1 -1
  183. package/lib/module/ui/navigation/bottomSheetManager.js +6 -7
  184. package/lib/module/ui/navigation/bottomSheetManager.js.map +1 -1
  185. package/lib/module/ui/navigation/routes.js +4 -3
  186. package/lib/module/ui/navigation/routes.js.map +1 -1
  187. package/lib/module/ui/navigation/surfaceBackBridge.js +63 -0
  188. package/lib/module/ui/navigation/surfaceBackBridge.js.map +1 -0
  189. package/lib/module/ui/navigation/surfaceNavStack.js +62 -15
  190. package/lib/module/ui/navigation/surfaceNavStack.js.map +1 -1
  191. package/lib/module/ui/navigation/surfaceRegistry.js +84 -19
  192. package/lib/module/ui/navigation/surfaceRegistry.js.map +1 -1
  193. package/lib/module/ui/navigation/surfaces.js +138 -26
  194. package/lib/module/ui/navigation/surfaces.js.map +1 -1
  195. package/lib/module/ui/screens/AccountMembersScreen.js +218 -286
  196. package/lib/module/ui/screens/AccountMembersScreen.js.map +1 -1
  197. package/lib/module/ui/screens/AccountSettingsScreen.js +92 -121
  198. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  199. package/lib/module/ui/screens/AccountVerificationScreen.js +25 -38
  200. package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
  201. package/lib/module/ui/screens/AppInfoScreen.js +220 -227
  202. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  203. package/lib/module/ui/screens/AvatarCropScreen.js +289 -291
  204. package/lib/module/ui/screens/AvatarCropScreen.js.map +1 -1
  205. package/lib/module/ui/screens/ChangeAvatarScreen.js +298 -0
  206. package/lib/module/ui/screens/ChangeAvatarScreen.js.map +1 -0
  207. package/lib/module/ui/screens/ConnectedAppsScreen.js +26 -40
  208. package/lib/module/ui/screens/ConnectedAppsScreen.js.map +1 -1
  209. package/lib/module/ui/screens/CreateAccountScreen.js +139 -160
  210. package/lib/module/ui/screens/CreateAccountScreen.js.map +1 -1
  211. package/lib/module/ui/screens/EditProfileFieldScreen.js +32 -38
  212. package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
  213. package/lib/module/ui/screens/EditProfileScreen.js +102 -110
  214. package/lib/module/ui/screens/EditProfileScreen.js.map +1 -1
  215. package/lib/module/ui/screens/FAQScreen.js +11 -15
  216. package/lib/module/ui/screens/FAQScreen.js.map +1 -1
  217. package/lib/module/ui/screens/FeedbackScreen.js +10 -17
  218. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  219. package/lib/module/ui/screens/FileManagementScreen.js +408 -631
  220. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  221. package/lib/module/ui/screens/HelpSupportScreen.js +64 -70
  222. package/lib/module/ui/screens/HelpSupportScreen.js.map +1 -1
  223. package/lib/module/ui/screens/HistoryViewScreen.js +65 -81
  224. package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
  225. package/lib/module/ui/screens/LanguageSelectorScreen.js +71 -99
  226. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
  227. package/lib/module/ui/screens/LearnMoreUsernamesScreen.js +10 -15
  228. package/lib/module/ui/screens/LearnMoreUsernamesScreen.js.map +1 -1
  229. package/lib/module/ui/screens/LegalDocumentsScreen.js +78 -94
  230. package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -1
  231. package/lib/module/ui/screens/ManageAccountScreen.js +102 -137
  232. package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
  233. package/lib/module/ui/screens/NotificationsScreen.js +71 -77
  234. package/lib/module/ui/screens/NotificationsScreen.js.map +1 -1
  235. package/lib/module/ui/screens/PaymentGatewayScreen.js +4 -9
  236. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
  237. package/lib/module/ui/screens/PreferencesScreen.js +69 -75
  238. package/lib/module/ui/screens/PreferencesScreen.js.map +1 -1
  239. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +58 -93
  240. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  241. package/lib/module/ui/screens/PrivacySettingsScreen.js +293 -305
  242. package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
  243. package/lib/module/ui/screens/ProfileScreen.js +102 -116
  244. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  245. package/lib/module/ui/screens/SavesCollectionsScreen.js +40 -46
  246. package/lib/module/ui/screens/SavesCollectionsScreen.js.map +1 -1
  247. package/lib/module/ui/screens/SearchSettingsScreen.js +46 -58
  248. package/lib/module/ui/screens/SearchSettingsScreen.js.map +1 -1
  249. package/lib/module/ui/screens/UserLinksScreen.js +26 -32
  250. package/lib/module/ui/screens/UserLinksScreen.js.map +1 -1
  251. package/lib/module/ui/screens/UserListScreen.js +14 -24
  252. package/lib/module/ui/screens/UserListScreen.js.map +1 -1
  253. package/lib/module/ui/screens/WelcomeNewUserScreen.js +17 -49
  254. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  255. package/lib/module/ui/screens/fileManagement/FileLibraryError.js +59 -0
  256. package/lib/module/ui/screens/fileManagement/FileLibraryError.js.map +1 -0
  257. package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js +54 -42
  258. package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
  259. package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js +45 -81
  260. package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
  261. package/lib/module/ui/screens/trust/TrustAboutScreen.js +67 -75
  262. package/lib/module/ui/screens/trust/TrustAboutScreen.js.map +1 -1
  263. package/lib/module/ui/screens/trust/TrustCenterScreen.js +112 -139
  264. package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  265. package/lib/module/ui/screens/trust/TrustFAQScreen.js +15 -21
  266. package/lib/module/ui/screens/trust/TrustFAQScreen.js.map +1 -1
  267. package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js +14 -26
  268. package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
  269. package/lib/module/ui/screens/trust/TrustRewardsScreen.js +69 -85
  270. package/lib/module/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
  271. package/lib/module/ui/screens/trust/TrustRulesScreen.js +30 -37
  272. package/lib/module/ui/screens/trust/TrustRulesScreen.js.map +1 -1
  273. package/lib/module/ui/stores/resetSessionScopedStores.js +8 -3
  274. package/lib/module/ui/stores/resetSessionScopedStores.js.map +1 -1
  275. package/lib/module/ui/utils/avatarUtils.js +11 -2
  276. package/lib/module/ui/utils/avatarUtils.js.map +1 -1
  277. package/lib/module/ui/utils/fileManagement.js +0 -78
  278. package/lib/module/ui/utils/fileManagement.js.map +1 -1
  279. package/lib/typescript/commonjs/index.d.ts +2 -0
  280. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  281. package/lib/typescript/commonjs/ui/components/AvatarCameraBadge.d.ts +4 -0
  282. package/lib/typescript/commonjs/ui/components/AvatarCameraBadge.d.ts.map +1 -0
  283. package/lib/typescript/{module/ui/components/OxyAccountDialog.d.ts → commonjs/ui/components/OxyAccountDialogScreen.d.ts} +5 -4
  284. package/lib/typescript/commonjs/ui/components/OxyAccountDialogScreen.d.ts.map +1 -0
  285. package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts +3 -3
  286. package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
  287. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +2 -2
  288. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
  289. package/lib/typescript/commonjs/ui/components/ProfileSummaryCard.d.ts.map +1 -1
  290. package/lib/typescript/commonjs/ui/components/RequireOxyAuth.d.ts +1 -1
  291. package/lib/typescript/commonjs/ui/components/SurfaceHeaderAction.d.ts +16 -0
  292. package/lib/typescript/commonjs/ui/components/SurfaceHeaderAction.d.ts.map +1 -0
  293. package/lib/typescript/commonjs/ui/components/SurfaceScreen.d.ts +3 -4
  294. package/lib/typescript/commonjs/ui/components/SurfaceScreen.d.ts.map +1 -1
  295. package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts +14 -4
  296. package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
  297. package/lib/typescript/commonjs/ui/components/modals/DeleteAccountModal.d.ts +17 -2
  298. package/lib/typescript/commonjs/ui/components/modals/DeleteAccountModal.d.ts.map +1 -1
  299. package/lib/typescript/commonjs/ui/components/oxyAuthChooserStyles.d.ts +75 -13
  300. package/lib/typescript/commonjs/ui/components/oxyAuthChooserStyles.d.ts.map +1 -1
  301. package/lib/typescript/commonjs/ui/components/photogrid/JustifiedPhotoGrid.d.ts +10 -8
  302. package/lib/typescript/commonjs/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -1
  303. package/lib/typescript/commonjs/ui/components/surfaces/ActionSheetSurface.d.ts +38 -0
  304. package/lib/typescript/commonjs/ui/components/surfaces/ActionSheetSurface.d.ts.map +1 -0
  305. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  306. package/lib/typescript/commonjs/ui/hooks/queries/queryKeys.d.ts +9 -0
  307. package/lib/typescript/commonjs/ui/hooks/queries/queryKeys.d.ts.map +1 -1
  308. package/lib/typescript/commonjs/ui/hooks/queries/useFileQueries.d.ts +50 -0
  309. package/lib/typescript/commonjs/ui/hooks/queries/useFileQueries.d.ts.map +1 -0
  310. package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts +17 -16
  311. package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts.map +1 -1
  312. package/lib/typescript/commonjs/ui/hooks/useReduceMotion.d.ts +14 -0
  313. package/lib/typescript/commonjs/ui/hooks/useReduceMotion.d.ts.map +1 -0
  314. package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts +31 -0
  315. package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts.map +1 -0
  316. package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts +1 -1
  317. package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts +27 -2
  318. package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts.map +1 -1
  319. package/lib/typescript/commonjs/ui/navigation/bottomSheetManager.d.ts +4 -5
  320. package/lib/typescript/commonjs/ui/navigation/bottomSheetManager.d.ts.map +1 -1
  321. package/lib/typescript/commonjs/ui/navigation/routes.d.ts +1 -1
  322. package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
  323. package/lib/typescript/commonjs/ui/navigation/surfaceBackBridge.d.ts +16 -0
  324. package/lib/typescript/commonjs/ui/navigation/surfaceBackBridge.d.ts.map +1 -0
  325. package/lib/typescript/commonjs/ui/navigation/surfaceNavStack.d.ts +21 -0
  326. package/lib/typescript/commonjs/ui/navigation/surfaceNavStack.d.ts.map +1 -1
  327. package/lib/typescript/commonjs/ui/navigation/surfaceRegistry.d.ts +101 -23
  328. package/lib/typescript/commonjs/ui/navigation/surfaceRegistry.d.ts.map +1 -1
  329. package/lib/typescript/commonjs/ui/navigation/surfaces.d.ts +42 -11
  330. package/lib/typescript/commonjs/ui/navigation/surfaces.d.ts.map +1 -1
  331. package/lib/typescript/commonjs/ui/screens/AccountMembersScreen.d.ts.map +1 -1
  332. package/lib/typescript/commonjs/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  333. package/lib/typescript/commonjs/ui/screens/AccountVerificationScreen.d.ts.map +1 -1
  334. package/lib/typescript/commonjs/ui/screens/AppInfoScreen.d.ts.map +1 -1
  335. package/lib/typescript/commonjs/ui/screens/AvatarCropScreen.d.ts +18 -9
  336. package/lib/typescript/commonjs/ui/screens/AvatarCropScreen.d.ts.map +1 -1
  337. package/lib/typescript/commonjs/ui/screens/ChangeAvatarScreen.d.ts +34 -0
  338. package/lib/typescript/commonjs/ui/screens/ChangeAvatarScreen.d.ts.map +1 -0
  339. package/lib/typescript/commonjs/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
  340. package/lib/typescript/commonjs/ui/screens/CreateAccountScreen.d.ts.map +1 -1
  341. package/lib/typescript/commonjs/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
  342. package/lib/typescript/commonjs/ui/screens/EditProfileScreen.d.ts.map +1 -1
  343. package/lib/typescript/commonjs/ui/screens/FAQScreen.d.ts.map +1 -1
  344. package/lib/typescript/commonjs/ui/screens/FeedbackScreen.d.ts.map +1 -1
  345. package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
  346. package/lib/typescript/commonjs/ui/screens/HelpSupportScreen.d.ts.map +1 -1
  347. package/lib/typescript/commonjs/ui/screens/HistoryViewScreen.d.ts.map +1 -1
  348. package/lib/typescript/commonjs/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
  349. package/lib/typescript/commonjs/ui/screens/LearnMoreUsernamesScreen.d.ts.map +1 -1
  350. package/lib/typescript/commonjs/ui/screens/LegalDocumentsScreen.d.ts.map +1 -1
  351. package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts +1 -1
  352. package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  353. package/lib/typescript/commonjs/ui/screens/NotificationsScreen.d.ts.map +1 -1
  354. package/lib/typescript/commonjs/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
  355. package/lib/typescript/commonjs/ui/screens/PreferencesScreen.d.ts.map +1 -1
  356. package/lib/typescript/commonjs/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
  357. package/lib/typescript/commonjs/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
  358. package/lib/typescript/commonjs/ui/screens/ProfileScreen.d.ts.map +1 -1
  359. package/lib/typescript/commonjs/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
  360. package/lib/typescript/commonjs/ui/screens/SearchSettingsScreen.d.ts.map +1 -1
  361. package/lib/typescript/commonjs/ui/screens/UserLinksScreen.d.ts.map +1 -1
  362. package/lib/typescript/commonjs/ui/screens/UserListScreen.d.ts.map +1 -1
  363. package/lib/typescript/commonjs/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  364. package/lib/typescript/commonjs/ui/screens/fileManagement/FileLibraryError.d.ts +23 -0
  365. package/lib/typescript/commonjs/ui/screens/fileManagement/FileLibraryError.d.ts.map +1 -0
  366. package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts +4 -0
  367. package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
  368. package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +10 -2
  369. package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
  370. package/lib/typescript/commonjs/ui/screens/trust/TrustAboutScreen.d.ts.map +1 -1
  371. package/lib/typescript/commonjs/ui/screens/trust/TrustCenterScreen.d.ts.map +1 -1
  372. package/lib/typescript/commonjs/ui/screens/trust/TrustFAQScreen.d.ts.map +1 -1
  373. package/lib/typescript/commonjs/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
  374. package/lib/typescript/commonjs/ui/screens/trust/TrustRewardsScreen.d.ts.map +1 -1
  375. package/lib/typescript/commonjs/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -1
  376. package/lib/typescript/commonjs/ui/stores/resetSessionScopedStores.d.ts +8 -1
  377. package/lib/typescript/commonjs/ui/stores/resetSessionScopedStores.d.ts.map +1 -1
  378. package/lib/typescript/commonjs/ui/types/navigation.d.ts +10 -0
  379. package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
  380. package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts.map +1 -1
  381. package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts +0 -48
  382. package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts.map +1 -1
  383. package/lib/typescript/module/index.d.ts +2 -0
  384. package/lib/typescript/module/index.d.ts.map +1 -1
  385. package/lib/typescript/module/ui/components/AvatarCameraBadge.d.ts +4 -0
  386. package/lib/typescript/module/ui/components/AvatarCameraBadge.d.ts.map +1 -0
  387. package/lib/typescript/{commonjs/ui/components/OxyAccountDialog.d.ts → module/ui/components/OxyAccountDialogScreen.d.ts} +5 -4
  388. package/lib/typescript/module/ui/components/OxyAccountDialogScreen.d.ts.map +1 -0
  389. package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts +3 -3
  390. package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
  391. package/lib/typescript/module/ui/components/ProfileButton.d.ts +2 -2
  392. package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
  393. package/lib/typescript/module/ui/components/ProfileSummaryCard.d.ts.map +1 -1
  394. package/lib/typescript/module/ui/components/RequireOxyAuth.d.ts +1 -1
  395. package/lib/typescript/module/ui/components/SurfaceHeaderAction.d.ts +16 -0
  396. package/lib/typescript/module/ui/components/SurfaceHeaderAction.d.ts.map +1 -0
  397. package/lib/typescript/module/ui/components/SurfaceScreen.d.ts +3 -4
  398. package/lib/typescript/module/ui/components/SurfaceScreen.d.ts.map +1 -1
  399. package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts +14 -4
  400. package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
  401. package/lib/typescript/module/ui/components/modals/DeleteAccountModal.d.ts +17 -2
  402. package/lib/typescript/module/ui/components/modals/DeleteAccountModal.d.ts.map +1 -1
  403. package/lib/typescript/module/ui/components/oxyAuthChooserStyles.d.ts +75 -13
  404. package/lib/typescript/module/ui/components/oxyAuthChooserStyles.d.ts.map +1 -1
  405. package/lib/typescript/module/ui/components/photogrid/JustifiedPhotoGrid.d.ts +10 -8
  406. package/lib/typescript/module/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -1
  407. package/lib/typescript/module/ui/components/surfaces/ActionSheetSurface.d.ts +38 -0
  408. package/lib/typescript/module/ui/components/surfaces/ActionSheetSurface.d.ts.map +1 -0
  409. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  410. package/lib/typescript/module/ui/hooks/queries/queryKeys.d.ts +9 -0
  411. package/lib/typescript/module/ui/hooks/queries/queryKeys.d.ts.map +1 -1
  412. package/lib/typescript/module/ui/hooks/queries/useFileQueries.d.ts +50 -0
  413. package/lib/typescript/module/ui/hooks/queries/useFileQueries.d.ts.map +1 -0
  414. package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts +17 -16
  415. package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts.map +1 -1
  416. package/lib/typescript/module/ui/hooks/useReduceMotion.d.ts +14 -0
  417. package/lib/typescript/module/ui/hooks/useReduceMotion.d.ts.map +1 -0
  418. package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts +31 -0
  419. package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts.map +1 -0
  420. package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts +1 -1
  421. package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts +27 -2
  422. package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts.map +1 -1
  423. package/lib/typescript/module/ui/navigation/bottomSheetManager.d.ts +4 -5
  424. package/lib/typescript/module/ui/navigation/bottomSheetManager.d.ts.map +1 -1
  425. package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
  426. package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
  427. package/lib/typescript/module/ui/navigation/surfaceBackBridge.d.ts +16 -0
  428. package/lib/typescript/module/ui/navigation/surfaceBackBridge.d.ts.map +1 -0
  429. package/lib/typescript/module/ui/navigation/surfaceNavStack.d.ts +21 -0
  430. package/lib/typescript/module/ui/navigation/surfaceNavStack.d.ts.map +1 -1
  431. package/lib/typescript/module/ui/navigation/surfaceRegistry.d.ts +101 -23
  432. package/lib/typescript/module/ui/navigation/surfaceRegistry.d.ts.map +1 -1
  433. package/lib/typescript/module/ui/navigation/surfaces.d.ts +42 -11
  434. package/lib/typescript/module/ui/navigation/surfaces.d.ts.map +1 -1
  435. package/lib/typescript/module/ui/screens/AccountMembersScreen.d.ts.map +1 -1
  436. package/lib/typescript/module/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  437. package/lib/typescript/module/ui/screens/AccountVerificationScreen.d.ts.map +1 -1
  438. package/lib/typescript/module/ui/screens/AppInfoScreen.d.ts.map +1 -1
  439. package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts +18 -9
  440. package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts.map +1 -1
  441. package/lib/typescript/module/ui/screens/ChangeAvatarScreen.d.ts +34 -0
  442. package/lib/typescript/module/ui/screens/ChangeAvatarScreen.d.ts.map +1 -0
  443. package/lib/typescript/module/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
  444. package/lib/typescript/module/ui/screens/CreateAccountScreen.d.ts.map +1 -1
  445. package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
  446. package/lib/typescript/module/ui/screens/EditProfileScreen.d.ts.map +1 -1
  447. package/lib/typescript/module/ui/screens/FAQScreen.d.ts.map +1 -1
  448. package/lib/typescript/module/ui/screens/FeedbackScreen.d.ts.map +1 -1
  449. package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
  450. package/lib/typescript/module/ui/screens/HelpSupportScreen.d.ts.map +1 -1
  451. package/lib/typescript/module/ui/screens/HistoryViewScreen.d.ts.map +1 -1
  452. package/lib/typescript/module/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
  453. package/lib/typescript/module/ui/screens/LearnMoreUsernamesScreen.d.ts.map +1 -1
  454. package/lib/typescript/module/ui/screens/LegalDocumentsScreen.d.ts.map +1 -1
  455. package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts +1 -1
  456. package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  457. package/lib/typescript/module/ui/screens/NotificationsScreen.d.ts.map +1 -1
  458. package/lib/typescript/module/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
  459. package/lib/typescript/module/ui/screens/PreferencesScreen.d.ts.map +1 -1
  460. package/lib/typescript/module/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
  461. package/lib/typescript/module/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
  462. package/lib/typescript/module/ui/screens/ProfileScreen.d.ts.map +1 -1
  463. package/lib/typescript/module/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
  464. package/lib/typescript/module/ui/screens/SearchSettingsScreen.d.ts.map +1 -1
  465. package/lib/typescript/module/ui/screens/UserLinksScreen.d.ts.map +1 -1
  466. package/lib/typescript/module/ui/screens/UserListScreen.d.ts.map +1 -1
  467. package/lib/typescript/module/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  468. package/lib/typescript/module/ui/screens/fileManagement/FileLibraryError.d.ts +23 -0
  469. package/lib/typescript/module/ui/screens/fileManagement/FileLibraryError.d.ts.map +1 -0
  470. package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts +4 -0
  471. package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
  472. package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +10 -2
  473. package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
  474. package/lib/typescript/module/ui/screens/trust/TrustAboutScreen.d.ts.map +1 -1
  475. package/lib/typescript/module/ui/screens/trust/TrustCenterScreen.d.ts.map +1 -1
  476. package/lib/typescript/module/ui/screens/trust/TrustFAQScreen.d.ts.map +1 -1
  477. package/lib/typescript/module/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
  478. package/lib/typescript/module/ui/screens/trust/TrustRewardsScreen.d.ts.map +1 -1
  479. package/lib/typescript/module/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -1
  480. package/lib/typescript/module/ui/stores/resetSessionScopedStores.d.ts +8 -1
  481. package/lib/typescript/module/ui/stores/resetSessionScopedStores.d.ts.map +1 -1
  482. package/lib/typescript/module/ui/types/navigation.d.ts +10 -0
  483. package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
  484. package/lib/typescript/module/ui/utils/avatarUtils.d.ts.map +1 -1
  485. package/lib/typescript/module/ui/utils/fileManagement.d.ts +0 -48
  486. package/lib/typescript/module/ui/utils/fileManagement.d.ts.map +1 -1
  487. package/package.json +9 -5
  488. package/src/index.ts +12 -5
  489. package/src/ui/components/AvatarCameraBadge.tsx +35 -0
  490. package/src/ui/components/{OxyAccountDialog.tsx → OxyAccountDialogScreen.tsx} +50 -116
  491. package/src/ui/components/OxyAuthChooser.tsx +743 -86
  492. package/src/ui/components/OxyConsentScreen.tsx +1 -1
  493. package/src/ui/components/ProfileButton.tsx +18 -3
  494. package/src/ui/components/ProfileSummaryCard.tsx +2 -25
  495. package/src/ui/components/RequireOxyAuth.tsx +1 -1
  496. package/src/ui/components/SurfaceHeaderAction.tsx +60 -0
  497. package/src/ui/components/SurfaceScreen.tsx +108 -14
  498. package/src/ui/components/fileManagement/FileDetailsModal.tsx +50 -36
  499. package/src/ui/components/modals/DeleteAccountModal.tsx +47 -26
  500. package/src/ui/components/oxyAuthChooserStyles.ts +78 -16
  501. package/src/ui/components/photogrid/JustifiedPhotoGrid.tsx +158 -84
  502. package/src/ui/components/photogrid/__tests__/chunkPhotos.test.ts +51 -0
  503. package/src/ui/components/surfaces/ActionSheetSurface.tsx +98 -0
  504. package/src/ui/context/OxyContext.tsx +79 -25
  505. package/src/ui/hooks/queries/queryKeys.ts +15 -0
  506. package/src/ui/hooks/queries/useFileQueries.ts +162 -0
  507. package/src/ui/hooks/useAvatarPicker.ts +46 -74
  508. package/src/ui/hooks/useReduceMotion.ts +58 -0
  509. package/src/ui/hooks/useSurfaceHeader.ts +57 -0
  510. package/src/ui/hooks/useSwitchableAccounts.ts +1 -1
  511. package/src/ui/navigation/__tests__/getSurfaceConfig.test.ts +55 -7
  512. package/src/ui/navigation/__tests__/surfaceNavStack.test.ts +149 -0
  513. package/src/ui/navigation/accountDialogManager.ts +42 -2
  514. package/src/ui/navigation/bottomSheetManager.ts +6 -7
  515. package/src/ui/navigation/routes.ts +6 -4
  516. package/src/ui/navigation/surfaceBackBridge.ts +69 -0
  517. package/src/ui/navigation/surfaceNavStack.ts +72 -9
  518. package/src/ui/navigation/surfaceRegistry.ts +164 -24
  519. package/src/ui/navigation/surfaces.ts +137 -30
  520. package/src/ui/screens/AccountMembersScreen.tsx +39 -100
  521. package/src/ui/screens/AccountSettingsScreen.tsx +32 -54
  522. package/src/ui/screens/AccountVerificationScreen.tsx +23 -51
  523. package/src/ui/screens/AppInfoScreen.tsx +6 -13
  524. package/src/ui/screens/AvatarCropScreen.tsx +340 -311
  525. package/src/ui/screens/ChangeAvatarScreen.tsx +359 -0
  526. package/src/ui/screens/ConnectedAppsScreen.tsx +39 -60
  527. package/src/ui/screens/CreateAccountScreen.tsx +13 -39
  528. package/src/ui/screens/EditProfileFieldScreen.tsx +30 -48
  529. package/src/ui/screens/EditProfileScreen.tsx +7 -16
  530. package/src/ui/screens/FAQScreen.tsx +9 -13
  531. package/src/ui/screens/FeedbackScreen.tsx +8 -22
  532. package/src/ui/screens/FileManagementScreen.tsx +370 -610
  533. package/src/ui/screens/HelpSupportScreen.tsx +7 -13
  534. package/src/ui/screens/HistoryViewScreen.tsx +26 -31
  535. package/src/ui/screens/LanguageSelectorScreen.tsx +12 -46
  536. package/src/ui/screens/LearnMoreUsernamesScreen.tsx +8 -16
  537. package/src/ui/screens/LegalDocumentsScreen.tsx +7 -22
  538. package/src/ui/screens/ManageAccountScreen.tsx +96 -165
  539. package/src/ui/screens/NotificationsScreen.tsx +7 -13
  540. package/src/ui/screens/PaymentGatewayScreen.tsx +3 -10
  541. package/src/ui/screens/PreferencesScreen.tsx +7 -13
  542. package/src/ui/screens/PremiumSubscriptionScreen.tsx +52 -90
  543. package/src/ui/screens/PrivacySettingsScreen.tsx +9 -21
  544. package/src/ui/screens/ProfileScreen.tsx +9 -11
  545. package/src/ui/screens/SavesCollectionsScreen.tsx +7 -13
  546. package/src/ui/screens/SearchSettingsScreen.tsx +9 -21
  547. package/src/ui/screens/UserLinksScreen.tsx +7 -14
  548. package/src/ui/screens/UserListScreen.tsx +2 -5
  549. package/src/ui/screens/WelcomeNewUserScreen.tsx +18 -48
  550. package/src/ui/screens/fileManagement/FileLibraryError.tsx +56 -0
  551. package/src/ui/screens/fileManagement/PhotoPickerSection.tsx +56 -46
  552. package/src/ui/screens/fileManagement/hooks/useFileUploadState.ts +55 -71
  553. package/src/ui/screens/trust/TrustAboutScreen.tsx +10 -17
  554. package/src/ui/screens/trust/TrustCenterScreen.tsx +9 -28
  555. package/src/ui/screens/trust/TrustFAQScreen.tsx +15 -18
  556. package/src/ui/screens/trust/TrustLeaderboardScreen.tsx +3 -5
  557. package/src/ui/screens/trust/TrustRewardsScreen.tsx +11 -26
  558. package/src/ui/screens/trust/TrustRulesScreen.tsx +10 -13
  559. package/src/ui/stores/resetSessionScopedStores.ts +8 -3
  560. package/src/ui/types/navigation.ts +10 -0
  561. package/src/ui/utils/avatarUtils.ts +11 -2
  562. package/src/ui/utils/fileManagement.ts +1 -101
  563. package/lib/commonjs/ui/components/Header.js +0 -305
  564. package/lib/commonjs/ui/components/Header.js.map +0 -1
  565. package/lib/commonjs/ui/components/OxyAccountDialog.js.map +0 -1
  566. package/lib/commonjs/ui/stores/fileStore.js +0 -153
  567. package/lib/commonjs/ui/stores/fileStore.js.map +0 -1
  568. package/lib/module/ui/components/Header.js +0 -299
  569. package/lib/module/ui/components/Header.js.map +0 -1
  570. package/lib/module/ui/components/OxyAccountDialog.js.map +0 -1
  571. package/lib/module/ui/stores/fileStore.js +0 -145
  572. package/lib/module/ui/stores/fileStore.js.map +0 -1
  573. package/lib/typescript/commonjs/ui/components/Header.d.ts +0 -33
  574. package/lib/typescript/commonjs/ui/components/Header.d.ts.map +0 -1
  575. package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts.map +0 -1
  576. package/lib/typescript/commonjs/ui/stores/fileStore.d.ts +0 -31
  577. package/lib/typescript/commonjs/ui/stores/fileStore.d.ts.map +0 -1
  578. package/lib/typescript/module/ui/components/Header.d.ts +0 -33
  579. package/lib/typescript/module/ui/components/Header.d.ts.map +0 -1
  580. package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts.map +0 -1
  581. package/lib/typescript/module/ui/stores/fileStore.d.ts +0 -31
  582. package/lib/typescript/module/ui/stores/fileStore.d.ts.map +0 -1
  583. package/src/ui/components/Header.tsx +0 -224
  584. package/src/ui/stores/fileStore.ts +0 -118
@@ -1,34 +1,56 @@
1
1
  "use strict";
2
2
 
3
- import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
4
- import { View, Text, TouchableOpacity, StyleSheet, ScrollView, ActivityIndicator, RefreshControl, TextInput, Image, AccessibilityInfo, useWindowDimensions } from 'react-native';
3
+ import React, { useState, useCallback, useMemo, useRef } from 'react';
4
+ import { View, Text, TouchableOpacity, StyleSheet, ScrollView, ActivityIndicator, RefreshControl, TextInput, useWindowDimensions } from 'react-native';
5
+ import { useQueryClient } from '@tanstack/react-query';
5
6
  import { Image as ExpoImage } from 'expo-image';
6
- import { Dialog, toast, useDialogControl } from '@oxyhq/bloom';
7
+ import { toast } from '@oxyhq/bloom';
8
+ import { surfaces } from '@oxyhq/bloom/surfaces';
7
9
  import * as Skeleton from '@oxyhq/bloom/skeleton';
8
10
  import { Ionicons, MaterialCommunityIcons } from '@expo/vector-icons';
9
- import { useFileStore, useFiles, useUploading as useUploadingStore, useUploadAggregateProgress, useDeleting as useDeletingStore } from "../stores/fileStore.js";
10
- import Header from "../components/Header.js";
11
+ import { Pressable } from 'react-native';
12
+ import { queryKeys } from "../hooks/queries/queryKeys.js";
13
+ import { useUserFilesInfinite, removeFileFromCache, patchFileMetadataInCache } from "../hooks/queries/useFileQueries.js";
14
+ import { useSurfaceHeader } from "../hooks/useSurfaceHeader.js";
15
+ import { SurfaceHeaderAction } from "../components/SurfaceHeaderAction.js";
11
16
  import JustifiedPhotoGrid from "../components/photogrid/JustifiedPhotoGrid.js";
12
17
  import { useTheme } from '@oxyhq/bloom/theme';
13
18
  import { useOxy } from "../context/OxyContext.js";
14
19
  import { useI18n } from "../hooks/useI18n.js";
20
+ import { useReduceMotion } from "../hooks/useReduceMotion.js";
15
21
  import { useUploadFile } from "../hooks/mutations/useAccountMutations.js";
16
22
  import { formatFileSize, getFileIcon } from "../utils/fileManagement.js";
17
23
  import { useResolvedFileUrls, fileThumbSource } from "../hooks/useResolvedFileUrls.js";
18
24
  import { FileViewer } from "../components/fileManagement/FileViewer.js";
19
- import { FileDetailsModal } from "../components/fileManagement/FileDetailsModal.js";
25
+ import { presentFileDetails } from "../components/fileManagement/FileDetailsModal.js";
20
26
  import { UploadPreview } from "../components/fileManagement/UploadPreview.js";
27
+ import { presentActionSheet } from "../components/surfaces/ActionSheetSurface.js";
21
28
  import { getErrorMessage } from "./fileManagement/shared.js";
22
29
  import { useFileUploadState } from "./fileManagement/hooks/useFileUploadState.js";
23
30
  import PhotoPickerView from "./fileManagement/PhotoPickerSection.js";
24
31
  import FileListSection from "./fileManagement/FileListSection.js";
32
+ import FileLibraryError from "./fileManagement/FileLibraryError.js";
25
33
  import UploadBar from "./fileManagement/UploadBar.js";
26
34
  import { AnimatedButton } from "../components/fileManagement/AnimatedButton.js";
27
35
 
28
36
  // Genuinely-inline-only styles: `viewModeButton` is spread into an Animated.View
29
37
  // style array (interpolated backgroundColor), and the photo tiles are
30
38
  // `expo-image` (no className remap). Everything else uses NativeWind classNames.
39
+ // Nav-header slot layout for this screen's action row + review-mode back button.
31
40
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
41
+ const fmHeaderStyles = StyleSheet.create({
42
+ actionsRow: {
43
+ flexDirection: 'row',
44
+ gap: 8
45
+ },
46
+ backButton: {
47
+ width: 36,
48
+ height: 36,
49
+ borderRadius: 18,
50
+ alignItems: 'center',
51
+ justifyContent: 'center'
52
+ }
53
+ });
32
54
  const screenStyles = StyleSheet.create({
33
55
  viewModeButton: {
34
56
  paddingHorizontal: 10,
@@ -39,11 +61,6 @@ const screenStyles = StyleSheet.create({
39
61
  justifyContent: 'center',
40
62
  marginHorizontal: 1
41
63
  },
42
- photoImage: {
43
- width: '100%',
44
- height: '100%',
45
- borderRadius: 8
46
- },
47
64
  justifiedPhotoImage: {
48
65
  width: '100%',
49
66
  height: '100%',
@@ -52,9 +69,9 @@ const screenStyles = StyleSheet.create({
52
69
  });
53
70
  const FileManagementScreen = ({
54
71
  onClose,
55
- theme,
56
72
  goBack,
57
73
  navigate,
74
+ dismiss,
58
75
  userId,
59
76
  containerWidth,
60
77
  selectMode = false,
@@ -80,57 +97,49 @@ const FileManagementScreen = ({
80
97
  const {
81
98
  t
82
99
  } = useI18n();
100
+ const queryClient = useQueryClient();
83
101
  const uploadFileMutation = useUploadFile();
84
- // Prompt controls
85
- const fileDeleteDialog = useDialogControl();
86
- const bulkDeleteDialog = useDialogControl();
87
- const visibilityChangeDialog = useDialogControl();
88
- const [pendingDeleteFile, setPendingDeleteFile] = useState(null);
89
- const files = useFiles();
102
+
103
+ // Files are owned by the ACTIVE account. `targetUserId` scopes the query key,
104
+ // so switching accounts (or an explicit `userId` prop) shows that account's
105
+ // library with no manual reset.
106
+ const targetUserId = userId || user?.id;
107
+
108
+ // The file list is React Query's, NOT a store: infinite-paginated, fetched on
109
+ // mount + on owner change, edited optimistically via cache helpers. The
110
+ // rendered list is the flattened pages.
111
+ const filesQuery = useUserFilesInfinite(targetUserId);
112
+ const files = useMemo(() => filesQuery.data?.pages.flatMap(page => page.files) ?? [], [filesQuery.data]);
113
+ // No owner resolved yet reads as "loading" (matches the old skeleton-until-
114
+ // first-load behaviour); `isLoading` is the first-page fetch only.
115
+ const isLoadingFiles = !targetUserId || filesQuery.isLoading;
116
+ const isRefreshingFiles = filesQuery.isRefetching;
117
+ const isFetchingMore = filesQuery.isFetchingNextPage;
118
+ const hasMoreFiles = filesQuery.hasNextPage ?? false;
119
+ // Terminal load failure with nothing cached — render a DISTINCT error state
120
+ // (not the empty state) so a failed load never looks like an empty library.
121
+ const hasLoadError = filesQuery.isError && files.length === 0;
122
+ const invalidateFiles = useCallback(() => {
123
+ queryClient.invalidateQueries({
124
+ queryKey: queryKeys.files.list(targetUserId)
125
+ });
126
+ }, [queryClient, targetUserId]);
90
127
  const {
91
128
  width: windowWidth
92
129
  } = useWindowDimensions();
93
130
  // Prefer an explicit sheet width from the router; fall back to the window
94
131
  // so photo grids never size against a hardcoded 400px default.
95
132
  const safeContainerWidth = typeof containerWidth === 'number' && containerWidth > 0 ? containerWidth : windowWidth;
96
- const uploading = useUploadingStore();
97
- const uploadProgress = useUploadAggregateProgress();
98
- const deleting = useDeletingStore();
99
- const [loading, setLoading] = useState(true);
100
- const [refreshing, setRefreshing] = useState(false);
101
- const [paging, setPaging] = useState({
102
- offset: 0,
103
- limit: 40,
104
- total: 0,
105
- hasMore: true,
106
- loadingMore: false
107
- });
108
- const [selectedFile, setSelectedFile] = useState(null);
109
- const fileDetailsControl = useDialogControl();
133
+ // In-flight delete target (local UI state — was in the file store).
134
+ const [deletingId, setDeletingId] = useState(null);
110
135
  // In selectMode we never open the detailed viewer
111
136
  const [openedFile, setOpenedFile] = useState(null);
112
137
  const [fileContent, setFileContent] = useState(null);
113
138
  const [loadingFileContent, setLoadingFileContent] = useState(false);
114
139
  const [showFileDetailsInViewer, setShowFileDetailsInViewer] = useState(false);
115
- const [reduceMotion, setReduceMotion] = useState(false);
116
-
117
- // Detect reduce-motion preference once on mount + subscribe to changes.
118
- // Used by `PhotoPickerView` to skip cell stagger animations.
119
- useEffect(() => {
120
- let cancelled = false;
121
- AccessibilityInfo.isReduceMotionEnabled().then(enabled => {
122
- if (!cancelled) setReduceMotion(enabled);
123
- }).catch(() => {
124
- // Defaults to false; no action needed.
125
- });
126
- const sub = AccessibilityInfo.addEventListener('reduceMotionChanged', enabled => {
127
- setReduceMotion(enabled);
128
- });
129
- return () => {
130
- cancelled = true;
131
- sub.remove();
132
- };
133
- }, []);
140
+ // Reduce-motion preference, read as an external store (no effect). Passed to
141
+ // `PhotoPickerView` to skip cell stagger animations.
142
+ const reduceMotion = useReduceMotion();
134
143
 
135
144
  // Image-only picker mode: when the consumer restricts to image MIME types
136
145
  // (e.g. avatar picker), photos grid is the more useful default view.
@@ -182,24 +191,59 @@ const FileManagementScreen = ({
182
191
  });
183
192
  return sorted;
184
193
  }, [files, searchQuery, viewMode, sortBy, sortOrder]);
185
- const [photoDimensions, setPhotoDimensions] = useState({});
186
- const photoDimensionsRef = useRef(photoDimensions);
187
- photoDimensionsRef.current = photoDimensions;
188
- const [loadingDimensions, setLoadingDimensions] = useState(false);
189
- // Selection state
190
- const [selectedIds, setSelectedIds] = useState(new Set(initialSelectedIds));
191
- const [lastSelectedFileId, setLastSelectedFileId] = useState(null);
194
+ // Selection state. `initialSelectedIds` is the INITIAL selection only (lazy
195
+ // init) there is no prop→state sync effect, since no caller mutates it
196
+ // after mount.
197
+ const [selectedIds, setSelectedIds] = useState(() => new Set(initialSelectedIds));
192
198
  const scrollViewRef = useRef(null);
193
199
  const photoScrollViewRef = useRef(null);
194
- const containerRef = useRef(null);
195
- useEffect(() => {
196
- if (initialSelectedIds?.length) {
197
- setSelectedIds(new Set(initialSelectedIds));
200
+
201
+ // Scroll the browse list/grid to a just-selected file. Driven directly from
202
+ // the selection event handler (double-rAF so the selection re-render has
203
+ // committed first) — not an effect. No-ops in the image-only picker, whose
204
+ // own FlatList is not either ScrollView ref.
205
+ const scrollToSelectedFile = useCallback(fileId => {
206
+ if (viewMode === 'all' && scrollViewRef.current) {
207
+ const itemIndex = filteredFiles.findIndex(file => file.id === fileId);
208
+ if (itemIndex < 0) return;
209
+ // GroupedItem dense rows are ~65px, +30px when a description wraps.
210
+ const baseItemHeight = 65;
211
+ const descriptionHeight = 30;
212
+ let scrollPosition = 0;
213
+ for (let i = 0; i <= itemIndex && i < filteredFiles.length; i++) {
214
+ scrollPosition += baseItemHeight;
215
+ if (filteredFiles[i].metadata?.description) scrollPosition += descriptionHeight;
216
+ }
217
+ // Offset for the header/controls/search/stats chrome (~250px) so the
218
+ // item lands near the top, not under the chrome.
219
+ const finalScrollPosition = 250 + scrollPosition - 150;
220
+ requestAnimationFrame(() => {
221
+ requestAnimationFrame(() => {
222
+ scrollViewRef.current?.scrollTo({
223
+ y: Math.max(0, finalScrollPosition),
224
+ animated: true
225
+ });
226
+ });
227
+ });
228
+ } else if (viewMode === 'photos' && photoScrollViewRef.current) {
229
+ const photos = filteredFiles.filter(file => file.contentType.startsWith('image/'));
230
+ const photoIndex = photos.findIndex(p => p.id === fileId);
231
+ if (photoIndex < 0) return;
232
+ // Rough estimate for the justified grid (3 photos/row, variable heights).
233
+ const row = Math.floor(photoIndex / 3);
234
+ const finalScrollPosition = row * (150 + 4) - 100;
235
+ requestAnimationFrame(() => {
236
+ requestAnimationFrame(() => {
237
+ photoScrollViewRef.current?.scrollTo({
238
+ y: Math.max(0, finalScrollPosition),
239
+ animated: true
240
+ });
241
+ });
242
+ });
198
243
  }
199
- }, [initialSelectedIds]);
244
+ }, [viewMode, filteredFiles]);
200
245
  const toggleSelect = useCallback(async file => {
201
- // Allow selection in regular mode for bulk operations
202
- // if (!selectMode) return;
246
+ // Selection is allowed in regular mode too (for bulk operations).
203
247
  if (disabledMimeTypes.length) {
204
248
  const blocked = disabledMimeTypes.some(mt => file.contentType === mt || file.contentType.startsWith(mt.endsWith('/') ? mt : `${mt}/`));
205
249
  if (blocked) {
@@ -218,9 +262,6 @@ const FileManagementScreen = ({
218
262
  }
219
263
  }
220
264
 
221
- // Track the selected file for scrolling
222
- setLastSelectedFileId(file.id);
223
-
224
265
  // Link file to entity if linkContext is provided
225
266
  if (linkContext) {
226
267
  try {
@@ -230,11 +271,19 @@ const FileManagementScreen = ({
230
271
  }
231
272
  }
232
273
  if (!multiSelect) {
233
- onSelect?.(file);
234
- if (afterSelect === 'back') {
235
- goBack?.();
236
- } else if (afterSelect === 'close') {
237
- onClose?.();
274
+ if (onSelect) {
275
+ // Legacy callback caller (inbox, WelcomeNewUser): keep the
276
+ // callback + afterSelect behaviour unchanged.
277
+ onSelect(file);
278
+ if (afterSelect === 'back') {
279
+ goBack?.();
280
+ } else if (afterSelect === 'close') {
281
+ onClose?.();
282
+ }
283
+ } else {
284
+ // Promise-based picker (avatar picker): resolve the surface's
285
+ // present() promise with the picked file.
286
+ dismiss?.(file);
238
287
  }
239
288
  return;
240
289
  }
@@ -254,13 +303,14 @@ const FileManagementScreen = ({
254
303
  }
255
304
  return next;
256
305
  });
257
- }, [selectMode, multiSelect, onSelect, onClose, goBack, disabledMimeTypes, maxSelection, afterSelect, defaultVisibility, oxyServices, linkContext]);
306
+ scrollToSelectedFile(file.id);
307
+ }, [multiSelect, onSelect, onClose, goBack, dismiss, disabledMimeTypes, maxSelection, afterSelect, defaultVisibility, oxyServices, linkContext, t, scrollToSelectedFile]);
258
308
  const confirmMultiSelection = useCallback(async () => {
259
309
  if (!selectMode || !multiSelect) return;
260
310
  const map = {};
261
- files.forEach(f => {
311
+ for (const f of files) {
262
312
  map[f.id] = f;
263
- });
313
+ }
264
314
  const chosen = Array.from(selectedIds).map(id => map[id]).filter(Boolean);
265
315
 
266
316
  // Update visibility and link files if needed
@@ -287,9 +337,15 @@ const FileManagementScreen = ({
287
337
 
288
338
  // Wait for all updates (but don't block on failures)
289
339
  await Promise.allSettled(updatePromises);
290
- onConfirmSelection?.(chosen);
291
- onClose?.();
292
- }, [selectMode, multiSelect, selectedIds, files, onConfirmSelection, onClose, defaultVisibility, oxyServices, linkContext]);
340
+ if (onConfirmSelection) {
341
+ // Legacy callback caller (inbox): keep the callback + close.
342
+ onConfirmSelection(chosen);
343
+ onClose?.();
344
+ } else {
345
+ // Promise-based picker: resolve the surface with the chosen files.
346
+ dismiss?.(chosen);
347
+ }
348
+ }, [selectMode, multiSelect, selectedIds, files, onConfirmSelection, onClose, dismiss, defaultVisibility, oxyServices, linkContext]);
293
349
 
294
350
  // Private-safe thumbnail URLs for the currently-shown files, resolved in
295
351
  // ONE batch per page (not N per-tile) and cached by React Query. Uploads
@@ -308,81 +364,16 @@ const FileManagementScreen = ({
308
364
  // FileManagementScreen uses a slightly elevated page background.
309
365
  const backgroundColor = colors.backgroundSecondary;
310
366
  const borderColor = colors.border;
311
- const targetUserId = userId || user?.id;
312
- const storeSetDeleting = useFileStore(s => s.setDeleting);
313
- const loadFiles = useCallback(async (mode = 'initial') => {
314
- if (!targetUserId) return;
315
- try {
316
- if (mode === 'refresh') {
317
- setRefreshing(true);
318
- } else if (mode === 'initial') {
319
- setLoading(true);
320
- setPaging(p => ({
321
- ...p,
322
- offset: 0,
323
- hasMore: true
324
- }));
325
- } else if (mode === 'more') {
326
- // Prevent duplicate fetches
327
- setPaging(p => ({
328
- ...p,
329
- loadingMore: true
330
- }));
331
- }
332
- const currentPaging = mode === 'more' ? prevPagingRef.current ?? paging : paging;
333
- const effectiveOffset = mode === 'more' ? currentPaging.offset + currentPaging.limit : 0;
334
- const response = await oxyServices.listUserFiles(currentPaging.limit, effectiveOffset);
335
- const assets = (response.files || []).map(f => ({
336
- id: f.id,
337
- filename: f.originalName ?? f.sha256 ?? '',
338
- contentType: f.mime ?? '',
339
- length: f.size ?? 0,
340
- chunkSize: 0,
341
- uploadDate: f.createdAt ?? '',
342
- metadata: f.metadata ?? {},
343
- variants: f.variants ?? []
344
- }));
345
- if (mode === 'more') {
346
- // append
347
- useFileStore.getState().setFiles(assets, {
348
- merge: true
349
- });
350
- setPaging(p => ({
351
- ...p,
352
- offset: effectiveOffset,
353
- total: response.total || effectiveOffset + assets.length,
354
- hasMore: response.hasMore,
355
- loadingMore: false
356
- }));
357
- } else {
358
- useFileStore.getState().setFiles(assets, {
359
- merge: false
360
- });
361
- setPaging(p => ({
362
- ...p,
363
- offset: 0,
364
- total: response.total || assets.length,
365
- hasMore: response.hasMore,
366
- loadingMore: false
367
- }));
368
- }
369
- } catch (error) {
370
- toast.error(getErrorMessage(error) || t('fileManagement.toasts.loadFailed'));
371
- } finally {
372
- setLoading(false);
373
- setRefreshing(false);
374
- setPaging(p => ({
375
- ...p,
376
- loadingMore: false
377
- }));
378
- }
379
- }, [targetUserId, oxyServices, paging]);
380
367
 
381
368
  // Self-contained document-picking + upload-preview state and handlers.
369
+ // Optimistic uploads edit the file query cache directly (see
370
+ // useFileQueries), so no loader is threaded in.
382
371
  const {
383
372
  isPickingDocument,
384
373
  pendingFiles,
385
374
  showUploadPreview,
375
+ uploading,
376
+ uploadProgress,
386
377
  handleFileUpload,
387
378
  handleConfirmUpload,
388
379
  handleCancelUpload,
@@ -399,154 +390,59 @@ const FileManagementScreen = ({
399
390
  onClose,
400
391
  selectedIds,
401
392
  setSelectedIds,
402
- loadFiles,
403
393
  t
404
394
  });
405
-
406
- // Keep a ref to avoid stale closure when calculating next offset
407
- const prevPagingRef = useRef(paging);
408
- useEffect(() => {
409
- prevPagingRef.current = paging;
410
- }, [paging]);
411
-
412
- // (removed effect; filteredFiles is memoized)
413
-
414
- // Load photo dimensions for justified grid - unified approach using Image.getSize
415
- const loadPhotoDimensions = useCallback(async photos => {
416
- if (photos.length === 0) return;
417
- setLoadingDimensions(true);
418
-
419
- // Snapshot ids missing from the cache at kick-off; concurrent runs may
420
- // overlap but each merge is applied via a functional updater.
421
- const photosToLoad = photos.filter(photo => !photoDimensionsRef.current[photo.id]);
422
- if (photosToLoad.length === 0) {
423
- setLoadingDimensions(false);
424
- return;
425
- }
426
- try {
427
- const measured = {};
428
- await Promise.all(photosToLoad.map(async photo => {
429
- try {
430
- const downloadUrl = thumbSourceFor(photo);
431
- // URL not resolved yet — skip (do NOT record fallback
432
- // dims) so this photo is re-measured once its private-safe
433
- // URL resolves. Measuring the broken public URL is exactly
434
- // the bug we are fixing.
435
- if (!downloadUrl) {
436
- return;
437
- }
438
-
439
- // Unified approach using Image.getSize (works on all platforms)
440
- await new Promise(resolve => {
441
- Image.getSize(downloadUrl, (width, height) => {
442
- measured[photo.id] = {
443
- width,
444
- height
445
- };
446
- resolve();
447
- }, () => {
448
- // Fallback dimensions
449
- measured[photo.id] = {
450
- width: 1,
451
- height: 1
452
- };
453
- resolve();
454
- });
455
- });
456
- } catch (error) {
457
- // Fallback dimensions for any errors
458
- measured[photo.id] = {
459
- width: 1,
460
- height: 1
461
- };
462
- }
463
- }));
464
- if (Object.keys(measured).length > 0) {
465
- setPhotoDimensions(prev => ({
466
- ...prev,
467
- ...measured
468
- }));
469
- }
470
- } catch (error) {
471
- // Photo dimensions loading failed, continue without dimensions
472
- } finally {
473
- setLoadingDimensions(false);
474
- }
475
- }, [thumbSourceFor]);
476
-
477
- // Re-measure photo dimensions when their private-safe URLs resolve. The
478
- // justified grid's own trigger fires on the photo SET, not on URL
479
- // availability, so newly-resolved private tiles would otherwise keep their
480
- // skipped (unmeasured) state and render with fallback geometry.
481
- useEffect(() => {
482
- if (viewMode !== 'photos') return;
483
- const photos = filteredFiles.filter(file => file.contentType.startsWith('image/'));
484
- if (photos.length > 0) {
485
- loadPhotoDimensions(photos);
486
- }
487
- }, [resolvedThumbUrls, viewMode, filteredFiles, loadPhotoDimensions]);
488
-
489
- // Create justified rows from photos with responsive algorithm
490
- const createJustifiedRows = useCallback((photos, containerWidth) => {
491
- if (photos.length === 0) return [];
492
- const rows = [];
493
- const photosPerRow = 3; // Fixed 3 photos per row for consistency
494
-
495
- for (let i = 0; i < photos.length; i += photosPerRow) {
496
- const rowPhotos = photos.slice(i, i + photosPerRow);
497
- rows.push(rowPhotos);
498
- }
499
- return rows;
500
- }, []);
501
- const confirmFileDelete = useCallback((fileId, filename) => {
502
- setPendingDeleteFile({
503
- id: fileId,
504
- name: filename
395
+ const confirmFileDelete = useCallback(async (fileId, filename) => {
396
+ const confirmed = await surfaces.confirm({
397
+ title: t('fileManagement.deleteFile') || 'Delete File',
398
+ message: t('fileManagement.confirms.deleteFile', {
399
+ filename
400
+ }),
401
+ confirmLabel: t('fileManagement.confirm') || 'Delete',
402
+ cancelLabel: t('common.cancel') || 'Cancel',
403
+ destructive: true
505
404
  });
506
- fileDeleteDialog.open();
507
- }, [fileDeleteDialog]);
508
- const handleFileDelete = useCallback(async () => {
509
- if (!pendingDeleteFile) return;
510
- const {
511
- id: fileId
512
- } = pendingDeleteFile;
405
+ if (!confirmed) return;
513
406
  try {
514
- storeSetDeleting(fileId);
407
+ setDeletingId(fileId);
515
408
  await oxyServices.deleteFile(fileId);
516
409
  toast.success(t('fileManagement.toasts.deleteSuccess'));
517
410
 
518
- // Reload files after successful deletion
519
- // Optimistic remove
520
- useFileStore.getState().removeFile(fileId);
521
- // Silent background reconcile
522
- setTimeout(() => loadFiles('silent'), 800);
411
+ // Remove from the query cache, then reconcile against the server.
412
+ removeFileFromCache(queryClient, targetUserId, fileId);
413
+ invalidateFiles();
523
414
  } catch (error) {
524
415
  // Provide specific error messages
525
416
  if (getErrorMessage(error)?.includes('File not found') || getErrorMessage(error)?.includes('404')) {
526
417
  toast.error(t('fileManagement.toasts.fileNotFound'));
527
- // Still reload files to refresh the list
528
- setTimeout(() => loadFiles('silent'), 800);
418
+ // It's already gone server-side reconcile the list.
419
+ invalidateFiles();
529
420
  } else if (getErrorMessage(error)?.includes('permission') || getErrorMessage(error)?.includes('403')) {
530
421
  toast.error(t('fileManagement.toasts.noPermission'));
531
422
  } else {
532
423
  toast.error(getErrorMessage(error) || t('fileManagement.toasts.deleteFailed'));
533
424
  }
534
425
  } finally {
535
- storeSetDeleting(null);
536
- setPendingDeleteFile(null);
426
+ setDeletingId(null);
537
427
  }
538
- }, [pendingDeleteFile, storeSetDeleting, oxyServices, loadFiles, t]);
539
- const confirmBulkDelete = useCallback(() => {
540
- if (selectedIds.size === 0) return;
541
- bulkDeleteDialog.open();
542
- }, [selectedIds.size, bulkDeleteDialog]);
543
- const handleBulkDelete = useCallback(async () => {
428
+ }, [oxyServices, queryClient, targetUserId, invalidateFiles, t]);
429
+ const confirmBulkDelete = useCallback(async () => {
544
430
  if (selectedIds.size === 0) return;
431
+ const confirmed = await surfaces.confirm({
432
+ title: t('fileManagement.deleteFiles') || 'Delete Files',
433
+ message: t('fileManagement.confirms.deleteFiles', {
434
+ count: selectedIds.size
435
+ }),
436
+ confirmLabel: t('fileManagement.confirm') || 'Delete',
437
+ cancelLabel: t('common.cancel') || 'Cancel',
438
+ destructive: true
439
+ });
440
+ if (!confirmed) return;
545
441
  try {
546
442
  const deletePromises = Array.from(selectedIds).map(async fileId => {
547
443
  try {
548
444
  await oxyServices.deleteFile(fileId);
549
- useFileStore.getState().removeFile(fileId);
445
+ removeFileFromCache(queryClient, targetUserId, fileId);
550
446
  return {
551
447
  success: true,
552
448
  fileId
@@ -573,11 +469,11 @@ const FileManagementScreen = ({
573
469
  }));
574
470
  }
575
471
  setSelectedIds(new Set());
576
- setTimeout(() => loadFiles('silent'), 800);
472
+ invalidateFiles();
577
473
  } catch (error) {
578
474
  toast.error(getErrorMessage(error) || t('fileManagement.toasts.bulkDeleteError'));
579
475
  }
580
- }, [selectedIds, files, oxyServices, loadFiles]);
476
+ }, [selectedIds, oxyServices, queryClient, targetUserId, invalidateFiles, t]);
581
477
  const handleBulkVisibilityChange = useCallback(async visibility => {
582
478
  if (selectedIds.size === 0) return;
583
479
  try {
@@ -604,29 +500,47 @@ const FileManagementScreen = ({
604
500
  count: successful,
605
501
  visibility
606
502
  }));
607
- // Update file metadata in store
608
- Array.from(selectedIds).forEach(fileId => {
609
- useFileStore.getState().updateFile(fileId, {
610
- metadata: {
611
- ...files.find(f => f.id === fileId)?.metadata,
612
- visibility
613
- }
503
+ // Reflect the new visibility in the cached files.
504
+ for (const fileId of selectedIds) {
505
+ patchFileMetadataInCache(queryClient, targetUserId, fileId, {
506
+ visibility
614
507
  });
615
- });
508
+ }
616
509
  }
617
510
  if (failed > 0) {
618
511
  toast.error(t('fileManagement.toasts.visibilityFailed', {
619
512
  count: failed
620
513
  }));
621
514
  }
622
- setTimeout(() => loadFiles('silent'), 800);
515
+ invalidateFiles();
623
516
  } catch (error) {
624
517
  toast.error(getErrorMessage(error) || t('fileManagement.toasts.visibilityError'));
625
518
  }
626
- }, [selectedIds, oxyServices, files, loadFiles]);
519
+ }, [selectedIds, oxyServices, queryClient, targetUserId, invalidateFiles, t]);
520
+ const handleVisibilityChange = useCallback(async () => {
521
+ if (selectedIds.size === 0) return;
522
+ const visibility = await presentActionSheet({
523
+ title: t('fileManagement.changeVisibility') || 'Change Visibility',
524
+ message: t('fileManagement.changeVisibilityConfirm', {
525
+ count: selectedIds.size
526
+ }),
527
+ options: [{
528
+ label: t('fileManagement.private') || 'Private',
529
+ value: 'private'
530
+ }, {
531
+ label: t('fileManagement.public') || 'Public',
532
+ value: 'public'
533
+ }, {
534
+ label: t('fileManagement.unlisted') || 'Unlisted',
535
+ value: 'unlisted'
536
+ }],
537
+ cancelLabel: t('common.cancel') || 'Cancel'
538
+ });
539
+ if (visibility) await handleBulkVisibilityChange(visibility);
540
+ }, [selectedIds.size, handleBulkVisibilityChange, t]);
627
541
 
628
542
  // Unified download function - works on all platforms
629
- const handleFileDownload = async (fileId, filename) => {
543
+ const handleFileDownload = useCallback(async (fileId, filename) => {
630
544
  try {
631
545
  // Resolve an authenticated, private-safe URL. The synchronous
632
546
  // `getFileDownloadUrl` yields the public CDN origin, which 404s for
@@ -669,8 +583,8 @@ const FileManagementScreen = ({
669
583
  } catch (error) {
670
584
  toast.error(getErrorMessage(error) || t('fileManagement.toasts.downloadFailed'));
671
585
  }
672
- };
673
- const handleFileOpen = async file => {
586
+ }, [oxyServices, t]);
587
+ const handleFileOpen = useCallback(async file => {
674
588
  if (selectMode) {
675
589
  toggleSelect(file);
676
590
  return;
@@ -710,17 +624,21 @@ const FileManagementScreen = ({
710
624
  } finally {
711
625
  setLoadingFileContent(false);
712
626
  }
713
- };
714
- const handleCloseFile = () => {
627
+ }, [selectMode, toggleSelect, oxyServices, t]);
628
+ const handleCloseFile = useCallback(() => {
715
629
  setOpenedFile(null);
716
630
  setFileContent(null);
717
631
  setShowFileDetailsInViewer(false);
718
632
  // Don't reset view mode when closing a file
719
- };
720
- const showFileDetailsModal = file => {
721
- setSelectedFile(file);
722
- fileDetailsControl.open();
723
- };
633
+ }, []);
634
+ const showFileDetailsModal = useCallback(file => {
635
+ presentFileDetails({
636
+ file,
637
+ onDownload: handleFileDownload,
638
+ onDelete: confirmFileDelete,
639
+ isOwner: user?.id === targetUserId
640
+ });
641
+ }, [handleFileDownload, confirmFileDelete, user?.id, targetUserId]);
724
642
  const renderJustifiedPhotoItem = useCallback((photo, width, height, isLast) => {
725
643
  const downloadUrl = thumbSourceFor(photo);
726
644
  return /*#__PURE__*/_jsx(TouchableOpacity, {
@@ -765,18 +683,7 @@ const FileManagementScreen = ({
765
683
  })]
766
684
  })
767
685
  }, photo.id);
768
- }, [thumbSourceFor, selectMode, selectedIds, multiSelect, colors.primary, colors.text]);
769
-
770
- // Run initial load once per targetUserId change to avoid accidental loops
771
- const lastLoadedFor = useRef(undefined);
772
- useEffect(() => {
773
- const key = targetUserId || 'anonymous';
774
- if (lastLoadedFor.current !== key) {
775
- lastLoadedFor.current = key;
776
- loadFiles('initial');
777
- }
778
- // eslint-disable-next-line react-hooks/exhaustive-deps
779
- }, [targetUserId]);
686
+ }, [thumbSourceFor, selectMode, selectedIds, multiSelect, colors.primary, colors.text, handleFileOpen]);
780
687
 
781
688
  // SettingsListItem-based file items (for 'all' view)
782
689
  const groupedFileItems = useMemo(() => {
@@ -927,8 +834,8 @@ const FileManagementScreen = ({
927
834
  backgroundColor: colors.negativeSubtle
928
835
  },
929
836
  onPress: () => confirmFileDelete(file.id, file.filename),
930
- disabled: deleting === file.id,
931
- children: deleting === file.id ? /*#__PURE__*/_jsx(ActivityIndicator, {
837
+ disabled: deletingId === file.id,
838
+ children: deletingId === file.id ? /*#__PURE__*/_jsx(ActivityIndicator, {
932
839
  size: "small",
933
840
  color: colors.error
934
841
  }) : /*#__PURE__*/_jsx(Ionicons, {
@@ -940,85 +847,27 @@ const FileManagementScreen = ({
940
847
  }) : undefined
941
848
  };
942
849
  });
943
- }, [filteredFiles, theme, deleting, handleFileDownload, confirmFileDelete, handleFileOpen, thumbSourceFor, selectMode, selectedIds]);
944
-
945
- // Scroll to selected file after selection
946
- useEffect(() => {
947
- if (lastSelectedFileId && selectMode) {
948
- if (viewMode === 'all' && scrollViewRef.current) {
949
- // Find the index of the selected file (filteredFiles is already sorted)
950
- const itemIndex = filteredFiles.findIndex(file => file.id === lastSelectedFileId);
951
- if (itemIndex >= 0) {
952
- // Estimate item height (GroupedItem with dense mode is approximately 60-70px)
953
- // Account for description rows which add extra height
954
- const baseItemHeight = 65;
955
- const descriptionHeight = 30; // Approximate height for description
956
- // Use filteredFiles which is already sorted according to user's selection
957
- const sortedFiles = filteredFiles;
958
-
959
- // Calculate total height up to this item
960
- let scrollPosition = 0;
961
- for (let i = 0; i <= itemIndex && i < sortedFiles.length; i++) {
962
- const file = sortedFiles[i];
963
- scrollPosition += baseItemHeight;
964
- if (file.metadata?.description) {
965
- scrollPosition += descriptionHeight;
966
- }
967
- }
968
-
969
- // Add header, controls, search, and stats height (approximately 250px)
970
- const headerHeight = 250;
971
- const finalScrollPosition = headerHeight + scrollPosition - 150; // Offset to show item near top
972
-
973
- // Use requestAnimationFrame to ensure DOM is updated before scrolling
974
- requestAnimationFrame(() => {
975
- requestAnimationFrame(() => {
976
- scrollViewRef.current?.scrollTo({
977
- y: Math.max(0, finalScrollPosition),
978
- animated: true
979
- });
980
- });
981
- });
982
- }
983
- } else if (viewMode === 'photos' && photoScrollViewRef.current) {
984
- // For photo grid, find the photo index
985
- const photos = filteredFiles.filter(file => file.contentType.startsWith('image/'));
986
- const photoIndex = photos.findIndex(p => p.id === lastSelectedFileId);
987
- if (photoIndex >= 0) {
988
- // Rough scroll estimate for the justified grid (3 photos/row; variable row heights).
989
- const itemsPerRow = 3;
990
- const estimatedRowHeight = 150;
991
- const rowGap = 4;
992
- const row = Math.floor(photoIndex / itemsPerRow);
993
- const finalScrollPosition = row * (estimatedRowHeight + rowGap) - 100;
850
+ }, [filteredFiles, colors, deletingId, toggleSelect, handleFileDownload, confirmFileDelete, handleFileOpen, thumbSourceFor, selectMode, selectedIds]);
994
851
 
995
- // Use requestAnimationFrame to ensure DOM is updated before scrolling
996
- requestAnimationFrame(() => {
997
- requestAnimationFrame(() => {
998
- photoScrollViewRef.current?.scrollTo({
999
- y: Math.max(0, finalScrollPosition),
1000
- animated: true
1001
- });
1002
- });
1003
- });
1004
- }
1005
- }
1006
- }
1007
- }, [lastSelectedFileId, selectMode, viewMode, filteredFiles, safeContainerWidth]);
1008
-
1009
- // Clear selected file ID after scroll animation completes
1010
- useEffect(() => {
1011
- if (lastSelectedFileId && scrollViewRef.current) {
1012
- const timeoutId = setTimeout(() => {
1013
- setLastSelectedFileId(null);
1014
- }, 600); // Allow time for scroll animation to complete
852
+ // Browse-themed terminal load-failure state DISTINCT from the empty state.
853
+ const renderLoadError = () => /*#__PURE__*/_jsx(FileLibraryError, {
854
+ title: t('fileManagement.loadError.title'),
855
+ description: t('fileManagement.loadError.description'),
856
+ retryLabel: t('fileManagement.retry'),
857
+ onRetry: () => filesQuery.refetch(),
858
+ iconColor: colors.error,
859
+ titleColor: colors.text,
860
+ descriptionColor: colors.textSecondary,
861
+ buttonColor: colors.primary
862
+ });
1015
863
 
1016
- return () => clearTimeout(timeoutId);
1017
- }
1018
- }, [lastSelectedFileId]);
1019
- const renderPhotoGrid = useCallback(() => {
864
+ // Browse "photos" view. The justified grid owns its own dimension
865
+ // measurement + reflow (see JustifiedPhotoGrid); this only supplies the
866
+ // photo set, the private-safe URL resolver, and the tile renderer.
867
+ const renderPhotoGrid = () => {
1020
868
  const photos = filteredFiles.filter(file => file.contentType.startsWith('image/'));
1021
869
  if (photos.length === 0) {
870
+ if (hasLoadError) return renderLoadError();
1022
871
  return /*#__PURE__*/_jsxs(View, {
1023
872
  className: "items-center py-[40px] px-[24px]",
1024
873
  children: [/*#__PURE__*/_jsx(Ionicons, {
@@ -1044,10 +893,7 @@ const FileManagementScreen = ({
1044
893
  },
1045
894
  onPress: handleFileUpload,
1046
895
  disabled: uploading || isPickingDocument,
1047
- children: uploading ? /*#__PURE__*/_jsx(ActivityIndicator, {
1048
- size: "small",
1049
- color: "#FFFFFF"
1050
- }) : isPickingDocument ? /*#__PURE__*/_jsx(ActivityIndicator, {
896
+ children: uploading || isPickingDocument ? /*#__PURE__*/_jsx(ActivityIndicator, {
1051
897
  size: "small",
1052
898
  color: "#FFFFFF"
1053
899
  }) : /*#__PURE__*/_jsxs(_Fragment, {
@@ -1063,13 +909,13 @@ const FileManagementScreen = ({
1063
909
  })]
1064
910
  });
1065
911
  }
1066
- return /*#__PURE__*/_jsxs(ScrollView, {
912
+ return /*#__PURE__*/_jsx(ScrollView, {
1067
913
  ref: photoScrollViewRef,
1068
914
  className: "flex-1",
1069
915
  contentContainerClassName: "p-[10px]",
1070
916
  refreshControl: /*#__PURE__*/_jsx(RefreshControl, {
1071
- refreshing: refreshing,
1072
- onRefresh: () => loadFiles('refresh'),
917
+ refreshing: isRefreshingFiles,
918
+ onRefresh: () => filesQuery.refetch(),
1073
919
  tintColor: colors.primary
1074
920
  }),
1075
921
  showsVerticalScrollIndicator: false,
@@ -1082,38 +928,21 @@ const FileManagementScreen = ({
1082
928
  contentSize
1083
929
  } = nativeEvent;
1084
930
  const distanceFromBottom = contentSize.height - (contentOffset.y + layoutMeasurement.height);
1085
- if (distanceFromBottom < 200 && !paging.loadingMore && paging.hasMore) {
1086
- loadFiles('more');
931
+ if (distanceFromBottom < 200 && !isFetchingMore && hasMoreFiles) {
932
+ filesQuery.fetchNextPage();
1087
933
  }
1088
934
  },
1089
935
  scrollEventThrottle: 250,
1090
- children: [loadingDimensions && /*#__PURE__*/_jsxs(View, {
1091
- className: "flex-row items-center justify-center py-[16px] gap-[8px]",
1092
- children: [/*#__PURE__*/_jsx(ActivityIndicator, {
1093
- size: "small",
1094
- color: colors.primary
1095
- }), /*#__PURE__*/_jsx(Text, {
1096
- className: "text-[14px] italic",
1097
- style: {
1098
- color: colors.textSecondary
1099
- },
1100
- children: t('fileManagement.loadingPhotoLayout')
1101
- })]
1102
- }), /*#__PURE__*/_jsx(JustifiedPhotoGrid, {
936
+ children: /*#__PURE__*/_jsx(JustifiedPhotoGrid, {
1103
937
  photos: photos,
1104
- photoDimensions: photoDimensions,
1105
- loadPhotoDimensions: loadPhotoDimensions,
1106
- createJustifiedRows: createJustifiedRows,
938
+ getThumbUrl: thumbSourceFor,
1107
939
  renderJustifiedPhotoItem: renderJustifiedPhotoItem,
1108
940
  textColor: colors.text,
1109
941
  containerWidth: typeof containerWidth === 'number' && containerWidth > 0 ? containerWidth : undefined
1110
- })]
942
+ })
1111
943
  });
1112
- }, [filteredFiles, colors, user?.id, targetUserId, uploading, handleFileUpload, refreshing, loadFiles, loadingDimensions, photoDimensions, loadPhotoDimensions, createJustifiedRows, renderJustifiedPhotoItem, containerWidth]);
1113
-
1114
- // Inline justified grid removed (moved to components/photogrid/JustifiedPhotoGrid.tsx)
1115
-
1116
- const renderEmptyState = () => /*#__PURE__*/_jsxs(View, {
944
+ };
945
+ const renderEmptyState = () => hasLoadError ? renderLoadError() : /*#__PURE__*/_jsxs(View, {
1117
946
  className: "items-center py-[40px] px-[24px]",
1118
947
  children: [/*#__PURE__*/_jsx(Ionicons, {
1119
948
  name: "folder-open-outline",
@@ -1138,10 +967,7 @@ const FileManagementScreen = ({
1138
967
  },
1139
968
  onPress: handleFileUpload,
1140
969
  disabled: uploading || isPickingDocument,
1141
- children: uploading ? /*#__PURE__*/_jsx(ActivityIndicator, {
1142
- size: "small",
1143
- color: "#FFFFFF"
1144
- }) : isPickingDocument ? /*#__PURE__*/_jsx(ActivityIndicator, {
970
+ children: uploading || isPickingDocument ? /*#__PURE__*/_jsx(ActivityIndicator, {
1145
971
  size: "small",
1146
972
  color: "#FFFFFF"
1147
973
  }) : /*#__PURE__*/_jsxs(_Fragment, {
@@ -1167,7 +993,85 @@ const FileManagementScreen = ({
1167
993
  // picker's placement-aware container width / columns / tile size and the
1168
994
  // Dialog-vs-bottom-sheet sizing. Skipping the browse chrome here is what keeps
1169
995
  // the picker from flashing the wrong (file-manager) skeleton inside the Dialog.
1170
- if (loading && !isImageOnlyPicker) {
996
+ // The Dialog owns the nav header; this screen contributes its state-dependent
997
+ // title/subtitle + action slots. The image-only picker mode is headerless
998
+ // (PhotoPickerView owns its own bar), so this config is simply ignored there.
999
+ const fmHeaderRight = useMemo(() => {
1000
+ const actions = selectMode && multiSelect ? [{
1001
+ key: 'clear',
1002
+ label: t('fileManagement.clear'),
1003
+ onPress: () => setSelectedIds(new Set()),
1004
+ disabled: selectedIds.size === 0
1005
+ }, {
1006
+ key: 'confirm',
1007
+ label: t('fileManagement.confirm'),
1008
+ onPress: confirmMultiSelection,
1009
+ disabled: selectedIds.size === 0
1010
+ }] : !selectMode && selectedIds.size > 0 ? [{
1011
+ key: 'clear',
1012
+ label: t('fileManagement.clear'),
1013
+ onPress: () => setSelectedIds(new Set()),
1014
+ disabled: false
1015
+ }, {
1016
+ key: 'delete',
1017
+ label: t('fileManagement.delete', {
1018
+ count: selectedIds.size
1019
+ }),
1020
+ onPress: confirmBulkDelete,
1021
+ disabled: false
1022
+ }, {
1023
+ key: 'visibility',
1024
+ label: t('fileManagement.visibility'),
1025
+ onPress: handleVisibilityChange,
1026
+ disabled: false
1027
+ }] : [];
1028
+ if (actions.length === 0) return undefined;
1029
+ return /*#__PURE__*/_jsx(View, {
1030
+ style: fmHeaderStyles.actionsRow,
1031
+ children: actions.map(a => /*#__PURE__*/_jsx(SurfaceHeaderAction, {
1032
+ label: a.label,
1033
+ onPress: a.onPress,
1034
+ disabled: a.disabled
1035
+ }, a.key))
1036
+ });
1037
+ }, [selectMode, multiSelect, selectedIds, t, confirmMultiSelection, confirmBulkDelete, handleVisibilityChange]);
1038
+ const fmHeaderBack = useMemo(() => /*#__PURE__*/_jsx(Pressable, {
1039
+ onPress: handleCancelUpload,
1040
+ accessibilityRole: "button",
1041
+ accessibilityLabel: t('common.back') || 'Back',
1042
+ hitSlop: 8,
1043
+ style: fmHeaderStyles.backButton,
1044
+ children: /*#__PURE__*/_jsx(Ionicons, {
1045
+ name: "chevron-back",
1046
+ size: 20,
1047
+ color: colors.text
1048
+ })
1049
+ }), [handleCancelUpload, colors.text, t]);
1050
+ useSurfaceHeader(showUploadPreview ? {
1051
+ title: t('fileManagement.reviewFiles'),
1052
+ subtitle: t('fileManagement.readyToUpload', {
1053
+ count: pendingFiles.length
1054
+ }),
1055
+ left: fmHeaderBack,
1056
+ largeTitle: false
1057
+ } : {
1058
+ title: selectMode ? multiSelect ? maxSelection ? t('fileManagement.selectedWithMax', {
1059
+ count: selectedIds.size,
1060
+ max: maxSelection
1061
+ }) : t('fileManagement.selected', {
1062
+ count: selectedIds.size
1063
+ }) : t('fileManagement.selectFile') : viewMode === 'photos' ? t('fileManagement.photos') : t('fileManagement.title'),
1064
+ subtitle: selectMode ? multiSelect ? t('fileManagement.available', {
1065
+ count: filteredFiles.length
1066
+ }) : t('fileManagement.tapToSelect') : filteredFiles.length === 1 ? t('fileManagement.itemCount', {
1067
+ count: filteredFiles.length
1068
+ }) : t('fileManagement.itemCount_plural', {
1069
+ count: filteredFiles.length
1070
+ }),
1071
+ right: fmHeaderRight,
1072
+ largeTitle: false
1073
+ });
1074
+ if (isLoadingFiles && !isImageOnlyPicker) {
1171
1075
  const GRID_PADDING = 10;
1172
1076
  const TILE_GAP = 4;
1173
1077
  const GRID_COLUMNS = 3;
@@ -1260,141 +1164,77 @@ const FileManagementScreen = ({
1260
1164
  const photosOnly = filteredFiles.filter(file => file.contentType.startsWith('image/'));
1261
1165
  const isOwner = user?.id === targetUserId;
1262
1166
  const allowUpload = isOwner && allowUploadInSelectMode;
1263
- return /*#__PURE__*/_jsxs(_Fragment, {
1264
- children: [/*#__PURE__*/_jsx(PhotoPickerView, {
1265
- photos: photosOnly,
1266
- selectedIds: selectedIds,
1267
- multiSelect: multiSelect,
1268
- maxSelection: maxSelection,
1269
- allowUpload: allowUpload,
1270
- refreshing: refreshing,
1271
- uploading: uploading,
1272
- isPickingDocument: isPickingDocument,
1273
- uploadProgress: uploadProgress,
1274
- hasMore: paging.hasMore,
1275
- loadingMore: paging.loadingMore,
1276
- loading: loading,
1277
- reduceMotion: reduceMotion,
1278
- getThumbUrl: thumbSourceFor,
1279
- primaryColor: colors.primary,
1280
- isOwner: isOwner,
1281
- onTogglePhoto: toggleSelect,
1282
- onPreviewPhoto: file => showFileDetailsModal(file),
1283
- onUpload: handleFileUpload,
1284
- onRefresh: () => loadFiles('refresh'),
1285
- onLoadMore: () => loadFiles('more'),
1286
- onCancel: () => {
1167
+ return /*#__PURE__*/_jsx(PhotoPickerView, {
1168
+ photos: photosOnly,
1169
+ selectedIds: selectedIds,
1170
+ multiSelect: multiSelect,
1171
+ maxSelection: maxSelection,
1172
+ allowUpload: allowUpload,
1173
+ refreshing: isRefreshingFiles,
1174
+ uploading: uploading,
1175
+ isPickingDocument: isPickingDocument,
1176
+ uploadProgress: uploadProgress,
1177
+ hasMore: hasMoreFiles,
1178
+ loadingMore: isFetchingMore,
1179
+ loading: isLoadingFiles,
1180
+ loadError: hasLoadError,
1181
+ onRetry: () => filesQuery.refetch(),
1182
+ reduceMotion: reduceMotion,
1183
+ getThumbUrl: thumbSourceFor,
1184
+ primaryColor: colors.primary,
1185
+ isOwner: isOwner,
1186
+ onTogglePhoto: toggleSelect
1187
+ // Long-press preview surfaces the file-detail panel on the stack.
1188
+ ,
1189
+ onPreviewPhoto: file => showFileDetailsModal(file),
1190
+ onUpload: handleFileUpload,
1191
+ onRefresh: () => filesQuery.refetch(),
1192
+ onLoadMore: () => filesQuery.fetchNextPage(),
1193
+ onCancel: () => {
1194
+ if (onSelect || onConfirmSelection) {
1195
+ // Legacy callback caller: preserve close/back behaviour.
1287
1196
  if (onClose) onClose();else goBack?.();
1288
- },
1289
- onConfirm: confirmMultiSelection,
1290
- t: t
1291
- }), /*#__PURE__*/_jsx(FileDetailsModal, {
1292
- control: fileDetailsControl,
1293
- file: selectedFile,
1294
- onDownload: handleFileDownload,
1295
- onDelete: confirmFileDelete,
1296
- isOwner: isOwner
1297
- })]
1197
+ } else {
1198
+ // Promise picker (avatar): dismiss just this surface.
1199
+ dismiss?.();
1200
+ }
1201
+ },
1202
+ onConfirm: confirmMultiSelection,
1203
+ t: t
1298
1204
  });
1299
1205
  }
1300
1206
 
1301
1207
  // If a file is opened, show the file viewer
1302
1208
  if (!selectMode && openedFile) {
1303
- return /*#__PURE__*/_jsxs(_Fragment, {
1304
- children: [/*#__PURE__*/_jsx(FileViewer, {
1305
- file: openedFile,
1306
- fileContent: fileContent,
1307
- loadingFileContent: loadingFileContent,
1308
- showFileDetailsInViewer: showFileDetailsInViewer,
1309
- onToggleDetails: () => setShowFileDetailsInViewer(!showFileDetailsInViewer),
1310
- onClose: handleCloseFile,
1311
- onDownload: handleFileDownload,
1312
- onDelete: confirmFileDelete,
1313
- isOwner: user?.id === targetUserId
1314
- }), /*#__PURE__*/_jsx(FileDetailsModal, {
1315
- control: fileDetailsControl,
1316
- file: selectedFile,
1317
- onDownload: handleFileDownload,
1318
- onDelete: confirmFileDelete,
1319
- isOwner: user?.id === targetUserId
1320
- })]
1209
+ return /*#__PURE__*/_jsx(FileViewer, {
1210
+ file: openedFile,
1211
+ fileContent: fileContent,
1212
+ loadingFileContent: loadingFileContent,
1213
+ showFileDetailsInViewer: showFileDetailsInViewer,
1214
+ onToggleDetails: () => setShowFileDetailsInViewer(!showFileDetailsInViewer),
1215
+ onClose: handleCloseFile,
1216
+ onDownload: handleFileDownload,
1217
+ onDelete: confirmFileDelete,
1218
+ isOwner: user?.id === targetUserId
1321
1219
  });
1322
1220
  }
1323
1221
 
1324
1222
  // If upload preview is showing, render it inline instead of the file list
1325
1223
  if (showUploadPreview) {
1326
- return /*#__PURE__*/_jsxs(View, {
1224
+ return /*#__PURE__*/_jsx(View, {
1327
1225
  className: "flex-1",
1328
- children: [/*#__PURE__*/_jsx(Header, {
1329
- title: t('fileManagement.reviewFiles'),
1330
- subtitle: t('fileManagement.readyToUpload', {
1331
- count: pendingFiles.length
1332
- }),
1333
- onBack: handleCancelUpload,
1334
- showBackButton: true,
1335
- variant: "minimal",
1336
- elevation: "none",
1337
- titleAlignment: "left"
1338
- }), /*#__PURE__*/_jsx(UploadPreview, {
1226
+ children: /*#__PURE__*/_jsx(UploadPreview, {
1339
1227
  pendingFiles: pendingFiles,
1340
1228
  onConfirm: handleConfirmUpload,
1341
1229
  onCancel: handleCancelUpload,
1342
1230
  onRemoveFile: removePendingFile,
1343
1231
  inline: true
1344
- })]
1232
+ })
1345
1233
  });
1346
1234
  }
1347
1235
  return /*#__PURE__*/_jsxs(View, {
1348
1236
  className: "flex-1",
1349
- children: [/*#__PURE__*/_jsx(Header, {
1350
- title: selectMode ? multiSelect ? maxSelection ? t('fileManagement.selectedWithMax', {
1351
- count: selectedIds.size,
1352
- max: maxSelection
1353
- }) : t('fileManagement.selected', {
1354
- count: selectedIds.size
1355
- }) : t('fileManagement.selectFile') : viewMode === 'photos' ? t('fileManagement.photos') : t('fileManagement.title'),
1356
- subtitle: selectMode ? multiSelect ? t('fileManagement.available', {
1357
- count: filteredFiles.length
1358
- }) : t('fileManagement.tapToSelect') : filteredFiles.length === 1 ? t('fileManagement.itemCount', {
1359
- count: filteredFiles.length
1360
- }) : t('fileManagement.itemCount_plural', {
1361
- count: filteredFiles.length
1362
- }),
1363
- actions: selectMode && multiSelect ? [{
1364
- key: 'clear',
1365
- text: t('fileManagement.clear'),
1366
- onPress: () => setSelectedIds(new Set()),
1367
- disabled: selectedIds.size === 0
1368
- }, {
1369
- key: 'confirm',
1370
- text: t('fileManagement.confirm'),
1371
- onPress: confirmMultiSelection,
1372
- disabled: selectedIds.size === 0
1373
- }] : !selectMode && selectedIds.size > 0 ? [{
1374
- key: 'clear',
1375
- text: t('fileManagement.clear'),
1376
- onPress: () => setSelectedIds(new Set())
1377
- }, {
1378
- key: 'delete',
1379
- text: t('fileManagement.delete', {
1380
- count: selectedIds.size
1381
- }),
1382
- onPress: confirmBulkDelete,
1383
- icon: 'delete'
1384
- }, {
1385
- key: 'visibility',
1386
- text: t('fileManagement.visibility'),
1387
- onPress: () => {
1388
- visibilityChangeDialog.open();
1389
- },
1390
- icon: 'eye'
1391
- }] : undefined,
1392
- onBack: onClose || goBack,
1393
- showBackButton: true,
1394
- variant: "minimal",
1395
- elevation: "none",
1396
- titleAlignment: "left"
1397
- }), /*#__PURE__*/_jsxs(View, {
1237
+ children: [/*#__PURE__*/_jsxs(View, {
1398
1238
  className: "flex-row items-center justify-between px-[12px] py-[12px] gap-[12px]",
1399
1239
  children: [/*#__PURE__*/_jsx(ScrollView, {
1400
1240
  horizontal: true,
@@ -1424,32 +1264,30 @@ const FileManagementScreen = ({
1424
1264
  textColor: colors.text,
1425
1265
  style: screenStyles.viewModeButton,
1426
1266
  accessibilityLabel: t('fileManagement.a11y.viewPhotos') || 'Show photos only'
1427
- }), !isImageOnlyPicker && /*#__PURE__*/_jsxs(_Fragment, {
1428
- children: [/*#__PURE__*/_jsx(AnimatedButton, {
1429
- isSelected: viewMode === 'videos',
1430
- onPress: () => setViewMode('videos'),
1431
- icon: viewMode === 'videos' ? 'video' : 'video-outline',
1432
- primaryColor: colors.primary,
1433
- textColor: colors.text,
1434
- style: screenStyles.viewModeButton,
1435
- accessibilityLabel: t('fileManagement.a11y.viewVideos') || 'Show videos only'
1436
- }), /*#__PURE__*/_jsx(AnimatedButton, {
1437
- isSelected: viewMode === 'documents',
1438
- onPress: () => setViewMode('documents'),
1439
- icon: viewMode === 'documents' ? 'file-document' : 'file-document-outline',
1440
- primaryColor: colors.primary,
1441
- textColor: colors.text,
1442
- style: screenStyles.viewModeButton,
1443
- accessibilityLabel: t('fileManagement.a11y.viewDocuments') || 'Show documents only'
1444
- }), /*#__PURE__*/_jsx(AnimatedButton, {
1445
- isSelected: viewMode === 'audio',
1446
- onPress: () => setViewMode('audio'),
1447
- icon: viewMode === 'audio' ? 'music-note' : 'music-note-outline',
1448
- primaryColor: colors.primary,
1449
- textColor: colors.text,
1450
- style: screenStyles.viewModeButton,
1451
- accessibilityLabel: t('fileManagement.a11y.viewAudio') || 'Show audio only'
1452
- })]
1267
+ }), /*#__PURE__*/_jsx(AnimatedButton, {
1268
+ isSelected: viewMode === 'videos',
1269
+ onPress: () => setViewMode('videos'),
1270
+ icon: viewMode === 'videos' ? 'video' : 'video-outline',
1271
+ primaryColor: colors.primary,
1272
+ textColor: colors.text,
1273
+ style: screenStyles.viewModeButton,
1274
+ accessibilityLabel: t('fileManagement.a11y.viewVideos') || 'Show videos only'
1275
+ }), /*#__PURE__*/_jsx(AnimatedButton, {
1276
+ isSelected: viewMode === 'documents',
1277
+ onPress: () => setViewMode('documents'),
1278
+ icon: viewMode === 'documents' ? 'file-document' : 'file-document-outline',
1279
+ primaryColor: colors.primary,
1280
+ textColor: colors.text,
1281
+ style: screenStyles.viewModeButton,
1282
+ accessibilityLabel: t('fileManagement.a11y.viewDocuments') || 'Show documents only'
1283
+ }), /*#__PURE__*/_jsx(AnimatedButton, {
1284
+ isSelected: viewMode === 'audio',
1285
+ onPress: () => setViewMode('audio'),
1286
+ icon: viewMode === 'audio' ? 'music-note' : 'music-note-outline',
1287
+ primaryColor: colors.primary,
1288
+ textColor: colors.text,
1289
+ style: screenStyles.viewModeButton,
1290
+ accessibilityLabel: t('fileManagement.a11y.viewAudio') || 'Show audio only'
1453
1291
  })]
1454
1292
  })
1455
1293
  }), /*#__PURE__*/_jsxs(TouchableOpacity, {
@@ -1482,15 +1320,15 @@ const FileManagementScreen = ({
1482
1320
  size: 14,
1483
1321
  color: colors.textSecondary
1484
1322
  })]
1485
- }), user?.id === targetUserId && (!selectMode || selectMode && allowUploadInSelectMode) && /*#__PURE__*/_jsx(TouchableOpacity, {
1486
- className: `h-[44px] rounded-[22px] items-center justify-center ${isImageOnlyPicker ? 'w-auto min-w-[44px] px-[14px]' : 'w-[44px]'}`,
1323
+ }), user?.id === targetUserId && (!selectMode || allowUploadInSelectMode) && /*#__PURE__*/_jsx(TouchableOpacity, {
1324
+ className: "h-[44px] w-[44px] rounded-[22px] items-center justify-center",
1487
1325
  style: {
1488
1326
  backgroundColor: colors.primary
1489
1327
  },
1490
1328
  onPress: handleFileUpload,
1491
1329
  disabled: uploading || isPickingDocument,
1492
1330
  accessibilityRole: "button",
1493
- accessibilityLabel: isImageOnlyPicker ? t('fileManagement.a11y.uploadFromDevice') || 'Upload photo from device' : t('fileManagement.a11y.uploadFile') || 'Upload file',
1331
+ accessibilityLabel: t('fileManagement.a11y.uploadFile') || 'Upload file',
1494
1332
  accessibilityState: {
1495
1333
  busy: uploading || isPickingDocument
1496
1334
  },
@@ -1506,17 +1344,6 @@ const FileManagementScreen = ({
1506
1344
  }) : isPickingDocument ? /*#__PURE__*/_jsx(ActivityIndicator, {
1507
1345
  size: "small",
1508
1346
  color: "#FFFFFF"
1509
- }) : isImageOnlyPicker ? /*#__PURE__*/_jsxs(View, {
1510
- className: "flex-row items-center gap-[6px]",
1511
- children: [/*#__PURE__*/_jsx(Ionicons, {
1512
- name: "cloud-upload",
1513
- size: 18,
1514
- color: "#FFFFFF"
1515
- }), /*#__PURE__*/_jsx(Text, {
1516
- className: "text-white text-[14px] font-semibold",
1517
- numberOfLines: 1,
1518
- children: t('fileManagement.upload') || 'Upload'
1519
- })]
1520
1347
  }) : /*#__PURE__*/_jsx(Ionicons, {
1521
1348
  name: "add",
1522
1349
  size: 22,
@@ -1612,72 +1439,22 @@ const FileManagementScreen = ({
1612
1439
  filteredFiles: filteredFiles,
1613
1440
  searchQuery: searchQuery,
1614
1441
  items: groupedFileItems,
1615
- paging: paging,
1616
- refreshing: refreshing,
1442
+ paging: {
1443
+ loadingMore: isFetchingMore,
1444
+ hasMore: hasMoreFiles
1445
+ },
1446
+ refreshing: isRefreshingFiles,
1617
1447
  colors: colors,
1618
1448
  t: t,
1619
- onRefresh: () => loadFiles('refresh'),
1620
- onLoadMore: () => loadFiles('more'),
1449
+ onRefresh: () => filesQuery.refetch(),
1450
+ onLoadMore: () => filesQuery.fetchNextPage(),
1621
1451
  onClearSearch: () => setSearchQuery(''),
1622
1452
  renderEmptyState: renderEmptyState
1623
- }), !selectMode && /*#__PURE__*/_jsx(FileDetailsModal, {
1624
- control: fileDetailsControl,
1625
- file: selectedFile,
1626
- onDownload: handleFileDownload,
1627
- onDelete: confirmFileDelete,
1628
- isOwner: user?.id === targetUserId
1629
1453
  }), !selectMode && uploading && /*#__PURE__*/_jsx(UploadBar, {
1630
1454
  uploadProgress: uploadProgress,
1631
1455
  isDark: bloomTheme.isDark,
1632
1456
  colors: colors,
1633
1457
  t: t
1634
- }), /*#__PURE__*/_jsx(Dialog, {
1635
- control: fileDeleteDialog,
1636
- title: t('fileManagement.deleteFile') || 'Delete File',
1637
- description: pendingDeleteFile ? t('fileManagement.confirms.deleteFile', {
1638
- filename: pendingDeleteFile.name
1639
- }) : '',
1640
- actions: [{
1641
- label: t('fileManagement.confirm') || 'Delete',
1642
- color: 'destructive',
1643
- onPress: handleFileDelete
1644
- }, {
1645
- label: t('common.cancel') || 'Cancel',
1646
- color: 'cancel'
1647
- }]
1648
- }), /*#__PURE__*/_jsx(Dialog, {
1649
- control: bulkDeleteDialog,
1650
- title: t('fileManagement.deleteFiles') || 'Delete Files',
1651
- description: t('fileManagement.confirms.deleteFiles', {
1652
- count: selectedIds.size
1653
- }),
1654
- actions: [{
1655
- label: t('fileManagement.confirm') || 'Delete',
1656
- color: 'destructive',
1657
- onPress: handleBulkDelete
1658
- }, {
1659
- label: t('common.cancel') || 'Cancel',
1660
- color: 'cancel'
1661
- }]
1662
- }), /*#__PURE__*/_jsx(Dialog, {
1663
- control: visibilityChangeDialog,
1664
- title: t('fileManagement.changeVisibility') || 'Change Visibility',
1665
- description: t('fileManagement.changeVisibilityConfirm', {
1666
- count: selectedIds.size
1667
- }),
1668
- actions: [{
1669
- label: t('fileManagement.private') || 'Private',
1670
- onPress: () => handleBulkVisibilityChange('private')
1671
- }, {
1672
- label: t('fileManagement.public') || 'Public',
1673
- onPress: () => handleBulkVisibilityChange('public')
1674
- }, {
1675
- label: t('fileManagement.unlisted') || 'Unlisted',
1676
- onPress: () => handleBulkVisibilityChange('unlisted')
1677
- }, {
1678
- label: t('common.cancel') || 'Cancel',
1679
- color: 'cancel'
1680
- }]
1681
1458
  })]
1682
1459
  });
1683
1460
  };