@plusscommunities/pluss-core-app 8.0.0 → 8.0.1-auth.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) hide show
  1. package/dist/module/actions/FollowerActions.js +4 -4
  2. package/dist/module/actions/FollowerActions.js.map +1 -1
  3. package/dist/module/actions/MediaActions.js +1 -1
  4. package/dist/module/actions/MediaActions.js.map +1 -1
  5. package/dist/module/actions/ResidentActions.js +1 -1
  6. package/dist/module/actions/ResidentActions.js.map +1 -1
  7. package/dist/module/actions/UserActions.js +1 -1
  8. package/dist/module/actions/UserActions.js.map +1 -1
  9. package/dist/module/actions/UserSettingsActions.js +1 -1
  10. package/dist/module/actions/UserSettingsActions.js.map +1 -1
  11. package/dist/module/actions/index.js +5 -5
  12. package/dist/module/actions/index.js.map +1 -1
  13. package/dist/module/actions/types.js +16 -16
  14. package/dist/module/actions/types.js.map +1 -1
  15. package/dist/module/apis/analyticsActions.js +5 -5
  16. package/dist/module/apis/analyticsActions.js.map +1 -1
  17. package/dist/module/apis/contactActions.js +6 -6
  18. package/dist/module/apis/contactActions.js.map +1 -1
  19. package/dist/module/apis/eventActions.js +28 -28
  20. package/dist/module/apis/eventActions.js.map +1 -1
  21. package/dist/module/apis/fileActions.js +15 -15
  22. package/dist/module/apis/fileActions.js.map +1 -1
  23. package/dist/module/apis/followerActions.js +8 -8
  24. package/dist/module/apis/followerActions.js.map +1 -1
  25. package/dist/module/apis/index.js +12 -12
  26. package/dist/module/apis/index.js.map +1 -1
  27. package/dist/module/apis/notificationActions.js +17 -17
  28. package/dist/module/apis/notificationActions.js.map +1 -1
  29. package/dist/module/apis/profileActions.js +4 -4
  30. package/dist/module/apis/profileActions.js.map +1 -1
  31. package/dist/module/apis/reactionActions.js +15 -15
  32. package/dist/module/apis/reactionActions.js.map +1 -1
  33. package/dist/module/apis/settingActions.js +6 -6
  34. package/dist/module/apis/settingActions.js.map +1 -1
  35. package/dist/module/apis/stringActions.js +8 -8
  36. package/dist/module/apis/stringActions.js.map +1 -1
  37. package/dist/module/apis/typeActions.js +4 -4
  38. package/dist/module/apis/typeActions.js.map +1 -1
  39. package/dist/module/apis/userActions.js +8 -8
  40. package/dist/module/apis/userActions.js.map +1 -1
  41. package/dist/module/assets/icons/fontawesome/fa-brands-400.ttf +0 -0
  42. package/dist/module/assets/icons/fontawesome/fa-light-300.ttf +0 -0
  43. package/dist/module/assets/icons/fontawesome/fa-regular-400.ttf +0 -0
  44. package/dist/module/assets/icons/fontawesome/fa-solid-900.ttf +0 -0
  45. package/dist/module/assets/icons/fontawesome/fa-thin-100.ttf +0 -0
  46. package/dist/module/assets/icons/fontawesome/fa7-glyphmap.json +4205 -0
  47. package/dist/module/colours.js +26 -29
  48. package/dist/module/colours.js.map +1 -1
  49. package/dist/module/components/AddButton.js +8 -8
  50. package/dist/module/components/AddButton.js.map +1 -1
  51. package/dist/module/components/AddToCalendarButton.js +30 -29
  52. package/dist/module/components/AddToCalendarButton.js.map +1 -1
  53. package/dist/module/components/Attachment.js +10 -9
  54. package/dist/module/components/Attachment.js.map +1 -1
  55. package/dist/module/components/AudienceSelectorLauncher.js +11 -11
  56. package/dist/module/components/AudienceSelectorLauncher.js.map +1 -1
  57. package/dist/module/components/AudienceSelectorPage.js +45 -44
  58. package/dist/module/components/AudienceSelectorPage.js.map +1 -1
  59. package/dist/module/components/AutoOffsetImage.js +13 -13
  60. package/dist/module/components/AutoOffsetImage.js.map +1 -1
  61. package/dist/module/components/BackButton.js +10 -10
  62. package/dist/module/components/BackButton.js.map +1 -1
  63. package/dist/module/components/CalendarPopup.js +21 -21
  64. package/dist/module/components/CalendarPopup.js.map +1 -1
  65. package/dist/module/components/CategoryTabs.js +30 -29
  66. package/dist/module/components/CategoryTabs.js.map +1 -1
  67. package/dist/module/components/CommentReply.js +43 -37
  68. package/dist/module/components/CommentReply.js.map +1 -1
  69. package/dist/module/components/CommentSection.js +74 -74
  70. package/dist/module/components/CommentSection.js.map +1 -1
  71. package/dist/module/components/ConfirmPopup.js +21 -20
  72. package/dist/module/components/ConfirmPopup.js.map +1 -1
  73. package/dist/module/components/ConfirmationPopup.js +11 -11
  74. package/dist/module/components/ConfirmationPopup.js.map +1 -1
  75. package/dist/module/components/DocumentUploader.js +50 -50
  76. package/dist/module/components/DocumentUploader.js.map +1 -1
  77. package/dist/module/components/DropDownItem.js +14 -13
  78. package/dist/module/components/DropDownItem.js.map +1 -1
  79. package/dist/module/components/DropDownMenu.js +5 -5
  80. package/dist/module/components/DropDownMenu.js.map +1 -1
  81. package/dist/module/components/EmptyStateMain.js +10 -9
  82. package/dist/module/components/EmptyStateMain.js.map +1 -1
  83. package/dist/module/components/EmptyStateWidget.js +7 -6
  84. package/dist/module/components/EmptyStateWidget.js.map +1 -1
  85. package/dist/module/components/FontScaleButton.js +5 -4
  86. package/dist/module/components/FontScaleButton.js.map +1 -1
  87. package/dist/module/components/FontScalePopup.js +11 -10
  88. package/dist/module/components/FontScalePopup.js.map +1 -1
  89. package/dist/module/components/Forbidden.js +13 -13
  90. package/dist/module/components/Forbidden.js.map +1 -1
  91. package/dist/module/components/FormCard.js +4 -4
  92. package/dist/module/components/FormCard.js.map +1 -1
  93. package/dist/module/components/FormCardSection.js +20 -18
  94. package/dist/module/components/FormCardSection.js.map +1 -1
  95. package/dist/module/components/FormCardSectionOptionLauncher.js +13 -12
  96. package/dist/module/components/FormCardSectionOptionLauncher.js.map +1 -1
  97. package/dist/module/components/FormattedText.js +18 -16
  98. package/dist/module/components/FormattedText.js.map +1 -1
  99. package/dist/module/components/GenericInput.js +24 -21
  100. package/dist/module/components/GenericInput.js.map +1 -1
  101. package/dist/module/components/GenericInputSection.js +27 -26
  102. package/dist/module/components/GenericInputSection.js.map +1 -1
  103. package/dist/module/components/Header.js +70 -69
  104. package/dist/module/components/Header.js.map +1 -1
  105. package/dist/module/components/Icon.js +109 -0
  106. package/dist/module/components/Icon.js.map +1 -0
  107. package/dist/module/components/ImagePopup.js +211 -73
  108. package/dist/module/components/ImagePopup.js.map +1 -1
  109. package/dist/module/components/ImageUploadProgress.js +10 -9
  110. package/dist/module/components/ImageUploadProgress.js.map +1 -1
  111. package/dist/module/components/ImageUploader.js +116 -96
  112. package/dist/module/components/ImageUploader.js.map +1 -1
  113. package/dist/module/components/InlineButton.js +9 -8
  114. package/dist/module/components/InlineButton.js.map +1 -1
  115. package/dist/module/components/Input.js +28 -26
  116. package/dist/module/components/Input.js.map +1 -1
  117. package/dist/module/components/LoadingCircles.js +20 -20
  118. package/dist/module/components/LoadingCircles.js.map +1 -1
  119. package/dist/module/components/LoadingIndicator.js +11 -11
  120. package/dist/module/components/LoadingIndicator.js.map +1 -1
  121. package/dist/module/components/LoadingStateWidget.js +5 -5
  122. package/dist/module/components/LoadingStateWidget.js.map +1 -1
  123. package/dist/module/components/MediaPlayer.js +31 -31
  124. package/dist/module/components/MediaPlayer.js.map +1 -1
  125. package/dist/module/components/MiddlePopup.js +17 -11
  126. package/dist/module/components/MiddlePopup.js.map +1 -1
  127. package/dist/module/components/PDFPopup.js +52 -39
  128. package/dist/module/components/PDFPopup.js.map +1 -1
  129. package/dist/module/components/PlussChat.js +168 -149
  130. package/dist/module/components/PlussChat.js.map +1 -1
  131. package/dist/module/components/PlussChatMessage.js +42 -42
  132. package/dist/module/components/PlussChatMessage.js.map +1 -1
  133. package/dist/module/components/PlussChatTime.js +18 -17
  134. package/dist/module/components/PlussChatTime.js.map +1 -1
  135. package/dist/module/components/Popup.js +20 -19
  136. package/dist/module/components/Popup.js.map +1 -1
  137. package/dist/module/components/PopupMenu.js +15 -14
  138. package/dist/module/components/PopupMenu.js.map +1 -1
  139. package/dist/module/components/PositionedImage.js +20 -20
  140. package/dist/module/components/PositionedImage.js.map +1 -1
  141. package/dist/module/components/ProfilePic.js +10 -10
  142. package/dist/module/components/ProfilePic.js.map +1 -1
  143. package/dist/module/components/RadioButton.js +10 -9
  144. package/dist/module/components/RadioButton.js.map +1 -1
  145. package/dist/module/components/Reaction.js +18 -17
  146. package/dist/module/components/Reaction.js.map +1 -1
  147. package/dist/module/components/Reactions.js +7 -7
  148. package/dist/module/components/Reactions.js.map +1 -1
  149. package/dist/module/components/SharingTools.js +78 -43
  150. package/dist/module/components/SharingTools.js.map +1 -1
  151. package/dist/module/components/Spinner.js +5 -5
  152. package/dist/module/components/Spinner.js.map +1 -1
  153. package/dist/module/components/StickyFooter.js +6 -6
  154. package/dist/module/components/StickyFooter.js.map +1 -1
  155. package/dist/module/components/Text.js +57 -0
  156. package/dist/module/components/Text.js.map +1 -0
  157. package/dist/module/components/TickIcon.js +6 -6
  158. package/dist/module/components/TickIcon.js.map +1 -1
  159. package/dist/module/components/Toggle.js +10 -9
  160. package/dist/module/components/Toggle.js.map +1 -1
  161. package/dist/module/components/TouchableSearchBar.js +18 -17
  162. package/dist/module/components/TouchableSearchBar.js.map +1 -1
  163. package/dist/module/components/UserListPopup.js +20 -19
  164. package/dist/module/components/UserListPopup.js.map +1 -1
  165. package/dist/module/components/UserListing.js +41 -40
  166. package/dist/module/components/UserListing.js.map +1 -1
  167. package/dist/module/components/VideoPopup.js +20 -20
  168. package/dist/module/components/VideoPopup.js.map +1 -1
  169. package/dist/module/components/WarningPopup.js +21 -20
  170. package/dist/module/components/WarningPopup.js.map +1 -1
  171. package/dist/module/components/expo-image-picker-multiple/ImageBrowser.js +13 -13
  172. package/dist/module/components/expo-image-picker-multiple/ImageBrowser.js.map +1 -1
  173. package/dist/module/components/expo-image-picker-multiple/ImageTile.js +24 -23
  174. package/dist/module/components/expo-image-picker-multiple/ImageTile.js.map +1 -1
  175. package/dist/module/components/index.js +59 -58
  176. package/dist/module/components/index.js.map +1 -1
  177. package/dist/module/components/react-native-expo-image-cropper/ExpoImageManipulator.js +94 -64
  178. package/dist/module/components/react-native-expo-image-cropper/ExpoImageManipulator.js.map +1 -1
  179. package/dist/module/components/react-native-expo-image-cropper/ImageCropOverlay.js +64 -64
  180. package/dist/module/components/react-native-expo-image-cropper/ImageCropOverlay.js.map +1 -1
  181. package/dist/module/config.js +15 -10
  182. package/dist/module/config.js.map +1 -1
  183. package/dist/module/constants.js +3 -4
  184. package/dist/module/constants.js.map +1 -1
  185. package/dist/module/helper.js +83 -82
  186. package/dist/module/helper.js.map +1 -1
  187. package/dist/module/index.js +12 -12
  188. package/dist/module/index.js.map +1 -1
  189. package/dist/module/js/images/detectFaces.js +11 -10
  190. package/dist/module/js/images/detectFaces.js.map +1 -1
  191. package/dist/module/js/images/findLandmarkRange.js +8 -8
  192. package/dist/module/js/images/findLandmarkRange.js.map +1 -1
  193. package/dist/module/js/images/getScaledOffset.js.map +1 -1
  194. package/dist/module/js/site/getSiteLevelFromState.js +2 -2
  195. package/dist/module/js/site/getSiteLevelFromState.js.map +1 -1
  196. package/dist/module/js/site/isTVEnabled.js +2 -2
  197. package/dist/module/js/site/isTVEnabled.js.map +1 -1
  198. package/dist/module/session.js +6 -6
  199. package/dist/module/session.js.map +1 -1
  200. package/dist/module/styles.js +17 -17
  201. package/dist/module/styles.js.map +1 -1
  202. package/dist/module/withNavigationFocus.js +30 -0
  203. package/dist/module/withNavigationFocus.js.map +1 -0
  204. package/package.json +71 -68
  205. package/src/actions/FollowerActions.js +36 -32
  206. package/src/actions/MediaActions.js +25 -20
  207. package/src/actions/ResidentActions.js +26 -21
  208. package/src/actions/UserActions.js +22 -22
  209. package/src/actions/UserSettingsActions.js +11 -11
  210. package/src/actions/index.js +5 -5
  211. package/src/actions/types.js +16 -16
  212. package/src/apis/analyticsActions.js +17 -17
  213. package/src/apis/contactActions.js +20 -20
  214. package/src/apis/eventActions.js +153 -144
  215. package/src/apis/fileActions.js +96 -86
  216. package/src/apis/followerActions.js +29 -29
  217. package/src/apis/index.js +12 -12
  218. package/src/apis/notificationActions.js +44 -44
  219. package/src/apis/profileActions.js +8 -8
  220. package/src/apis/reactionActions.js +81 -73
  221. package/src/apis/settingActions.js +15 -15
  222. package/src/apis/stringActions.js +29 -25
  223. package/src/apis/typeActions.js +10 -10
  224. package/src/apis/userActions.js +93 -93
  225. package/src/assets/icons/fontawesome/fa-brands-400.ttf +0 -0
  226. package/src/assets/icons/fontawesome/fa-light-300.ttf +0 -0
  227. package/src/assets/icons/fontawesome/fa-regular-400.ttf +0 -0
  228. package/src/assets/icons/fontawesome/fa-solid-900.ttf +0 -0
  229. package/src/assets/icons/fontawesome/fa-thin-100.ttf +0 -0
  230. package/src/assets/icons/fontawesome/fa7-glyphmap.json +4205 -0
  231. package/src/colours.js +116 -96
  232. package/src/components/AddButton.js +32 -27
  233. package/src/components/AddToCalendarButton.js +236 -202
  234. package/src/components/Attachment.js +59 -36
  235. package/src/components/AudienceSelectorLauncher.js +52 -48
  236. package/src/components/AudienceSelectorPage.js +353 -311
  237. package/src/components/AutoOffsetImage.js +237 -196
  238. package/src/components/BackButton.js +57 -41
  239. package/src/components/CalendarPopup.js +127 -97
  240. package/src/components/CategoryTabs.js +208 -163
  241. package/src/components/CommentReply.js +370 -309
  242. package/src/components/CommentSection.js +974 -781
  243. package/src/components/ConfirmPopup.js +141 -110
  244. package/src/components/ConfirmationPopup.js +80 -69
  245. package/src/components/DocumentUploader.js +245 -215
  246. package/src/components/DropDownItem.js +70 -60
  247. package/src/components/DropDownMenu.js +31 -27
  248. package/src/components/EmptyStateMain.js +51 -44
  249. package/src/components/EmptyStateWidget.js +47 -38
  250. package/src/components/FontScaleButton.js +29 -25
  251. package/src/components/FontScalePopup.js +67 -56
  252. package/src/components/Forbidden.js +48 -46
  253. package/src/components/FormCard.js +21 -17
  254. package/src/components/FormCardSection.js +284 -233
  255. package/src/components/FormCardSectionOptionLauncher.js +72 -46
  256. package/src/components/FormattedText.js +128 -111
  257. package/src/components/GenericInput.js +168 -136
  258. package/src/components/GenericInputSection.js +209 -161
  259. package/src/components/Header.js +620 -474
  260. package/src/components/Icon.js +119 -0
  261. package/src/components/ImagePopup.js +425 -221
  262. package/src/components/ImageUploadProgress.js +49 -41
  263. package/src/components/ImageUploader.js +968 -797
  264. package/src/components/InlineButton.js +79 -69
  265. package/src/components/Input.js +190 -156
  266. package/src/components/LoadingCircles.js +233 -233
  267. package/src/components/LoadingIndicator.js +87 -76
  268. package/src/components/LoadingStateWidget.js +47 -37
  269. package/src/components/MediaPlayer.js +416 -387
  270. package/src/components/MiddlePopup.js +62 -33
  271. package/src/components/PDFPopup.js +212 -159
  272. package/src/components/PlussChat.js +1224 -1025
  273. package/src/components/PlussChatMessage.js +329 -298
  274. package/src/components/PlussChatTime.js +57 -53
  275. package/src/components/Popup.js +138 -116
  276. package/src/components/PopupMenu.js +140 -110
  277. package/src/components/PositionedImage.js +281 -237
  278. package/src/components/ProfilePic.js +122 -113
  279. package/src/components/RadioButton.js +76 -52
  280. package/src/components/Reaction.js +134 -96
  281. package/src/components/Reactions.js +65 -63
  282. package/src/components/SharingTools.js +185 -134
  283. package/src/components/Spinner.js +13 -13
  284. package/src/components/StickyFooter.js +36 -26
  285. package/src/components/Text.js +62 -0
  286. package/src/components/TickIcon.js +20 -20
  287. package/src/components/Toggle.js +74 -73
  288. package/src/components/TouchableSearchBar.js +68 -50
  289. package/src/components/UserListPopup.js +161 -124
  290. package/src/components/UserListing.js +273 -238
  291. package/src/components/VideoPopup.js +110 -96
  292. package/src/components/WarningPopup.js +92 -71
  293. package/src/components/expo-image-picker-multiple/ImageBrowser.js +288 -256
  294. package/src/components/expo-image-picker-multiple/ImageTile.js +108 -84
  295. package/src/components/index.js +59 -58
  296. package/src/components/react-native-expo-image-cropper/ExpoImageManipulator.js +444 -359
  297. package/src/components/react-native-expo-image-cropper/ImageCropOverlay.js +420 -324
  298. package/src/config.js +26 -21
  299. package/src/constants.js +8 -10
  300. package/src/helper.js +469 -438
  301. package/src/index.js +24 -12
  302. package/src/js/images/detectFaces.js +28 -21
  303. package/src/js/images/findLandmarkRange.js +97 -90
  304. package/src/js/images/getScaledOffset.js +80 -75
  305. package/src/js/site/getSiteLevelFromState.js +26 -26
  306. package/src/js/site/isTVEnabled.js +10 -10
  307. package/src/session.js +32 -32
  308. package/src/styles.js +61 -61
  309. package/src/withNavigationFocus.js +28 -0
  310. package/dist/module/components/TextStyle.js +0 -45
  311. package/dist/module/components/TextStyle.js.map +0 -1
  312. package/dist/module/fonts/index.js +0 -2
  313. package/dist/module/fonts/index.js.map +0 -1
  314. package/dist/module/fonts/pluss60-icons.js +0 -5
  315. package/dist/module/fonts/pluss60-icons.js.map +0 -1
  316. package/dist/module/fonts/pluss60-icons.json +0 -1097
  317. package/src/components/TextStyle.js +0 -48
  318. package/src/fonts/index.js +0 -1
  319. package/src/fonts/pluss60-icons.js +0 -7
  320. package/src/fonts/pluss60-icons.json +0 -1097
