@plusscommunities/pluss-core-app 8.0.1-beta.0 → 8.0.2-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 +122 -97
  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 +152 -46
  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 +113 -76
  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 +81 -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 +973 -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 +307 -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 +447 -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,989 @@
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 multiple = !!this.props.multiple;
398
+ const result = await ImagePicker.launchImageLibraryAsync({
399
+ allowsEditing: this.isEditingEnabled(),
400
+ allowsMultipleSelection: multiple,
401
+ ...(multiple && {
402
+ selectionLimit: getValueOrDefault(this.props.imagesLimit, 10),
403
+ }),
404
+ aspect: getValueOrDefault(this.props.aspect, DEFAULT_ASPECT),
405
+ exif: getValueOrDefault(this.props.exif, DEFAULT_EXIF),
406
+ mediaTypes: this.props.allowVideo
407
+ ? ImagePicker.MediaTypeOptions.All
408
+ : ImagePicker.MediaTypeOptions.Images,
409
+ });
410
+ if (!(result.canceled || result.cancelled) && !_.isEmpty(result.assets)) {
411
+ if (result.assets.length === 1 && result.assets[0].type === "video") {
412
+ this.handleVideoPicked(result.assets[0].uri);
413
+ } else {
414
+ this.handleMultiImagePicked(result.assets);
415
+ }
416
+ }
417
+ return;
418
+ }
419
+
420
+ // iOS behaviour
421
+ if (!(await this.askPermissionsAsync())) return;
422
+
423
+ this.setState(
424
+ {
425
+ showUploadMenu: false,
426
+ },
427
+ () => {
428
+ setTimeout(() => {
429
+ this.setState({
430
+ showPhotos: true,
431
+ selected: [],
432
+ showRemote: false,
433
+ selectedAlbumId: "",
434
+ });
435
+ }, 1000);
436
+ },
437
+ );
438
+ };
439
+
440
+ hidePhotos = () => {
441
+ this.setState({ showPhotos: false });
442
+ };
443
+
444
+ openCropper = () => {
445
+ // Switching modals - requires a timeout to ensure the modal is closed before opening the next one
446
+ this.setState(
447
+ {
448
+ showPhotos: false,
449
+ },
450
+ () => {
451
+ setTimeout(() => {
452
+ this.setState({
453
+ showCropper: true,
454
+ });
455
+ }, 1000);
456
+ },
457
+ );
458
+ };
459
+
460
+ toggleCropper = () => {
461
+ this.setState({ showCropper: !this.state.showCropper });
462
+ };
463
+
464
+ onSelectAlbum = () => {
465
+ this.setState({ showSelectAlbum: true });
466
+ };
467
+
468
+ onSelectAlbumClosed = () => {
469
+ this.setState({ showSelectAlbum: false });
470
+ };
471
+
472
+ onAlbumSelected = (selectedAlbumId) => {
473
+ this.setState({ showSelectAlbum: false, selectedAlbumId });
474
+ };
475
+
476
+ onSelectionChange = (selected, videoSelected, onAttach) => {
477
+ this.setState({
478
+ selected,
479
+ selectedType: videoSelected ? "video" : "image",
480
+ onAttach,
481
+ });
482
+ };
483
+
484
+ onSelected = async (callback) => {
485
+ if (this.isEditingEnabled()) {
486
+ this.openCropper();
487
+ } else {
488
+ const mediaSelected = await callback;
489
+ // console.log('mediaSelected', mediaSelected);
490
+ if (this.state.showRemote) {
491
+ if (this.props.onLibrarySelected) {
492
+ mediaSelected.map((media) => {
493
+ this.props.onLibrarySelected(media.uri);
494
+ });
495
+ }
496
+ } else {
497
+ if (mediaSelected[0].mediaType === MediaLibrary.MediaType.video) {
498
+ const uri = mediaSelected[0].localUri || mediaSelected[0].uri;
499
+ this.handleVideoPicked(uri);
500
+ } else {
501
+ this.handleMultiImagePicked(mediaSelected);
502
+ }
503
+ }
504
+
505
+ this.hidePhotos();
506
+ }
507
+ };
508
+
509
+ onRemoveImage = (uri) => {
510
+ const selected = [...this.state.selected];
511
+ const deleteIndex = selected.indexOf(uri);
512
+ selected.splice(deleteIndex, 1);
513
+ this.setState({ selected });
514
+ };
515
+
516
+ buildOptions = () => {
517
+ const options = [
518
+ {
519
+ text: "Take photo",
520
+ onPress: this.openCamera,
521
+ },
522
+ ];
523
+ if (this.props.allowVideo)
524
+ options.push({
525
+ text: "Record video",
526
+ onPress: this.openVideoCamera,
527
+ });
528
+ options.push({
529
+ text: "Camera Roll",
530
+ onPress: this.openPhotos,
531
+ });
532
+ if (!this.props.hideLibrary)
533
+ options.push({
534
+ text: "Image Library",
535
+ onPress: this.openLibrary,
536
+ });
537
+
538
+ return options;
539
+ };
540
+
541
+ renderSelectionPreview() {
542
+ const { selected, showRemote } = this.state;
543
+
544
+ return (
545
+ <View>
546
+ <ScrollView
547
+ horizontal
548
+ showsHorizontalScrollIndicator={false}
549
+ contentContainerStyle={styles.selectionPreviewContainer}
550
+ >
551
+ {selected &&
552
+ selected.map((uri) => {
553
+ const imageUri = showRemote ? getThumb300(uri) : uri;
554
+ return (
555
+ <View key={uri} style={styles.previewItemContainer}>
556
+ <ImageBackground
557
+ style={styles.previewItemImage}
558
+ source={{ uri: imageUri }}
559
+ />
560
+ <TouchableOpacity
561
+ style={styles.previewItemRemoveButton}
562
+ onPress={() => this.onRemoveImage(uri)}
563
+ >
564
+ <View
565
+ style={[
566
+ styles.previewItemRemoveContainer,
567
+ { backgroundColor: this.props.colourBrandingMain },
568
+ ]}
569
+ >
570
+ <Icon
571
+ name="times"
572
+ type="font-awesome"
573
+ iconStyle={styles.previewItemRemoveIcon}
574
+ />
575
+ </View>
576
+ </TouchableOpacity>
577
+ </View>
578
+ );
579
+ })}
580
+ </ScrollView>
581
+ </View>
582
+ );
583
+ }
584
+
585
+ renderSelectedAlbum() {
586
+ const { localAlbums, selectedAlbumId, showRemote } = this.state;
587
+ const selectedAlbum = (
588
+ showRemote ? this.props.imageLibrary : localAlbums
589
+ ).find((album) => album.id === selectedAlbumId);
590
+ const selectedAlbumText = selectedAlbum ? selectedAlbum.title : "";
591
+
592
+ return (
593
+ <TouchableOpacity onPress={this.onSelectAlbum}>
594
+ <View style={styles.selectAlbumButton}>
595
+ <Text style={styles.selectAlbumButtonText}>{selectedAlbumText}</Text>
596
+ <Icon
597
+ name="angle-down"
598
+ type="font-awesome"
599
+ iconStyle={styles.selectAlbumButtonIcon}
600
+ />
601
+ </View>
602
+ </TouchableOpacity>
603
+ );
604
+ }
605
+
606
+ renderSelectedComponent = (selectedItemNumber) => {
607
+ return (
608
+ <View style={styles.selectedItemContainer}>
609
+ <View
610
+ style={[
611
+ styles.selectedMarkerContainer,
612
+ { backgroundColor: this.props.colourBrandingMain },
613
+ ]}
614
+ >
615
+ {this.props.multiple ? (
616
+ <Text style={styles.selectedItemText}>{selectedItemNumber}</Text>
617
+ ) : (
618
+ <Icon
619
+ name="check"
620
+ type="font-awesome"
621
+ iconStyle={styles.selectedItemIcon}
622
+ />
623
+ )}
624
+ </View>
625
+ </View>
626
+ );
627
+ };
628
+
629
+ renderBrowser() {
630
+ const { selected, selectedAlbumId, showRemote } = this.state;
631
+ const { imagesLimit, multiple, allowVideo, imageLibrary } = this.props;
632
+ const width = (SCREEN_WIDTH - 10 * 2) / 4;
633
+
634
+ return (
635
+ <ImageBrowser
636
+ max={!multiple ? 1 : imagesLimit}
637
+ loadCount={30}
638
+ onChange={this.onSelectionChange}
639
+ renderSelectedComponent={this.renderSelectedComponent}
640
+ callback={this.onSelected}
641
+ selected={selected}
642
+ allowVideo={allowVideo}
643
+ style={styles.browserContainer}
644
+ itemStyle={styles.itemContainer}
645
+ itemWidth={width}
646
+ itemHeight={width}
647
+ album={selectedAlbumId}
648
+ remoteAlbums={showRemote ? imageLibrary : null}
649
+ />
650
+ );
651
+ }
652
+
653
+ renderAttachButton() {
654
+ const { selected, selectedType } = this.state;
655
+ const canAttach = selected.length > 0 && !_.isEmpty(selectedType);
656
+ const attachText = `Attach ${canAttach ? selected.length : ""} ${canAttach ? selectedType : ""}${selected.length > 1 ? "s" : ""}`;
657
+ const bottom =
658
+ Platform.OS === "android" ? (this.props.insets?.bottom ?? 0) : 0;
659
+
660
+ return (
661
+ <View style={{ backgroundColor: "#fff" }}>
662
+ <View style={styles.buttonContainer}>
663
+ <InlineButton
664
+ color={canAttach ? this.props.colourBrandingMain : INACTIVE_BUTTON}
665
+ onPress={this.state.onAttach}
666
+ fillTouchable
667
+ large
668
+ disabled={!canAttach}
669
+ >
670
+ {attachText}
671
+ </InlineButton>
672
+ </View>
673
+ {bottom > 0 && <View style={{ height: bottom }} />}
674
+ </View>
675
+ );
676
+ }
677
+
678
+ renderSelectAlbumPopup() {
679
+ const { showSelectAlbum, localAlbums, showRemote } = this.state;
680
+ if (!showSelectAlbum) return null;
681
+
682
+ return (
683
+ <Modal
684
+ visible
685
+ transparent
686
+ animationType="slide"
687
+ onRequestClose={this.onSelectAlbumClosed}
688
+ >
689
+ <View style={styles.selectAlbumModal}>
690
+ <View style={styles.selectAlbumContainer}>
691
+ <View style={styles.selectAlbumTitleContainer}>
692
+ <Text style={styles.selectAlbumTitle}>Select Album</Text>
693
+ </View>
694
+ <ScrollView>
695
+ {(showRemote ? this.props.imageLibrary : localAlbums).map(
696
+ (album, index) => {
697
+ return (
698
+ <TouchableOpacity
699
+ key={album.id}
700
+ onPress={() => this.onAlbumSelected(album.id)}
701
+ >
702
+ <View
703
+ style={[
704
+ styles.albumOptionContainer,
705
+ index === 0 && { borderTopWidth: 0 },
706
+ ]}
707
+ >
708
+ <Text style={styles.albumOptionText}>
709
+ {album.title}
710
+ </Text>
711
+ </View>
712
+ </TouchableOpacity>
713
+ );
714
+ },
715
+ )}
716
+ </ScrollView>
717
+ <TouchableOpacity onPress={this.onSelectAlbumClosed}>
718
+ <View
719
+ style={[
720
+ styles.albumOptionContainer,
721
+ { marginHorizontal: 0 },
722
+ Platform.OS === "android" && {
723
+ paddingBottom: 16 + (this.props.insets?.bottom ?? 0),
724
+ },
725
+ ]}
726
+ >
727
+ <Text
728
+ style={[
729
+ styles.albumOptionText,
730
+ { color: this.props.colourBrandingMain },
731
+ ]}
732
+ >
733
+ Cancel
734
+ </Text>
735
+ </View>
736
+ </TouchableOpacity>
737
+ </View>
738
+ </View>
739
+ </Modal>
740
+ );
741
+ }
742
+
743
+ renderPhotos() {
744
+ return (
745
+ <Modal
746
+ visible
747
+ transparent
748
+ animationType="slide"
749
+ onRequestClose={this.hidePhotos}
750
+ >
751
+ <View style={styles.modalContainer}>
752
+ <Header
753
+ leftIcon="angle-left"
754
+ onPressLeft={this.hidePhotos}
755
+ text={this.props.popupTitle || "Attach image"}
756
+ />
757
+ <View style={styles.contentContainer}>
758
+ {this.renderSelectionPreview()}
759
+ {this.renderSelectedAlbum()}
760
+ {this.renderBrowser()}
761
+ </View>
762
+ {this.renderAttachButton()}
763
+ </View>
764
+ {this.renderSelectAlbumPopup()}
765
+ </Modal>
766
+ );
767
+ }
768
+
769
+ render() {
770
+ const { warning, showUploadMenu, showPhotos, showCropper, selected } =
771
+ this.state;
772
+
773
+ if (warning != null) {
774
+ return (
775
+ <Popup
776
+ title="Permissions missing"
777
+ text={warning}
778
+ options={[
779
+ {
780
+ text: "Go to settings",
781
+ action: this.goToPermissionSettings.bind(this),
782
+ bold: true,
783
+ },
784
+ {
785
+ text: "Ignore",
786
+ action: this.closeWarningPopup.bind(this),
787
+ },
788
+ ]}
789
+ />
790
+ );
791
+ }
792
+
793
+ if (showUploadMenu) {
794
+ const options = this.buildOptions();
795
+ return (
796
+ <PopupMenu
797
+ onClose={this.hideUploadMenu.bind(this)}
798
+ options={options}
799
+ title={this.props.popupTitle}
800
+ cancelText="Cancel"
801
+ />
802
+ );
803
+ }
804
+
805
+ if (showPhotos) return this.renderPhotos();
806
+
807
+ if (showCropper) {
808
+ return (
809
+ <ExpoImageManipulator
810
+ photo={{ uri: selected[0] }}
811
+ onToggleModal={this.toggleCropper}
812
+ isVisible={showCropper}
813
+ onPictureChoosed={(data) => {
814
+ this.handleImagePicked(data.uri);
815
+ }}
816
+ />
817
+ );
818
+ }
819
+
820
+ return null;
821
+ }
654
822
  }
