@oxyhq/services 5.4.2 → 5.4.3

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 (359) hide show
  1. package/lib/commonjs/assets/OxyLogo.svg +1 -0
  2. package/lib/commonjs/assets/assets/OxyLogo.svg +1 -0
  3. package/lib/commonjs/assets/assets/fonts/Phudu/Phudu-Black.ttf +0 -0
  4. package/lib/commonjs/assets/assets/fonts/Phudu/Phudu-Bold.ttf +0 -0
  5. package/lib/commonjs/assets/assets/fonts/Phudu/Phudu-ExtraBold.ttf +0 -0
  6. package/lib/commonjs/assets/assets/fonts/Phudu/Phudu-Light.ttf +0 -0
  7. package/lib/commonjs/assets/assets/fonts/Phudu/Phudu-Medium.ttf +0 -0
  8. package/lib/commonjs/assets/assets/fonts/Phudu/Phudu-Regular.ttf +0 -0
  9. package/lib/commonjs/assets/assets/fonts/Phudu/Phudu-SemiBold.ttf +0 -0
  10. package/lib/commonjs/assets/assets/icons/OxyServices.tsx +67 -0
  11. package/lib/commonjs/assets/assets/icons/logo_OxyServices.svg +1 -0
  12. package/lib/commonjs/assets/fonts/Phudu/Phudu-Black.ttf +0 -0
  13. package/lib/commonjs/assets/fonts/Phudu/Phudu-Bold.ttf +0 -0
  14. package/lib/commonjs/assets/fonts/Phudu/Phudu-ExtraBold.ttf +0 -0
  15. package/lib/commonjs/assets/fonts/Phudu/Phudu-Light.ttf +0 -0
  16. package/lib/commonjs/assets/fonts/Phudu/Phudu-Medium.ttf +0 -0
  17. package/lib/commonjs/assets/fonts/Phudu/Phudu-Regular.ttf +0 -0
  18. package/lib/commonjs/assets/fonts/Phudu/Phudu-SemiBold.ttf +0 -0
  19. package/lib/commonjs/assets/icons/OxyServices.js +53 -0
  20. package/lib/commonjs/assets/icons/OxyServices.js.map +1 -0
  21. package/lib/commonjs/assets/icons/logo_OxyServices.svg +1 -0
  22. package/lib/commonjs/constants/version.js +28 -0
  23. package/lib/commonjs/constants/version.js.map +1 -0
  24. package/lib/commonjs/core/index.js +1660 -0
  25. package/lib/commonjs/core/index.js.map +1 -0
  26. package/lib/commonjs/index.js +160 -0
  27. package/lib/commonjs/index.js.map +1 -0
  28. package/lib/commonjs/lib/sonner.js +21 -0
  29. package/lib/commonjs/lib/sonner.js.map +1 -0
  30. package/lib/commonjs/models/interfaces.js +2 -0
  31. package/lib/commonjs/models/interfaces.js.map +1 -0
  32. package/lib/commonjs/models/secureSession.js +2 -0
  33. package/lib/commonjs/models/secureSession.js.map +1 -0
  34. package/lib/commonjs/node/index.js +54 -0
  35. package/lib/commonjs/node/index.js.map +1 -0
  36. package/lib/commonjs/ui/components/Avatar.js +98 -0
  37. package/lib/commonjs/ui/components/Avatar.js.map +1 -0
  38. package/lib/commonjs/ui/components/FollowButton.js +246 -0
  39. package/lib/commonjs/ui/components/FollowButton.js.map +1 -0
  40. package/lib/commonjs/ui/components/FontLoader.js +181 -0
  41. package/lib/commonjs/ui/components/FontLoader.js.map +1 -0
  42. package/lib/commonjs/ui/components/GroupedItem.js +109 -0
  43. package/lib/commonjs/ui/components/GroupedItem.js.map +1 -0
  44. package/lib/commonjs/ui/components/GroupedSection.js +33 -0
  45. package/lib/commonjs/ui/components/GroupedSection.js.map +1 -0
  46. package/lib/commonjs/ui/components/OxyLogo.js +56 -0
  47. package/lib/commonjs/ui/components/OxyLogo.js.map +1 -0
  48. package/lib/commonjs/ui/components/OxyProvider.js +517 -0
  49. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -0
  50. package/lib/commonjs/ui/components/OxySignInButton.js +178 -0
  51. package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -0
  52. package/lib/commonjs/ui/components/ProfileCard.js +124 -0
  53. package/lib/commonjs/ui/components/ProfileCard.js.map +1 -0
  54. package/lib/commonjs/ui/components/QuickActions.js +87 -0
  55. package/lib/commonjs/ui/components/QuickActions.js.map +1 -0
  56. package/lib/commonjs/ui/components/Section.js +36 -0
  57. package/lib/commonjs/ui/components/Section.js.map +1 -0
  58. package/lib/commonjs/ui/components/SectionTitle.js +35 -0
  59. package/lib/commonjs/ui/components/SectionTitle.js.map +1 -0
  60. package/lib/commonjs/ui/components/bottomSheet/index.js +37 -0
  61. package/lib/commonjs/ui/components/bottomSheet/index.js.map +1 -0
  62. package/lib/commonjs/ui/components/icon/OxyIcon.js +27 -0
  63. package/lib/commonjs/ui/components/icon/OxyIcon.js.map +1 -0
  64. package/lib/commonjs/ui/components/icon/index.js +14 -0
  65. package/lib/commonjs/ui/components/icon/index.js.map +1 -0
  66. package/lib/commonjs/ui/components/index.js +97 -0
  67. package/lib/commonjs/ui/components/index.js.map +1 -0
  68. package/lib/commonjs/ui/context/OxyContext.js +584 -0
  69. package/lib/commonjs/ui/context/OxyContext.js.map +1 -0
  70. package/lib/commonjs/ui/index.js +128 -0
  71. package/lib/commonjs/ui/index.js.map +1 -0
  72. package/lib/commonjs/ui/navigation/OxyRouter.js +264 -0
  73. package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -0
  74. package/lib/commonjs/ui/navigation/types.js +6 -0
  75. package/lib/commonjs/ui/navigation/types.js.map +1 -0
  76. package/lib/commonjs/ui/screens/AccountCenterScreen.js +313 -0
  77. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -0
  78. package/lib/commonjs/ui/screens/AccountManagementDemo.js +299 -0
  79. package/lib/commonjs/ui/screens/AccountManagementDemo.js.map +1 -0
  80. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +855 -0
  81. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -0
  82. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +843 -0
  83. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -0
  84. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +788 -0
  85. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -0
  86. package/lib/commonjs/ui/screens/AppInfoScreen.js +664 -0
  87. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -0
  88. package/lib/commonjs/ui/screens/BillingManagementScreen.js +636 -0
  89. package/lib/commonjs/ui/screens/BillingManagementScreen.js.map +1 -0
  90. package/lib/commonjs/ui/screens/FileManagementScreen.js +2515 -0
  91. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -0
  92. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +1620 -0
  93. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -0
  94. package/lib/commonjs/ui/screens/ProfileScreen.js +450 -0
  95. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -0
  96. package/lib/commonjs/ui/screens/SessionManagementScreen.js +449 -0
  97. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -0
  98. package/lib/commonjs/ui/screens/SignInScreen.js +1004 -0
  99. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -0
  100. package/lib/commonjs/ui/screens/SignUpScreen.js +937 -0
  101. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -0
  102. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +88 -0
  103. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -0
  104. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +364 -0
  105. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -0
  106. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +227 -0
  107. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -0
  108. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +148 -0
  109. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -0
  110. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +127 -0
  111. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -0
  112. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +105 -0
  113. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -0
  114. package/lib/commonjs/ui/styles/FONTS.md +126 -0
  115. package/lib/commonjs/ui/styles/fonts.js +84 -0
  116. package/lib/commonjs/ui/styles/fonts.js.map +1 -0
  117. package/lib/commonjs/ui/styles/index.js +28 -0
  118. package/lib/commonjs/ui/styles/index.js.map +1 -0
  119. package/lib/commonjs/ui/styles/theme.js +121 -0
  120. package/lib/commonjs/ui/styles/theme.js.map +1 -0
  121. package/lib/commonjs/utils/deviceManager.js +173 -0
  122. package/lib/commonjs/utils/deviceManager.js.map +1 -0
  123. package/lib/commonjs/utils/index.js +13 -0
  124. package/lib/commonjs/utils/index.js.map +1 -0
  125. package/lib/commonjs/utils/polyfills.js +42 -0
  126. package/lib/commonjs/utils/polyfills.js.map +1 -0
  127. package/lib/module/assets/OxyLogo.svg +1 -0
  128. package/lib/module/assets/assets/OxyLogo.svg +1 -0
  129. package/lib/module/assets/assets/fonts/Phudu/Phudu-Black.ttf +0 -0
  130. package/lib/module/assets/assets/fonts/Phudu/Phudu-Bold.ttf +0 -0
  131. package/lib/module/assets/assets/fonts/Phudu/Phudu-ExtraBold.ttf +0 -0
  132. package/lib/module/assets/assets/fonts/Phudu/Phudu-Light.ttf +0 -0
  133. package/lib/module/assets/assets/fonts/Phudu/Phudu-Medium.ttf +0 -0
  134. package/lib/module/assets/assets/fonts/Phudu/Phudu-Regular.ttf +0 -0
  135. package/lib/module/assets/assets/fonts/Phudu/Phudu-SemiBold.ttf +0 -0
  136. package/lib/module/assets/assets/icons/OxyServices.tsx +67 -0
  137. package/lib/module/assets/assets/icons/logo_OxyServices.svg +1 -0
  138. package/lib/module/assets/fonts/Phudu/Phudu-Black.ttf +0 -0
  139. package/lib/module/assets/fonts/Phudu/Phudu-Bold.ttf +0 -0
  140. package/lib/module/assets/fonts/Phudu/Phudu-ExtraBold.ttf +0 -0
  141. package/lib/module/assets/fonts/Phudu/Phudu-Light.ttf +0 -0
  142. package/lib/module/assets/fonts/Phudu/Phudu-Medium.ttf +0 -0
  143. package/lib/module/assets/fonts/Phudu/Phudu-Regular.ttf +0 -0
  144. package/lib/module/assets/fonts/Phudu/Phudu-SemiBold.ttf +0 -0
  145. package/lib/module/assets/icons/OxyServices.js +46 -0
  146. package/lib/module/assets/icons/OxyServices.js.map +1 -0
  147. package/lib/module/assets/icons/logo_OxyServices.svg +1 -0
  148. package/lib/module/constants/version.js +21 -0
  149. package/lib/module/constants/version.js.map +1 -0
  150. package/lib/module/core/index.js +1634 -0
  151. package/lib/module/core/index.js.map +1 -0
  152. package/lib/module/index.js +48 -0
  153. package/lib/module/index.js.map +1 -0
  154. package/lib/module/lib/sonner.js +16 -0
  155. package/lib/module/lib/sonner.js.map +1 -0
  156. package/lib/module/models/interfaces.js +2 -0
  157. package/lib/module/models/interfaces.js.map +1 -0
  158. package/lib/module/models/secureSession.js +2 -0
  159. package/lib/module/models/secureSession.js.map +1 -0
  160. package/lib/module/node/index.js +23 -0
  161. package/lib/module/node/index.js.map +1 -0
  162. package/lib/module/ui/components/Avatar.js +93 -0
  163. package/lib/module/ui/components/Avatar.js.map +1 -0
  164. package/lib/module/ui/components/FollowButton.js +241 -0
  165. package/lib/module/ui/components/FollowButton.js.map +1 -0
  166. package/lib/module/ui/components/FontLoader.js +176 -0
  167. package/lib/module/ui/components/FontLoader.js.map +1 -0
  168. package/lib/module/ui/components/GroupedItem.js +104 -0
  169. package/lib/module/ui/components/GroupedItem.js.map +1 -0
  170. package/lib/module/ui/components/GroupedSection.js +28 -0
  171. package/lib/module/ui/components/GroupedSection.js.map +1 -0
  172. package/lib/module/ui/components/OxyLogo.js +49 -0
  173. package/lib/module/ui/components/OxyLogo.js.map +1 -0
  174. package/lib/module/ui/components/OxyProvider.js +511 -0
  175. package/lib/module/ui/components/OxyProvider.js.map +1 -0
  176. package/lib/module/ui/components/OxySignInButton.js +172 -0
  177. package/lib/module/ui/components/OxySignInButton.js.map +1 -0
  178. package/lib/module/ui/components/ProfileCard.js +119 -0
  179. package/lib/module/ui/components/ProfileCard.js.map +1 -0
  180. package/lib/module/ui/components/QuickActions.js +82 -0
  181. package/lib/module/ui/components/QuickActions.js.map +1 -0
  182. package/lib/module/ui/components/Section.js +31 -0
  183. package/lib/module/ui/components/Section.js.map +1 -0
  184. package/lib/module/ui/components/SectionTitle.js +30 -0
  185. package/lib/module/ui/components/SectionTitle.js.map +1 -0
  186. package/lib/module/ui/components/bottomSheet/index.js +5 -0
  187. package/lib/module/ui/components/bottomSheet/index.js.map +1 -0
  188. package/lib/module/ui/components/icon/OxyIcon.js +22 -0
  189. package/lib/module/ui/components/icon/OxyIcon.js.map +1 -0
  190. package/lib/module/ui/components/icon/index.js +4 -0
  191. package/lib/module/ui/components/icon/index.js.map +1 -0
  192. package/lib/module/ui/components/index.js +18 -0
  193. package/lib/module/ui/components/index.js.map +1 -0
  194. package/lib/module/ui/context/OxyContext.js +579 -0
  195. package/lib/module/ui/context/OxyContext.js.map +1 -0
  196. package/lib/module/ui/index.js +24 -0
  197. package/lib/module/ui/index.js.map +1 -0
  198. package/lib/module/ui/navigation/OxyRouter.js +257 -0
  199. package/lib/module/ui/navigation/OxyRouter.js.map +1 -0
  200. package/lib/module/ui/navigation/types.js +4 -0
  201. package/lib/module/ui/navigation/types.js.map +1 -0
  202. package/lib/module/ui/screens/AccountCenterScreen.js +308 -0
  203. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -0
  204. package/lib/module/ui/screens/AccountManagementDemo.js +296 -0
  205. package/lib/module/ui/screens/AccountManagementDemo.js.map +1 -0
  206. package/lib/module/ui/screens/AccountOverviewScreen.js +849 -0
  207. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -0
  208. package/lib/module/ui/screens/AccountSettingsScreen.js +837 -0
  209. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -0
  210. package/lib/module/ui/screens/AccountSwitcherScreen.js +782 -0
  211. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -0
  212. package/lib/module/ui/screens/AppInfoScreen.js +658 -0
  213. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -0
  214. package/lib/module/ui/screens/BillingManagementScreen.js +631 -0
  215. package/lib/module/ui/screens/BillingManagementScreen.js.map +1 -0
  216. package/lib/module/ui/screens/FileManagementScreen.js +2510 -0
  217. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -0
  218. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +1615 -0
  219. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -0
  220. package/lib/module/ui/screens/ProfileScreen.js +444 -0
  221. package/lib/module/ui/screens/ProfileScreen.js.map +1 -0
  222. package/lib/module/ui/screens/SessionManagementScreen.js +444 -0
  223. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -0
  224. package/lib/module/ui/screens/SignInScreen.js +998 -0
  225. package/lib/module/ui/screens/SignInScreen.js.map +1 -0
  226. package/lib/module/ui/screens/SignUpScreen.js +932 -0
  227. package/lib/module/ui/screens/SignUpScreen.js.map +1 -0
  228. package/lib/module/ui/screens/karma/KarmaAboutScreen.js +83 -0
  229. package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -0
  230. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +358 -0
  231. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -0
  232. package/lib/module/ui/screens/karma/KarmaFAQScreen.js +222 -0
  233. package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -0
  234. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +142 -0
  235. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -0
  236. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +122 -0
  237. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -0
  238. package/lib/module/ui/screens/karma/KarmaRulesScreen.js +100 -0
  239. package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -0
  240. package/lib/module/ui/styles/FONTS.md +126 -0
  241. package/lib/module/ui/styles/fonts.js +81 -0
  242. package/lib/module/ui/styles/fonts.js.map +1 -0
  243. package/lib/module/ui/styles/index.js +5 -0
  244. package/lib/module/ui/styles/index.js.map +1 -0
  245. package/lib/module/ui/styles/theme.js +114 -0
  246. package/lib/module/ui/styles/theme.js.map +1 -0
  247. package/lib/module/utils/deviceManager.js +167 -0
  248. package/lib/module/utils/deviceManager.js.map +1 -0
  249. package/lib/module/utils/index.js +4 -0
  250. package/lib/module/utils/index.js.map +1 -0
  251. package/lib/module/utils/polyfills.js +36 -0
  252. package/lib/module/utils/polyfills.js.map +1 -0
  253. package/lib/typescript/assets/icons/OxyServices.d.ts +29 -0
  254. package/lib/typescript/assets/icons/OxyServices.d.ts.map +1 -0
  255. package/lib/typescript/constants/version.d.ts +14 -0
  256. package/lib/typescript/constants/version.d.ts.map +1 -0
  257. package/lib/typescript/core/index.d.ts +603 -0
  258. package/lib/typescript/core/index.d.ts.map +1 -0
  259. package/lib/typescript/index.d.ts +20 -0
  260. package/lib/typescript/index.d.ts.map +1 -0
  261. package/lib/typescript/lib/sonner.d.ts +6 -0
  262. package/lib/typescript/lib/sonner.d.ts.map +1 -0
  263. package/lib/typescript/models/interfaces.d.ts +179 -0
  264. package/lib/typescript/models/interfaces.d.ts.map +1 -0
  265. package/lib/typescript/models/secureSession.d.ts +27 -0
  266. package/lib/typescript/models/secureSession.d.ts.map +1 -0
  267. package/lib/typescript/node/index.d.ts +11 -0
  268. package/lib/typescript/node/index.d.ts.map +1 -0
  269. package/lib/typescript/ui/components/Avatar.d.ts +62 -0
  270. package/lib/typescript/ui/components/Avatar.d.ts.map +1 -0
  271. package/lib/typescript/ui/components/FollowButton.d.ts +92 -0
  272. package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -0
  273. package/lib/typescript/ui/components/FontLoader.d.ts +15 -0
  274. package/lib/typescript/ui/components/FontLoader.d.ts.map +1 -0
  275. package/lib/typescript/ui/components/GroupedItem.d.ts +17 -0
  276. package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -0
  277. package/lib/typescript/ui/components/GroupedSection.d.ts +19 -0
  278. package/lib/typescript/ui/components/GroupedSection.d.ts.map +1 -0
  279. package/lib/typescript/ui/components/OxyLogo.d.ts +29 -0
  280. package/lib/typescript/ui/components/OxyLogo.d.ts.map +1 -0
  281. package/lib/typescript/ui/components/OxyProvider.d.ts +12 -0
  282. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -0
  283. package/lib/typescript/ui/components/OxySignInButton.d.ts +70 -0
  284. package/lib/typescript/ui/components/OxySignInButton.d.ts.map +1 -0
  285. package/lib/typescript/ui/components/ProfileCard.d.ts +20 -0
  286. package/lib/typescript/ui/components/ProfileCard.d.ts.map +1 -0
  287. package/lib/typescript/ui/components/QuickActions.d.ts +15 -0
  288. package/lib/typescript/ui/components/QuickActions.d.ts.map +1 -0
  289. package/lib/typescript/ui/components/Section.d.ts +11 -0
  290. package/lib/typescript/ui/components/Section.d.ts.map +1 -0
  291. package/lib/typescript/ui/components/SectionTitle.d.ts +9 -0
  292. package/lib/typescript/ui/components/SectionTitle.d.ts.map +1 -0
  293. package/lib/typescript/ui/components/bottomSheet/index.d.ts +4 -0
  294. package/lib/typescript/ui/components/bottomSheet/index.d.ts.map +1 -0
  295. package/lib/typescript/ui/components/icon/OxyIcon.d.ts +10 -0
  296. package/lib/typescript/ui/components/icon/OxyIcon.d.ts.map +1 -0
  297. package/lib/typescript/ui/components/icon/index.d.ts +3 -0
  298. package/lib/typescript/ui/components/icon/index.d.ts.map +1 -0
  299. package/lib/typescript/ui/components/index.d.ts +13 -0
  300. package/lib/typescript/ui/components/index.d.ts.map +1 -0
  301. package/lib/typescript/ui/context/OxyContext.d.ts +42 -0
  302. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -0
  303. package/lib/typescript/ui/index.d.ts +15 -0
  304. package/lib/typescript/ui/index.d.ts.map +1 -0
  305. package/lib/typescript/ui/navigation/OxyRouter.d.ts +5 -0
  306. package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -0
  307. package/lib/typescript/ui/navigation/types.d.ts +116 -0
  308. package/lib/typescript/ui/navigation/types.d.ts.map +1 -0
  309. package/lib/typescript/ui/screens/AccountCenterScreen.d.ts +5 -0
  310. package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -0
  311. package/lib/typescript/ui/screens/AccountManagementDemo.d.ts +8 -0
  312. package/lib/typescript/ui/screens/AccountManagementDemo.d.ts.map +1 -0
  313. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts +5 -0
  314. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -0
  315. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts +5 -0
  316. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -0
  317. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts +5 -0
  318. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -0
  319. package/lib/typescript/ui/screens/AppInfoScreen.d.ts +5 -0
  320. package/lib/typescript/ui/screens/AppInfoScreen.d.ts.map +1 -0
  321. package/lib/typescript/ui/screens/BillingManagementScreen.d.ts +5 -0
  322. package/lib/typescript/ui/screens/BillingManagementScreen.d.ts.map +1 -0
  323. package/lib/typescript/ui/screens/FileManagementScreen.d.ts +8 -0
  324. package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -0
  325. package/lib/typescript/ui/screens/PremiumSubscriptionScreen.d.ts +5 -0
  326. package/lib/typescript/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -0
  327. package/lib/typescript/ui/screens/ProfileScreen.d.ts +9 -0
  328. package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -0
  329. package/lib/typescript/ui/screens/SessionManagementScreen.d.ts +5 -0
  330. package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -0
  331. package/lib/typescript/ui/screens/SignInScreen.d.ts +5 -0
  332. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -0
  333. package/lib/typescript/ui/screens/SignUpScreen.d.ts +5 -0
  334. package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -0
  335. package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts +5 -0
  336. package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts.map +1 -0
  337. package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts +5 -0
  338. package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts.map +1 -0
  339. package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts +5 -0
  340. package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts.map +1 -0
  341. package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts +5 -0
  342. package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +1 -0
  343. package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts +5 -0
  344. package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -0
  345. package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts +5 -0
  346. package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts.map +1 -0
  347. package/lib/typescript/ui/styles/fonts.d.ts +21 -0
  348. package/lib/typescript/ui/styles/fonts.d.ts.map +1 -0
  349. package/lib/typescript/ui/styles/index.d.ts +3 -0
  350. package/lib/typescript/ui/styles/index.d.ts.map +1 -0
  351. package/lib/typescript/ui/styles/theme.d.ts +68 -0
  352. package/lib/typescript/ui/styles/theme.d.ts.map +1 -0
  353. package/lib/typescript/utils/deviceManager.d.ts +66 -0
  354. package/lib/typescript/utils/deviceManager.d.ts.map +1 -0
  355. package/lib/typescript/utils/index.d.ts +3 -0
  356. package/lib/typescript/utils/index.d.ts.map +1 -0
  357. package/lib/typescript/utils/polyfills.d.ts +6 -0
  358. package/lib/typescript/utils/polyfills.d.ts.map +1 -0
  359. package/package.json +20 -4