@@ -1,813 +1,984 @@
1
- import React, { Component } from 'react';
2
- import { View, ScrollView, TouchableOpacity, Text, Platform, Linking, Modal, Dimensions, StyleSheet, ImageBackground } from 'react-native';
3
- import { connect } from 'react-redux';
4
- import { Icon } from '@rneui/themed';
5
- import _ from 'lodash';
6
- import { Camera } from 'expo-camera';
7
- import * as MediaLibrary from 'expo-media-library';
8
- import * as ImageManipulator from 'expo-image-manipulator';
9
- import * as ImagePicker from 'expo-image-picker';
10
- import ImageBrowser from './expo-image-picker-multiple/ImageBrowser';
11
- import ExpoImageManipulator from './react-native-expo-image-cropper/ExpoImageManipulator';
12
- import Header from './Header';
13
- import { Popup } from './Popup';
14
- import { PopupMenu } from './PopupMenu';
15
- import { InlineButton } from './InlineButton';
16
- import { getValueOrDefault, getThumb300, isVideo } from '../helper';
17
- import { getMainBrandingColourFromState, BOXGREY, INACTIVE_BUTTON, TEXT_BLUEGREY, TEXT_DARK, LINEGREY } from '../colours';
18
- import Config from '../config';
19
- import { fileActions } from '../apis';
20
- import { stockImagesLoaded, imageLibraryLoaded } from '../actions';
21
-
22
- const SCREEN_WIDTH = Dimensions.get('window').width;
23
- const SCREEN_HEIGHT = Dimensions.get('window').height;
1
+ import React, { Component } from "react";
2
+ import { Text } from "@plusscommunities/pluss-core-app/components";
3
+ import {
4
+ View,
5
+ ScrollView,
6
+ TouchableOpacity,
7
+ Platform,
8
+ Linking,
9
+ Modal,
10
+ Dimensions,
11
+ StyleSheet,
12
+ ImageBackground,
13
+ } from "react-native";
14
+ import { connect } from "react-redux";
15
+ import { withSafeAreaInsets } from "react-native-safe-area-context";
16
+ import { Icon } from "@rneui/themed";
17
+ import _ from "lodash";
18
+ import { Camera } from "expo-camera";
19
+ import * as MediaLibrary from "expo-media-library";
20
+ import * as ImageManipulator from "expo-image-manipulator";
21
+ import * as ImagePicker from "expo-image-picker";
22
+ import ImageBrowser from "./expo-image-picker-multiple/ImageBrowser";
23
+ import ExpoImageManipulator from "./react-native-expo-image-cropper/ExpoImageManipulator";
24
+ import Header from "./Header";
25
+ import { Popup } from "./Popup";
26
+ import { PopupMenu } from "./PopupMenu";
27
+ import { InlineButton } from "./InlineButton";
28
+ import { getValueOrDefault, getThumb300, isVideo } from "../helper";
29
+ import {
30
+ getMainBrandingColourFromState,
31
+ BOXGREY,
32
+ INACTIVE_BUTTON,
33
+ TEXT_BLUEGREY,
34
+ TEXT_DARK,
35
+ LINEGREY,
36
+ } from "../colours";
37
+ import Config from "../config";
38
+ import { fileActions } from "../apis";
39
+ import { stockImagesLoaded, imageLibraryLoaded } from "../actions";
40
+
41
+ const SCREEN_WIDTH = Dimensions.get("window").width;
42
+ const SCREEN_HEIGHT = Dimensions.get("window").height;
24
43
  const DEFAULT_ASPECT = [1, 1];