655
823
 
656
824
  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
- },
825
+ modalContainer: {
826
+ flex: 1,
827
+ },
828
+ contentContainer: {
829
+ flex: 1,
830
+ backgroundColor: BOXGREY,
831
+ },
832
+ browserContainer: {
833
+ padding: 10,
834
+ },
835
+ itemContainer: {
836
+ padding: 4,
837
+ },
838
+ selectedItemContainer: {
839
+ flex: 1,
840
+ backgroundColor: "#0008",
841
+ },
842
+ selectedMarkerContainer: {
843
+ position: "absolute",
844
+ top: 6,
845
+ right: 6,
846
+ width: 20,
847
+ height: 20,
848
+ borderRadius: 10,
849
+ alignItems: "center",
850
+ justifyContent: "center",
851
+ },
852
+ selectedItemText: {
853
+ fontFamily: "sf-semibold",
854
+ fontSize: 12,
855
+ color: "#fff",
856
+ marginBottom: 1,
857
+ },
858
+ selectedItemIcon: {
859
+ fontSize: 12,
860
+ color: "#fff",
861
+ marginBottom: 1,
862
+ },
863
+ buttonContainer: {
864
+ alignItems: "center",
865
+ justifyContent: "center",
866
+ height: 60,
867
+ paddingHorizontal: 14,
868
+ backgroundColor: "#fff",
869
+ },
870
+ selectAlbumButton: {
871
+ paddingTop: 13,
872
+ paddingHorizontal: 14,
873
+ flexDirection: "row",
874
+ alignItems: "center",
875
+ },
876
+ selectAlbumButtonText: {
877
+ fontFamily: "sf-medium",
878
+ fontSize: 14,
879
+ color: TEXT_BLUEGREY,
880
+ marginRight: 6,
881
+ },
882
+ selectAlbumButtonIcon: {
883
+ fontSize: 20,
884
+ color: TEXT_BLUEGREY,
885
+ },
886
+ selectAlbumModal: {
887
+ position: "absolute",
888
+ bottom: 0,
889
+ left: 0,
890
+ right: 0,
891
+ top: 0,
892
+ backgroundColor: "rgba(0,0,0,0.5)",
893
+ zIndex: 1000,
894
+ },
895
+ selectAlbumContainer: {
896
+ position: "absolute",
897
+ bottom: 0,
898
+ left: 0,
899
+ right: 0,
900
+ backgroundColor: "#fff",
901
+ borderTopLeftRadius: 12,
902
+ borderTopRightRadius: 12,
903
+ maxHeight: SCREEN_HEIGHT / 2,
904
+ },
905
+ selectAlbumTitleContainer: {
906
+ padding: 16,
907
+ borderColor: LINEGREY,
908
+ borderBottomWidth: 1,
909
+ },
910
+ selectAlbumTitle: {
911
+ fontFamily: "sf-semibold",
912
+ fontSize: 16,
913
+ textAlign: "center",
914
+ color: TEXT_DARK,
915
+ },
916
+ albumOptionContainer: {
917
+ marginHorizontal: 16,
918
+ paddingVertical: 16,
919
+ borderColor: LINEGREY,
920
+ borderTopWidth: 1,
921
+ },
922
+ albumOptionText: {
923
+ fontFamily: "sf-regular",
924
+ fontSize: 16,
925
+ textAlign: "center",
926
+ color: TEXT_DARK,
927
+ },
928
+ selectionPreviewContainer: {
929
+ paddingTop: 14,
930
+ paddingRight: 2,
931
+ paddingLeft: 14,
932
+ },
933
+ previewItemContainer: {
934
+ marginRight: 12,
935
+ },
936
+ previewItemImage: {
937
+ width: 50,
938
+ height: 50,
939
+ alignItems: "center",
940
+ justifyContent: "center",
941
+ borderRadius: 4,
942
+ overflow: "hidden",
943
+ },
944
+ previewItemRemoveButton: {
945
+ position: "absolute",
946
+ top: -8,
947
+ right: -8,
948
+ },
949
+ previewItemRemoveContainer: {
950
+ justifyContent: "center",
951
+ alignItems: "center",
952
+ borderRadius: 10,
953
+ width: 20,
954
+ height: 20,
955
+ borderWidth: 2,
956
+ borderColor: "#fff",
957
+ },
958
+ previewItemRemoveIcon: {
959
+ fontSize: 10,
960
+ color: "#fff",
961
+ marginBottom: 1,
962
+ },
792
963
  });
793
964
 
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
- };
965
+ const mapStateToProps = (state) => {
966
+ const { user, media } = state;
967
+ const imageLibrary = media.imageLibrary
968
+ .filter((folder) => !folder.Public)
969
+ .map((album) => {
970
+ return {
971
+ title: album.Name,
972
+ id: album.RowId || "",
973
+ images: album.RowId ? album.Images : media.stockImages,
974
+ };
975
+ });
976
+
977
+ return {
978
+ user,
979
+ imageLibrary,
980
+ colourBrandingMain: getMainBrandingColourFromState(state),
981
+ };
811
982
  };
812
983
 
813
- export default connect(mapStateToProps, { stockImagesLoaded, imageLibraryLoaded }, null, { forwardRef: true })(ImageUploader);
984
+ export default connect(
985
+ mapStateToProps,
986
+ { stockImagesLoaded, imageLibraryLoaded },
987
+ null,
988
+ { forwardRef: true },
989
+ )(withSafeAreaInsets(ImageUploader));