@@ -0,0 +1,2515 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _OxyContext = require("../context/OxyContext.js");
10
+ var _fonts = require("../styles/fonts.js");
11
+ var _sonner = require("../../lib/sonner.js");
12
+ var _vectorIcons = require("@expo/vector-icons");
13
+ var _jsxRuntime = require("react/jsx-runtime");
14
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
15
+ const FileManagementScreen = ({
16
+ onClose,
17
+ theme,
18
+ goBack,
19
+ navigate,
20
+ userId,
21
+ containerWidth = 400 // Fallback for when not provided by the router
22
+ }) => {
23
+ const {
24
+ user,
25
+ oxyServices
26
+ } = (0, _OxyContext.useOxy)();
27
+
28
+ // Debug: log the actual container width
29
+ (0, _react.useEffect)(() => {
30
+ console.log('[FileManagementScreen] Container width (full):', containerWidth);
31
+ // Padding structure:
32
+ // - containerWidth = full bottom sheet container width (measured from OxyProvider)
33
+ // - photoScrollContainer adds padding: 16 (32px total horizontal padding)
34
+ // - Available content width = containerWidth - 32
35
+ const availableContentWidth = containerWidth - 32;
36
+ console.log('[FileManagementScreen] Available content width:', availableContentWidth);
37
+ console.log('[FileManagementScreen] Spacing fix applied: 4px uniform gap both horizontal and vertical');
38
+ }, [containerWidth]);
39
+ const [files, setFiles] = (0, _react.useState)([]);
40
+ const [loading, setLoading] = (0, _react.useState)(true);
41
+ const [refreshing, setRefreshing] = (0, _react.useState)(false);
42
+ const [uploading, setUploading] = (0, _react.useState)(false);
43
+ const [uploadProgress, setUploadProgress] = (0, _react.useState)(null);
44
+ const [deleting, setDeleting] = (0, _react.useState)(null);
45
+ const [selectedFile, setSelectedFile] = (0, _react.useState)(null);
46
+ const [showFileDetails, setShowFileDetails] = (0, _react.useState)(false);
47
+ const [openedFile, setOpenedFile] = (0, _react.useState)(null);
48
+ const [fileContent, setFileContent] = (0, _react.useState)(null);
49
+ const [loadingFileContent, setLoadingFileContent] = (0, _react.useState)(false);
50
+ const [showFileDetailsInViewer, setShowFileDetailsInViewer] = (0, _react.useState)(false);
51
+ const [viewMode, setViewMode] = (0, _react.useState)('all');
52
+ const [searchQuery, setSearchQuery] = (0, _react.useState)('');
53
+ const [filteredFiles, setFilteredFiles] = (0, _react.useState)([]);
54
+ const [isDragging, setIsDragging] = (0, _react.useState)(false);
55
+ const [photoDimensions, setPhotoDimensions] = (0, _react.useState)({});
56
+ const [loadingDimensions, setLoadingDimensions] = (0, _react.useState)(false);
57
+ const [hoveredPreview, setHoveredPreview] = (0, _react.useState)(null);
58
+
59
+ // Memoize theme-related calculations to prevent unnecessary recalculations
60
+ const themeStyles = (0, _react.useMemo)(() => {
61
+ const isDarkTheme = theme === 'dark';
62
+ return {
63
+ isDarkTheme,
64
+ textColor: isDarkTheme ? '#FFFFFF' : '#000000',
65
+ backgroundColor: isDarkTheme ? '#121212' : '#f2f2f2',
66
+ secondaryBackgroundColor: isDarkTheme ? '#222222' : '#FFFFFF',
67
+ borderColor: isDarkTheme ? '#444444' : '#E0E0E0',
68
+ primaryColor: '#007AFF',
69
+ dangerColor: '#FF3B30',
70
+ successColor: '#34C759'
71
+ };
72
+ }, [theme]);
73
+
74
+ // Extract commonly used theme variables
75
+ const backgroundColor = themeStyles.backgroundColor;
76
+ const borderColor = themeStyles.borderColor;
77
+ const targetUserId = userId || user?.id;
78
+ const loadFiles = (0, _react.useCallback)(async (isRefresh = false) => {
79
+ if (!targetUserId) return;
80
+ try {
81
+ if (isRefresh) {
82
+ setRefreshing(true);
83
+ } else {
84
+ setLoading(true);
85
+ }
86
+ const response = await oxyServices.listUserFiles(targetUserId);
87
+ setFiles(response.files || []);
88
+ } catch (error) {
89
+ console.error('Failed to load files:', error);
90
+ _sonner.toast.error(error.message || 'Failed to load files');
91
+ } finally {
92
+ setLoading(false);
93
+ setRefreshing(false);
94
+ }
95
+ }, [targetUserId, oxyServices]);
96
+
97
+ // Filter files based on search query and view mode
98
+ (0, _react.useEffect)(() => {
99
+ let filteredByMode = files;
100
+
101
+ // Filter by view mode first
102
+ if (viewMode === 'photos') {
103
+ filteredByMode = files.filter(file => file.contentType.startsWith('image/'));
104
+ }
105
+
106
+ // Then filter by search query
107
+ if (!searchQuery.trim()) {
108
+ setFilteredFiles(filteredByMode);
109
+ } else {
110
+ const query = searchQuery.toLowerCase();
111
+ const filtered = filteredByMode.filter(file => file.filename.toLowerCase().includes(query) || file.contentType.toLowerCase().includes(query) || file.metadata?.description && file.metadata.description.toLowerCase().includes(query));
112
+ setFilteredFiles(filtered);
113
+ }
114
+ }, [files, searchQuery, viewMode]);
115
+
116
+ // Load photo dimensions for justified grid
117
+ const loadPhotoDimensions = (0, _react.useCallback)(async photos => {
118
+ if (photos.length === 0) return;
119
+ setLoadingDimensions(true);
120
+ const newDimensions = {
121
+ ...photoDimensions
122
+ };
123
+ let hasNewDimensions = false;
124
+
125
+ // Only load dimensions for photos we don't have yet
126
+ const photosToLoad = photos.filter(photo => !newDimensions[photo.id]);
127
+ if (photosToLoad.length === 0) {
128
+ setLoadingDimensions(false);
129
+ return;
130
+ }
131
+ try {
132
+ await Promise.all(photosToLoad.map(async photo => {
133
+ try {
134
+ const downloadUrl = oxyServices.getFileDownloadUrl(photo.id);
135
+ if (_reactNative.Platform.OS === 'web') {
136
+ const img = new window.Image();
137
+ await new Promise((resolve, reject) => {
138
+ img.onload = () => {
139
+ newDimensions[photo.id] = {
140
+ width: img.naturalWidth,
141
+ height: img.naturalHeight
142
+ };
143
+ hasNewDimensions = true;
144
+ resolve();
145
+ };
146
+ img.onerror = () => {
147
+ // Fallback dimensions for failed loads
148
+ newDimensions[photo.id] = {
149
+ width: 1,
150
+ height: 1
151
+ };
152
+ hasNewDimensions = true;
153
+ resolve();
154
+ };
155
+ img.src = downloadUrl;
156
+ });
157
+ } else {
158
+ // For mobile, use Image.getSize from react-native
159
+ await new Promise(resolve => {
160
+ _reactNative.Image.getSize(downloadUrl, (width, height) => {
161
+ newDimensions[photo.id] = {
162
+ width,
163
+ height
164
+ };
165
+ hasNewDimensions = true;
166
+ resolve();
167
+ }, () => {
168
+ // Fallback dimensions
169
+ newDimensions[photo.id] = {
170
+ width: 1,
171
+ height: 1
172
+ };
173
+ hasNewDimensions = true;
174
+ resolve();
175
+ });
176
+ });
177
+ }
178
+ } catch (error) {
179
+ // Fallback dimensions for any errors
180
+ newDimensions[photo.id] = {
181
+ width: 1,
182
+ height: 1
183
+ };
184
+ hasNewDimensions = true;
185
+ }
186
+ }));
187
+ if (hasNewDimensions) {
188
+ setPhotoDimensions(newDimensions);
189
+ }
190
+ } catch (error) {
191
+ console.error('Error loading photo dimensions:', error);
192
+ } finally {
193
+ setLoadingDimensions(false);
194
+ }
195
+ }, [oxyServices, photoDimensions]);
196
+
197
+ // Create justified rows from photos with responsive algorithm
198
+ const createJustifiedRows = (0, _react.useCallback)((photos, containerWidth) => {
199
+ if (photos.length === 0) return [];
200
+ const rows = [];
201
+ const photosPerRow = 3; // Fixed 3 photos per row for consistency
202
+
203
+ for (let i = 0; i < photos.length; i += photosPerRow) {
204
+ const rowPhotos = photos.slice(i, i + photosPerRow);
205
+ rows.push(rowPhotos);
206
+ }
207
+ return rows;
208
+ }, []);
209
+ const processFileUploads = async selectedFiles => {
210
+ if (selectedFiles.length === 0) return;
211
+ try {
212
+ // Show initial progress
213
+ setUploadProgress({
214
+ current: 0,
215
+ total: selectedFiles.length
216
+ });
217
+
218
+ // Validate file sizes (example: 50MB limit per file)
219
+ const maxSize = 50 * 1024 * 1024; // 50MB
220
+ const oversizedFiles = selectedFiles.filter(file => file.size > maxSize);
221
+ if (oversizedFiles.length > 0) {
222
+ const fileList = oversizedFiles.map(f => f.name).join('\n');
223
+ window.alert(`File Size Limit\n\nThe following files are too large (max 50MB):\n${fileList}`);
224
+ return;
225
+ }
226
+
227
+ // Option 1: Bulk upload (faster, all-or-nothing) for 5 or fewer files
228
+ if (selectedFiles.length <= 5) {
229
+ const filenames = selectedFiles.map(f => f.name);
230
+ const response = await oxyServices.uploadFiles(selectedFiles, filenames, {
231
+ userId: targetUserId,
232
+ uploadDate: new Date().toISOString()
233
+ });
234
+ _sonner.toast.success(`${response.files.length} file(s) uploaded successfully`);
235
+ // Small delay to ensure backend processing is complete
236
+ setTimeout(async () => {
237
+ await loadFiles();
238
+ }, 500);
239
+ } else {
240
+ // Option 2: Individual uploads for better progress and error handling
241
+ let successCount = 0;
242
+ let failureCount = 0;
243
+ const errors = [];
244
+ for (let i = 0; i < selectedFiles.length; i++) {
245
+ const file = selectedFiles[i];
246
+ setUploadProgress({
247
+ current: i + 1,
248
+ total: selectedFiles.length
249
+ });
250
+ try {
251
+ await oxyServices.uploadFile(file, file.name, {
252
+ userId: targetUserId,
253
+ uploadDate: new Date().toISOString()
254
+ });
255
+ successCount++;
256
+ } catch (error) {
257
+ failureCount++;
258
+ errors.push(`${file.name}: ${error.message || 'Upload failed'}`);
259
+ }
260
+ }
261
+
262
+ // Show results summary
263
+ if (successCount > 0) {
264
+ _sonner.toast.success(`${successCount} file(s) uploaded successfully`);
265
+ }
266
+ if (failureCount > 0) {
267
+ const errorMessage = `${failureCount} file(s) failed to upload${errors.length > 0 ? ':\n' + errors.slice(0, 3).join('\n') + (errors.length > 3 ? '\n...' : '') : ''}`;
268
+ _sonner.toast.error(errorMessage);
269
+ }
270
+
271
+ // Small delay to ensure backend processing is complete
272
+ setTimeout(async () => {
273
+ await loadFiles();
274
+ }, 500);
275
+ }
276
+ } catch (error) {
277
+ console.error('Upload error:', error);
278
+ _sonner.toast.error(error.message || 'Failed to upload files');
279
+ } finally {
280
+ setUploadProgress(null);
281
+ }
282
+ };
283
+ const handleFileUpload = async () => {
284
+ try {
285
+ setUploading(true);
286
+ setUploadProgress(null);
287
+ if (_reactNative.Platform.OS === 'web') {
288
+ // Web file picker implementation
289
+ const input = document.createElement('input');
290
+ input.type = 'file';
291
+ input.multiple = true;
292
+ input.accept = '*/*';
293
+ input.onchange = async e => {
294
+ const selectedFiles = Array.from(e.target.files);
295
+ await processFileUploads(selectedFiles);
296
+ };
297
+ input.click();
298
+ } else {
299
+ // Mobile - show info that file picker can be added
300
+ const installCommand = 'npm install expo-document-picker';
301
+ const message = `Mobile File Upload\n\nTo enable file uploads on mobile, install expo-document-picker:\n\n${installCommand}\n\nThen import and use DocumentPicker.getDocumentAsync() in this method.`;
302
+ if (window.confirm(`${message}\n\nWould you like to copy the install command?`)) {
303
+ _sonner.toast.info(`Install: ${installCommand}`);
304
+ } else {
305
+ _sonner.toast.info('Mobile file upload requires expo-document-picker');
306
+ }
307
+ }
308
+ } catch (error) {
309
+ _sonner.toast.error(error.message || 'Failed to upload file');
310
+ } finally {
311
+ setUploading(false);
312
+ setUploadProgress(null);
313
+ }
314
+ };
315
+ const handleFileDelete = async (fileId, filename) => {
316
+ // Use web-compatible confirmation dialog
317
+ const confirmed = window.confirm(`Are you sure you want to delete "${filename}"? This action cannot be undone.`);
318
+ if (!confirmed) {
319
+ console.log('Delete cancelled by user');
320
+ return;
321
+ }
322
+ try {
323
+ console.log('Deleting file:', {
324
+ fileId,
325
+ filename
326
+ });
327
+ console.log('Target user ID:', targetUserId);
328
+ console.log('Current user ID:', user?.id);
329
+ setDeleting(fileId);
330
+ const result = await oxyServices.deleteFile(fileId);
331
+ console.log('Delete result:', result);
332
+ _sonner.toast.success('File deleted successfully');
333
+
334
+ // Reload files after successful deletion
335
+ setTimeout(async () => {
336
+ await loadFiles();
337
+ }, 500);
338
+ } catch (error) {
339
+ console.error('Delete error:', error);
340
+ console.error('Error details:', error.response?.data || error.message);
341
+
342
+ // Provide specific error messages
343
+ if (error.message?.includes('File not found') || error.message?.includes('404')) {
344
+ _sonner.toast.error('File not found. It may have already been deleted.');
345
+ // Still reload files to refresh the list
346
+ setTimeout(async () => {
347
+ await loadFiles();
348
+ }, 500);
349
+ } else if (error.message?.includes('permission') || error.message?.includes('403')) {
350
+ _sonner.toast.error('You do not have permission to delete this file.');
351
+ } else {
352
+ _sonner.toast.error(error.message || 'Failed to delete file');
353
+ }
354
+ } finally {
355
+ setDeleting(null);
356
+ }
357
+ };
358
+
359
+ // Drag and drop handlers for web
360
+ const handleDragOver = e => {
361
+ if (_reactNative.Platform.OS === 'web' && user?.id === targetUserId) {
362
+ e.preventDefault();
363
+ setIsDragging(true);
364
+ }
365
+ };
366
+ const handleDragLeave = e => {
367
+ if (_reactNative.Platform.OS === 'web') {
368
+ e.preventDefault();
369
+ setIsDragging(false);
370
+ }
371
+ };
372
+ const handleDrop = async e => {
373
+ if (_reactNative.Platform.OS === 'web' && user?.id === targetUserId) {
374
+ e.preventDefault();
375
+ setIsDragging(false);
376
+ setUploading(true);
377
+ try {
378
+ const files = Array.from(e.dataTransfer.files);
379
+ await processFileUploads(files);
380
+ } catch (error) {
381
+ _sonner.toast.error(error.message || 'Failed to upload files');
382
+ } finally {
383
+ setUploading(false);
384
+ }
385
+ }
386
+ };
387
+ const handleFileDownload = async (fileId, filename) => {
388
+ try {
389
+ if (_reactNative.Platform.OS === 'web') {
390
+ console.log('Downloading file:', {
391
+ fileId,
392
+ filename
393
+ });
394
+
395
+ // Use the public download URL method
396
+ const downloadUrl = oxyServices.getFileDownloadUrl(fileId);
397
+ console.log('Download URL:', downloadUrl);
398
+ try {
399
+ // Method 1: Try simple link download first
400
+ const link = document.createElement('a');
401
+ link.href = downloadUrl;
402
+ link.download = filename;
403
+ link.target = '_blank';
404
+ document.body.appendChild(link);
405
+ link.click();
406
+ document.body.removeChild(link);
407
+ _sonner.toast.success('File download started');
408
+ } catch (linkError) {
409
+ console.warn('Link download failed, trying fetch method:', linkError);
410
+
411
+ // Method 2: Fallback to fetch download
412
+ const response = await fetch(downloadUrl);
413
+ if (!response.ok) {
414
+ if (response.status === 404) {
415
+ throw new Error('File not found. It may have been deleted.');
416
+ } else {
417
+ throw new Error(`Download failed: ${response.status} ${response.statusText}`);
418
+ }
419
+ }
420
+ const blob = await response.blob();
421
+ const url = window.URL.createObjectURL(blob);
422
+ const link = document.createElement('a');
423
+ link.href = url;
424
+ link.download = filename;
425
+ document.body.appendChild(link);
426
+ link.click();
427
+ document.body.removeChild(link);
428
+
429
+ // Clean up the blob URL
430
+ window.URL.revokeObjectURL(url);
431
+ _sonner.toast.success('File downloaded successfully');
432
+ }
433
+ } else {
434
+ _sonner.toast.info('File download not implemented for mobile yet');
435
+ }
436
+ } catch (error) {
437
+ console.error('Download error:', error);
438
+ _sonner.toast.error(error.message || 'Failed to download file');
439
+ }
440
+ };
441
+ const formatFileSize = bytes => {
442
+ if (bytes === 0) return '0 Bytes';
443
+ const k = 1024;
444
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
445
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
446
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
447
+ };
448
+ const getFileIcon = contentType => {
449
+ if (contentType.startsWith('image/')) return 'image';
450
+ if (contentType.startsWith('video/')) return 'videocam';
451
+ if (contentType.startsWith('audio/')) return 'musical-notes';
452
+ if (contentType.includes('pdf')) return 'document-text';
453
+ if (contentType.includes('word') || contentType.includes('doc')) return 'document';
454
+ if (contentType.includes('excel') || contentType.includes('sheet')) return 'grid';
455
+ if (contentType.includes('zip') || contentType.includes('archive')) return 'archive';
456
+ return 'document-outline';
457
+ };
458
+ const handleFileOpen = async file => {
459
+ try {
460
+ setLoadingFileContent(true);
461
+ setOpenedFile(file);
462
+
463
+ // For text files, images, and other viewable content, try to load the content
464
+ if (file.contentType.startsWith('text/') || file.contentType.includes('json') || file.contentType.includes('xml') || file.contentType.includes('javascript') || file.contentType.includes('typescript') || file.contentType.startsWith('image/') || file.contentType.includes('pdf') || file.contentType.startsWith('video/') || file.contentType.startsWith('audio/')) {
465
+ try {
466
+ const downloadUrl = oxyServices.getFileDownloadUrl(file.id);
467
+ const response = await fetch(downloadUrl);
468
+ if (response.ok) {
469
+ if (file.contentType.startsWith('image/') || file.contentType.includes('pdf') || file.contentType.startsWith('video/') || file.contentType.startsWith('audio/')) {
470
+ // For images, PDFs, videos, and audio, we'll use the URL directly
471
+ setFileContent(downloadUrl);
472
+ } else {
473
+ // For text files, get the content
474
+ const content = await response.text();
475
+ setFileContent(content);
476
+ }
477
+ } else {
478
+ if (response.status === 404) {
479
+ _sonner.toast.error('File not found. It may have been deleted.');
480
+ } else {
481
+ _sonner.toast.error(`Failed to load file: ${response.status} ${response.statusText}`);
482
+ }
483
+ setFileContent(null);
484
+ }
485
+ } catch (error) {
486
+ console.error('Failed to load file content:', error);
487
+ if (error.message?.includes('404') || error.message?.includes('not found')) {
488
+ _sonner.toast.error('File not found. It may have been deleted.');
489
+ } else {
490
+ _sonner.toast.error('Failed to load file content');
491
+ }
492
+ setFileContent(null);
493
+ }
494
+ } else {
495
+ // For non-viewable files, don't load content
496
+ setFileContent(null);
497
+ }
498
+ } catch (error) {
499
+ console.error('Failed to open file:', error);
500
+ _sonner.toast.error(error.message || 'Failed to open file');
501
+ } finally {
502
+ setLoadingFileContent(false);
503
+ }
504
+ };
505
+ const handleCloseFile = () => {
506
+ setOpenedFile(null);
507
+ setFileContent(null);
508
+ setShowFileDetailsInViewer(false);
509
+ // Don't reset view mode when closing a file
510
+ };
511
+ const showFileDetailsModal = file => {
512
+ setSelectedFile(file);
513
+ setShowFileDetails(true);
514
+ };
515
+ const renderSimplePhotoItem = (0, _react.useCallback)((photo, index) => {
516
+ const downloadUrl = oxyServices.getFileDownloadUrl(photo.id);
517
+
518
+ // Calculate photo item width based on actual container size from bottom sheet
519
+ let itemsPerRow = 3; // Default for mobile
520
+ if (containerWidth > 768) itemsPerRow = 4; // Desktop/tablet
521
+ else if (containerWidth > 480) itemsPerRow = 3; // Large mobile
522
+
523
+ // Account for the photoScrollContainer padding (16px on each side = 32px total)
524
+ const scrollContainerPadding = 32; // Total horizontal padding from photoScrollContainer
525
+ const gaps = (itemsPerRow - 1) * 4; // Gap between items (4px)
526
+ const availableWidth = containerWidth - scrollContainerPadding;
527
+ const itemWidth = (availableWidth - gaps) / itemsPerRow;
528
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
529
+ style: [styles.simplePhotoItem, {
530
+ width: itemWidth,
531
+ height: itemWidth,
532
+ marginRight: (index + 1) % itemsPerRow === 0 ? 0 : 4
533
+ }],
534
+ onPress: () => handleFileOpen(photo),
535
+ activeOpacity: 0.8,
536
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
537
+ style: styles.simplePhotoContainer,
538
+ children: _reactNative.Platform.OS === 'web' ? /*#__PURE__*/(0, _jsxRuntime.jsx)("img", {
539
+ src: downloadUrl,
540
+ alt: photo.filename,
541
+ style: {
542
+ width: '100%',
543
+ height: '100%',
544
+ objectFit: 'cover',
545
+ borderRadius: 8,
546
+ transition: 'transform 0.2s ease'
547
+ },
548
+ loading: "lazy",
549
+ onError: e => {
550
+ console.error('Photo failed to load:', e);
551
+ },
552
+ onMouseEnter: e => {
553
+ e.currentTarget.style.transform = 'scale(1.05)';
554
+ },
555
+ onMouseLeave: e => {
556
+ e.currentTarget.style.transform = 'scale(1)';
557
+ }
558
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
559
+ source: {
560
+ uri: downloadUrl
561
+ },
562
+ style: styles.simplePhotoImage,
563
+ resizeMode: "cover",
564
+ onError: e => {
565
+ console.error('Photo failed to load:', e);
566
+ }
567
+ })
568
+ })
569
+ }, photo.id);
570
+ }, [oxyServices, containerWidth]);
571
+ const renderJustifiedPhotoItem = (0, _react.useCallback)((photo, width, height, isLast) => {
572
+ const downloadUrl = oxyServices.getFileDownloadUrl(photo.id);
573
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
574
+ style: [styles.justifiedPhotoItem, {
575
+ width,
576
+ height
577
+ }],
578
+ onPress: () => handleFileOpen(photo),
579
+ activeOpacity: 0.8,
580
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
581
+ style: styles.justifiedPhotoContainer,
582
+ children: _reactNative.Platform.OS === 'web' ? /*#__PURE__*/(0, _jsxRuntime.jsx)("img", {
583
+ src: downloadUrl,
584
+ alt: photo.filename,
585
+ style: {
586
+ width: '100%',
587
+ height: '100%',
588
+ objectFit: 'cover',
589
+ borderRadius: 6,
590
+ transition: 'transform 0.2s ease, box-shadow 0.2s ease'
591
+ },
592
+ loading: "lazy",
593
+ onError: e => {
594
+ console.error('Photo failed to load:', e);
595
+ },
596
+ onMouseEnter: e => {
597
+ e.currentTarget.style.transform = 'scale(1.02)';
598
+ e.currentTarget.style.boxShadow = '0 8px 25px rgba(0,0,0,0.15)';
599
+ e.currentTarget.style.zIndex = '10';
600
+ },
601
+ onMouseLeave: e => {
602
+ e.currentTarget.style.transform = 'scale(1)';
603
+ e.currentTarget.style.boxShadow = '0 2px 8px rgba(0,0,0,0.1)';
604
+ e.currentTarget.style.zIndex = '1';
605
+ }
606
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
607
+ source: {
608
+ uri: downloadUrl
609
+ },
610
+ style: styles.justifiedPhotoImage,
611
+ resizeMode: "cover",
612
+ onError: e => {
613
+ console.error('Photo failed to load:', e);
614
+ }
615
+ })
616
+ })
617
+ }, photo.id);
618
+ }, [oxyServices]);
619
+ (0, _react.useEffect)(() => {
620
+ loadFiles();
621
+ }, [loadFiles]);
622
+ const renderFileItem = file => {
623
+ const isImage = file.contentType.startsWith('image/');
624
+ const isPDF = file.contentType.includes('pdf');
625
+ const isVideo = file.contentType.startsWith('video/');
626
+ const isAudio = file.contentType.startsWith('audio/');
627
+ const hasPreview = isImage || isPDF || isVideo;
628
+ const borderColor = themeStyles.borderColor;
629
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
630
+ style: [styles.fileItem, {
631
+ backgroundColor: themeStyles.secondaryBackgroundColor,
632
+ borderColor
633
+ }],
634
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
635
+ style: styles.fileContent,
636
+ onPress: () => handleFileOpen(file),
637
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
638
+ style: styles.filePreviewContainer,
639
+ children: hasPreview ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
640
+ style: styles.filePreview,
641
+ ...(_reactNative.Platform.OS === 'web' && {
642
+ onMouseEnter: () => setHoveredPreview(file.id),
643
+ onMouseLeave: () => setHoveredPreview(null)
644
+ }),
645
+ children: [isImage && (_reactNative.Platform.OS === 'web' ? /*#__PURE__*/(0, _jsxRuntime.jsx)("img", {
646
+ src: oxyServices.getFileDownloadUrl(file.id),
647
+ style: {
648
+ width: '100%',
649
+ height: '100%',
650
+ objectFit: 'cover',
651
+ borderRadius: 8,
652
+ transition: 'transform 0.2s ease',
653
+ transform: hoveredPreview === file.id ? 'scale(1.05)' : 'scale(1)'
654
+ },
655
+ onError: e => {
656
+ // Show fallback icon if image fails to load
657
+ e.currentTarget.style.display = 'none';
658
+ const fallbackElement = e.currentTarget.parentElement?.querySelector('[data-fallback="true"]');
659
+ if (fallbackElement) {
660
+ fallbackElement.style.display = 'flex';
661
+ }
662
+ }
663
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
664
+ source: {
665
+ uri: oxyServices.getFileDownloadUrl(file.id)
666
+ },
667
+ style: styles.previewImage,
668
+ resizeMode: "cover",
669
+ onError: () => {
670
+ // For React Native, you might want to set an error state
671
+ console.warn('Failed to load image preview for file:', file.id);
672
+ }
673
+ })), isPDF && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
674
+ style: styles.pdfPreview,
675
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
676
+ name: "document",
677
+ size: 32,
678
+ color: themeStyles.primaryColor
679
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
680
+ style: [styles.pdfLabel, {
681
+ color: themeStyles.primaryColor
682
+ }],
683
+ children: "PDF"
684
+ })]
685
+ }), isVideo && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
686
+ style: styles.videoPreview,
687
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
688
+ name: "play-circle",
689
+ size: 32,
690
+ color: themeStyles.primaryColor
691
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
692
+ style: [styles.videoLabel, {
693
+ color: themeStyles.primaryColor
694
+ }],
695
+ children: "VIDEO"
696
+ })]
697
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
698
+ style: [styles.fallbackIcon, {
699
+ display: isImage ? 'none' : 'flex'
700
+ }],
701
+ ...(_reactNative.Platform.OS === 'web' && {
702
+ 'data-fallback': 'true'
703
+ }),
704
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
705
+ name: getFileIcon(file.contentType),
706
+ size: 32,
707
+ color: themeStyles.primaryColor
708
+ })
709
+ }), _reactNative.Platform.OS === 'web' && hoveredPreview === file.id && isImage && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
710
+ style: styles.previewOverlay,
711
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
712
+ name: "eye",
713
+ size: 24,
714
+ color: "#FFFFFF"
715
+ })
716
+ })]
717
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
718
+ style: styles.fileIconContainer,
719
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
720
+ name: getFileIcon(file.contentType),
721
+ size: 32,
722
+ color: themeStyles.primaryColor
723
+ })
724
+ })
725
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
726
+ style: styles.fileInfo,
727
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
728
+ style: [styles.fileName, {
729
+ color: themeStyles.textColor
730
+ }],
731
+ numberOfLines: 1,
732
+ children: file.filename
733
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
734
+ style: [styles.fileDetails, {
735
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
736
+ }],
737
+ children: [formatFileSize(file.length), " \u2022 ", new Date(file.uploadDate).toLocaleDateString()]
738
+ }), file.metadata?.description && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
739
+ style: [styles.fileDescription, {
740
+ color: themeStyles.isDarkTheme ? '#AAAAAA' : '#888888'
741
+ }],
742
+ numberOfLines: 2,
743
+ children: file.metadata.description
744
+ })]
745
+ })]
746
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
747
+ style: styles.fileActions,
748
+ children: [hasPreview && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
749
+ style: [styles.actionButton, {
750
+ backgroundColor: themeStyles.isDarkTheme ? '#333333' : '#F0F0F0'
751
+ }],
752
+ onPress: () => handleFileOpen(file),
753
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
754
+ name: "eye",
755
+ size: 20,
756
+ color: themeStyles.primaryColor
757
+ })
758
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
759
+ style: [styles.actionButton, {
760
+ backgroundColor: themeStyles.isDarkTheme ? '#333333' : '#F0F0F0'
761
+ }],
762
+ onPress: () => handleFileDownload(file.id, file.filename),
763
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
764
+ name: "download",
765
+ size: 20,
766
+ color: themeStyles.primaryColor
767
+ })
768
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
769
+ style: [styles.actionButton, {
770
+ backgroundColor: themeStyles.isDarkTheme ? '#400000' : '#FFEBEE'
771
+ }],
772
+ onPress: () => {
773
+ handleFileDelete(file.id, file.filename);
774
+ },
775
+ disabled: deleting === file.id,
776
+ children: deleting === file.id ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
777
+ size: "small",
778
+ color: themeStyles.dangerColor
779
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
780
+ name: "trash",
781
+ size: 20,
782
+ color: themeStyles.dangerColor
783
+ })
784
+ })]
785
+ })]
786
+ }, file.id);
787
+ };
788
+ const renderPhotoItem = (photo, index) => {
789
+ const downloadUrl = oxyServices.getFileDownloadUrl(photo.id);
790
+
791
+ // Calculate photo item width based on actual container size from bottom sheet
792
+ let itemsPerRow = 3; // Default for mobile
793
+ if (containerWidth > 768) itemsPerRow = 6; // Tablet/Desktop
794
+ else if (containerWidth > 480) itemsPerRow = 4; // Large mobile
795
+
796
+ // Account for the photoScrollContainer padding (16px on each side = 32px total)
797
+ const scrollContainerPadding = 32; // Total horizontal padding from photoScrollContainer
798
+ const gaps = (itemsPerRow - 1) * 4; // Gap between items
799
+ const availableWidth = containerWidth - scrollContainerPadding;
800
+ const itemWidth = (availableWidth - gaps) / itemsPerRow;
801
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
802
+ style: [styles.photoItem, {
803
+ width: itemWidth,
804
+ height: itemWidth
805
+ }],
806
+ onPress: () => handleFileOpen(photo),
807
+ activeOpacity: 0.8,
808
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
809
+ style: styles.photoContainer,
810
+ children: _reactNative.Platform.OS === 'web' ? /*#__PURE__*/(0, _jsxRuntime.jsx)("img", {
811
+ src: downloadUrl,
812
+ alt: photo.filename,
813
+ style: {
814
+ width: '100%',
815
+ height: '100%',
816
+ objectFit: 'cover',
817
+ borderRadius: 8,
818
+ transition: 'transform 0.2s ease'
819
+ },
820
+ loading: "lazy",
821
+ onError: e => {
822
+ console.error('Photo failed to load:', e);
823
+ // Could replace with placeholder image
824
+ },
825
+ onMouseEnter: e => {
826
+ e.currentTarget.style.transform = 'scale(1.02)';
827
+ },
828
+ onMouseLeave: e => {
829
+ e.currentTarget.style.transform = 'scale(1)';
830
+ }
831
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
832
+ source: {
833
+ uri: downloadUrl
834
+ },
835
+ style: styles.photoImage,
836
+ resizeMode: "cover",
837
+ onError: e => {
838
+ console.error('Photo failed to load:', e);
839
+ }
840
+ })
841
+ })
842
+ }, photo.id);
843
+ };
844
+ const renderPhotoGrid = (0, _react.useCallback)(() => {
845
+ const photos = filteredFiles.filter(file => file.contentType.startsWith('image/'));
846
+ if (photos.length === 0) {
847
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
848
+ style: styles.emptyState,
849
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
850
+ name: "images-outline",
851
+ size: 64,
852
+ color: themeStyles.isDarkTheme ? '#666666' : '#CCCCCC'
853
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
854
+ style: [styles.emptyStateTitle, {
855
+ color: themeStyles.textColor
856
+ }],
857
+ children: "No Photos Yet"
858
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
859
+ style: [styles.emptyStateDescription, {
860
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
861
+ }],
862
+ children: user?.id === targetUserId ? `Upload photos to get started. You can select multiple photos at once${_reactNative.Platform.OS === 'web' ? ' or drag & drop them here.' : '.'}` : "This user hasn't uploaded any photos yet"
863
+ }), user?.id === targetUserId && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
864
+ style: [styles.emptyStateButton, {
865
+ backgroundColor: themeStyles.primaryColor
866
+ }],
867
+ onPress: handleFileUpload,
868
+ disabled: uploading,
869
+ children: uploading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
870
+ size: "small",
871
+ color: "#FFFFFF"
872
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
873
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
874
+ name: "cloud-upload",
875
+ size: 20,
876
+ color: "#FFFFFF"
877
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
878
+ style: styles.emptyStateButtonText,
879
+ children: "Upload Photos"
880
+ })]
881
+ })
882
+ })]
883
+ });
884
+ }
885
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
886
+ style: styles.scrollView,
887
+ contentContainerStyle: styles.photoScrollContainer,
888
+ refreshControl: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.RefreshControl, {
889
+ refreshing: refreshing,
890
+ onRefresh: () => loadFiles(true),
891
+ tintColor: themeStyles.primaryColor
892
+ }),
893
+ showsVerticalScrollIndicator: false,
894
+ children: [loadingDimensions && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
895
+ style: styles.dimensionsLoadingIndicator,
896
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
897
+ size: "small",
898
+ color: themeStyles.primaryColor
899
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
900
+ style: [styles.dimensionsLoadingText, {
901
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
902
+ }],
903
+ children: "Loading photo layout..."
904
+ })]
905
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(JustifiedPhotoGrid, {
906
+ photos: photos,
907
+ photoDimensions: photoDimensions,
908
+ loadPhotoDimensions: loadPhotoDimensions,
909
+ createJustifiedRows: createJustifiedRows,
910
+ renderJustifiedPhotoItem: renderJustifiedPhotoItem,
911
+ renderSimplePhotoItem: renderPhotoItem,
912
+ textColor: themeStyles.textColor,
913
+ containerWidth: containerWidth
914
+ })]
915
+ });
916
+ }, [filteredFiles, themeStyles, user?.id, targetUserId, uploading, handleFileUpload, refreshing, loadFiles, loadingDimensions, photoDimensions, loadPhotoDimensions, createJustifiedRows, renderJustifiedPhotoItem, renderPhotoItem, containerWidth]);
917
+
918
+ // Separate component for the photo grid to optimize rendering
919
+ const JustifiedPhotoGrid = /*#__PURE__*/_react.default.memo(({
920
+ photos,
921
+ photoDimensions,
922
+ loadPhotoDimensions,
923
+ createJustifiedRows,
924
+ renderJustifiedPhotoItem,
925
+ renderSimplePhotoItem,
926
+ textColor,
927
+ containerWidth
928
+ }) => {
929
+ // Load dimensions for new photos
930
+ _react.default.useEffect(() => {
931
+ loadPhotoDimensions(photos);
932
+ }, [photos.map(p => p.id).join(','), loadPhotoDimensions]);
933
+
934
+ // Group photos by date
935
+ const photosByDate = _react.default.useMemo(() => {
936
+ return photos.reduce((groups, photo) => {
937
+ const date = new Date(photo.uploadDate).toDateString();
938
+ if (!groups[date]) {
939
+ groups[date] = [];
940
+ }
941
+ groups[date].push(photo);
942
+ return groups;
943
+ }, {});
944
+ }, [photos]);
945
+ const sortedDates = _react.default.useMemo(() => {
946
+ return Object.keys(photosByDate).sort((a, b) => new Date(b).getTime() - new Date(a).getTime());
947
+ }, [photosByDate]);
948
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
949
+ children: sortedDates.map(date => {
950
+ const dayPhotos = photosByDate[date];
951
+ const justifiedRows = createJustifiedRows(dayPhotos, containerWidth);
952
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
953
+ style: styles.photoDateSection,
954
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
955
+ style: [styles.photoDateHeader, {
956
+ color: themeStyles.textColor
957
+ }],
958
+ children: new Date(date).toLocaleDateString('en-US', {
959
+ weekday: 'long',
960
+ year: 'numeric',
961
+ month: 'long',
962
+ day: 'numeric'
963
+ })
964
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
965
+ style: styles.justifiedPhotoGrid,
966
+ children: justifiedRows.map((row, rowIndex) => {
967
+ // Calculate row height based on available width
968
+ const gap = 4;
969
+ let totalAspectRatio = 0;
970
+
971
+ // Calculate total aspect ratio for this row
972
+ row.forEach(photo => {
973
+ const dimensions = photoDimensions[photo.id];
974
+ const aspectRatio = dimensions ? dimensions.width / dimensions.height : 1.33; // Default 4:3 ratio
975
+ totalAspectRatio += aspectRatio;
976
+ });
977
+
978
+ // Calculate the height that makes the row fill the available width
979
+ // Account for photoScrollContainer padding (32px total) and gaps between photos
980
+ const scrollContainerPadding = 32;
981
+ const availableWidth = containerWidth - scrollContainerPadding - gap * (row.length - 1);
982
+ const calculatedHeight = availableWidth / totalAspectRatio;
983
+
984
+ // Clamp height for visual consistency
985
+ const rowHeight = Math.max(120, Math.min(calculatedHeight, 300));
986
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
987
+ style: [styles.justifiedPhotoRow, {
988
+ height: rowHeight,
989
+ maxWidth: containerWidth - 32,
990
+ // Account for scroll container padding
991
+ gap: 4 // Add horizontal gap between photos in row
992
+ }],
993
+ children: row.map((photo, photoIndex) => {
994
+ const dimensions = photoDimensions[photo.id];
995
+ const aspectRatio = dimensions ? dimensions.width / dimensions.height : 1.33; // Default 4:3 ratio
996
+
997
+ const photoWidth = rowHeight * aspectRatio;
998
+ const isLast = photoIndex === row.length - 1;
999
+ return renderJustifiedPhotoItem(photo, photoWidth, rowHeight, isLast);
1000
+ })
1001
+ }, `row-${rowIndex}`);
1002
+ })
1003
+ })]
1004
+ }, date);
1005
+ })
1006
+ });
1007
+ });
1008
+ const renderFileDetailsModal = () => {
1009
+ const backgroundColor = themeStyles.backgroundColor;
1010
+ const borderColor = themeStyles.borderColor;
1011
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Modal, {
1012
+ visible: showFileDetails,
1013
+ animationType: "slide",
1014
+ presentationStyle: "pageSheet",
1015
+ onRequestClose: () => setShowFileDetails(false),
1016
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1017
+ style: [styles.modalContainer, {
1018
+ backgroundColor
1019
+ }],
1020
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1021
+ style: [styles.modalHeader, {
1022
+ borderBottomColor: borderColor
1023
+ }],
1024
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1025
+ style: styles.modalCloseButton,
1026
+ onPress: () => setShowFileDetails(false),
1027
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1028
+ name: "close",
1029
+ size: 24,
1030
+ color: themeStyles.textColor
1031
+ })
1032
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1033
+ style: [styles.modalTitle, {
1034
+ color: themeStyles.textColor
1035
+ }],
1036
+ children: "File Details"
1037
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1038
+ style: styles.modalPlaceholder
1039
+ })]
1040
+ }), selectedFile && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
1041
+ style: styles.modalContent,
1042
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1043
+ style: [styles.fileDetailCard, {
1044
+ backgroundColor: themeStyles.secondaryBackgroundColor,
1045
+ borderColor
1046
+ }],
1047
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1048
+ style: styles.fileDetailIcon,
1049
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1050
+ name: getFileIcon(selectedFile.contentType),
1051
+ size: 64,
1052
+ color: themeStyles.primaryColor
1053
+ })
1054
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1055
+ style: [styles.fileDetailName, {
1056
+ color: themeStyles.textColor
1057
+ }],
1058
+ children: selectedFile.filename
1059
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1060
+ style: styles.fileDetailInfo,
1061
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1062
+ style: styles.detailRow,
1063
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1064
+ style: [styles.detailLabel, {
1065
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1066
+ }],
1067
+ children: "Size:"
1068
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1069
+ style: [styles.detailValue, {
1070
+ color: themeStyles.textColor
1071
+ }],
1072
+ children: formatFileSize(selectedFile.length)
1073
+ })]
1074
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1075
+ style: styles.detailRow,
1076
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1077
+ style: [styles.detailLabel, {
1078
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1079
+ }],
1080
+ children: "Type:"
1081
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1082
+ style: [styles.detailValue, {
1083
+ color: themeStyles.textColor
1084
+ }],
1085
+ children: selectedFile.contentType
1086
+ })]
1087
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1088
+ style: styles.detailRow,
1089
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1090
+ style: [styles.detailLabel, {
1091
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1092
+ }],
1093
+ children: "Uploaded:"
1094
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1095
+ style: [styles.detailValue, {
1096
+ color: themeStyles.textColor
1097
+ }],
1098
+ children: new Date(selectedFile.uploadDate).toLocaleString()
1099
+ })]
1100
+ }), selectedFile.metadata?.description && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1101
+ style: styles.detailRow,
1102
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1103
+ style: [styles.detailLabel, {
1104
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1105
+ }],
1106
+ children: "Description:"
1107
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1108
+ style: [styles.detailValue, {
1109
+ color: themeStyles.textColor
1110
+ }],
1111
+ children: selectedFile.metadata.description
1112
+ })]
1113
+ })]
1114
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1115
+ style: styles.modalActions,
1116
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
1117
+ style: [styles.modalActionButton, {
1118
+ backgroundColor: themeStyles.primaryColor
1119
+ }],
1120
+ onPress: () => {
1121
+ handleFileDownload(selectedFile.id, selectedFile.filename);
1122
+ setShowFileDetails(false);
1123
+ },
1124
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1125
+ name: "download",
1126
+ size: 20,
1127
+ color: "#FFFFFF"
1128
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1129
+ style: styles.modalActionText,
1130
+ children: "Download"
1131
+ })]
1132
+ }), user?.id === targetUserId && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
1133
+ style: [styles.modalActionButton, {
1134
+ backgroundColor: themeStyles.dangerColor
1135
+ }],
1136
+ onPress: () => {
1137
+ setShowFileDetails(false);
1138
+ handleFileDelete(selectedFile.id, selectedFile.filename);
1139
+ },
1140
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1141
+ name: "trash",
1142
+ size: 20,
1143
+ color: "#FFFFFF"
1144
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1145
+ style: styles.modalActionText,
1146
+ children: "Delete"
1147
+ })]
1148
+ })]
1149
+ })]
1150
+ })
1151
+ })]
1152
+ })
1153
+ });
1154
+ };
1155
+ const renderFileViewer = () => {
1156
+ if (!openedFile) return null;
1157
+ const backgroundColor = themeStyles.backgroundColor;
1158
+ const borderColor = themeStyles.borderColor;
1159
+ const isImage = openedFile.contentType.startsWith('image/');
1160
+ const isText = openedFile.contentType.startsWith('text/') || openedFile.contentType.includes('json') || openedFile.contentType.includes('xml') || openedFile.contentType.includes('javascript') || openedFile.contentType.includes('typescript');
1161
+ const isPDF = openedFile.contentType.includes('pdf');
1162
+ const isVideo = openedFile.contentType.startsWith('video/');
1163
+ const isAudio = openedFile.contentType.startsWith('audio/');
1164
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1165
+ style: [styles.fileViewerContainer, {
1166
+ backgroundColor
1167
+ }],
1168
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1169
+ style: [styles.fileViewerHeader, {
1170
+ borderBottomColor: borderColor
1171
+ }],
1172
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1173
+ style: styles.backButton,
1174
+ onPress: handleCloseFile,
1175
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1176
+ name: "arrow-back",
1177
+ size: 24,
1178
+ color: themeStyles.textColor
1179
+ })
1180
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1181
+ style: styles.fileViewerTitleContainer,
1182
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1183
+ style: [styles.fileViewerTitle, {
1184
+ color: themeStyles.textColor
1185
+ }],
1186
+ numberOfLines: 1,
1187
+ children: openedFile.filename
1188
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
1189
+ style: [styles.fileViewerSubtitle, {
1190
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1191
+ }],
1192
+ children: [formatFileSize(openedFile.length), " \u2022 ", openedFile.contentType]
1193
+ })]
1194
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1195
+ style: styles.fileViewerActions,
1196
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1197
+ style: [styles.actionButton, {
1198
+ backgroundColor: themeStyles.isDarkTheme ? '#333333' : '#F0F0F0'
1199
+ }],
1200
+ onPress: () => handleFileDownload(openedFile.id, openedFile.filename),
1201
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1202
+ name: "download",
1203
+ size: 20,
1204
+ color: themeStyles.primaryColor
1205
+ })
1206
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1207
+ style: [styles.actionButton, {
1208
+ backgroundColor: showFileDetailsInViewer ? themeStyles.primaryColor : themeStyles.isDarkTheme ? '#333333' : '#F0F0F0'
1209
+ }],
1210
+ onPress: () => setShowFileDetailsInViewer(!showFileDetailsInViewer),
1211
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1212
+ name: showFileDetailsInViewer ? "chevron-up" : "information-circle",
1213
+ size: 20,
1214
+ color: showFileDetailsInViewer ? "#FFFFFF" : themeStyles.primaryColor
1215
+ })
1216
+ })]
1217
+ })]
1218
+ }), showFileDetailsInViewer && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1219
+ style: [styles.fileDetailsSection, {
1220
+ backgroundColor: themeStyles.secondaryBackgroundColor,
1221
+ borderColor
1222
+ }],
1223
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1224
+ style: styles.fileDetailsSectionHeader,
1225
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1226
+ style: [styles.fileDetailsSectionTitle, {
1227
+ color: themeStyles.textColor
1228
+ }],
1229
+ children: "File Details"
1230
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1231
+ style: styles.fileDetailsSectionToggle,
1232
+ onPress: () => setShowFileDetailsInViewer(false),
1233
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1234
+ name: "chevron-up",
1235
+ size: 20,
1236
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1237
+ })
1238
+ })]
1239
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1240
+ style: styles.fileDetailInfo,
1241
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1242
+ style: styles.detailRow,
1243
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1244
+ style: [styles.detailLabel, {
1245
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1246
+ }],
1247
+ children: "File Name:"
1248
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1249
+ style: [styles.detailValue, {
1250
+ color: themeStyles.textColor
1251
+ }],
1252
+ children: openedFile.filename
1253
+ })]
1254
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1255
+ style: styles.detailRow,
1256
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1257
+ style: [styles.detailLabel, {
1258
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1259
+ }],
1260
+ children: "Size:"
1261
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1262
+ style: [styles.detailValue, {
1263
+ color: themeStyles.textColor
1264
+ }],
1265
+ children: formatFileSize(openedFile.length)
1266
+ })]
1267
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1268
+ style: styles.detailRow,
1269
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1270
+ style: [styles.detailLabel, {
1271
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1272
+ }],
1273
+ children: "Type:"
1274
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1275
+ style: [styles.detailValue, {
1276
+ color: themeStyles.textColor
1277
+ }],
1278
+ children: openedFile.contentType
1279
+ })]
1280
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1281
+ style: styles.detailRow,
1282
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1283
+ style: [styles.detailLabel, {
1284
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1285
+ }],
1286
+ children: "Uploaded:"
1287
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1288
+ style: [styles.detailValue, {
1289
+ color: themeStyles.textColor
1290
+ }],
1291
+ children: new Date(openedFile.uploadDate).toLocaleString()
1292
+ })]
1293
+ }), openedFile.metadata?.description && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1294
+ style: styles.detailRow,
1295
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1296
+ style: [styles.detailLabel, {
1297
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1298
+ }],
1299
+ children: "Description:"
1300
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1301
+ style: [styles.detailValue, {
1302
+ color: themeStyles.textColor
1303
+ }],
1304
+ children: openedFile.metadata.description
1305
+ })]
1306
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1307
+ style: styles.detailRow,
1308
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1309
+ style: [styles.detailLabel, {
1310
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1311
+ }],
1312
+ children: "File ID:"
1313
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1314
+ style: [styles.detailValue, {
1315
+ color: themeStyles.textColor,
1316
+ fontSize: 12,
1317
+ fontFamily: _reactNative.Platform.OS === 'web' ? 'monospace' : 'Courier'
1318
+ }],
1319
+ children: openedFile.id
1320
+ })]
1321
+ })]
1322
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1323
+ style: styles.fileDetailsActions,
1324
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
1325
+ style: [styles.fileDetailsActionButton, {
1326
+ backgroundColor: themeStyles.primaryColor
1327
+ }],
1328
+ onPress: () => handleFileDownload(openedFile.id, openedFile.filename),
1329
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1330
+ name: "download",
1331
+ size: 16,
1332
+ color: "#FFFFFF"
1333
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1334
+ style: styles.fileDetailsActionText,
1335
+ children: "Download"
1336
+ })]
1337
+ }), user?.id === targetUserId && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
1338
+ style: [styles.fileDetailsActionButton, {
1339
+ backgroundColor: themeStyles.dangerColor
1340
+ }],
1341
+ onPress: () => {
1342
+ handleCloseFile();
1343
+ handleFileDelete(openedFile.id, openedFile.filename);
1344
+ },
1345
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1346
+ name: "trash",
1347
+ size: 16,
1348
+ color: "#FFFFFF"
1349
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1350
+ style: styles.fileDetailsActionText,
1351
+ children: "Delete"
1352
+ })]
1353
+ })]
1354
+ })]
1355
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
1356
+ style: [styles.fileViewerContent, showFileDetailsInViewer && styles.fileViewerContentWithDetails],
1357
+ contentContainerStyle: styles.fileViewerContentContainer,
1358
+ children: loadingFileContent ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1359
+ style: styles.fileViewerLoading,
1360
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
1361
+ size: "large",
1362
+ color: themeStyles.primaryColor
1363
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1364
+ style: [styles.fileViewerLoadingText, {
1365
+ color: themeStyles.textColor
1366
+ }],
1367
+ children: "Loading file content..."
1368
+ })]
1369
+ }) : isImage && fileContent ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1370
+ style: styles.imageContainer,
1371
+ children: _reactNative.Platform.OS === 'web' ? /*#__PURE__*/(0, _jsxRuntime.jsx)("img", {
1372
+ src: fileContent,
1373
+ alt: openedFile.filename,
1374
+ style: {
1375
+ maxWidth: '100%',
1376
+ maxHeight: '80vh',
1377
+ objectFit: 'contain',
1378
+ borderRadius: 8
1379
+ },
1380
+ onError: e => {
1381
+ console.error('Image failed to load:', e);
1382
+ }
1383
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
1384
+ source: {
1385
+ uri: fileContent
1386
+ },
1387
+ style: {
1388
+ width: '100%',
1389
+ height: 400,
1390
+ resizeMode: 'contain',
1391
+ borderRadius: 8
1392
+ },
1393
+ onError: e => {
1394
+ console.error('Image failed to load:', e);
1395
+ }
1396
+ })
1397
+ }) : isText && fileContent ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1398
+ style: [styles.textContainer, {
1399
+ backgroundColor: themeStyles.secondaryBackgroundColor,
1400
+ borderColor
1401
+ }],
1402
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
1403
+ style: {
1404
+ flex: 1
1405
+ },
1406
+ nestedScrollEnabled: true,
1407
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1408
+ style: [styles.textContent, {
1409
+ color: themeStyles.textColor
1410
+ }],
1411
+ children: fileContent
1412
+ })
1413
+ })
1414
+ }) : isPDF && fileContent && _reactNative.Platform.OS === 'web' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1415
+ style: styles.pdfContainer,
1416
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("iframe", {
1417
+ src: fileContent,
1418
+ width: "100%",
1419
+ height: "600px",
1420
+ style: {
1421
+ border: 'none',
1422
+ borderRadius: 8
1423
+ },
1424
+ title: openedFile.filename
1425
+ })
1426
+ }) : isVideo && fileContent ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1427
+ style: styles.mediaContainer,
1428
+ children: _reactNative.Platform.OS === 'web' ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("video", {
1429
+ controls: true,
1430
+ style: {
1431
+ width: '100%',
1432
+ maxHeight: '70vh',
1433
+ borderRadius: 8
1434
+ },
1435
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("source", {
1436
+ src: fileContent,
1437
+ type: openedFile.contentType
1438
+ }), "Your browser does not support the video tag."]
1439
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1440
+ style: [styles.unsupportedText, {
1441
+ color: themeStyles.textColor
1442
+ }],
1443
+ children: "Video playback not supported on mobile"
1444
+ })
1445
+ }) : isAudio && fileContent ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1446
+ style: styles.mediaContainer,
1447
+ children: _reactNative.Platform.OS === 'web' ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("audio", {
1448
+ controls: true,
1449
+ style: {
1450
+ width: '100%',
1451
+ borderRadius: 8
1452
+ },
1453
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("source", {
1454
+ src: fileContent,
1455
+ type: openedFile.contentType
1456
+ }), "Your browser does not support the audio tag."]
1457
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1458
+ style: [styles.unsupportedText, {
1459
+ color: themeStyles.textColor
1460
+ }],
1461
+ children: "Audio playback not supported on mobile"
1462
+ })
1463
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1464
+ style: styles.unsupportedFileContainer,
1465
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1466
+ name: getFileIcon(openedFile.contentType),
1467
+ size: 64,
1468
+ color: themeStyles.isDarkTheme ? '#666666' : '#CCCCCC'
1469
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1470
+ style: [styles.unsupportedFileTitle, {
1471
+ color: themeStyles.textColor
1472
+ }],
1473
+ children: "Preview Not Available"
1474
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
1475
+ style: [styles.unsupportedFileDescription, {
1476
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1477
+ }],
1478
+ children: ["This file type cannot be previewed in the browser.", '\n', "Download the file to view its contents."]
1479
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
1480
+ style: [styles.downloadButtonLarge, {
1481
+ backgroundColor: themeStyles.primaryColor
1482
+ }],
1483
+ onPress: () => handleFileDownload(openedFile.id, openedFile.filename),
1484
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1485
+ name: "download",
1486
+ size: 20,
1487
+ color: "#FFFFFF"
1488
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1489
+ style: styles.downloadButtonText,
1490
+ children: "Download File"
1491
+ })]
1492
+ })]
1493
+ })
1494
+ })]
1495
+ });
1496
+ };
1497
+ const renderEmptyState = () => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1498
+ style: styles.emptyState,
1499
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1500
+ name: "folder-open-outline",
1501
+ size: 64,
1502
+ color: themeStyles.isDarkTheme ? '#666666' : '#CCCCCC'
1503
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1504
+ style: [styles.emptyStateTitle, {
1505
+ color: themeStyles.textColor
1506
+ }],
1507
+ children: "No Files Yet"
1508
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1509
+ style: [styles.emptyStateDescription, {
1510
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1511
+ }],
1512
+ children: user?.id === targetUserId ? `Upload files to get started. You can select multiple files at once${_reactNative.Platform.OS === 'web' ? ' or drag & drop them here.' : '.'}` : "This user hasn't uploaded any files yet"
1513
+ }), user?.id === targetUserId && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1514
+ style: [styles.emptyStateButton, {
1515
+ backgroundColor: themeStyles.primaryColor
1516
+ }],
1517
+ onPress: handleFileUpload,
1518
+ disabled: uploading,
1519
+ children: uploading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
1520
+ size: "small",
1521
+ color: "#FFFFFF"
1522
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
1523
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1524
+ name: "cloud-upload",
1525
+ size: 20,
1526
+ color: "#FFFFFF"
1527
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1528
+ style: styles.emptyStateButtonText,
1529
+ children: "Upload Files"
1530
+ })]
1531
+ })
1532
+ })]
1533
+ });
1534
+ if (loading) {
1535
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1536
+ style: [styles.container, styles.centerContent, {
1537
+ backgroundColor
1538
+ }],
1539
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
1540
+ size: "large",
1541
+ color: themeStyles.primaryColor
1542
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1543
+ style: [styles.loadingText, {
1544
+ color: themeStyles.textColor
1545
+ }],
1546
+ children: "Loading files..."
1547
+ })]
1548
+ });
1549
+ }
1550
+
1551
+ // If a file is opened, show the file viewer
1552
+ if (openedFile) {
1553
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
1554
+ children: [renderFileViewer(), renderFileDetailsModal()]
1555
+ });
1556
+ }
1557
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1558
+ style: [styles.container, {
1559
+ backgroundColor
1560
+ }, isDragging && _reactNative.Platform.OS === 'web' && styles.dragOverlay],
1561
+ ...(_reactNative.Platform.OS === 'web' && user?.id === targetUserId ? {
1562
+ onDragOver: handleDragOver,
1563
+ onDragLeave: handleDragLeave,
1564
+ onDrop: handleDrop
1565
+ } : {}),
1566
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1567
+ style: [styles.header, {
1568
+ borderBottomColor: borderColor,
1569
+ backgroundColor: themeStyles.isDarkTheme ? '#1A1A1A' : '#FFFFFF',
1570
+ shadowColor: '#000000',
1571
+ shadowOffset: {
1572
+ width: 0,
1573
+ height: 2
1574
+ },
1575
+ shadowOpacity: themeStyles.isDarkTheme ? 0.3 : 0.1,
1576
+ shadowRadius: 8,
1577
+ elevation: 4
1578
+ }],
1579
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1580
+ style: [styles.backButton, {
1581
+ backgroundColor: themeStyles.isDarkTheme ? '#2A2A2A' : '#F8F9FA',
1582
+ borderRadius: 12
1583
+ }],
1584
+ onPress: onClose || goBack,
1585
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1586
+ name: "arrow-back",
1587
+ size: 22,
1588
+ color: themeStyles.textColor
1589
+ })
1590
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1591
+ style: styles.headerTitleContainer,
1592
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1593
+ style: [styles.headerTitle, {
1594
+ color: themeStyles.textColor
1595
+ }],
1596
+ children: viewMode === 'photos' ? 'Photos' : 'File Management'
1597
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
1598
+ style: [styles.headerSubtitle, {
1599
+ color: themeStyles.isDarkTheme ? '#AAAAAA' : '#666666'
1600
+ }],
1601
+ children: [filteredFiles.length, " ", filteredFiles.length === 1 ? 'item' : 'items']
1602
+ })]
1603
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1604
+ style: styles.headerActions,
1605
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1606
+ style: [styles.viewModeToggle, {
1607
+ backgroundColor: themeStyles.isDarkTheme ? '#2A2A2A' : '#F8F9FA',
1608
+ borderWidth: 1,
1609
+ borderColor: themeStyles.isDarkTheme ? '#3A3A3A' : '#E8E9EA',
1610
+ shadowColor: '#000000',
1611
+ shadowOffset: {
1612
+ width: 0,
1613
+ height: 1
1614
+ },
1615
+ shadowOpacity: themeStyles.isDarkTheme ? 0.3 : 0.05,
1616
+ shadowRadius: 4,
1617
+ elevation: 2
1618
+ }],
1619
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1620
+ style: [styles.viewModeButton, viewMode === 'all' && {
1621
+ backgroundColor: themeStyles.primaryColor,
1622
+ shadowColor: themeStyles.primaryColor,
1623
+ shadowOffset: {
1624
+ width: 0,
1625
+ height: 2
1626
+ },
1627
+ shadowOpacity: 0.3,
1628
+ shadowRadius: 4,
1629
+ elevation: 3
1630
+ }],
1631
+ onPress: () => setViewMode('all'),
1632
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1633
+ name: "folder",
1634
+ size: 18,
1635
+ color: viewMode === 'all' ? '#FFFFFF' : themeStyles.textColor
1636
+ })
1637
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1638
+ style: [styles.viewModeButton, viewMode === 'photos' && {
1639
+ backgroundColor: themeStyles.primaryColor,
1640
+ shadowColor: themeStyles.primaryColor,
1641
+ shadowOffset: {
1642
+ width: 0,
1643
+ height: 2
1644
+ },
1645
+ shadowOpacity: 0.3,
1646
+ shadowRadius: 4,
1647
+ elevation: 3
1648
+ }],
1649
+ onPress: () => setViewMode('photos'),
1650
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1651
+ name: "images",
1652
+ size: 18,
1653
+ color: viewMode === 'photos' ? '#FFFFFF' : themeStyles.textColor
1654
+ })
1655
+ })]
1656
+ }), user?.id === targetUserId && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1657
+ style: [styles.uploadButton, {
1658
+ backgroundColor: themeStyles.primaryColor,
1659
+ shadowColor: themeStyles.primaryColor,
1660
+ shadowOffset: {
1661
+ width: 0,
1662
+ height: 3
1663
+ },
1664
+ shadowOpacity: 0.4,
1665
+ shadowRadius: 6,
1666
+ elevation: 5,
1667
+ transform: uploading ? [{
1668
+ scale: 0.95
1669
+ }] : [{
1670
+ scale: 1
1671
+ }]
1672
+ }],
1673
+ onPress: handleFileUpload,
1674
+ disabled: uploading,
1675
+ children: uploading ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1676
+ style: styles.uploadProgress,
1677
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
1678
+ size: "small",
1679
+ color: "#FFFFFF"
1680
+ }), uploadProgress && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
1681
+ style: styles.uploadProgressText,
1682
+ children: [uploadProgress.current, "/", uploadProgress.total]
1683
+ })]
1684
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1685
+ name: "add",
1686
+ size: 26,
1687
+ color: "#FFFFFF"
1688
+ })
1689
+ })]
1690
+ })]
1691
+ }), files.length > 0 && (viewMode === 'all' || files.some(f => f.contentType.startsWith('image/'))) && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1692
+ style: [styles.searchContainer, {
1693
+ backgroundColor: themeStyles.isDarkTheme ? '#1A1A1A' : '#FFFFFF',
1694
+ borderColor: themeStyles.isDarkTheme ? '#3A3A3A' : '#E8E9EA',
1695
+ shadowColor: '#000000',
1696
+ shadowOffset: {
1697
+ width: 0,
1698
+ height: 1
1699
+ },
1700
+ shadowOpacity: themeStyles.isDarkTheme ? 0.2 : 0.05,
1701
+ shadowRadius: 4,
1702
+ elevation: 2
1703
+ }],
1704
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1705
+ name: "search",
1706
+ size: 22,
1707
+ color: themeStyles.isDarkTheme ? '#888888' : '#666666'
1708
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
1709
+ style: [styles.searchInput, {
1710
+ color: themeStyles.textColor
1711
+ }],
1712
+ placeholder: viewMode === 'photos' ? 'Search photos...' : 'Search files...',
1713
+ placeholderTextColor: themeStyles.isDarkTheme ? '#888888' : '#999999',
1714
+ value: searchQuery,
1715
+ onChangeText: setSearchQuery
1716
+ }), searchQuery.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1717
+ onPress: () => setSearchQuery(''),
1718
+ style: styles.searchClearButton,
1719
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1720
+ name: "close-circle",
1721
+ size: 22,
1722
+ color: themeStyles.isDarkTheme ? '#888888' : '#666666'
1723
+ })
1724
+ })]
1725
+ }), files.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1726
+ style: [styles.statsContainer, {
1727
+ backgroundColor: themeStyles.isDarkTheme ? '#1A1A1A' : '#FFFFFF',
1728
+ borderColor: themeStyles.isDarkTheme ? '#3A3A3A' : '#E8E9EA',
1729
+ shadowColor: '#000000',
1730
+ shadowOffset: {
1731
+ width: 0,
1732
+ height: 1
1733
+ },
1734
+ shadowOpacity: themeStyles.isDarkTheme ? 0.2 : 0.05,
1735
+ shadowRadius: 4,
1736
+ elevation: 2
1737
+ }],
1738
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1739
+ style: styles.statItem,
1740
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1741
+ style: [styles.statValue, {
1742
+ color: themeStyles.textColor
1743
+ }],
1744
+ children: filteredFiles.length
1745
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1746
+ style: [styles.statLabel, {
1747
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1748
+ }],
1749
+ children: searchQuery.length > 0 ? 'Found' : filteredFiles.length === 1 ? viewMode === 'photos' ? 'Photo' : 'File' : viewMode === 'photos' ? 'Photos' : 'Files'
1750
+ })]
1751
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1752
+ style: styles.statItem,
1753
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1754
+ style: [styles.statValue, {
1755
+ color: themeStyles.textColor
1756
+ }],
1757
+ children: formatFileSize(filteredFiles.reduce((total, file) => total + file.length, 0))
1758
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1759
+ style: [styles.statLabel, {
1760
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1761
+ }],
1762
+ children: searchQuery.length > 0 ? 'Size' : 'Total Size'
1763
+ })]
1764
+ }), searchQuery.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1765
+ style: styles.statItem,
1766
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1767
+ style: [styles.statValue, {
1768
+ color: themeStyles.textColor
1769
+ }],
1770
+ children: files.length
1771
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1772
+ style: [styles.statLabel, {
1773
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1774
+ }],
1775
+ children: "Total"
1776
+ })]
1777
+ })]
1778
+ }), viewMode === 'photos' ? renderPhotoGrid() : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
1779
+ style: styles.scrollView,
1780
+ contentContainerStyle: styles.scrollContainer,
1781
+ refreshControl: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.RefreshControl, {
1782
+ refreshing: refreshing,
1783
+ onRefresh: () => loadFiles(true),
1784
+ tintColor: themeStyles.primaryColor
1785
+ }),
1786
+ children: filteredFiles.length === 0 && searchQuery.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1787
+ style: styles.emptyState,
1788
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1789
+ name: "search",
1790
+ size: 64,
1791
+ color: themeStyles.isDarkTheme ? '#666666' : '#CCCCCC'
1792
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1793
+ style: [styles.emptyStateTitle, {
1794
+ color: themeStyles.textColor
1795
+ }],
1796
+ children: "No Results Found"
1797
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
1798
+ style: [styles.emptyStateDescription, {
1799
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1800
+ }],
1801
+ children: ["No files match your search for \"", searchQuery, "\""]
1802
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
1803
+ style: [styles.emptyStateButton, {
1804
+ backgroundColor: themeStyles.primaryColor
1805
+ }],
1806
+ onPress: () => setSearchQuery(''),
1807
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1808
+ name: "refresh",
1809
+ size: 20,
1810
+ color: "#FFFFFF"
1811
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1812
+ style: styles.emptyStateButtonText,
1813
+ children: "Clear Search"
1814
+ })]
1815
+ })]
1816
+ }) : filteredFiles.length === 0 ? renderEmptyState() : /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
1817
+ children: filteredFiles.map(renderFileItem)
1818
+ })
1819
+ }), renderFileDetailsModal(), isDragging && _reactNative.Platform.OS === 'web' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1820
+ style: styles.dragDropOverlay,
1821
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1822
+ style: styles.dragDropContent,
1823
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_vectorIcons.Ionicons, {
1824
+ name: "cloud-upload",
1825
+ size: 64,
1826
+ color: themeStyles.primaryColor
1827
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1828
+ style: [styles.dragDropTitle, {
1829
+ color: themeStyles.primaryColor
1830
+ }],
1831
+ children: "Drop files to upload"
1832
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
1833
+ style: [styles.dragDropSubtitle, {
1834
+ color: themeStyles.isDarkTheme ? '#BBBBBB' : '#666666'
1835
+ }],
1836
+ children: ["Release to upload", uploadProgress ? ` (${uploadProgress.current}/${uploadProgress.total})` : ' multiple files']
1837
+ })]
1838
+ })
1839
+ })]
1840
+ });
1841
+ };
1842
+ const styles = _reactNative.StyleSheet.create({
1843
+ container: {
1844
+ flex: 1
1845
+ },
1846
+ dragOverlay: {
1847
+ backgroundColor: 'rgba(0, 122, 255, 0.1)',
1848
+ borderWidth: 2,
1849
+ borderColor: '#007AFF',
1850
+ borderStyle: 'dashed'
1851
+ },
1852
+ centerContent: {
1853
+ justifyContent: 'center',
1854
+ alignItems: 'center'
1855
+ },
1856
+ header: {
1857
+ flexDirection: 'row',
1858
+ alignItems: 'center',
1859
+ justifyContent: 'space-between',
1860
+ paddingHorizontal: 24,
1861
+ paddingVertical: 20,
1862
+ borderBottomWidth: 1,
1863
+ position: 'relative'
1864
+ },
1865
+ backButton: {
1866
+ padding: 12,
1867
+ borderRadius: 12,
1868
+ alignItems: 'center',
1869
+ justifyContent: 'center',
1870
+ minWidth: 44,
1871
+ minHeight: 44
1872
+ },
1873
+ headerTitleContainer: {
1874
+ flex: 1,
1875
+ alignItems: 'center',
1876
+ justifyContent: 'center',
1877
+ marginHorizontal: 16
1878
+ },
1879
+ headerTitle: {
1880
+ fontSize: 22,
1881
+ fontWeight: '700',
1882
+ fontFamily: _fonts.fontFamilies.phuduBold,
1883
+ letterSpacing: -0.5,
1884
+ lineHeight: 28
1885
+ },
1886
+ headerSubtitle: {
1887
+ fontSize: 13,
1888
+ fontWeight: '500',
1889
+ fontFamily: _fonts.fontFamilies.phuduMedium,
1890
+ marginTop: 2,
1891
+ letterSpacing: 0.2
1892
+ },
1893
+ uploadButton: {
1894
+ width: 44,
1895
+ height: 44,
1896
+ borderRadius: 22,
1897
+ alignItems: 'center',
1898
+ justifyContent: 'center'
1899
+ },
1900
+ uploadProgress: {
1901
+ alignItems: 'center',
1902
+ justifyContent: 'center'
1903
+ },
1904
+ uploadProgressText: {
1905
+ color: '#FFFFFF',
1906
+ fontSize: 10,
1907
+ fontWeight: '600',
1908
+ marginTop: 2
1909
+ },
1910
+ searchContainer: {
1911
+ flexDirection: 'row',
1912
+ alignItems: 'center',
1913
+ paddingHorizontal: 20,
1914
+ paddingVertical: 16,
1915
+ marginHorizontal: 24,
1916
+ marginTop: 20,
1917
+ borderRadius: 16,
1918
+ borderWidth: 1,
1919
+ gap: 16
1920
+ },
1921
+ searchInput: {
1922
+ flex: 1,
1923
+ fontSize: 16,
1924
+ fontFamily: _fonts.fontFamilies.phudu,
1925
+ lineHeight: 20
1926
+ },
1927
+ searchClearButton: {
1928
+ padding: 4,
1929
+ borderRadius: 12,
1930
+ alignItems: 'center',
1931
+ justifyContent: 'center'
1932
+ },
1933
+ searchIcon: {
1934
+ marginRight: 8
1935
+ },
1936
+ statsContainer: {
1937
+ flexDirection: 'row',
1938
+ paddingHorizontal: 24,
1939
+ paddingVertical: 20,
1940
+ marginHorizontal: 24,
1941
+ marginTop: 20,
1942
+ borderRadius: 16,
1943
+ borderWidth: 1
1944
+ },
1945
+ statItem: {
1946
+ flex: 1,
1947
+ alignItems: 'center',
1948
+ paddingVertical: 4
1949
+ },
1950
+ statValue: {
1951
+ fontSize: 28,
1952
+ fontWeight: '800',
1953
+ fontFamily: _fonts.fontFamilies.phuduBold,
1954
+ letterSpacing: -0.5,
1955
+ lineHeight: 32
1956
+ },
1957
+ statLabel: {
1958
+ fontSize: 15,
1959
+ fontWeight: '500',
1960
+ fontFamily: _fonts.fontFamilies.phuduMedium,
1961
+ marginTop: 4,
1962
+ letterSpacing: 0.3
1963
+ },
1964
+ scrollView: {
1965
+ flex: 1
1966
+ },
1967
+ scrollContainer: {
1968
+ padding: 20
1969
+ },
1970
+ fileItem: {
1971
+ flexDirection: 'row',
1972
+ alignItems: 'center',
1973
+ padding: 16,
1974
+ marginBottom: 12,
1975
+ borderRadius: 12,
1976
+ borderWidth: 1
1977
+ },
1978
+ fileContent: {
1979
+ flexDirection: 'row',
1980
+ alignItems: 'center',
1981
+ flex: 1
1982
+ },
1983
+ fileIconContainer: {
1984
+ width: 50,
1985
+ height: 50,
1986
+ alignItems: 'center',
1987
+ justifyContent: 'center',
1988
+ marginRight: 12
1989
+ },
1990
+ filePreviewContainer: {
1991
+ width: 60,
1992
+ height: 60,
1993
+ marginRight: 12
1994
+ },
1995
+ filePreview: {
1996
+ width: '100%',
1997
+ height: '100%',
1998
+ borderRadius: 8,
1999
+ backgroundColor: '#F5F5F5',
2000
+ alignItems: 'center',
2001
+ justifyContent: 'center',
2002
+ overflow: 'hidden',
2003
+ position: 'relative'
2004
+ },
2005
+ previewImage: {
2006
+ width: '100%',
2007
+ height: '100%',
2008
+ borderRadius: 8
2009
+ },
2010
+ pdfPreview: {
2011
+ alignItems: 'center',
2012
+ justifyContent: 'center',
2013
+ width: '100%',
2014
+ height: '100%',
2015
+ backgroundColor: '#FF6B6B20'
2016
+ },
2017
+ pdfLabel: {
2018
+ fontSize: 8,
2019
+ fontWeight: 'bold',
2020
+ marginTop: 2
2021
+ },
2022
+ videoPreview: {
2023
+ alignItems: 'center',
2024
+ justifyContent: 'center',
2025
+ width: '100%',
2026
+ height: '100%',
2027
+ backgroundColor: '#4ECDC420'
2028
+ },
2029
+ videoLabel: {
2030
+ fontSize: 8,
2031
+ fontWeight: 'bold',
2032
+ marginTop: 2
2033
+ },
2034
+ fallbackIcon: {
2035
+ position: 'absolute',
2036
+ top: 0,
2037
+ left: 0,
2038
+ right: 0,
2039
+ bottom: 0,
2040
+ alignItems: 'center',
2041
+ justifyContent: 'center',
2042
+ backgroundColor: '#F5F5F5',
2043
+ borderRadius: 8
2044
+ },
2045
+ previewOverlay: {
2046
+ position: 'absolute',
2047
+ top: 0,
2048
+ left: 0,
2049
+ right: 0,
2050
+ bottom: 0,
2051
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
2052
+ alignItems: 'center',
2053
+ justifyContent: 'center',
2054
+ borderRadius: 8
2055
+ },
2056
+ fileInfo: {
2057
+ flex: 1
2058
+ },
2059
+ fileName: {
2060
+ fontSize: 16,
2061
+ fontWeight: '600',
2062
+ marginBottom: 4
2063
+ },
2064
+ fileDetails: {
2065
+ fontSize: 14,
2066
+ marginBottom: 2
2067
+ },
2068
+ fileDescription: {
2069
+ fontSize: 12,
2070
+ fontStyle: 'italic'
2071
+ },
2072
+ fileActions: {
2073
+ flexDirection: 'row',
2074
+ gap: 8
2075
+ },
2076
+ actionButton: {
2077
+ width: 40,
2078
+ height: 40,
2079
+ borderRadius: 20,
2080
+ alignItems: 'center',
2081
+ justifyContent: 'center'
2082
+ },
2083
+ emptyState: {
2084
+ alignItems: 'center',
2085
+ paddingVertical: 60,
2086
+ paddingHorizontal: 40
2087
+ },
2088
+ emptyStateTitle: {
2089
+ fontSize: 24,
2090
+ fontWeight: 'bold',
2091
+ fontFamily: _fonts.fontFamilies.phuduBold,
2092
+ marginTop: 16,
2093
+ marginBottom: 8
2094
+ },
2095
+ emptyStateDescription: {
2096
+ fontSize: 16,
2097
+ textAlign: 'center',
2098
+ lineHeight: 24,
2099
+ marginBottom: 32
2100
+ },
2101
+ emptyStateButton: {
2102
+ flexDirection: 'row',
2103
+ alignItems: 'center',
2104
+ paddingHorizontal: 24,
2105
+ paddingVertical: 12,
2106
+ borderRadius: 24,
2107
+ gap: 8
2108
+ },
2109
+ emptyStateButtonText: {
2110
+ color: '#FFFFFF',
2111
+ fontSize: 16,
2112
+ fontWeight: '600'
2113
+ },
2114
+ loadingText: {
2115
+ fontSize: 16,
2116
+ marginTop: 16
2117
+ },
2118
+ // Modal styles
2119
+ modalContainer: {
2120
+ flex: 1
2121
+ },
2122
+ modalHeader: {
2123
+ flexDirection: 'row',
2124
+ alignItems: 'center',
2125
+ justifyContent: 'space-between',
2126
+ paddingHorizontal: 20,
2127
+ paddingVertical: 16,
2128
+ borderBottomWidth: 1
2129
+ },
2130
+ modalCloseButton: {
2131
+ padding: 8
2132
+ },
2133
+ modalTitle: {
2134
+ fontSize: 18,
2135
+ fontWeight: '600',
2136
+ fontFamily: _fonts.fontFamilies.phuduSemiBold
2137
+ },
2138
+ modalPlaceholder: {
2139
+ width: 40
2140
+ },
2141
+ modalContent: {
2142
+ flex: 1,
2143
+ padding: 20
2144
+ },
2145
+ fileDetailCard: {
2146
+ padding: 24,
2147
+ borderRadius: 16,
2148
+ borderWidth: 1,
2149
+ alignItems: 'center'
2150
+ },
2151
+ fileDetailIcon: {
2152
+ marginBottom: 16
2153
+ },
2154
+ fileDetailName: {
2155
+ fontSize: 20,
2156
+ fontWeight: 'bold',
2157
+ fontFamily: _fonts.fontFamilies.phuduBold,
2158
+ textAlign: 'center',
2159
+ marginBottom: 24
2160
+ },
2161
+ fileDetailInfo: {
2162
+ width: '100%',
2163
+ marginBottom: 32
2164
+ },
2165
+ detailRow: {
2166
+ flexDirection: 'row',
2167
+ justifyContent: 'space-between',
2168
+ alignItems: 'flex-start',
2169
+ marginBottom: 12,
2170
+ flexWrap: 'wrap'
2171
+ },
2172
+ detailLabel: {
2173
+ fontSize: 16,
2174
+ fontWeight: '500',
2175
+ flex: 1,
2176
+ minWidth: 100
2177
+ },
2178
+ detailValue: {
2179
+ fontSize: 16,
2180
+ flex: 2,
2181
+ textAlign: 'right'
2182
+ },
2183
+ modalActions: {
2184
+ flexDirection: 'row',
2185
+ gap: 12,
2186
+ width: '100%'
2187
+ },
2188
+ modalActionButton: {
2189
+ flex: 1,
2190
+ flexDirection: 'row',
2191
+ alignItems: 'center',
2192
+ justifyContent: 'center',
2193
+ paddingVertical: 16,
2194
+ borderRadius: 12,
2195
+ gap: 8
2196
+ },
2197
+ modalActionText: {
2198
+ color: '#FFFFFF',
2199
+ fontSize: 16,
2200
+ fontWeight: '600'
2201
+ },
2202
+ // Drag and Drop styles
2203
+ dragDropOverlay: {
2204
+ position: 'absolute',
2205
+ top: 0,
2206
+ left: 0,
2207
+ right: 0,
2208
+ bottom: 0,
2209
+ backgroundColor: 'rgba(0, 0, 0, 0.8)',
2210
+ justifyContent: 'center',
2211
+ alignItems: 'center',
2212
+ zIndex: 1000
2213
+ },
2214
+ dragDropContent: {
2215
+ alignItems: 'center',
2216
+ backgroundColor: 'rgba(255, 255, 255, 0.9)',
2217
+ padding: 40,
2218
+ borderRadius: 20,
2219
+ borderWidth: 3,
2220
+ borderColor: '#007AFF',
2221
+ borderStyle: 'dashed'
2222
+ },
2223
+ dragDropTitle: {
2224
+ fontSize: 24,
2225
+ fontWeight: 'bold',
2226
+ marginTop: 16,
2227
+ marginBottom: 8
2228
+ },
2229
+ dragDropSubtitle: {
2230
+ fontSize: 16,
2231
+ textAlign: 'center'
2232
+ },
2233
+ // File Viewer styles
2234
+ fileViewerContainer: {
2235
+ flex: 1
2236
+ },
2237
+ fileViewerHeader: {
2238
+ flexDirection: 'row',
2239
+ alignItems: 'center',
2240
+ paddingHorizontal: 20,
2241
+ paddingVertical: 16,
2242
+ borderBottomWidth: 1
2243
+ },
2244
+ fileViewerTitleContainer: {
2245
+ flex: 1,
2246
+ marginHorizontal: 16
2247
+ },
2248
+ fileViewerTitle: {
2249
+ fontSize: 18,
2250
+ fontWeight: '600',
2251
+ fontFamily: _fonts.fontFamilies.phuduSemiBold,
2252
+ marginBottom: 2
2253
+ },
2254
+ fileViewerSubtitle: {
2255
+ fontSize: 14
2256
+ },
2257
+ fileViewerActions: {
2258
+ flexDirection: 'row',
2259
+ gap: 8
2260
+ },
2261
+ fileViewerContent: {
2262
+ flex: 1
2263
+ },
2264
+ fileViewerContentWithDetails: {
2265
+ paddingBottom: 20
2266
+ },
2267
+ fileViewerContentContainer: {
2268
+ flexGrow: 1,
2269
+ padding: 20
2270
+ },
2271
+ fileViewerLoading: {
2272
+ flex: 1,
2273
+ justifyContent: 'center',
2274
+ alignItems: 'center'
2275
+ },
2276
+ fileViewerLoadingText: {
2277
+ fontSize: 16,
2278
+ marginTop: 16
2279
+ },
2280
+ imageContainer: {
2281
+ alignItems: 'center',
2282
+ justifyContent: 'center',
2283
+ flex: 1
2284
+ },
2285
+ textContainer: {
2286
+ flex: 1,
2287
+ borderRadius: 12,
2288
+ borderWidth: 1,
2289
+ padding: 16,
2290
+ minHeight: 200,
2291
+ maxHeight: '80%'
2292
+ },
2293
+ textContent: {
2294
+ fontSize: 14,
2295
+ fontFamily: _reactNative.Platform.OS === 'web' ? 'monospace' : 'Courier',
2296
+ lineHeight: 20
2297
+ },
2298
+ unsupportedFileContainer: {
2299
+ flex: 1,
2300
+ justifyContent: 'center',
2301
+ alignItems: 'center',
2302
+ paddingVertical: 60,
2303
+ paddingHorizontal: 40
2304
+ },
2305
+ unsupportedFileTitle: {
2306
+ fontSize: 24,
2307
+ fontWeight: 'bold',
2308
+ fontFamily: _fonts.fontFamilies.phuduBold,
2309
+ marginTop: 16,
2310
+ marginBottom: 8,
2311
+ textAlign: 'center'
2312
+ },
2313
+ unsupportedFileDescription: {
2314
+ fontSize: 16,
2315
+ textAlign: 'center',
2316
+ lineHeight: 24,
2317
+ marginBottom: 32
2318
+ },
2319
+ downloadButtonLarge: {
2320
+ flexDirection: 'row',
2321
+ alignItems: 'center',
2322
+ paddingHorizontal: 24,
2323
+ paddingVertical: 16,
2324
+ borderRadius: 24,
2325
+ gap: 8
2326
+ },
2327
+ downloadButtonText: {
2328
+ color: '#FFFFFF',
2329
+ fontSize: 16,
2330
+ fontWeight: '600'
2331
+ },
2332
+ pdfContainer: {
2333
+ flex: 1,
2334
+ alignItems: 'center',
2335
+ justifyContent: 'center'
2336
+ },
2337
+ mediaContainer: {
2338
+ flex: 1,
2339
+ alignItems: 'center',
2340
+ justifyContent: 'center',
2341
+ padding: 20
2342
+ },
2343
+ unsupportedText: {
2344
+ fontSize: 16,
2345
+ textAlign: 'center',
2346
+ fontStyle: 'italic'
2347
+ },
2348
+ // File Details in Viewer styles
2349
+ fileDetailsSection: {
2350
+ margin: 16,
2351
+ marginTop: 0,
2352
+ padding: 20,
2353
+ borderRadius: 12,
2354
+ borderWidth: 1
2355
+ },
2356
+ fileDetailsSectionTitle: {
2357
+ fontSize: 18,
2358
+ fontWeight: '600',
2359
+ fontFamily: _fonts.fontFamilies.phuduSemiBold,
2360
+ flex: 1
2361
+ },
2362
+ fileDetailsSectionHeader: {
2363
+ flexDirection: 'row',
2364
+ alignItems: 'center',
2365
+ justifyContent: 'space-between',
2366
+ marginBottom: 16
2367
+ },
2368
+ fileDetailsSectionToggle: {
2369
+ padding: 4
2370
+ },
2371
+ fileDetailsActions: {
2372
+ flexDirection: 'row',
2373
+ gap: 12,
2374
+ marginTop: 16
2375
+ },
2376
+ fileDetailsActionButton: {
2377
+ flex: 1,
2378
+ flexDirection: 'row',
2379
+ alignItems: 'center',
2380
+ justifyContent: 'center',
2381
+ paddingVertical: 12,
2382
+ borderRadius: 8,
2383
+ gap: 6
2384
+ },
2385
+ fileDetailsActionText: {
2386
+ color: '#FFFFFF',
2387
+ fontSize: 14,
2388
+ fontWeight: '600'
2389
+ },
2390
+ // Header styles
2391
+ headerActions: {
2392
+ flexDirection: 'row',
2393
+ alignItems: 'center',
2394
+ gap: 16
2395
+ },
2396
+ viewModeToggle: {
2397
+ flexDirection: 'row',
2398
+ borderRadius: 24,
2399
+ padding: 3,
2400
+ overflow: 'hidden'
2401
+ },
2402
+ viewModeButton: {
2403
+ paddingHorizontal: 14,
2404
+ paddingVertical: 10,
2405
+ borderRadius: 20,
2406
+ minWidth: 44,
2407
+ alignItems: 'center',
2408
+ justifyContent: 'center',
2409
+ marginHorizontal: 1
2410
+ },
2411
+ // Photo Grid styles
2412
+ photoScrollContainer: {
2413
+ padding: 16
2414
+ },
2415
+ photoDateSection: {
2416
+ marginBottom: 24
2417
+ },
2418
+ photoDateHeader: {
2419
+ fontSize: 18,
2420
+ fontWeight: '600',
2421
+ fontFamily: _fonts.fontFamilies.phuduSemiBold,
2422
+ marginBottom: 12,
2423
+ paddingHorizontal: 4
2424
+ },
2425
+ photoGrid: {
2426
+ flexDirection: 'row',
2427
+ flexWrap: 'wrap',
2428
+ gap: 4,
2429
+ justifyContent: 'flex-start'
2430
+ },
2431
+ photoItem: {
2432
+ borderRadius: 8,
2433
+ overflow: 'hidden'
2434
+ },
2435
+ photoContainer: {
2436
+ width: '100%',
2437
+ height: '100%',
2438
+ position: 'relative',
2439
+ borderRadius: 8,
2440
+ overflow: 'hidden'
2441
+ },
2442
+ photoImage: {
2443
+ width: '100%',
2444
+ height: '100%'
2445
+ },
2446
+ // Justified Grid styles
2447
+ dimensionsLoadingIndicator: {
2448
+ flexDirection: 'row',
2449
+ alignItems: 'center',
2450
+ justifyContent: 'center',
2451
+ paddingVertical: 16,
2452
+ gap: 8
2453
+ },
2454
+ dimensionsLoadingText: {
2455
+ fontSize: 14,
2456
+ fontStyle: 'italic'
2457
+ },
2458
+ justifiedPhotoGrid: {
2459
+ gap: 4
2460
+ },
2461
+ justifiedPhotoRow: {
2462
+ flexDirection: 'row'
2463
+ },
2464
+ justifiedPhotoItem: {
2465
+ borderRadius: 6,
2466
+ overflow: 'hidden',
2467
+ position: 'relative'
2468
+ },
2469
+ justifiedPhotoContainer: {
2470
+ width: '100%',
2471
+ height: '100%',
2472
+ position: 'relative',
2473
+ borderRadius: 6,
2474
+ overflow: 'hidden',
2475
+ backgroundColor: '#F5F5F5'
2476
+ },
2477
+ justifiedPhotoImage: {
2478
+ width: '100%',
2479
+ height: '100%',
2480
+ borderRadius: 6
2481
+ },
2482
+ // Simple Photo Grid styles
2483
+ simplePhotoItem: {
2484
+ borderRadius: 8,
2485
+ overflow: 'hidden',
2486
+ backgroundColor: '#F5F5F5'
2487
+ },
2488
+ simplePhotoContainer: {
2489
+ width: '100%',
2490
+ height: '100%',
2491
+ position: 'relative',
2492
+ borderRadius: 8,
2493
+ overflow: 'hidden'
2494
+ },
2495
+ simplePhotoImage: {
2496
+ width: '100%',
2497
+ height: '100%',
2498
+ borderRadius: 8
2499
+ },
2500
+ // Loading skeleton styles
2501
+ photoSkeletonGrid: {
2502
+ flexDirection: 'row',
2503
+ flexWrap: 'wrap',
2504
+ gap: 4,
2505
+ marginTop: 20
2506
+ },
2507
+ photoSkeletonItem: {
2508
+ width: '32%',
2509
+ aspectRatio: 1,
2510
+ borderRadius: 8,
2511
+ marginBottom: 4
2512
+ }
2513
+ });
2514
+ var _default = exports.default = FileManagementScreen;
2515
+ //# sourceMappingURL=FileManagementScreen.js.map