25
44
  const DEFAULT_ALLOWS_EDITING = true;
26
45
  const DEFAULT_ALLOWS_IOS_CAMERA_EDITING = false;
27
46
  const DEFAULT_EXIF = true;
28
- const DEFULAT_IMAGE_TYPE = 'jpeg';
29
- const DEFAULT_IMAGE_NAME = 'image';
30
- const DEFAULT_VIDEO_NAME = 'video';
47
+ const DEFULAT_IMAGE_TYPE = "jpeg";
48
+ const DEFAULT_IMAGE_NAME = "image";
49
+ const DEFAULT_VIDEO_NAME = "video";
31
50
  const DEFAULT_SIZE = {
32
- width: 1400,
51
+ width: 1400,
33
52
  };
34
53
  const DEFAULT_COMPRESSION = 0.8;
35
54
 
36
55
  class ImageUploader extends Component {
37
- constructor(props) {
38
- super(props);
39
-
40
- this.state = {
41
- showUploadMenu: false,
42
- warning: null,
43
- showPhotos: false,
44
- showRemote: false,
45
- selected: [],
46
- selectedType: '',
47
- onAttach: null,
48
- selectedAlbumId: '',
49
- showSelectAlbum: false,
50
- showCropper: false,
51
- localAlbums: [],
52
- loadingLocalFolders: false,
53
- loadingRemoteFolders: false,
54
- };
55
- }
56
-
57
- componentDidMount() {
58
- this.loadLocalAlbums();
59
- this.loadRemoteAlbums();
60
- }
61
-
62
- loadLocalAlbums = async () => {
63
- const hasPermission = await MediaLibrary.getPermissionsAsync();
64
- if (!hasPermission.granted) return;
65
-
66
- this.setState({ loadingLocalFolders: true }, async () => {
67
- try {
68
- const localAlbums = await MediaLibrary.getAlbumsAsync({ includeSmartAlbums: true });
69
- this.setState({
70
- loadingLocalFolders: false,
71
- localAlbums: [
72
- {
73
- title: 'All Photos',
74
- id: '',
75
- },
76
- ...localAlbums,
77
- ],
78
- });
79
- } catch (error) {
80
- console.log('loadLocalAlbums - error', error);
81
- this.setState({ loadingLocalFolders: false });
82
- }
83
- });
84
- };
85
-
86
- loadRemoteAlbums = () => {
87
- this.setState({ loadingRemoteFolders: true }, async () => {
88
- try {
89
- const stockImages = await fileActions.getStockPhotos();
90
- this.props.stockImagesLoaded(stockImages);
91
- const libraryRes = await fileActions.getMediaFolders(this.props.user.site);
92
- this.props.imageLibraryLoaded(libraryRes.data);
93
- } catch (error) {
94
- console.log('loadRemoteAlbums - error', error);
95
- } finally {
96
- this.setState({ loadingRemoteFolders: false });
97
- }
98
- });
99
- };
100
-
101
- showUploadMenu() {
102
- this.setState({
103
- showUploadMenu: true,
104
- });
105
- }
106
-
107
- hideUploadMenu() {
108
- this.setState({
109
- showUploadMenu: false,
110
- });
111
- }
112
-
113
- retryUpload = async (mediaUri, uploadUri) => {
114
- try {
115
- const uri = isVideo(uploadUri) ? mediaUri : (await this.resizeImageAsync(mediaUri)).uri;
116
- const res = await fileActions.uploadUserMediaWithProgress(uri, uploadUri, progress => {
117
- if (this.props.onUploadProgress) this.props.onUploadProgress(progress);
118
- });
119
- this.props.onUploadSuccess(Config.env.baseUploadsUrl + res.key, uploadUri);
120
- console.log('upload(retry) success', Config.env.baseUploadsUrl + res.key);
121
- } catch (e) {
122
- console.log('retryUpload error', e);
123
- this.props.onUploadFailed(uploadUri);
124
- }
125
- };
126
-
127
- resizeImageAsync = async uri => {
128
- const actions = [
129
- {
130
- resize: getValueOrDefault(this.props.size, DEFAULT_SIZE),
131
- },
132
- ];
133
- const saveOptions = {
134
- format: DEFULAT_IMAGE_TYPE,
135
- compress: getValueOrDefault(this.props.quality, DEFAULT_COMPRESSION),
136
- base64: true,
137
- };
138
- return await ImageManipulator.manipulateAsync(uri, actions, saveOptions);
139
- };
140
-
141
- handleImagePicked = async imageUri => {
142
- let uploadUri;
143
- try {
144
- const fileName = `${getValueOrDefault(this.props.fileName, DEFAULT_IMAGE_NAME)}.${DEFULAT_IMAGE_TYPE}`;
145
- uploadUri = fileActions.getUploadUrl(this.props.userId, fileName);
146
-
147
- this.props.onUploadStarted(uploadUri, imageUri);
148
- this.hideUploadMenu();
149
-
150
- const resized = await this.resizeImageAsync(imageUri);
151
- if (this.props.onlySelectImage) {
152
- this.props.onImageSelected(resized, fileName);
153
- return;
154
- }
155
-
156
- const res = await fileActions.uploadUserMediaWithProgress(resized.uri, uploadUri, progress => {
157
- if (this.props.onUploadProgress) this.props.onUploadProgress(progress);
158
- });
159
-
160
- this.props.onUploadSuccess(Config.env.baseUploadsUrl + res.key, uploadUri);
161
- console.log('upload success', Config.env.baseUploadsUrl + res.key);
162
- } catch (e) {
163
- console.log('handleImagePicked error', e);
164
- this.props.onUploadFailed(uploadUri);
165
- }
166
- };
167
-
168
- handleMultiImagePicked = async imagesSelected => {
169
- // Signal start of all images selected
170
- const imagesUploaded = imagesSelected.map(image => {
171
- const fileName = `${getValueOrDefault(this.props.fileName, DEFAULT_IMAGE_NAME)}.${DEFULAT_IMAGE_TYPE}`;
172
- const uploadUri = fileActions.getUploadUrl(this.props.userId, fileName);
173
- if (!this.props.onlySelectImage) this.props.onUploadStarted(uploadUri, image.uri);
174
- return { imageUri: image.uri, uploadUri, fileName };
175
- });
176
- this.hideUploadMenu();
177
-
178
- // Sequentially upload all imagesUploaded
179
- for (let i = 0; i < imagesUploaded.length; i++) {
180
- const image = imagesUploaded[i];
181
- const { imageUri, uploadUri, fileName } = image;
182
- try {
183
- const resized = await this.resizeImageAsync(imageUri);
184
- if (this.props.onlySelectImage) {
185
- this.props.onImageSelected(resized, fileName);
186
- return;
187
- }
188
-
189
- const res = await fileActions.uploadUserMediaWithProgress(resized.uri, uploadUri, progress => {
190
- if (this.props.onUploadProgress) this.props.onUploadProgress(progress);
191
- });
192
- this.props.onUploadSuccess(Config.env.baseUploadsUrl + res.key, uploadUri);
193
- console.log('upload success', Config.env.baseUploadsUrl + res.key);
194
- } catch (e) {
195
- console.log('handleMultiImagePicked error', e);
196
- this.props.onUploadFailed(uploadUri);
197
- }
198
- }
199
- };
200
-
201
- handleVideoPicked = async uri => {
202
- let uploadUri;
203
- try {
204
- const fileType = uri.substring(uri.lastIndexOf('.') + 1);
205
- const fileName = `${getValueOrDefault(this.props.fileName, DEFAULT_VIDEO_NAME)}.${fileType}`;
206
- uploadUri = fileActions.getUploadUrl(this.props.userId, fileName);
207
-
208
- this.props.onUploadStarted(uploadUri, uri);
209
- this.hideUploadMenu();
210
-
211
- const res = await fileActions.uploadUserMediaWithProgress(uri, uploadUri, progress => {
212
- if (this.props.onUploadProgress) this.props.onUploadProgress(progress);
213
- });
214
-
215
- this.props.onUploadSuccess(Config.env.baseUploadsUrl + res.key, uploadUri);
216
- console.log('upload success', Config.env.baseUploadsUrl + res.key);
217
- } catch (e) {
218
- console.log('handleVideoPicked error', e);
219
- this.props.onUploadFailed(uploadUri);
220
- }
221
- };
222
-
223
- showWarningPopup(camera, roll) {
224
- if (Platform.OS !== 'ios') {
225
- return;
226
- }
227
- let innerWarning = '';
228
- if (camera && roll) {
229
- innerWarning = 'both your camera and photo library';
230
- } else if (camera) {
231
- innerWarning = 'your camera';
232
- } else if (roll) {
233
- innerWarning = 'your photo library';
234
- } else {
235
- // nothing to warn about
236
- return;
237
- }
238
- this.setState({
239
- warning: `You must grant access to ${innerWarning}. Tap Go to settings to change your permission settings.`,
240
- });
241
- }
242
-
243
- closeWarningPopup() {
244
- this.setState({
245
- warning: null,
246
- });
247
- }
248
-
249
- goToPermissionSettings() {
250
- Linking.openURL('app-settings:');
251
- this.setState({
252
- warning: null,
253
- });
254
- }
255
-
256
- askPermissionsAsync = async () => {
257
- const cameraPermission = await Camera.requestCameraPermissionsAsync();
258
- const rollPermission = await MediaLibrary.requestPermissionsAsync();
259
- if (cameraPermission.status !== 'granted' || (Platform.OS === 'ios' && rollPermission.status !== 'granted')) {
260
- this.showWarningPopup(cameraPermission.status !== 'granted', rollPermission.status !== 'granted');
261
- return false;
262
- }
263
- if (this.state.localAlbums?.length <= 0) this.loadLocalAlbums();
264
-
265
- return true;
266
- };
267
-
268
- isEditingEnabled = () => {
269
- return !this.props.multiple && !this.props.allowVideo && getValueOrDefault(this.props.allowsEditing, DEFAULT_ALLOWS_EDITING);
270
- };
271
-
272
- openCamera = async () => {
273
- if (!(await this.askPermissionsAsync())) return;
274
-
275
- let editingAllowed = this.isEditingEnabled();
276
- if (Platform.OS === 'ios') {
277
- editingAllowed = getValueOrDefault(
278
- this.props.allowsEditingIOSCamera,
279
- getValueOrDefault(this.props.allowsEditing, DEFAULT_ALLOWS_IOS_CAMERA_EDITING),
280
- );
281
- }
282
- const result = await ImagePicker.launchCameraAsync({
283
- allowsEditing: editingAllowed,
284
- aspect: getValueOrDefault(this.props.aspect, DEFAULT_ASPECT),
285
- exif: getValueOrDefault(this.props.exif, DEFAULT_EXIF),
286
- });
287
-
288
- if (!result.canceled && !_.isEmpty(result.assets)) {
289
- this.handleImagePicked(result.assets[0].uri);
290
- }
291
- };
292
-
293
- openVideoCamera = async () => {
294
- if (!(await this.askPermissionsAsync())) return;
295
-
296
- const result = await ImagePicker.launchCameraAsync({
297
- allowsEditing: this.isEditingEnabled(),
298
- mediaTypes: ImagePicker.MediaTypeOptions.Videos,
299
- });
300
-
301
- if (!result.canceled && !_.isEmpty(result.assets)) {
302
- this.handleImagePicked(result.assets[0].uri);
303
- }
304
- };
305
-
306
- openLibrary = async () => {
307
- this.setState(
308
- {
309
- showUploadMenu: false,
310
- },
311
- () => {
312
- setTimeout(() => {
313
- this.setState({
314
- showPhotos: true,
315
- selected: [],
316
- showRemote: true,
317
- selectedAlbumId: '',
318
- });
319
- }, 1000);
320
- },
321
- );
322
- };
323
-
324
- openPhotos = async () => {
325
- if (Platform.OS === 'android') {
326
- const result = await ImagePicker.launchImageLibraryAsync({
327
- allowsEditing: this.isEditingEnabled(),
328
- aspect: getValueOrDefault(this.props.aspect, DEFAULT_ASPECT),
329
- exif: getValueOrDefault(this.props.exif, DEFAULT_EXIF),
330
- mediaTypes: this.props.allowVideo ? ImagePicker.MediaTypeOptions.All : ImagePicker.MediaTypeOptions.Images,
331
- });
332
- if (!result.cancelled) {
333
- if (result.assets.length === 1 && result.assets[0].type === 'video') {
334
- this.handleVideoPicked(result.assets[0].uri);
335
- } else {
336
- this.handleMultiImagePicked(result.assets);
337
- }
338
- }
339
- return;
340
- }
341
-
342
- // iOS behaviour
343
- if (!(await this.askPermissionsAsync())) return;
344
-
345
- this.setState(
346
- {
347
- showUploadMenu: false,
348
- },
349
- () => {
350
- setTimeout(() => {
351
- this.setState({
352
- showPhotos: true,
353
- selected: [],
354
- showRemote: false,
355
- selectedAlbumId: '',
356
- });
357
- }, 1000);
358
- },
359
- );
360
- };
361
-
362
- hidePhotos = () => {
363
- this.setState({ showPhotos: false });
364
- };
365
-
366
- openCropper = () => {
367
- // Switching modals - requires a timeout to ensure the modal is closed before opening the next one
368
- this.setState(
369
- {
370
- showPhotos: false,
371
- },
372
- () => {
373
- setTimeout(() => {
374
- this.setState({
375
- showCropper: true,
376
- });
377
- }, 1000);
378
- },
379
- );
380
- };
381
-
382
- toggleCropper = () => {
383
- this.setState({ showCropper: !this.state.showCropper });
384
- };
385
-
386
- onSelectAlbum = () => {
387
- this.setState({ showSelectAlbum: true });
388
- };
389
-
390
- onSelectAlbumClosed = () => {
391
- this.setState({ showSelectAlbum: false });
392
- };
393
-
394
- onAlbumSelected = selectedAlbumId => {
395
- this.setState({ showSelectAlbum: false, selectedAlbumId });
396
- };
397
-
398
- onSelectionChange = (selected, videoSelected, onAttach) => {
399
- this.setState({
400
- selected,
401
- selectedType: videoSelected ? 'video' : 'image',
402
- onAttach,
403
- });
404
- };
405
-
406
- onSelected = async callback => {
407
- if (this.isEditingEnabled()) {
408
- this.openCropper();
409
- } else {
410
- const mediaSelected = await callback;
411
- // console.log('mediaSelected', mediaSelected);
412
- if (this.state.showRemote) {
413
- if (this.props.onLibrarySelected) {
414
- mediaSelected.map(media => {
415
- this.props.onLibrarySelected(media.uri);
416
- });
417
- }
418
- } else {
419
- if (mediaSelected[0].mediaType === MediaLibrary.MediaType.video) {
420
- const uri = mediaSelected[0].localUri || mediaSelected[0].uri;
421
- this.handleVideoPicked(uri);
422
- } else {
423
- this.handleMultiImagePicked(mediaSelected);
424
- }
425
- }
426
-
427
- this.hidePhotos();
428
- }
429
- };
430
-
431
- onRemoveImage = uri => {
432
- const selected = [...this.state.selected];
433
- const deleteIndex = selected.indexOf(uri);
434
- selected.splice(deleteIndex, 1);
435
- this.setState({ selected });
436
- };
437
-
438
- buildOptions = () => {
439
- const options = [
440
- {
441
- text: 'Take photo',
442
- onPress: this.openCamera,
443
- },
444
- ];
445
- if (this.props.allowVideo)
446
- options.push({
447
- text: 'Record video',
448
- onPress: this.openVideoCamera,
449
- });
450
- options.push({
451
- text: 'Camera Roll',
452
- onPress: this.openPhotos,
453
- });
454
- if (!this.props.hideLibrary)
455
- options.push({
456
- text: 'Image Library',
457
- onPress: this.openLibrary,
458
- });
459
-
460
- return options;
461
- };
462
-
463
- renderSelectionPreview() {
464
- const { selected, showRemote } = this.state;
465
-
466
- return (
467
- <View>
468
- <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.selectionPreviewContainer}>
469
- {selected &&
470
- selected.map(uri => {
471
- const imageUri = showRemote ? getThumb300(uri) : uri;
472
- return (
473
- <View key={uri} style={styles.previewItemContainer}>
474
- <ImageBackground style={styles.previewItemImage} source={{ uri: imageUri }} />
475
- <TouchableOpacity style={styles.previewItemRemoveButton} onPress={() => this.onRemoveImage(uri)}>
476
- <View style={[styles.previewItemRemoveContainer, { backgroundColor: this.props.colourBrandingMain }]}>
477
- <Icon name="times" type="font-awesome" iconStyle={styles.previewItemRemoveIcon} />
478
- </View>
479
- </TouchableOpacity>
480
- </View>
481
- );
482
- })}
483
- </ScrollView>
484
- </View>
485
- );
486
- }
487
-
488
- renderSelectedAlbum() {
489
- const { localAlbums, selectedAlbumId, showRemote } = this.state;
490
- const selectedAlbum = (showRemote ? this.props.imageLibrary : localAlbums).find(album => album.id === selectedAlbumId);
491
- const selectedAlbumText = selectedAlbum ? selectedAlbum.title : '';
492
-
493
- return (
494
- <TouchableOpacity onPress={this.onSelectAlbum}>
495
- <View style={styles.selectAlbumButton}>
496
- <Text style={styles.selectAlbumButtonText}>{selectedAlbumText}</Text>
497
- <Icon name="angle-down" type="font-awesome" iconStyle={styles.selectAlbumButtonIcon} />
498
- </View>
499
- </TouchableOpacity>
500
- );
501
- }
502
-
503
- renderSelectedComponent = selectedItemNumber => {
504
- return (
505
- <View style={styles.selectedItemContainer}>
506
- <View style={[styles.selectedMarkerContainer, { backgroundColor: this.props.colourBrandingMain }]}>
507
- {this.props.multiple ? (
508
- <Text style={styles.selectedItemText}>{selectedItemNumber}</Text>
509
- ) : (
510
- <Icon name="check" type="font-awesome" iconStyle={styles.selectedItemIcon} />
511
- )}
512
- </View>
513
- </View>
514
- );
515
- };
516
-
517
- renderBrowser() {
518
- const { selected, selectedAlbumId, showRemote } = this.state;
519
- const { imagesLimit, multiple, allowVideo, imageLibrary } = this.props;
520
- const width = (SCREEN_WIDTH - 10 * 2) / 4;
521
-
522
- return (
523
- <ImageBrowser
524
- max={!multiple ? 1 : imagesLimit}
525
- loadCount={30}
526
- onChange={this.onSelectionChange}
527
- renderSelectedComponent={this.renderSelectedComponent}
528
- callback={this.onSelected}
529
- selected={selected}
530
- allowVideo={allowVideo}
531
- style={styles.browserContainer}
532
- itemStyle={styles.itemContainer}
533
- itemWidth={width}
534
- itemHeight={width}
535
- album={selectedAlbumId}
536
- remoteAlbums={showRemote ? imageLibrary : null}
537
- />
538
- );
539
- }
540
-
541
- renderAttachButton() {
542
- const { selected, selectedType } = this.state;
543
- const canAttach = selected.length > 0 && !_.isEmpty(selectedType);
544
- const attachText = `Attach ${canAttach ? selected.length : ''} ${canAttach ? selectedType : ''}${selected.length > 1 ? 's' : ''}`;
545
-
546
- return (
547
- <View style={styles.buttonContainer}>
548
- <InlineButton
549
- color={canAttach ? this.props.colourBrandingMain : INACTIVE_BUTTON}
550
- onPress={this.state.onAttach}
551
- fillTouchable
552
- large
553
- disabled={!canAttach}
554
- >
555
- {attachText}
556
- </InlineButton>
557
- </View>
558
- );
559
- }
560
-
561
- renderSelectAlbumPopup() {
562
- const { showSelectAlbum, localAlbums, showRemote } = this.state;
563
- if (!showSelectAlbum) return null;
564
-
565
- return (
566
- <Modal visible transparent animationType="slide" onRequestClose={this.onSelectAlbumClosed}>
567
- <View style={styles.selectAlbumModal}>
568
- <View style={styles.selectAlbumContainer}>
569
- <View style={styles.selectAlbumTitleContainer}>
570
- <Text style={styles.selectAlbumTitle}>Select Album</Text>
571
- </View>
572
- <ScrollView>
573
- {(showRemote ? this.props.imageLibrary : localAlbums).map((album, index) => {
574
- return (
575
- <TouchableOpacity key={album.id} onPress={() => this.onAlbumSelected(album.id)}>
576
- <View style={[styles.albumOptionContainer, index === 0 && { borderTopWidth: 0 }]}>
577
- <Text style={styles.albumOptionText}>{album.title}</Text>
578
- </View>
579
- </TouchableOpacity>
580
- );
581
- })}
582
- </ScrollView>
583
- <TouchableOpacity onPress={this.onSelectAlbumClosed}>
584
- <View style={[styles.albumOptionContainer, { marginHorizontal: 0 }]}>
585
- <Text style={[styles.albumOptionText, { color: this.props.colourBrandingMain }]}>Cancel</Text>
586
- </View>
587
- </TouchableOpacity>
588
- </View>
589
- </View>
590
- </Modal>
591
- );
592
- }
593
-
594
- renderPhotos() {
595
- return (
596
- <Modal visible transparent animationType="slide" onRequestClose={this.hidePhotos}>
597
- <Header leftIcon="angle-left" onPressLeft={this.hidePhotos} text={this.props.popupTitle || 'Attach image'} />
598
- <View style={styles.contentContainer}>
599
- {this.renderSelectionPreview()}
600
- {this.renderSelectedAlbum()}
601
- {this.renderBrowser()}
602
- </View>
603
- {this.renderAttachButton()}
604
- {this.renderSelectAlbumPopup()}
605
- </Modal>
606
- );
607
- }
608
-
609
- render() {
610
- const { warning, showUploadMenu, showPhotos, showCropper, selected } = this.state;
611
-
612
- if (warning != null) {
613
- return (
614
- <Popup
615
- title="Permissions missing"
616
- text={warning}
617
- options={[
618
- {
619
- text: 'Go to settings',
620
- action: this.goToPermissionSettings.bind(this),
621
- bold: true,
622
- },
623
- {
624
- text: 'Ignore',
625
- action: this.closeWarningPopup.bind(this),
626
- },
627
- ]}
628
- />
629
- );
630
- }
631
-
632
- if (showUploadMenu) {
633
- const options = this.buildOptions();
634
- return <PopupMenu onClose={this.hideUploadMenu.bind(this)} options={options} title={this.props.popupTitle} cancelText="Cancel" />;
635
- }
636
-
637
- if (showPhotos) return this.renderPhotos();
638
-
639
- if (showCropper) {
640
- return (
641
- <ExpoImageManipulator
642
- photo={{ uri: selected[0] }}
643
- onToggleModal={this.toggleCropper}
644
- isVisible={showCropper}
645
- onPictureChoosed={data => {
646
- this.handleImagePicked(data.uri);
647
- }}
648
- />
649
- );
650
- }
651
-
652
- return null;
653
- }
56
+ constructor(props) {
57
+ super(props);
58
+
59
+ this.state = {
60
+ showUploadMenu: false,
61
+ warning: null,
62
+ showPhotos: false,
63
+ showRemote: false,
64
+ selected: [],
65
+ selectedType: "",
66
+ onAttach: null,
67
+ selectedAlbumId: "",
68
+ showSelectAlbum: false,
69
+ showCropper: false,
70
+ localAlbums: [],
71
+ loadingLocalFolders: false,
72
+ loadingRemoteFolders: false,
73
+ };
74
+ }
75
+
76
+ componentDidMount() {
77
+ this.loadLocalAlbums();
78
+ this.loadRemoteAlbums();
79
+ }
80
+
81
+ loadLocalAlbums = async () => {
82
+ const hasPermission = await MediaLibrary.getPermissionsAsync();
83
+ if (!hasPermission.granted) return;
84
+
85
+ this.setState({ loadingLocalFolders: true }, async () => {
86
+ try {
87
+ const localAlbums = await MediaLibrary.getAlbumsAsync({
88
+ includeSmartAlbums: true,
89
+ });
90
+ this.setState({
91
+ loadingLocalFolders: false,
92
+ localAlbums: [
93
+ {
94
+ title: "All Photos",
95
+ id: "",
96
+ },
97
+ ...localAlbums,
98
+ ],
99
+ });
100
+ } catch (error) {
101
+ console.log("loadLocalAlbums - error", error);
102
+ this.setState({ loadingLocalFolders: false });
103
+ }
104
+ });
105
+ };
106
+
107
+ loadRemoteAlbums = () => {
108
+ this.setState({ loadingRemoteFolders: true }, async () => {
109
+ try {
110
+ const stockImages = await fileActions.getStockPhotos();
111
+ this.props.stockImagesLoaded(stockImages);
112
+ const libraryRes = await fileActions.getMediaFolders(
113
+ this.props.user.site,
114
+ );
115
+ this.props.imageLibraryLoaded(libraryRes.data);
116
+ } catch (error) {
117
+ console.log("loadRemoteAlbums - error", error);
118
+ } finally {
119
+ this.setState({ loadingRemoteFolders: false });
120
+ }
121
+ });
122
+ };
123
+
124
+ showUploadMenu() {
125
+ this.setState({
126
+ showUploadMenu: true,
127
+ });
128
+ }
129
+
130
+ hideUploadMenu() {
131
+ this.setState({
132
+ showUploadMenu: false,
133
+ });
134
+ }
135
+
136
+ retryUpload = async (mediaUri, uploadUri) => {
137
+ try {
138
+ const uri = isVideo(uploadUri)
139
+ ? mediaUri
140
+ : (await this.resizeImageAsync(mediaUri)).uri;
141
+ const res = await fileActions.uploadUserMediaWithProgress(
142
+ uri,
143
+ uploadUri,
144
+ (progress) => {
145
+ if (this.props.onUploadProgress)
146
+ this.props.onUploadProgress(progress);
147
+ },
148
+ );
149
+ this.props.onUploadSuccess(
150
+ Config.env.baseUploadsUrl + res.key,
151
+ uploadUri,
152
+ );
153
+ console.log("upload(retry) success", Config.env.baseUploadsUrl + res.key);
154
+ } catch (e) {
155
+ console.log("retryUpload error", e);
156
+ this.props.onUploadFailed(uploadUri);
157
+ }
158
+ };
159
+
160
+ resizeImageAsync = async (uri) => {
161
+ const actions = [
162
+ {
163
+ resize: getValueOrDefault(this.props.size, DEFAULT_SIZE),
164
+ },
165
+ ];
166
+ const saveOptions = {
167
+ format: DEFULAT_IMAGE_TYPE,
168
+ compress: getValueOrDefault(this.props.quality, DEFAULT_COMPRESSION),
169
+ base64: true,
170
+ };
171
+ return await ImageManipulator.manipulateAsync(uri, actions, saveOptions);
172
+ };
173
+
174
+ handleImagePicked = async (imageUri) => {
175
+ let uploadUri;
176
+ try {
177
+ const fileName = `${getValueOrDefault(this.props.fileName, DEFAULT_IMAGE_NAME)}.${DEFULAT_IMAGE_TYPE}`;
178
+ uploadUri = fileActions.getUploadUrl(this.props.userId, fileName);
179
+
180
+ this.props.onUploadStarted(uploadUri, imageUri);
181
+ this.hideUploadMenu();
182
+
183
+ const resized = await this.resizeImageAsync(imageUri);
184
+ if (this.props.onlySelectImage) {
185
+ this.props.onImageSelected(resized, fileName);
186
+ return;
187
+ }
188
+
189
+ const res = await fileActions.uploadUserMediaWithProgress(
190
+ resized.uri,
191
+ uploadUri,
192
+ (progress) => {
193
+ if (this.props.onUploadProgress)
194
+ this.props.onUploadProgress(progress);
195
+ },
196
+ );
197
+
198
+ this.props.onUploadSuccess(
199
+ Config.env.baseUploadsUrl + res.key,
200
+ uploadUri,
201
+ );
202
+ console.log("upload success", Config.env.baseUploadsUrl + res.key);
203
+ } catch (e) {
204
+ console.log("handleImagePicked error", e);
205
+ this.props.onUploadFailed(uploadUri);
206
+ }
207
+ };
208
+
209
+ handleMultiImagePicked = async (imagesSelected) => {
210
+ // Signal start of all images selected
211
+ const imagesUploaded = imagesSelected.map((image) => {
212
+ const fileName = `${getValueOrDefault(this.props.fileName, DEFAULT_IMAGE_NAME)}.${DEFULAT_IMAGE_TYPE}`;
213
+ const uploadUri = fileActions.getUploadUrl(this.props.userId, fileName);
214
+ if (!this.props.onlySelectImage)
215
+ this.props.onUploadStarted(uploadUri, image.uri);
216
+ return { imageUri: image.uri, uploadUri, fileName };
217
+ });
218
+ this.hideUploadMenu();
219
+
220
+ // Sequentially upload all imagesUploaded
221
+ for (let i = 0; i < imagesUploaded.length; i++) {
222
+ const image = imagesUploaded[i];
223
+ const { imageUri, uploadUri, fileName } = image;
224
+ try {
225
+ const resized = await this.resizeImageAsync(imageUri);
226
+ if (this.props.onlySelectImage) {
227
+ this.props.onImageSelected(resized, fileName);
228
+ return;
229
+ }
230
+
231
+ const res = await fileActions.uploadUserMediaWithProgress(
232
+ resized.uri,
233
+ uploadUri,
234
+ (progress) => {
235
+ if (this.props.onUploadProgress)
236
+ this.props.onUploadProgress(progress);
237
+ },
238
+ );
239
+ this.props.onUploadSuccess(
240
+ Config.env.baseUploadsUrl + res.key,
241
+ uploadUri,
242
+ );
243
+ console.log("upload success", Config.env.baseUploadsUrl + res.key);
244
+ } catch (e) {
245
+ console.log("handleMultiImagePicked error", e);
246
+ this.props.onUploadFailed(uploadUri);
247
+ }
248
+ }
249
+ };
250
+
251
+ handleVideoPicked = async (uri) => {
252
+ let uploadUri;
253
+ try {
254
+ const fileType = uri.substring(uri.lastIndexOf(".") + 1);
255
+ const fileName = `${getValueOrDefault(this.props.fileName, DEFAULT_VIDEO_NAME)}.${fileType}`;
256
+ uploadUri = fileActions.getUploadUrl(this.props.userId, fileName);
257
+
258
+ this.props.onUploadStarted(uploadUri, uri);
259
+ this.hideUploadMenu();
260
+
261
+ const res = await fileActions.uploadUserMediaWithProgress(
262
+ uri,
263
+ uploadUri,
264
+ (progress) => {
265
+ if (this.props.onUploadProgress)
266
+ this.props.onUploadProgress(progress);
267
+ },
268
+ );
269
+
270
+ this.props.onUploadSuccess(
271
+ Config.env.baseUploadsUrl + res.key,
272
+ uploadUri,
273
+ );
274
+ console.log("upload success", Config.env.baseUploadsUrl + res.key);
275
+ } catch (e) {
276
+ console.log("handleVideoPicked error", e);
277
+ this.props.onUploadFailed(uploadUri);
278
+ }
279
+ };
280
+
281
+ showWarningPopup(camera, roll) {
282
+ if (Platform.OS !== "ios") {
283
+ return;
284
+ }
285
+ let innerWarning = "";
286
+ if (camera && roll) {
287
+ innerWarning = "both your camera and photo library";
288
+ } else if (camera) {
289
+ innerWarning = "your camera";
290
+ } else if (roll) {
291
+ innerWarning = "your photo library";
292
+ } else {
293
+ // nothing to warn about
294
+ return;
295
+ }
296
+ this.setState({
297
+ warning: `You must grant access to ${innerWarning}. Tap Go to settings to change your permission settings.`,
298
+ });
299
+ }
300
+
301
+ closeWarningPopup() {
302
+ this.setState({
303
+ warning: null,
304
+ });
305
+ }
306
+
307
+ goToPermissionSettings() {
308
+ Linking.openURL("app-settings:");
309
+ this.setState({
310
+ warning: null,
311
+ });
312
+ }
313
+
314
+ askPermissionsAsync = async () => {
315
+ const cameraPermission = await Camera.requestCameraPermissionsAsync();
316
+ const rollPermission = await MediaLibrary.requestPermissionsAsync();
317
+ if (
318
+ cameraPermission.status !== "granted" ||
319
+ (Platform.OS === "ios" && rollPermission.status !== "granted")
320
+ ) {
321
+ this.showWarningPopup(
322
+ cameraPermission.status !== "granted",
323
+ rollPermission.status !== "granted",
324
+ );
325
+ return false;
326
+ }
327
+ if (this.state.localAlbums?.length <= 0) this.loadLocalAlbums();
328
+
329
+ return true;
330
+ };
331
+
332
+ isEditingEnabled = () => {
333
+ return (
334
+ !this.props.multiple &&
335
+ !this.props.allowVideo &&
336
+ getValueOrDefault(this.props.allowsEditing, DEFAULT_ALLOWS_EDITING)
337
+ );
338
+ };
339
+
340
+ openCamera = async () => {
341
+ if (!(await this.askPermissionsAsync())) return;
342
+
343
+ let editingAllowed = this.isEditingEnabled();
344
+ if (Platform.OS === "ios") {
345
+ editingAllowed = getValueOrDefault(
346
+ this.props.allowsEditingIOSCamera,
347
+ getValueOrDefault(
348
+ this.props.allowsEditing,
349
+ DEFAULT_ALLOWS_IOS_CAMERA_EDITING,
350
+ ),
351
+ );
352
+ }
353
+ const result = await ImagePicker.launchCameraAsync({
354
+ allowsEditing: editingAllowed,
355
+ aspect: getValueOrDefault(this.props.aspect, DEFAULT_ASPECT),
356
+ exif: getValueOrDefault(this.props.exif, DEFAULT_EXIF),
357
+ });
358
+
359
+ if (!result.canceled && !_.isEmpty(result.assets)) {
360
+ this.handleImagePicked(result.assets[0].uri);
361
+ }
362
+ };
363
+
364
+ openVideoCamera = async () => {
365
+ if (!(await this.askPermissionsAsync())) return;
366
+
367
+ const result = await ImagePicker.launchCameraAsync({
368
+ allowsEditing: this.isEditingEnabled(),
369
+ mediaTypes: ImagePicker.MediaTypeOptions.Videos,
370
+ });
371
+
372
+ if (!result.canceled && !_.isEmpty(result.assets)) {
373
+ this.handleImagePicked(result.assets[0].uri);
374
+ }
375
+ };
376
+
377
+ openLibrary = async () => {
378
+ this.setState(
379
+ {
380
+ showUploadMenu: false,
381
+ },
382
+ () => {
383
+ setTimeout(() => {
384
+ this.setState({
385
+ showPhotos: true,
386
+ selected: [],
387
+ showRemote: true,
388
+ selectedAlbumId: "",
389
+ });
390
+ }, 1000);
391
+ },
392
+ );
393
+ };
394
+
395
+ openPhotos = async () => {
396
+ if (Platform.OS === "android") {
397
+ const result = await ImagePicker.launchImageLibraryAsync({
398
+ allowsEditing: this.isEditingEnabled(),
399
+ aspect: getValueOrDefault(this.props.aspect, DEFAULT_ASPECT),
400
+ exif: getValueOrDefault(this.props.exif, DEFAULT_EXIF),
401
+ mediaTypes: this.props.allowVideo
402
+ ? ImagePicker.MediaTypeOptions.All
403
+ : ImagePicker.MediaTypeOptions.Images,
404
+ });
405
+ if (!result.cancelled) {
406
+ if (result.assets.length === 1 && result.assets[0].type === "video") {
407
+ this.handleVideoPicked(result.assets[0].uri);
408
+ } else {
409
+ this.handleMultiImagePicked(result.assets);
410
+ }
411
+ }
412
+ return;
413
+ }
414
+
415
+ // iOS behaviour
416
+ if (!(await this.askPermissionsAsync())) return;
417
+
418
+ this.setState(
419
+ {
420
+ showUploadMenu: false,
421
+ },
422
+ () => {
423
+ setTimeout(() => {
424
+ this.setState({
425
+ showPhotos: true,
426
+ selected: [],
427
+ showRemote: false,
428
+ selectedAlbumId: "",
429
+ });
430
+ }, 1000);
431
+ },
432
+ );
433
+ };
434
+
435
+ hidePhotos = () => {
436
+ this.setState({ showPhotos: false });
437
+ };
438
+
439
+ openCropper = () => {
440
+ // Switching modals - requires a timeout to ensure the modal is closed before opening the next one
441
+ this.setState(
442
+ {
443
+ showPhotos: false,
444
+ },
445
+ () => {
446
+ setTimeout(() => {
447
+ this.setState({
448
+ showCropper: true,
449
+ });
450
+ }, 1000);
451
+ },
452
+ );
453
+ };
454
+
455
+ toggleCropper = () => {
456
+ this.setState({ showCropper: !this.state.showCropper });
457
+ };
458
+
459
+ onSelectAlbum = () => {
460
+ this.setState({ showSelectAlbum: true });
461
+ };
462
+
463
+ onSelectAlbumClosed = () => {
464
+ this.setState({ showSelectAlbum: false });
465
+ };
466
+
467
+ onAlbumSelected = (selectedAlbumId) => {
468
+ this.setState({ showSelectAlbum: false, selectedAlbumId });
469
+ };
470
+
471
+ onSelectionChange = (selected, videoSelected, onAttach) => {
472
+ this.setState({
473
+ selected,
474
+ selectedType: videoSelected ? "video" : "image",
475
+ onAttach,
476
+ });
477
+ };
478
+
479
+ onSelected = async (callback) => {
480
+ if (this.isEditingEnabled()) {
481
+ this.openCropper();
482
+ } else {
483
+ const mediaSelected = await callback;
484
+ // console.log('mediaSelected', mediaSelected);
485
+ if (this.state.showRemote) {
486
+ if (this.props.onLibrarySelected) {
487
+ mediaSelected.map((media) => {
488
+ this.props.onLibrarySelected(media.uri);
489
+ });
490
+ }
491
+ } else {
492
+ if (mediaSelected[0].mediaType === MediaLibrary.MediaType.video) {
493
+ const uri = mediaSelected[0].localUri || mediaSelected[0].uri;
494
+ this.handleVideoPicked(uri);
495
+ } else {
496
+ this.handleMultiImagePicked(mediaSelected);
497
+ }
498
+ }
499
+
500
+ this.hidePhotos();
501
+ }
502
+ };
503
+
504
+ onRemoveImage = (uri) => {
505
+ const selected = [...this.state.selected];
506
+ const deleteIndex = selected.indexOf(uri);
507
+ selected.splice(deleteIndex, 1);
508
+ this.setState({ selected });
509
+ };
510
+
511
+ buildOptions = () => {
512
+ const options = [
513
+ {
514
+ text: "Take photo",
515
+ onPress: this.openCamera,
516
+ },
517
+ ];
518
+ if (this.props.allowVideo)
519
+ options.push({
520
+ text: "Record video",
521
+ onPress: this.openVideoCamera,
522
+ });
523
+ options.push({
524
+ text: "Camera Roll",
525
+ onPress: this.openPhotos,
526
+ });
527
+ if (!this.props.hideLibrary)
528
+ options.push({
529
+ text: "Image Library",
530
+ onPress: this.openLibrary,
531
+ });
532
+
533
+ return options;
534
+ };
535
+
536
+ renderSelectionPreview() {
537
+ const { selected, showRemote } = this.state;
538
+
539
+ return (
540
+ <View>
541
+ <ScrollView
542
+ horizontal
543
+ showsHorizontalScrollIndicator={false}
544
+ contentContainerStyle={styles.selectionPreviewContainer}
545
+ >
546
+ {selected &&
547
+ selected.map((uri) => {
548
+ const imageUri = showRemote ? getThumb300(uri) : uri;
549
+ return (
550
+ <View key={uri} style={styles.previewItemContainer}>
551
+ <ImageBackground
552
+ style={styles.previewItemImage}
553
+ source={{ uri: imageUri }}
554
+ />
555
+ <TouchableOpacity
556
+ style={styles.previewItemRemoveButton}
557
+ onPress={() => this.onRemoveImage(uri)}
558
+ >
559
+ <View
560
+ style={[
561
+ styles.previewItemRemoveContainer,
562
+ { backgroundColor: this.props.colourBrandingMain },
563
+ ]}
564
+ >
565
+ <Icon
566
+ name="times"
567
+ type="font-awesome"
568
+ iconStyle={styles.previewItemRemoveIcon}
569
+ />
570
+ </View>
571
+ </TouchableOpacity>
572
+ </View>
573
+ );
574
+ })}
575
+ </ScrollView>
576
+ </View>
577
+ );
578
+ }
579
+
580
+ renderSelectedAlbum() {
581
+ const { localAlbums, selectedAlbumId, showRemote } = this.state;
582
+ const selectedAlbum = (
583
+ showRemote ? this.props.imageLibrary : localAlbums
584
+ ).find((album) => album.id === selectedAlbumId);
585
+ const selectedAlbumText = selectedAlbum ? selectedAlbum.title : "";
586
+
587
+ return (
588
+ <TouchableOpacity onPress={this.onSelectAlbum}>
589
+ <View style={styles.selectAlbumButton}>
590
+ <Text style={styles.selectAlbumButtonText}>{selectedAlbumText}</Text>
591
+ <Icon
592
+ name="angle-down"
593
+ type="font-awesome"
594
+ iconStyle={styles.selectAlbumButtonIcon}
595
+ />
596
+ </View>
597
+ </TouchableOpacity>
598
+ );
599
+ }
600
+
601
+ renderSelectedComponent = (selectedItemNumber) => {
602
+ return (
603
+ <View style={styles.selectedItemContainer}>
604
+ <View
605
+ style={[
606
+ styles.selectedMarkerContainer,
607
+ { backgroundColor: this.props.colourBrandingMain },
608
+ ]}
609
+ >
610
+ {this.props.multiple ? (
611
+ <Text style={styles.selectedItemText}>{selectedItemNumber}</Text>
612
+ ) : (
613
+ <Icon
614
+ name="check"
615
+ type="font-awesome"
616
+ iconStyle={styles.selectedItemIcon}
617
+ />
618
+ )}
619
+ </View>
620
+ </View>
621
+ );
622
+ };
623
+
624
+ renderBrowser() {
625
+ const { selected, selectedAlbumId, showRemote } = this.state;
626
+ const { imagesLimit, multiple, allowVideo, imageLibrary } = this.props;
627
+ const width = (SCREEN_WIDTH - 10 * 2) / 4;
628
+
629
+ return (
630
+ <ImageBrowser
631
+ max={!multiple ? 1 : imagesLimit}
632
+ loadCount={30}
633
+ onChange={this.onSelectionChange}
634
+ renderSelectedComponent={this.renderSelectedComponent}
635
+ callback={this.onSelected}
636
+ selected={selected}
637
+ allowVideo={allowVideo}
638
+ style={styles.browserContainer}
639
+ itemStyle={styles.itemContainer}
640
+ itemWidth={width}
641
+ itemHeight={width}
642
+ album={selectedAlbumId}
643
+ remoteAlbums={showRemote ? imageLibrary : null}
644
+ />
645
+ );
646
+ }
647
+
648
+ renderAttachButton() {
649
+ const { selected, selectedType } = this.state;
650
+ const canAttach = selected.length > 0 && !_.isEmpty(selectedType);
651
+ const attachText = `Attach ${canAttach ? selected.length : ""} ${canAttach ? selectedType : ""}${selected.length > 1 ? "s" : ""}`;
652
+ const bottom =
653
+ Platform.OS === "android" ? (this.props.insets?.bottom ?? 0) : 0;
654
+
655
+ return (
656
+ <View style={{ backgroundColor: "#fff" }}>
657
+ <View style={styles.buttonContainer}>
658
+ <InlineButton
659
+ color={canAttach ? this.props.colourBrandingMain : INACTIVE_BUTTON}
660
+ onPress={this.state.onAttach}
661
+ fillTouchable
662
+ large
663
+ disabled={!canAttach}
664
+ >
665
+ {attachText}
666
+ </InlineButton>
667
+ </View>
668
+ {bottom > 0 && <View style={{ height: bottom }} />}
669
+ </View>
670
+ );
671
+ }
672
+
673
+ renderSelectAlbumPopup() {
674
+ const { showSelectAlbum, localAlbums, showRemote } = this.state;
675
+ if (!showSelectAlbum) return null;
676
+
677
+ return (
678
+ <Modal
679
+ visible
680
+ transparent
681
+ animationType="slide"
682
+ onRequestClose={this.onSelectAlbumClosed}
683
+ >
684
+ <View style={styles.selectAlbumModal}>
685
+ <View style={styles.selectAlbumContainer}>
686
+ <View style={styles.selectAlbumTitleContainer}>
687
+ <Text style={styles.selectAlbumTitle}>Select Album</Text>
688
+ </View>
689
+ <ScrollView>
690
+ {(showRemote ? this.props.imageLibrary : localAlbums).map(
691
+ (album, index) => {
692
+ return (
693
+ <TouchableOpacity
694
+ key={album.id}
695
+ onPress={() => this.onAlbumSelected(album.id)}
696
+ >
697
+ <View
698
+ style={[
699
+ styles.albumOptionContainer,
700
+ index === 0 && { borderTopWidth: 0 },
701
+ ]}
702
+ >
703
+ <Text style={styles.albumOptionText}>
704
+ {album.title}
705
+ </Text>
706
+ </View>
707
+ </TouchableOpacity>
708
+ );
709
+ },
710
+ )}
711
+ </ScrollView>
712
+ <TouchableOpacity onPress={this.onSelectAlbumClosed}>
713
+ <View
714
+ style={[
715
+ styles.albumOptionContainer,
716
+ { marginHorizontal: 0 },
717
+ Platform.OS === "android" && {
718
+ paddingBottom: 16 + (this.props.insets?.bottom ?? 0),
719
+ },
720
+ ]}
721
+ >
722
+ <Text
723
+ style={[
724
+ styles.albumOptionText,
725
+ { color: this.props.colourBrandingMain },
726
+ ]}
727
+ >
728
+ Cancel
729
+ </Text>
730
+ </View>
731
+ </TouchableOpacity>
732
+ </View>
733
+ </View>
734
+ </Modal>
735
+ );
736
+ }
737
+
738
+ renderPhotos() {
739
+ return (
740
+ <Modal
741
+ visible
742
+ transparent
743
+ animationType="slide"
744
+ onRequestClose={this.hidePhotos}
745
+ >
746
+ <View style={styles.modalContainer}>
747
+ <Header
748
+ leftIcon="angle-left"
749
+ onPressLeft={this.hidePhotos}
750
+ text={this.props.popupTitle || "Attach image"}
751
+ />
752
+ <View style={styles.contentContainer}>
753
+ {this.renderSelectionPreview()}
754
+ {this.renderSelectedAlbum()}
755
+ {this.renderBrowser()}
756
+ </View>
757
+ {this.renderAttachButton()}
758
+ </View>
759
+ {this.renderSelectAlbumPopup()}
760
+ </Modal>
761
+ );
762
+ }
763
+
764
+ render() {
765
+ const { warning, showUploadMenu, showPhotos, showCropper, selected } =
766
+ this.state;
767
+
768
+ if (warning != null) {
769
+ return (
770
+ <Popup
771
+ title="Permissions missing"
772
+ text={warning}
773
+ options={[
774
+ {
775
+ text: "Go to settings",
776
+ action: this.goToPermissionSettings.bind(this),
777
+ bold: true,
778
+ },
779
+ {
780
+ text: "Ignore",
781
+ action: this.closeWarningPopup.bind(this),
782
+ },
783
+ ]}
784
+ />
785
+ );
786
+ }
787
+
788
+ if (showUploadMenu) {
789
+ const options = this.buildOptions();
790
+ return (
791
+ <PopupMenu
792
+ onClose={this.hideUploadMenu.bind(this)}
793
+ options={options}
794
+ title={this.props.popupTitle}
795
+ cancelText="Cancel"
796
+ />
797
+ );
798
+ }
799
+
800
+ if (showPhotos) return this.renderPhotos();
801
+
802
+ if (showCropper) {
803
+ return (
804
+ <ExpoImageManipulator
805
+ photo={{ uri: selected[0] }}
806
+ onToggleModal={this.toggleCropper}
807
+ isVisible={showCropper}
808
+ onPictureChoosed={(data) => {
809
+ this.handleImagePicked(data.uri);
810
+ }}
811
+ />
812
+ );
813
+ }
814
+
815
+ return null;
816
+ }
654
817
  }
