@widergy/mobile-ui 0.33.0 → 0.34.2
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.
- package/CHANGELOG.md +21 -0
- package/lib/components/Capture/index.js +55 -0
- package/lib/components/Capture/propTypes.js +14 -0
- package/lib/components/Capture/styles.js +11 -0
- package/lib/components/Label/utils.js +4 -1
- package/lib/components/PhotoAlbum/components/AddAnotherPhotoButton/index.js +19 -0
- package/lib/components/PhotoAlbum/components/AddAnotherPhotoButton/propTypes.js +7 -0
- package/lib/components/PhotoAlbum/components/AddAnotherPhotoButton/styles.js +29 -0
- package/lib/components/PhotoAlbum/components/DeleteView/index.js +19 -0
- package/lib/components/PhotoAlbum/components/DeleteView/propTypes.js +6 -0
- package/lib/components/PhotoAlbum/components/DeleteView/styles.js +9 -0
- package/lib/components/PhotoAlbum/components/Photo/index.js +69 -0
- package/lib/components/PhotoAlbum/components/Photo/propTypes.js +10 -0
- package/lib/components/PhotoAlbum/components/Photo/styles.js +53 -0
- package/lib/components/PhotoAlbum/components/ReplaceView/index.js +18 -0
- package/lib/components/PhotoAlbum/components/ReplaceView/propTypes.js +6 -0
- package/lib/components/PhotoAlbum/components/ReplaceView/styles.js +15 -0
- package/lib/components/PhotoAlbum/components/SvgIconCheck/index.js +17 -0
- package/lib/components/PhotoAlbum/components/SvgIconCheck/propTypes.js +5 -0
- package/lib/components/PhotoAlbum/components/SvgIconCheck/styles.js +18 -0
- package/lib/components/PhotoAlbum/index.js +168 -0
- package/lib/components/PhotoAlbum/propTypes.js +17 -0
- package/lib/components/PhotoAlbum/styles.js +51 -0
- package/lib/components/RadioGroup/components/RadioButton/index.js +60 -30
- package/lib/components/RadioGroup/components/RadioButton/styles.js +6 -0
- package/lib/components/RadioGroup/index.js +2 -0
- package/lib/index.js +4 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
## [0.34.2](https://github.com/widergy/mobile-ui/compare/v0.34.1...v0.34.2) (2022-05-06)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* modify radio button components and others ([#221](https://github.com/widergy/mobile-ui/issues/221)) ([530345a](https://github.com/widergy/mobile-ui/commit/530345a3cb103ce761a4d780544b72f101d6a5e8))
|
|
7
|
+
|
|
8
|
+
## [0.34.1](https://github.com/widergy/mobile-ui/compare/v0.34.0...v0.34.1) (2022-04-26)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* undefined is not a function ([#219](https://github.com/widergy/mobile-ui/issues/219)) ([ca80c4d](https://github.com/widergy/mobile-ui/commit/ca80c4d6b90176376f980234be432da87f6ed5ff))
|
|
14
|
+
|
|
15
|
+
# [0.34.0](https://github.com/widergy/mobile-ui/compare/v0.33.0...v0.34.0) (2022-04-11)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* photo album and capture component added ([08f0749](https://github.com/widergy/mobile-ui/commit/08f07498f274b36bfc2a3be901527bd73f338a7a))
|
|
21
|
+
|
|
1
22
|
# [0.33.0](https://github.com/widergy/mobile-ui/compare/v0.32.4...v0.33.0) (2022-03-25)
|
|
2
23
|
|
|
3
24
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React, { Fragment } from 'react';
|
|
2
|
+
|
|
3
|
+
import Label from '../Label';
|
|
4
|
+
import PhotoAlbum from '../PhotoAlbum';
|
|
5
|
+
|
|
6
|
+
import styles from './styles';
|
|
7
|
+
import propTypes from './propTypes';
|
|
8
|
+
|
|
9
|
+
const Capture = ({
|
|
10
|
+
label,
|
|
11
|
+
helpText,
|
|
12
|
+
maxImages,
|
|
13
|
+
images,
|
|
14
|
+
selectedImages,
|
|
15
|
+
setSelectedImages,
|
|
16
|
+
deletePhoto,
|
|
17
|
+
onPressAddAnotherPhoto,
|
|
18
|
+
onUnknownCameraError,
|
|
19
|
+
selectedMode,
|
|
20
|
+
sourceCameraImage,
|
|
21
|
+
sourceEditImage,
|
|
22
|
+
messageErrorPermissionCamera
|
|
23
|
+
}) => {
|
|
24
|
+
const isOnlyOnePicture = maxImages === 1 && images.length === 1;
|
|
25
|
+
const isItPossibleToAddAnotherPhoto = isOnlyOnePicture ? false : images.length <= maxImages;
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Fragment>
|
|
29
|
+
{!!label && (
|
|
30
|
+
<Label semiBold big style={styles.paddingText}>
|
|
31
|
+
{label}
|
|
32
|
+
</Label>
|
|
33
|
+
)}
|
|
34
|
+
<PhotoAlbum
|
|
35
|
+
images={images}
|
|
36
|
+
selectedImages={selectedImages}
|
|
37
|
+
setSelectedImages={setSelectedImages}
|
|
38
|
+
deletePhoto={deletePhoto}
|
|
39
|
+
isItPossibleToAddAnotherPhoto={isItPossibleToAddAnotherPhoto}
|
|
40
|
+
onPressAddAnotherPhoto={onPressAddAnotherPhoto}
|
|
41
|
+
onUnknownCameraError={onUnknownCameraError}
|
|
42
|
+
selectedMode={selectedMode}
|
|
43
|
+
numberOfPhotosInTheAlbumHasExceeded={images.length === maxImages}
|
|
44
|
+
isOnlyOnePicture={isOnlyOnePicture}
|
|
45
|
+
sourceCameraImage={sourceCameraImage}
|
|
46
|
+
sourceEditImage={sourceEditImage}
|
|
47
|
+
messageErrorPermissionCamera={messageErrorPermissionCamera}
|
|
48
|
+
/>
|
|
49
|
+
{!!helpText && <Label style={styles.paddingText}>{helpText}</Label>}
|
|
50
|
+
</Fragment>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
Capture.propTypes = propTypes;
|
|
54
|
+
|
|
55
|
+
export default Capture;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { bool, string, func, array, number } from 'prop-types';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
label: string,
|
|
5
|
+
helpText: string,
|
|
6
|
+
maxImages: number,
|
|
7
|
+
images: array,
|
|
8
|
+
selectedImages: array,
|
|
9
|
+
setSelectedImages: func,
|
|
10
|
+
deletePhoto: func,
|
|
11
|
+
onPressAddAnotherPhoto: func,
|
|
12
|
+
onUnknownCameraError: func,
|
|
13
|
+
selectedMode: bool
|
|
14
|
+
};
|
|
@@ -48,4 +48,7 @@ export const formatStyles = (useMarkdown, styles, newMarkdownStyles = {}) => {
|
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
export const markdownFormat = content =>
|
|
51
|
-
content
|
|
51
|
+
content
|
|
52
|
+
?.toString()
|
|
53
|
+
.replace(/(<\s*br\s*\/?>|\n)/gi, '\n\n')
|
|
54
|
+
.replace(/(<\s*hr\s*\/?>)/gi, '\n\n---') || null;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Image, TouchableOpacity } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import styles from './styles';
|
|
5
|
+
import propTypes from './propTypes';
|
|
6
|
+
|
|
7
|
+
const AddAnotherPhotoButton = ({ sourceCameraImage, onPress, disabled }) => (
|
|
8
|
+
<TouchableOpacity
|
|
9
|
+
onPress={onPress}
|
|
10
|
+
style={[styles.container, disabled && styles.disabledContainer]}
|
|
11
|
+
disabled={disabled}
|
|
12
|
+
>
|
|
13
|
+
<Image source={sourceCameraImage} style={[styles.image, disabled && styles.imageDisabled]} />
|
|
14
|
+
</TouchableOpacity>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
AddAnotherPhotoButton.propTypes = propTypes;
|
|
18
|
+
|
|
19
|
+
export default AddAnotherPhotoButton;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Dimensions, StyleSheet } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import { moderateVerticalScale, moderateHorizontalScale } from '../../../../utils/scaleUtils';
|
|
4
|
+
|
|
5
|
+
const IMAGE_SIZE = (Dimensions.get('window').width - 30) * 0.333333 - 10;
|
|
6
|
+
const styles = StyleSheet.create({
|
|
7
|
+
container: {
|
|
8
|
+
width: IMAGE_SIZE,
|
|
9
|
+
height: IMAGE_SIZE,
|
|
10
|
+
paddingHorizontal: moderateHorizontalScale(10),
|
|
11
|
+
borderRadius: 5,
|
|
12
|
+
marginBottom: moderateVerticalScale(10),
|
|
13
|
+
backgroundColor: '#F7F8F9',
|
|
14
|
+
justifyContent: 'center',
|
|
15
|
+
alignItems: 'center'
|
|
16
|
+
},
|
|
17
|
+
disabledContainer: {
|
|
18
|
+
backgroundColor: 'rgba(247, 248, 249, 0.5)'
|
|
19
|
+
},
|
|
20
|
+
image: {
|
|
21
|
+
width: moderateHorizontalScale(48),
|
|
22
|
+
height: moderateHorizontalScale(48)
|
|
23
|
+
},
|
|
24
|
+
imageDisabled: {
|
|
25
|
+
opacity: 0.5
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export default styles;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import Icon from '../../../Icon';
|
|
5
|
+
import Label from '../../../Label';
|
|
6
|
+
|
|
7
|
+
import styles from './styles';
|
|
8
|
+
import propTypes from './propTypes';
|
|
9
|
+
|
|
10
|
+
const DeleteView = ({ label, color }) => (
|
|
11
|
+
<View style={styles.buttonContainer}>
|
|
12
|
+
<Icon name="trash-2" type="feather" size={20} color={color} />
|
|
13
|
+
<Label color={color}>{label}</Label>
|
|
14
|
+
</View>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
DeleteView.propTypes = propTypes;
|
|
18
|
+
|
|
19
|
+
export default DeleteView;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { View, Image, TouchableOpacity, Modal, ImageBackground } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import SvgIconCheck from '../SvgIconCheck';
|
|
5
|
+
import Icon from '../../../Icon';
|
|
6
|
+
import DeleteView from '../DeleteView';
|
|
7
|
+
|
|
8
|
+
import styles from './styles';
|
|
9
|
+
import propTypes from './propTypes';
|
|
10
|
+
|
|
11
|
+
const Photo = ({ image, onError, onLongPressImage, selectedImages, deletePhoto, isSelectedMode }) => {
|
|
12
|
+
const uri = image.uri ?? image;
|
|
13
|
+
const [fullScreenPhotoModalVisible, setFullScreenPhotoModalVisible] = useState(false);
|
|
14
|
+
|
|
15
|
+
const wasTheImagePressed = selectedImages.includes(uri);
|
|
16
|
+
|
|
17
|
+
const deletePhotoInModal = () => {
|
|
18
|
+
setFullScreenPhotoModalVisible(false);
|
|
19
|
+
deletePhoto(uri);
|
|
20
|
+
};
|
|
21
|
+
return (
|
|
22
|
+
<View>
|
|
23
|
+
<TouchableOpacity
|
|
24
|
+
onPress={() => {
|
|
25
|
+
if (isSelectedMode) {
|
|
26
|
+
onLongPressImage(uri);
|
|
27
|
+
} else {
|
|
28
|
+
setFullScreenPhotoModalVisible(true);
|
|
29
|
+
}
|
|
30
|
+
}}
|
|
31
|
+
onLongPress={() => {
|
|
32
|
+
onLongPressImage(uri);
|
|
33
|
+
}}
|
|
34
|
+
>
|
|
35
|
+
{wasTheImagePressed ? (
|
|
36
|
+
<ImageBackground borderRadius={5} source={{ uri }} style={styles.image}>
|
|
37
|
+
<SvgIconCheck size={24} />
|
|
38
|
+
</ImageBackground>
|
|
39
|
+
) : (
|
|
40
|
+
<Image onError={onError} source={{ uri }} style={styles.image} />
|
|
41
|
+
)}
|
|
42
|
+
</TouchableOpacity>
|
|
43
|
+
<Modal animationType="fade" visible={fullScreenPhotoModalVisible}>
|
|
44
|
+
<View style={styles.modalContainer}>
|
|
45
|
+
<View style={styles.headerContainerModal}>
|
|
46
|
+
<TouchableOpacity
|
|
47
|
+
onPress={() => {
|
|
48
|
+
setFullScreenPhotoModalVisible(!fullScreenPhotoModalVisible);
|
|
49
|
+
}}
|
|
50
|
+
style={styles.backButtonHeaderModal}
|
|
51
|
+
>
|
|
52
|
+
<Icon name="arrowleft" type="antdesign" size={24} color="white" />
|
|
53
|
+
</TouchableOpacity>
|
|
54
|
+
</View>
|
|
55
|
+
<Image onError={onError} source={{ uri }} style={styles.imageFullScreen} />
|
|
56
|
+
{deletePhoto && (
|
|
57
|
+
<TouchableOpacity onPress={deletePhotoInModal} style={styles.footerContainerModal}>
|
|
58
|
+
<DeleteView label="Eliminar" color="white" />
|
|
59
|
+
</TouchableOpacity>
|
|
60
|
+
)}
|
|
61
|
+
</View>
|
|
62
|
+
</Modal>
|
|
63
|
+
</View>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
Photo.propTypes = propTypes;
|
|
68
|
+
|
|
69
|
+
export default Photo;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Dimensions, StyleSheet } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import { moderateVerticalScale, moderateHorizontalScale } from '../../../../utils/scaleUtils';
|
|
4
|
+
|
|
5
|
+
const IMAGE_SIZE = (Dimensions.get('window').width - 30) * 0.333333 - 10;
|
|
6
|
+
const styles = StyleSheet.create({
|
|
7
|
+
image: {
|
|
8
|
+
width: IMAGE_SIZE,
|
|
9
|
+
height: IMAGE_SIZE,
|
|
10
|
+
borderRadius: 5,
|
|
11
|
+
marginBottom: moderateVerticalScale(10)
|
|
12
|
+
},
|
|
13
|
+
imageFullScreen: {
|
|
14
|
+
flex: 1,
|
|
15
|
+
width: '100%',
|
|
16
|
+
height: '100%',
|
|
17
|
+
resizeMode: 'cover'
|
|
18
|
+
},
|
|
19
|
+
selectedImageIcon: {
|
|
20
|
+
position: 'absolute',
|
|
21
|
+
alignItems: 'flex-start'
|
|
22
|
+
},
|
|
23
|
+
modalContainer: {
|
|
24
|
+
flex: 1,
|
|
25
|
+
justifyContent: 'space-between'
|
|
26
|
+
},
|
|
27
|
+
headerContainerModal: {
|
|
28
|
+
flexBasis: moderateHorizontalScale(54),
|
|
29
|
+
backgroundColor: '#3A3A3A',
|
|
30
|
+
flexDirection: 'row',
|
|
31
|
+
justifyContent: 'space-between',
|
|
32
|
+
alignItems: 'center',
|
|
33
|
+
paddingLeft: moderateHorizontalScale(15)
|
|
34
|
+
},
|
|
35
|
+
backButtonHeaderModal: {
|
|
36
|
+
width: moderateHorizontalScale(38),
|
|
37
|
+
height: moderateVerticalScale(38),
|
|
38
|
+
borderRadius: 50,
|
|
39
|
+
justifyContent: 'center',
|
|
40
|
+
alignItems: 'center'
|
|
41
|
+
},
|
|
42
|
+
footerContainerModal: {
|
|
43
|
+
flexBasis: moderateHorizontalScale(57),
|
|
44
|
+
backgroundColor: '#3A3A3A',
|
|
45
|
+
justifyContent: 'center',
|
|
46
|
+
alignItems: 'center'
|
|
47
|
+
},
|
|
48
|
+
buttonContainerFooterModal: {
|
|
49
|
+
alignItems: 'center'
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
export default styles;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Image } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import Label from '../../../Label';
|
|
5
|
+
|
|
6
|
+
import styles from './styles';
|
|
7
|
+
import propTypes from './propTypes';
|
|
8
|
+
|
|
9
|
+
const ReplaceView = ({ label, color, sourceEditImage }) => (
|
|
10
|
+
<View style={styles.buttonContainer}>
|
|
11
|
+
<Image source={sourceEditImage} style={styles.image} />
|
|
12
|
+
<Label color={color}>{label}</Label>
|
|
13
|
+
</View>
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
ReplaceView.propTypes = propTypes;
|
|
17
|
+
|
|
18
|
+
export default ReplaceView;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import { moderateHorizontalScale, moderateVerticalScale } from '../../../../utils/scaleUtils';
|
|
4
|
+
|
|
5
|
+
const styles = StyleSheet.create({
|
|
6
|
+
buttonContainer: {
|
|
7
|
+
alignItems: 'center'
|
|
8
|
+
},
|
|
9
|
+
image: {
|
|
10
|
+
width: moderateHorizontalScale(24),
|
|
11
|
+
height: moderateVerticalScale(24)
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export default styles;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import Icon from '../../../Icon';
|
|
5
|
+
|
|
6
|
+
import { styles, colorIcon } from './styles';
|
|
7
|
+
import propTypes from './propTypes';
|
|
8
|
+
|
|
9
|
+
const SvgIconCheck = ({ size }) => (
|
|
10
|
+
<View style={styles(size).backgroundIcon}>
|
|
11
|
+
<Icon color={colorIcon} name="check" size={16} />
|
|
12
|
+
</View>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
SvgIconCheck.propTypes = propTypes;
|
|
16
|
+
|
|
17
|
+
export default SvgIconCheck;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import { moderateVerticalScale } from '../../../../utils/scaleUtils';
|
|
4
|
+
|
|
5
|
+
export const styles = size =>
|
|
6
|
+
StyleSheet.create({
|
|
7
|
+
backgroundIcon: {
|
|
8
|
+
margin: moderateVerticalScale(10),
|
|
9
|
+
alignItems: 'center',
|
|
10
|
+
justifyContent: 'center',
|
|
11
|
+
backgroundColor: '#4D98FA',
|
|
12
|
+
borderRadius: 1000,
|
|
13
|
+
width: size,
|
|
14
|
+
height: size
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const colorIcon = 'white';
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import React, { Fragment, useEffect, useState } from 'react';
|
|
2
|
+
// eslint-disable-next-line react-native/split-platform-components
|
|
3
|
+
import { View, TouchableOpacity, PermissionsAndroid } from 'react-native';
|
|
4
|
+
// eslint-disable-next-line import/no-unresolved
|
|
5
|
+
import { launchCamera } from 'react-native-image-picker';
|
|
6
|
+
|
|
7
|
+
import Label from '../Label';
|
|
8
|
+
import Portal from '../Portal';
|
|
9
|
+
|
|
10
|
+
import AddAnotherPhotoButton from './components/AddAnotherPhotoButton';
|
|
11
|
+
import DeleteView from './components/DeleteView';
|
|
12
|
+
import ReplaceView from './components/ReplaceView';
|
|
13
|
+
import Photo from './components/Photo';
|
|
14
|
+
import styles from './styles';
|
|
15
|
+
import propTypes from './propTypes';
|
|
16
|
+
|
|
17
|
+
const PhotoAlbum = ({
|
|
18
|
+
images,
|
|
19
|
+
selectedImages,
|
|
20
|
+
setSelectedImages,
|
|
21
|
+
deletePhoto,
|
|
22
|
+
selectedMode,
|
|
23
|
+
isItPossibleToAddAnotherPhoto,
|
|
24
|
+
onPressAddAnotherPhoto,
|
|
25
|
+
onError,
|
|
26
|
+
title,
|
|
27
|
+
subTitle,
|
|
28
|
+
onUnknownCameraError,
|
|
29
|
+
numberOfPhotosInTheAlbumHasExceeded,
|
|
30
|
+
isOnlyOnePicture,
|
|
31
|
+
sourceCameraImage,
|
|
32
|
+
sourceEditImage,
|
|
33
|
+
messageErrorPermissionCamera
|
|
34
|
+
}) => {
|
|
35
|
+
const requestPermission = async () => {
|
|
36
|
+
const permissionsResponse = await PermissionsAndroid.requestMultiple([
|
|
37
|
+
PermissionsAndroid.PERMISSIONS.CAMERA,
|
|
38
|
+
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
const granted =
|
|
42
|
+
permissionsResponse[PermissionsAndroid.PERMISSIONS.CAMERA] === 'granted' &&
|
|
43
|
+
permissionsResponse[PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE] === 'granted';
|
|
44
|
+
|
|
45
|
+
if (!granted) {
|
|
46
|
+
throw messageErrorPermissionCamera;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const [isSelectedMode, setIsSelectedMode] = useState(false);
|
|
51
|
+
const onLongPressImage = uri => {
|
|
52
|
+
if (selectedImages.includes(uri)) {
|
|
53
|
+
setSelectedImages(selectedImages.filter(aPicUri => aPicUri !== uri));
|
|
54
|
+
} else {
|
|
55
|
+
setSelectedImages([...selectedImages, uri]);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const deleteSelectedPhotos = () => {
|
|
59
|
+
deletePhoto();
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const openCamera = async () => {
|
|
63
|
+
await requestPermission();
|
|
64
|
+
|
|
65
|
+
const response = await launchCamera({});
|
|
66
|
+
const { didCancel, errorCode, errorMessage, assets } = response;
|
|
67
|
+
if (didCancel || errorCode) {
|
|
68
|
+
if (errorCode) {
|
|
69
|
+
onUnknownCameraError(`[${errorCode}] : ${errorMessage}`);
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
const { uri } = assets[0];
|
|
73
|
+
onPressAddAnotherPhoto({ newImage: { uri }, numberOfPhotosInTheAlbumHasExceeded });
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const isDivisibleInModuleOfThree = () => {
|
|
78
|
+
const numberOfObjectsInView = isItPossibleToAddAnotherPhoto ? images.length + 1 : images.length;
|
|
79
|
+
return numberOfObjectsInView % 3 !== 0;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const cameraOnPress = () =>
|
|
83
|
+
openCamera().catch(error => {
|
|
84
|
+
if (typeof error === 'string') {
|
|
85
|
+
onError(error);
|
|
86
|
+
} else {
|
|
87
|
+
onUnknownCameraError(error);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const onPressAddAnotherPhotoButton = deleteSelectedImages => {
|
|
92
|
+
if (deleteSelectedImages) {
|
|
93
|
+
setSelectedImages([]);
|
|
94
|
+
}
|
|
95
|
+
cameraOnPress();
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (selectedImages.length > 0) {
|
|
100
|
+
setIsSelectedMode(true);
|
|
101
|
+
} else {
|
|
102
|
+
setIsSelectedMode(false);
|
|
103
|
+
}
|
|
104
|
+
}, [selectedImages]);
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<Fragment>
|
|
108
|
+
{title && (
|
|
109
|
+
<Label big semiBold color="#666666" style={styles.title}>
|
|
110
|
+
{title}
|
|
111
|
+
</Label>
|
|
112
|
+
)}
|
|
113
|
+
{subTitle && (
|
|
114
|
+
<Label color="#3A3A3A" style={styles.subTitle}>
|
|
115
|
+
{subTitle}
|
|
116
|
+
</Label>
|
|
117
|
+
)}
|
|
118
|
+
<View style={styles.container}>
|
|
119
|
+
{images.length !== 0 &&
|
|
120
|
+
images.map(image => (
|
|
121
|
+
<Photo
|
|
122
|
+
key={image.uri ?? image}
|
|
123
|
+
image={image}
|
|
124
|
+
onLongPressImage={onLongPressImage}
|
|
125
|
+
selectedImages={selectedImages}
|
|
126
|
+
deletePhoto={deletePhoto}
|
|
127
|
+
isSelectedMode={isSelectedMode}
|
|
128
|
+
onError={onError}
|
|
129
|
+
/>
|
|
130
|
+
))}
|
|
131
|
+
{isItPossibleToAddAnotherPhoto && (
|
|
132
|
+
<AddAnotherPhotoButton
|
|
133
|
+
onPress={onPressAddAnotherPhotoButton}
|
|
134
|
+
disabled={numberOfPhotosInTheAlbumHasExceeded}
|
|
135
|
+
sourceCameraImage={sourceCameraImage}
|
|
136
|
+
/>
|
|
137
|
+
)}
|
|
138
|
+
{isDivisibleInModuleOfThree() && <View style={styles.image} />}
|
|
139
|
+
{selectedMode && isSelectedMode && (
|
|
140
|
+
<Portal>
|
|
141
|
+
<View style={styles.selectedModeContainer}>
|
|
142
|
+
<View style={styles.selectionLabelContainer}>
|
|
143
|
+
<Label color="white">{`${selectedImages.length} selección`}</Label>
|
|
144
|
+
</View>
|
|
145
|
+
<View style={styles.buttonsContainer}>
|
|
146
|
+
{isOnlyOnePicture && (
|
|
147
|
+
<TouchableOpacity
|
|
148
|
+
onPress={() => onPressAddAnotherPhotoButton(numberOfPhotosInTheAlbumHasExceeded)}
|
|
149
|
+
style={styles.deleteSelectedPhotos}
|
|
150
|
+
>
|
|
151
|
+
<ReplaceView label="Remplazar" color="#3A3A3A" sourceEditImage={sourceEditImage} />
|
|
152
|
+
</TouchableOpacity>
|
|
153
|
+
)}
|
|
154
|
+
<TouchableOpacity onPress={deleteSelectedPhotos} style={styles.deleteSelectedPhotos}>
|
|
155
|
+
<DeleteView label="Eliminar" color="#3A3A3A" />
|
|
156
|
+
</TouchableOpacity>
|
|
157
|
+
</View>
|
|
158
|
+
</View>
|
|
159
|
+
</Portal>
|
|
160
|
+
)}
|
|
161
|
+
</View>
|
|
162
|
+
</Fragment>
|
|
163
|
+
);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
PhotoAlbum.propTypes = propTypes;
|
|
167
|
+
|
|
168
|
+
export default PhotoAlbum;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { bool, string, func, array } from 'prop-types';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
images: array,
|
|
5
|
+
selectedImages: array,
|
|
6
|
+
setSelectedImages: func,
|
|
7
|
+
deletePhoto: func,
|
|
8
|
+
selectedMode: bool,
|
|
9
|
+
isItPossibleToAddAnotherPhoto: bool,
|
|
10
|
+
onPressAddAnotherPhoto: func,
|
|
11
|
+
onError: func,
|
|
12
|
+
title: string,
|
|
13
|
+
subTitle: string,
|
|
14
|
+
onUnknownCameraError: func,
|
|
15
|
+
numberOfPhotosInTheAlbumHasExceeded: bool,
|
|
16
|
+
isOnlyOnePicture: bool
|
|
17
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Dimensions, StyleSheet } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import { moderateHorizontalScale, moderateVerticalScale, WINDOW_WIDTH } from '../../utils/scaleUtils';
|
|
4
|
+
|
|
5
|
+
const IMAGE_SIZE = (Dimensions.get('window').width - 30) * 0.333333 - 10;
|
|
6
|
+
const styles = StyleSheet.create({
|
|
7
|
+
container: {
|
|
8
|
+
flexDirection: 'row',
|
|
9
|
+
flexWrap: 'wrap',
|
|
10
|
+
justifyContent: 'space-between',
|
|
11
|
+
paddingHorizontal: moderateHorizontalScale(5)
|
|
12
|
+
},
|
|
13
|
+
selectedModeContainer: {
|
|
14
|
+
width: WINDOW_WIDTH,
|
|
15
|
+
position: 'absolute',
|
|
16
|
+
bottom: 0
|
|
17
|
+
},
|
|
18
|
+
selectionLabelContainer: {
|
|
19
|
+
height: moderateVerticalScale(27),
|
|
20
|
+
alignItems: 'center',
|
|
21
|
+
backgroundColor: '#4D98FA'
|
|
22
|
+
},
|
|
23
|
+
buttonsContainer: {
|
|
24
|
+
flexDirection: 'row',
|
|
25
|
+
alignItems: 'center',
|
|
26
|
+
justifyContent: 'space-around',
|
|
27
|
+
backgroundColor: '#E4E6EA',
|
|
28
|
+
paddingHorizontal: 60
|
|
29
|
+
},
|
|
30
|
+
deleteSelectedPhotos: {
|
|
31
|
+
height: moderateVerticalScale(58),
|
|
32
|
+
justifyContent: 'center'
|
|
33
|
+
},
|
|
34
|
+
title: {
|
|
35
|
+
marginBottom: moderateVerticalScale(10),
|
|
36
|
+
paddingHorizontal: moderateHorizontalScale(5)
|
|
37
|
+
},
|
|
38
|
+
subTitle: {
|
|
39
|
+
marginBottom: moderateVerticalScale(5),
|
|
40
|
+
paddingHorizontal: moderateHorizontalScale(5)
|
|
41
|
+
},
|
|
42
|
+
image: {
|
|
43
|
+
width: IMAGE_SIZE,
|
|
44
|
+
height: IMAGE_SIZE,
|
|
45
|
+
borderRadius: 5,
|
|
46
|
+
marginBottom: moderateVerticalScale(10),
|
|
47
|
+
paddingHorizontal: moderateHorizontalScale(10)
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export default styles;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import React, { Component } from 'react';
|
|
1
|
+
import React, { Component, Fragment } from 'react';
|
|
2
2
|
import { View, ViewPropTypes } from 'react-native';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
|
|
5
|
+
import SeparatorBar from '../../../SeparatorBar';
|
|
5
6
|
import Touchable from '../../../Touchable';
|
|
6
7
|
import Icon from '../../../Icon';
|
|
7
8
|
import Label from '../../../Label';
|
|
@@ -18,37 +19,64 @@ class RadioButton extends Component {
|
|
|
18
19
|
// TODO: labelComponent is a patch to allow to use tooltips next to radio button label.Change this when mobile-ui has its own tooltip component
|
|
19
20
|
|
|
20
21
|
render() {
|
|
21
|
-
const {
|
|
22
|
+
const {
|
|
23
|
+
status,
|
|
24
|
+
style,
|
|
25
|
+
label,
|
|
26
|
+
labelValue,
|
|
27
|
+
sublabel,
|
|
28
|
+
theme,
|
|
29
|
+
labelComponent,
|
|
30
|
+
descriptionComponent,
|
|
31
|
+
showSeparatorBar
|
|
32
|
+
} = this.props;
|
|
22
33
|
return (
|
|
23
|
-
<
|
|
24
|
-
<
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
</Label>
|
|
36
|
-
{labelComponent}
|
|
34
|
+
<Fragment>
|
|
35
|
+
<Touchable onPress={this.handlePress}>
|
|
36
|
+
<View style={[styles.container, style]}>
|
|
37
|
+
{descriptionComponent ? (
|
|
38
|
+
<View style={styles.descriptionComponentContainer}>
|
|
39
|
+
{descriptionComponent}
|
|
40
|
+
<Icon
|
|
41
|
+
name={status ? RADIO_CHECKED_ICON : RADIO_UNCHECKED_ICON}
|
|
42
|
+
color={theme.colors.primary}
|
|
43
|
+
style={styles.iconSpacing}
|
|
44
|
+
size={20}
|
|
45
|
+
/>
|
|
37
46
|
</View>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
) : (
|
|
48
|
+
<Fragment>
|
|
49
|
+
<Icon
|
|
50
|
+
name={status ? RADIO_CHECKED_ICON : RADIO_UNCHECKED_ICON}
|
|
51
|
+
color={status ? theme.colors.primary : theme.colors.disabled}
|
|
52
|
+
style={styles.iconSpacing}
|
|
53
|
+
/>
|
|
54
|
+
<View style={styles.labelsContainer}>
|
|
55
|
+
<View>
|
|
56
|
+
<View style={[styles.label, labelComponent && styles.labelComponent]}>
|
|
57
|
+
<Label small bold={status} primary={status}>
|
|
58
|
+
{label}
|
|
59
|
+
</Label>
|
|
60
|
+
{labelComponent}
|
|
61
|
+
</View>
|
|
62
|
+
{(sublabel || sublabel === 0) && (
|
|
63
|
+
<Label disabled xsmall bold={status}>
|
|
64
|
+
{sublabel}
|
|
65
|
+
</Label>
|
|
66
|
+
)}
|
|
67
|
+
</View>
|
|
68
|
+
</View>
|
|
69
|
+
{labelValue && (
|
|
70
|
+
<Label bold={status} primary={status} small>
|
|
71
|
+
{labelValue}
|
|
72
|
+
</Label>
|
|
73
|
+
)}
|
|
74
|
+
</Fragment>
|
|
75
|
+
)}
|
|
44
76
|
</View>
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
</Label>
|
|
49
|
-
)}
|
|
50
|
-
</View>
|
|
51
|
-
</Touchable>
|
|
77
|
+
</Touchable>
|
|
78
|
+
{showSeparatorBar && <SeparatorBar />}
|
|
79
|
+
</Fragment>
|
|
52
80
|
);
|
|
53
81
|
}
|
|
54
82
|
}
|
|
@@ -65,7 +93,9 @@ RadioButton.propTypes = {
|
|
|
65
93
|
sublabel: PropTypes.string
|
|
66
94
|
}),
|
|
67
95
|
theme: themeType,
|
|
68
|
-
labelComponent: PropTypes.node
|
|
96
|
+
labelComponent: PropTypes.node,
|
|
97
|
+
descriptionComponent: PropTypes.node,
|
|
98
|
+
showSeparatorBar: PropTypes.bool
|
|
69
99
|
};
|
|
70
100
|
|
|
71
101
|
export default withTheme(RadioButton);
|
|
@@ -26,6 +26,8 @@ class RadioGroup extends Component {
|
|
|
26
26
|
sublabel={option.sublabel}
|
|
27
27
|
onPress={this.handleOptionSelected}
|
|
28
28
|
status={selectedOption === option[keyField]}
|
|
29
|
+
descriptionComponent={option?.Component}
|
|
30
|
+
showSeparatorBar={option?.showSeparatorBar}
|
|
29
31
|
{...radioProps}
|
|
30
32
|
/>
|
|
31
33
|
);
|
package/lib/index.js
CHANGED
|
@@ -69,3 +69,7 @@ export { default as withLoading } from './components/WithLoading';
|
|
|
69
69
|
// Hooks
|
|
70
70
|
export { default as useEffectOnlyOnUpdates } from './hooks/useEffectOnlyOnUpdates';
|
|
71
71
|
export { default as useTogglableState } from './hooks/useTogglableState';
|
|
72
|
+
|
|
73
|
+
// Photo
|
|
74
|
+
export { default as PhotoAlbum } from './components/PhotoAlbum';
|
|
75
|
+
export { default as Capture } from './components/Capture';
|
package/package.json
CHANGED