655
818
 
656
819
  const styles = StyleSheet.create({
657
- contentContainer: {
658
- flex: 1,
659
- backgroundColor: BOXGREY,
660
- },
661
- browserContainer: {
662
- padding: 10,
663
- },
664
- itemContainer: {
665
- padding: 4,
666
- },
667
- selectedItemContainer: {
668
- flex: 1,
669
- backgroundColor: '#0008',
670
- },
671
- selectedMarkerContainer: {
672
- position: 'absolute',
673
- top: 6,
674
- right: 6,
675
- width: 20,
676
- height: 20,
677
- borderRadius: 10,
678
- alignItems: 'center',
679
- justifyContent: 'center',
680
- },
681
- selectedItemText: {
682
- fontFamily: 'sf-semibold',
683
- fontSize: 12,
684
- color: '#fff',
685
- marginBottom: 1,
686
- },
687
- selectedItemIcon: {
688
- fontSize: 12,
689
- color: '#fff',
690
- marginBottom: 1,
691
- },
692
- buttonContainer: {
693
- alignItems: 'center',
694
- justifyContent: 'center',
695
- height: 60,
696
- paddingHorizontal: 14,
697
- backgroundColor: '#fff',
698
- },
699
- selectAlbumButton: {
700
- paddingTop: 13,
701
- paddingHorizontal: 14,
702
- flexDirection: 'row',
703
- alignItems: 'center',
704
- },
705
- selectAlbumButtonText: {
706
- fontFamily: 'sf-medium',
707
- fontSize: 14,
708
- color: TEXT_BLUEGREY,
709
- marginRight: 6,
710
- },
711
- selectAlbumButtonIcon: {
712
- fontSize: 20,
713
- color: TEXT_BLUEGREY,
714
- },
715
- selectAlbumModal: {
716
- position: 'absolute',
717
- bottom: 0,
718
- left: 0,
719
- right: 0,
720
- top: 0,
721
- backgroundColor: 'rgba(0,0,0,0.5)',
722
- zIndex: 1000,
723
- },
724
- selectAlbumContainer: {
725
- position: 'absolute',
726
- bottom: 0,
727
- left: 0,
728
- right: 0,
729
- backgroundColor: '#fff',
730
- borderTopLeftRadius: 12,
731
- borderTopRightRadius: 12,
732
- maxHeight: SCREEN_HEIGHT / 2,
733
- },
734
- selectAlbumTitleContainer: {
735
- padding: 16,
736
- borderColor: LINEGREY,
737
- borderBottomWidth: 1,
738
- },
739
- selectAlbumTitle: {
740
- fontFamily: 'sf-semibold',
741
- fontSize: 16,
742
- textAlign: 'center',
743
- color: TEXT_DARK,
744
- },
745
- albumOptionContainer: {
746
- marginHorizontal: 16,
747
- paddingVertical: 16,
748
- borderColor: LINEGREY,
749
- borderTopWidth: 1,
750
- },
751
- albumOptionText: {
752
- fontFamily: 'sf-regular',
753
- fontSize: 16,
754
- textAlign: 'center',
755
- color: TEXT_DARK,
756
- },
757
- selectionPreviewContainer: {
758
- paddingTop: 14,
759
- paddingRight: 2,
760
- paddingLeft: 14,
761
- },
762
- previewItemContainer: {
763
- marginRight: 12,
764
- },
765
- previewItemImage: {
766
- width: 50,
767
- height: 50,
768
- alignItems: 'center',
769
- justifyContent: 'center',
770
- borderRadius: 4,
771
- overflow: 'hidden',
772
- },
773
- previewItemRemoveButton: {
774
- position: 'absolute',
775
- top: -8,
776
- right: -8,
777
- },
778
- previewItemRemoveContainer: {
779
- justifyContent: 'center',
780
- alignItems: 'center',
781
- borderRadius: 10,
782
- width: 20,
783
- height: 20,
784
- borderWidth: 2,
785
- borderColor: '#fff',
786
- },
787
- previewItemRemoveIcon: {
788
- fontSize: 10,
789
- color: '#fff',
790
- marginBottom: 1,
791
- },
820
+ modalContainer: {
821
+ flex: 1,
822
+ },
823
+ contentContainer: {
824
+ flex: 1,
825
+ backgroundColor: BOXGREY,
826
+ },
827
+ browserContainer: {
828
+ padding: 10,
829
+ },
830
+ itemContainer: {
831
+ padding: 4,
832
+ },
833
+ selectedItemContainer: {
834
+ flex: 1,
835
+ backgroundColor: "#0008",
836
+ },
837
+ selectedMarkerContainer: {
838
+ position: "absolute",
839
+ top: 6,
840
+ right: 6,
841
+ width: 20,
842
+ height: 20,
843
+ borderRadius: 10,
844
+ alignItems: "center",
845
+ justifyContent: "center",
846
+ },
847
+ selectedItemText: {
848
+ fontFamily: "sf-semibold",
849
+ fontSize: 12,
850
+ color: "#fff",
851
+ marginBottom: 1,
852
+ },
853
+ selectedItemIcon: {
854
+ fontSize: 12,
855
+ color: "#fff",
856
+ marginBottom: 1,
857
+ },
858
+ buttonContainer: {
859
+ alignItems: "center",
860
+ justifyContent: "center",
861
+ height: 60,
862
+ paddingHorizontal: 14,
863
+ backgroundColor: "#fff",
864
+ },
865
+ selectAlbumButton: {
866
+ paddingTop: 13,
867
+ paddingHorizontal: 14,
868
+ flexDirection: "row",
869
+ alignItems: "center",
870
+ },
871
+ selectAlbumButtonText: {
872
+ fontFamily: "sf-medium",
873
+ fontSize: 14,
874
+ color: TEXT_BLUEGREY,
875
+ marginRight: 6,
876
+ },
877
+ selectAlbumButtonIcon: {
878
+ fontSize: 20,
879
+ color: TEXT_BLUEGREY,
880
+ },
881
+ selectAlbumModal: {
882
+ position: "absolute",
883
+ bottom: 0,
884
+ left: 0,
885
+ right: 0,
886
+ top: 0,
887
+ backgroundColor: "rgba(0,0,0,0.5)",
888
+ zIndex: 1000,
889
+ },
890
+ selectAlbumContainer: {
891
+ position: "absolute",
892
+ bottom: 0,
893
+ left: 0,
894
+ right: 0,
895
+ backgroundColor: "#fff",
896
+ borderTopLeftRadius: 12,
897
+ borderTopRightRadius: 12,
898
+ maxHeight: SCREEN_HEIGHT / 2,
899
+ },
900
+ selectAlbumTitleContainer: {
901
+ padding: 16,
902
+ borderColor: LINEGREY,
903
+ borderBottomWidth: 1,
904
+ },
905
+ selectAlbumTitle: {
906
+ fontFamily: "sf-semibold",
907
+ fontSize: 16,
908
+ textAlign: "center",
909
+ color: TEXT_DARK,
910
+ },
911
+ albumOptionContainer: {
912
+ marginHorizontal: 16,
913
+ paddingVertical: 16,
914
+ borderColor: LINEGREY,
915
+ borderTopWidth: 1,
916
+ },
917
+ albumOptionText: {
918
+ fontFamily: "sf-regular",
919
+ fontSize: 16,
920
+ textAlign: "center",
921
+ color: TEXT_DARK,
922
+ },
923
+ selectionPreviewContainer: {
924
+ paddingTop: 14,
925
+ paddingRight: 2,
926
+ paddingLeft: 14,
927
+ },
928
+ previewItemContainer: {
929
+ marginRight: 12,
930
+ },
931
+ previewItemImage: {
932
+ width: 50,
933
+ height: 50,
934
+ alignItems: "center",
935
+ justifyContent: "center",
936
+ borderRadius: 4,
937
+ overflow: "hidden",
938
+ },
939
+ previewItemRemoveButton: {
940
+ position: "absolute",
941
+ top: -8,
942
+ right: -8,
943
+ },
944
+ previewItemRemoveContainer: {
945
+ justifyContent: "center",
946
+ alignItems: "center",
947
+ borderRadius: 10,
948
+ width: 20,
949
+ height: 20,
950
+ borderWidth: 2,
951
+ borderColor: "#fff",
952
+ },
953
+ previewItemRemoveIcon: {
954
+ fontSize: 10,
955
+ color: "#fff",
956
+ marginBottom: 1,
957
+ },
792
958
  });
793
959
 
794
- const mapStateToProps = state => {
795
- const { user, media } = state;
796
- const imageLibrary = media.imageLibrary
797
- .filter(folder => !folder.Public)
798
- .map(album => {
799
- return {
800
- title: album.Name,
801
- id: album.RowId || '',
802
- images: album.RowId ? album.Images : media.stockImages,
803
- };
804
- });
805
-
806
- return {
807
- user,
808
- imageLibrary,
809
- colourBrandingMain: getMainBrandingColourFromState(state),
810
- };
960
+ const mapStateToProps = (state) => {
961
+ const { user, media } = state;
962
+ const imageLibrary = media.imageLibrary
963
+ .filter((folder) => !folder.Public)
964
+ .map((album) => {
965
+ return {
966
+ title: album.Name,
967
+ id: album.RowId || "",
968
+ images: album.RowId ? album.Images : media.stockImages,
969
+ };
970
+ });
971
+
972
+ return {
973
+ user,
974
+ imageLibrary,
975
+ colourBrandingMain: getMainBrandingColourFromState(state),
976
+ };
811
977
  };
812
978
 
813
- export default connect(mapStateToProps, { stockImagesLoaded, imageLibraryLoaded }, null, { forwardRef: true })(ImageUploader);
979
+ export default connect(
980
+ mapStateToProps,
981
+ { stockImagesLoaded, imageLibraryLoaded },
982
+ null,
983
+ { forwardRef: true },
984
+ )(withSafeAreaInsets(ImageUploader));