Merge pull request #2053 from ecency/nt/native-render

WIP - Nt/native render
This commit is contained in:
Feruz M 2021-09-03 10:16:06 +03:00 committed by GitHub
commit fcd8bd7b56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1146 additions and 620 deletions

View File

@ -33,7 +33,6 @@
"@esteemapp/dhive": "0.15.0",
"@esteemapp/react-native-autocomplete-input": "^4.2.1",
"@esteemapp/react-native-multi-slider": "^1.1.0",
"@esteemapp/react-native-render-html": "^4.1.5",
"@esteemapp/react-native-slider": "^0.12.0",
"@hiveio/dhive": "^1.0.1",
"@react-native-community/async-storage": "^1.11.0",
@ -111,6 +110,7 @@
"react-native-randombytes": "^3.6.1",
"react-native-reanimated": "^1",
"react-native-receive-sharing-intent": "ecency/react-native-receive-sharing-intent",
"react-native-render-html": "^6.0.5",
"react-native-restart": "0.0.17",
"react-native-safe-area-context": "^3.1.9",
"react-native-screens": "^2.9.0",

View File

@ -0,0 +1,217 @@
import { ImageStyle } from 'react-native';
import { ViewStyle, TextStyle } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
baseStyle: {
color: '$primaryBlack',
fontFamily: '$primaryFont',
maxWidth: '100%',
fontSize: 16,
} as TextStyle,
body: {
color: '$primaryBlack',
} as TextStyle,
a:{
color: '$primaryBlue'
} as TextStyle,
img:{
alignSelf:'center',
} as ImageStyle,
th:{
flex: 1,
justifyContent: 'center',
fontWeight: 'bold',
color: '$primaryBlack',
fontSize: 14,
padding: 10,
} as TextStyle,
tr:{
backgroundColor:'$darkIconColor',
flexDirection:'row',
} as ViewStyle,
td:{
flex:1,
borderWidth: 0.5,
padding:10,
borderColor: '$tableBorderColor',
backgroundColor: '$tableTrColor'
} as ViewStyle,
blockquote: {
borderLeftWidth: 5,
borderStyle:'solid',
marginLeft:5,
paddingLeft:5,
borderColor: '$darkIconColor',
} as ViewStyle,
code:{
backgroundColor:'$darkIconColor',
fontFamily:'$editorFont',
} as TextStyle,
textCenter: {
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center',
} as TextStyle,
phishy:{
color:'red',
flexDirection:'row',
flexWrap:'wrap'
} as TextStyle,
textJustify:{
textAlign:'justify',
letterSpacing:0
} as TextStyle,
revealButton: {
backgroundColor: '$iconColor',
height: 22,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 20,
minWidth: 40,
maxWidth: 170,
},
revealText: {
color: '$white',
fontSize: 14,
},
videoThumb:{
width:'100%',
alignItems:'center',
justifyContent:'center',
},
playButton:{
alignItems:'center',
justifyContent:'center',
width: 60,
height: 60,
borderRadius: 30,
backgroundColor:'$primaryBlack'
} as ViewStyle
});
//legacy style
// const customStyle = `
// * {
// color: ${EStyleSheet.value('$primaryBlack')};
// font-family: Roboto, sans-serif;
// max-width: 100%;
// overflow-wrap: break-word;
// word-wrap: break-word;
// -ms-word-break: break-all;
// word-break: break-all;
// word-break: break-word;
// -ms-hyphens: auto;
// -moz-hyphens: auto;
// -webkit-hyphens: auto;
// hyphens: auto;
// }
// body {
// color: ${EStyleSheet.value('$primaryBlack')};
// }
// a {
// color: ${EStyleSheet.value('$primaryBlue')};
// cursor: pointer;
// }
// img {
// align-self: 'center';
// max-width: 100%;
// }
// center {
// text-align: 'center';
// align-items: 'center';
// justify-content: 'center';
// }
// table {
// table-layout: fixed;
// width: 100%;
// }
// th {
// flex: 1;
// justify-content: 'center';
// font-weight: 'bold';
// color: ${EStyleSheet.value('$primaryBlack')};
// font-size: 14;
// padding: 5;
// }
// tr {
// background-color: ${EStyleSheet.value('$darkIconColor')};
// flex-direction: 'row';
// }
// td {
// border-width: 0.5;
// border-color: ${EStyleSheet.value('$tableBorderColor')};
// flex: 1;
// padding: 10;
// background-color: ${EStyleSheet.value('$tableTrColor')};
// }
// blockquote {
// border-left-width: 5;
// border-left-style: solid;
// border-color: ${EStyleSheet.value('$darkIconColor')};
// margin-left: 5;
// padding-left: 5;
// }
// code {
// background-color: ${EStyleSheet.value('$darkIconColor')};
// font-family: ${EStyleSheet.value('$editorFont')};
// }
// center {
// text-align: 'center';
// align-items: 'center';
// justify-content: 'center';
// }
// .markdown-video-link {
// max-width: 100%;
// position: relative;
// }
// .markdown-video-play {
// position: absolute;
// width: 100px;
// height: 100px;
// background: url('data:image/png;base64,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') no-repeat center center;
// z-index: 20;
// opacity: 0.9;
// left: 50%;
// top: 50%;
// margin-top: -100px;
// transform: translateX(-50%) translateY(-50%);
// -webkit-transform: translateX(-50%) translateY(-50%);
// -moz-transform: translateX(-50%) translateY(-50%);
// }
// b > * {
// display: inline-block;
// margin: 2 10;
// }
// iframe {
// width: 100%;
// height: 240px;
// }
// .pull-right {
// float: right;
// }
// .pull-left {
// float: left;
// }
// .pull-left,
// .pull-right {
// max-width: calc(50% - 10px);
// padding-left: 10px;
// margin-bottom: 10px;
// box-sizing: border-box;
// }
// .phishy {
// display: inline;
// color: red;
// }
// .text-justify {
// text-align: justify;
// text-justify: inter-word;
// letter-spacing: 0px;
// }
// `;

View File

@ -1,502 +0,0 @@
import React, { Fragment, useState, useEffect, useRef } from 'react';
import { Dimensions, Linking, Modal, PermissionsAndroid, Platform } from 'react-native';
import { useIntl } from 'react-intl';
import CameraRoll from '@react-native-community/cameraroll';
import RNFetchBlob from 'rn-fetch-blob';
import ImageViewer from 'react-native-image-zoom-viewer';
import ActionSheet from 'react-native-actionsheet';
import { connect } from 'react-redux';
import AutoHeightWebView from 'react-native-autoheight-webview';
import EStyleSheet from 'react-native-extended-stylesheet';
import get from 'lodash/get';
import { navigate } from '../../../../navigation/service';
// Constants
import { default as ROUTES } from '../../../../constants/routeNames';
import { CommentPlaceHolder } from '../../../basicUIElements';
import { customCommentScript } from './config';
import { TextButton } from '../../..';
// Styles
import styles from './postBodyStyles';
// Services and Actions
import { writeToClipboard } from '../../../../utils/clipboard';
import { toastNotification } from '../../../../redux/actions/uiAction';
const WIDTH = Dimensions.get('window').width;
const CommentBody = ({
body,
textSelectable = true,
handleOnUserPress,
handleOnPostPress,
handleOnLongPress,
created,
commentDepth,
reputation,
dispatch,
}) => {
const [isImageModalOpen, setIsImageModalOpen] = useState(false);
const [postImages, setPostImages] = useState([]);
const [selectedImage, setSelectedImage] = useState(null);
const [selectedLink, setSelectedLink] = useState(null);
const [revealComment, setRevealComment] = useState(reputation > 0);
const intl = useIntl();
const actionImage = useRef(null);
const actionLink = useRef(null);
useEffect(() => {
if (selectedLink) {
actionLink.current.show();
}
}, [selectedLink]);
useEffect(() => {
if (postImages.length > 0 && selectedImage) {
actionImage.current.show();
}
}, [postImages, selectedImage]);
const _showLowComment = () => {
setRevealComment(true);
};
//new renderer functions
const __handleOnLinkPress = (event) => {
if ((!event && !get(event, 'nativeEvent.data'), false)) {
return;
}
try {
let data = {};
try {
data = JSON.parse(get(event, 'nativeEvent.data'));
} catch (error) {
data = {};
}
const {
type,
href,
images,
image,
author,
category,
permlink,
tag,
proposal,
videoHref,
} = data;
switch (type) {
case '_external':
case 'markdown-external-link':
setSelectedLink(href);
break;
case 'longpress':
handleOnLongPress();
break;
case 'markdown-author-link':
if (!handleOnUserPress) {
__handleOnUserPress(author);
} else {
handleOnUserPress(author);
}
break;
case 'markdown-post-link':
if (!handleOnPostPress) {
__handleOnPostPress(permlink, author);
} else {
handleOnPostPress(permlink, author);
}
break;
case 'markdown-tag-link':
__handleTagPress(tag);
break;
case 'markdown-witnesses-link':
break;
case 'markdown-proposal-link':
break;
case 'markdown-video-link':
break;
case 'image':
setPostImages(images);
setSelectedImage(image);
break;
default:
break;
}
} catch (error) {}
};
const handleImagePress = (ind) => {
if (ind === 1) {
//open gallery mode
setIsImageModalOpen(true);
}
if (ind === 0) {
//copy to clipboard
writeToClipboard(selectedImage).then(() => {
dispatch(
toastNotification(
intl.formatMessage({
id: 'alert.copied',
}),
),
);
});
}
if (ind === 2) {
//save to local
_saveImage(selectedImage);
}
if (ind === 3) {
setPostImages([]);
setSelectedImage(null);
}
};
const handleLinkPress = (ind) => {
if (ind === 1) {
//open link
if (selectedLink) {
Linking.canOpenURL(selectedLink).then((supported) => {
if (supported) {
Linking.openURL(selectedLink);
} else {
dispatch(
toastNotification(
intl.formatMessage({
id: 'alert.failed_to_open',
}),
),
);
}
});
}
}
if (ind === 0) {
//copy to clipboard
writeToClipboard(selectedLink).then(() => {
dispatch(
toastNotification(
intl.formatMessage({
id: 'alert.copied',
}),
),
);
});
}
if (ind === 2) {
setSelectedLink(null);
}
};
const __handleTagPress = (tag) => {
if (tag) {
navigate({
routeName: ROUTES.SCREENS.TAG_RESULT,
params: {
tag,
},
});
}
};
const __handleOnPostPress = (permlink, author) => {
if (permlink) {
navigate({
routeName: ROUTES.SCREENS.POST,
params: {
author,
permlink,
},
key: `@${author}/${permlink}`,
});
}
};
const __handleOnUserPress = (username) => {
if (username) {
navigate({
routeName: ROUTES.SCREENS.PROFILE,
params: {
username,
},
key: username,
});
} else {
dispatch(
toastNotification(
intl.formatMessage({
id: 'post.wrong_link',
}),
),
);
}
};
const checkAndroidPermission = async () => {
try {
const permission = PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE;
await PermissionsAndroid.request(permission);
Promise.resolve();
} catch (error) {
Promise.reject(error);
}
};
const _downloadImage = async (uri) => {
return RNFetchBlob.config({
fileCache: true,
appendExt: 'jpg',
})
.fetch('GET', uri)
.then((res) => {
let status = res.info().status;
if (status == 200) {
return res.path();
} else {
Promise.reject();
}
})
.catch((errorMessage) => {
Promise.reject(errorMessage);
});
};
const _saveImage = async (uri) => {
try {
if (Platform.OS === 'android') {
await checkAndroidPermission();
uri = `file://${await _downloadImage(uri)}`;
}
CameraRoll.saveToCameraRoll(uri)
.then((res) => {
dispatch(
toastNotification(
intl.formatMessage({
id: 'post.image_saved',
}),
),
);
})
.catch((error) => {
dispatch(
toastNotification(
intl.formatMessage({
id: 'post.image_saved_error',
}),
),
);
});
} catch (error) {
dispatch(
toastNotification(
intl.formatMessage({
id: 'post.image_saved_error',
}),
),
);
}
};
const html = body.replace(/<a/g, '<a target="_blank"');
const customStyle = `
* {
color: ${EStyleSheet.value('$primaryBlack')};
font-family: Roboto, sans-serif;
max-width: 100%;
overflow-wrap: break-word;
word-wrap: break-word;
-ms-word-break: break-all;
word-break: break-all;
word-break: break-word;
-ms-hyphens: auto;
-moz-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
body {
color: ${EStyleSheet.value('$primaryBlack')};
}
a {
color: ${EStyleSheet.value('$primaryBlue')};
cursor: pointer;
}
img {
align-self: 'center';
max-width: 100%;
}
center {
text-align: 'center';
align-items: 'center';
justify-content: 'center';
}
table {
table-layout: fixed;
width: 100%;
}
th {
flex: 1;
justify-content: 'center';
font-weight: 'bold';
color: ${EStyleSheet.value('$primaryBlack')};
font-size: 14;
padding: 5;
}
tr {
background-color: ${EStyleSheet.value('$darkIconColor')};
flex-direction: 'row';
}
td {
border-width: 0.5;
border-color: ${EStyleSheet.value('$tableBorderColor')};
flex: 1;
padding: 10;
background-color: ${EStyleSheet.value('$tableTrColor')};
}
blockquote {
border-left-width: 5;
border-left-style: solid;
border-color: ${EStyleSheet.value('$darkIconColor')};
margin-left: 5;
padding-left: 5;
}
code {
background-color: ${EStyleSheet.value('$darkIconColor')};
font-family: ${EStyleSheet.value('$editorFont')};
}
center {
text-align: 'center';
align-items: 'center';
justify-content: 'center';
}
.markdown-video-link {
max-width: 100%;
position: relative;
}
.markdown-video-play {
position: absolute;
width: 100px;
height: 100px;
background: url('data:image/png;base64,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') no-repeat center center;
z-index: 20;
opacity: 0.9;
left: 50%;
top: 50%;
margin-top: -100px;
transform: translateX(-50%) translateY(-50%);
-webkit-transform: translateX(-50%) translateY(-50%);
-moz-transform: translateX(-50%) translateY(-50%);
}
b > * {
display: inline-block;
margin: 2 10;
}
iframe {
width: 100%;
height: 240px;
}
.pull-right {
float: right;
}
.pull-left {
float: left;
}
.pull-left,
.pull-right {
max-width: calc(50% - 10px);
padding-left: 10px;
margin-bottom: 10px;
box-sizing: border-box;
}
.phishy {
display: inline;
color: red;
}
.text-justify {
text-align: justify;
text-justify: inter-word;
letter-spacing: 0px;
}
`;
return (
<Fragment>
<Modal key={`mkey-${created.toString()}`} visible={isImageModalOpen} transparent={true}>
<ImageViewer
imageUrls={postImages}
enableSwipeDown
onCancel={() => setIsImageModalOpen(false)}
onClick={() => setIsImageModalOpen(false)}
/>
</Modal>
<ActionSheet
ref={actionImage}
options={[
intl.formatMessage({ id: 'post.copy_link' }),
intl.formatMessage({ id: 'post.gallery_mode' }),
intl.formatMessage({ id: 'post.save_to_local' }),
intl.formatMessage({ id: 'alert.cancel' }),
]}
title={intl.formatMessage({ id: 'post.image' })}
cancelButtonIndex={3}
onPress={(index) => {
handleImagePress(index);
}}
/>
<ActionSheet
ref={actionLink}
options={[
intl.formatMessage({ id: 'post.copy_link' }),
intl.formatMessage({ id: 'alert.external_link' }),
intl.formatMessage({ id: 'alert.cancel' }),
]}
title={intl.formatMessage({ id: 'post.link' })}
cancelButtonIndex={2}
onPress={(index) => {
handleLinkPress(index);
}}
/>
{revealComment ? (
<AutoHeightWebView
key={`akey-${created.toString()}`}
source={{ html }}
allowsFullscreenVideo={true}
style={{ width: WIDTH - (32 + 34 * (commentDepth % 6)) }}
customStyle={customStyle}
onMessage={__handleOnLinkPress}
customScript={customCommentScript}
renderLoading={() => <CommentPlaceHolder />}
startInLoadingState={true}
onShouldStartLoadWithRequest={false}
scrollEnabled={false}
scalesPageToFit={false}
zoomable={false}
/>
) : (
<TextButton
style={styles.revealButton}
textStyle={styles.revealText}
onPress={() => _showLowComment()}
text={intl.formatMessage({ id: 'comments.reveal_comment' })}
/>
)}
</Fragment>
);
};
const areEqual = (prevProps, nextProps) => prevProps.body !== nextProps.body;
const mapStateToProps = (state) => ({});
export default connect(mapStateToProps)(React.memo(CommentBody, areEqual));

View File

@ -0,0 +1,372 @@
import React, { Fragment, useState, useEffect, useRef } from 'react';
import { Alert, Dimensions, Linking, Modal, PermissionsAndroid, Platform, View } from 'react-native';
import { useIntl } from 'react-intl';
import CameraRoll from '@react-native-community/cameraroll';
import RNFetchBlob from 'rn-fetch-blob';
import ImageViewer from 'react-native-image-zoom-viewer';
import ActionSheet from 'react-native-actionsheet';
import ActionsSheetView from 'react-native-actions-sheet';
// import AutoHeightWebView from 'react-native-autoheight-webview';
import EStyleSheet from 'react-native-extended-stylesheet';
import { navigate } from '../../../../navigation/service';
// Constants
import { default as ROUTES } from '../../../../constants/routeNames';
import { TextButton } from '../../..';
// Styles
import styles from './commentBodyStyles';
// Services and Actions
import { writeToClipboard } from '../../../../utils/clipboard';
import { toastNotification } from '../../../../redux/actions/uiAction';
import getYoutubeId from '../../../../utils/getYoutubeId';
import VideoPlayerSheet from './videoPlayerSheet';
import { LongPressGestureHandler, State } from 'react-native-gesture-handler';
import { useCallback } from 'react';
import HtmlRenderer from './htmlRenderer';
const WIDTH = Dimensions.get('window').width;
const CommentBody = ({
body,
textSelectable = true,
handleOnUserPress,
handleOnPostPress,
handleOnLongPress,
created,
commentDepth,
reputation,
dispatch,
}) => {
const _contentWidth = WIDTH - (32 + 34 * (commentDepth % 6))
const [isImageModalOpen, setIsImageModalOpen] = useState(false);
const [postImages, setPostImages] = useState<string[]>([]);
const [selectedImage, setSelectedImage] = useState(null);
const [selectedLink, setSelectedLink] = useState(null);
const [revealComment, setRevealComment] = useState(reputation > 0);
const [videoUrl, setVideoUrl] = useState(null);
const [youtubeVideoId, setYoutubeVideoId] = useState(null)
const intl = useIntl();
const actionImage = useRef(null);
const actionLink = useRef(null);
const youtubePlayerRef = useRef(null);
useEffect(() => {
if (selectedLink) {
actionLink.current.show();
}
}, [selectedLink]);
useEffect(() => {
if (postImages.length > 0 && selectedImage !== null) {
actionImage.current.show();
}
}, [selectedImage]);
const _onLongPressStateChange = ({nativeEvent}) => {
if(nativeEvent.state === State.ACTIVE){
handleOnLongPress();
}
}
const _showLowComment = () => {
setRevealComment(true);
};
const handleImagePress = (ind) => {
if (ind === 1) {
//open gallery mode
setIsImageModalOpen(true);
}
if (ind === 0) {
//copy to clipboard
writeToClipboard(selectedImage).then(() => {
dispatch(
toastNotification(
intl.formatMessage({
id: 'alert.copied',
}),
),
);
});
}
if (ind === 2) {
//save to local
_saveImage(selectedImage);
}
if (ind === 3) {
setSelectedImage(null);
}
};
const handleLinkPress = (ind) => {
if (ind === 1) {
//open link
if (selectedLink) {
Linking.canOpenURL(selectedLink).then((supported) => {
if (supported) {
Linking.openURL(selectedLink);
} else {
dispatch(
toastNotification(
intl.formatMessage({
id: 'alert.failed_to_open',
}),
),
);
}
});
}
}
if (ind === 0) {
//copy to clipboard
writeToClipboard(selectedLink).then(() => {
dispatch(
toastNotification(
intl.formatMessage({
id: 'alert.copied',
}),
),
);
});
}
if (ind === 2) {
setSelectedLink(null);
}
};
const _handleTagPress = (tag) => {
if (tag) {
navigate({
routeName: ROUTES.SCREENS.TAG_RESULT,
params: {
tag,
},
});
}
};
const _handleOnPostPress = (permlink, author) => {
if(handleOnPostPress){
handleOnUserPress(permlink, author);
return;
}
if (permlink) {
navigate({
routeName: ROUTES.SCREENS.POST,
params: {
author,
permlink,
},
key: `@${author}/${permlink}`,
});
}
};
const _handleOnUserPress = (username) => {
if(handleOnUserPress){
handleOnUserPress(username);
return;
}
if (username) {
navigate({
routeName: ROUTES.SCREENS.PROFILE,
params: {
username,
},
key: username,
});
} else {
dispatch(
toastNotification(
intl.formatMessage({
id: 'post.wrong_link',
}),
),
);
}
};
const checkAndroidPermission = async () => {
try {
const permission = PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE;
await PermissionsAndroid.request(permission);
Promise.resolve();
} catch (error) {
Promise.reject(error);
}
};
const _downloadImage = async (uri) => {
return RNFetchBlob.config({
fileCache: true,
appendExt: 'jpg',
})
.fetch('GET', uri)
.then((res) => {
let status = res.info().status;
if (status == 200) {
return res.path();
} else {
Promise.reject();
}
})
.catch((errorMessage) => {
Promise.reject(errorMessage);
});
};
const _saveImage = async (uri) => {
try {
if (Platform.OS === 'android') {
await checkAndroidPermission();
uri = `file://${await _downloadImage(uri)}`;
}
CameraRoll.saveToCameraRoll(uri)
.then((res) => {
dispatch(
toastNotification(
intl.formatMessage({
id: 'post.image_saved',
}),
),
);
})
.catch((error) => {
dispatch(
toastNotification(
intl.formatMessage({
id: 'post.image_saved_error',
}),
),
);
});
} catch (error) {
dispatch(
toastNotification(
intl.formatMessage({
id: 'post.image_saved_error',
}),
),
);
}
};
const _handleYoutubePress = (embedUrl) => {
const videoId = getYoutubeId(embedUrl);
if (videoId && youtubePlayerRef.current) {
setYoutubeVideoId(videoId);
youtubePlayerRef.current.setModalVisible(true);
}
};
const _handleVideoPress = (embedUrl) => {
if (embedUrl && youtubePlayerRef.current) {
setVideoUrl(embedUrl);
youtubePlayerRef.current.setModalVisible(true);
}
};
const _onElementIsImage = useCallback((imgUrl) =>{
if(postImages.indexOf(imgUrl) == -1){
postImages.push(imgUrl);
setPostImages(postImages);
}
},[postImages])
return (
<Fragment>
<Modal key={`mkey-${created.toString()}`} visible={isImageModalOpen} transparent={true}>
<ImageViewer
imageUrls={postImages.map((url)=>({url}))}
enableSwipeDown
onCancel={() => setIsImageModalOpen(false)}
onClick={() => setIsImageModalOpen(false)}
/>
</Modal>
<ActionSheet
ref={actionImage}
options={[
intl.formatMessage({ id: 'post.copy_link' }),
intl.formatMessage({ id: 'post.gallery_mode' }),
intl.formatMessage({ id: 'post.save_to_local' }),
intl.formatMessage({ id: 'alert.cancel' }),
]}
title={intl.formatMessage({ id: 'post.image' })}
cancelButtonIndex={3}
onPress={(index) => {
handleImagePress(index);
}}
/>
<ActionSheet
ref={actionLink}
options={[
intl.formatMessage({ id: 'post.copy_link' }),
intl.formatMessage({ id: 'alert.external_link' }),
intl.formatMessage({ id: 'alert.cancel' }),
]}
title={intl.formatMessage({ id: 'post.link' })}
cancelButtonIndex={2}
onPress={(index) => {
handleLinkPress(index);
}}
/>
{revealComment ? (
<LongPressGestureHandler onHandlersStateChange={_onLongPressStateChange}>
<View>
<HtmlRenderer
contentWidth={_contentWidth}
body={body}
onElementIsImage={_onElementIsImage}
setSelectedImage={setSelectedImage}
setSelectedLink={setSelectedLink}
handleOnPostPress={_handleOnPostPress}
handleOnUserPress={_handleOnUserPress}
handleTagPress={_handleTagPress}
handleVideoPress={_handleVideoPress}
handleYoutubePress={_handleYoutubePress}
/>
</View>
</LongPressGestureHandler>
) : (
<TextButton
style={styles.revealButton}
textStyle={styles.revealText}
onPress={() => _showLowComment()}
text={intl.formatMessage({ id: 'comments.reveal_comment' })}
/>
)}
<ActionsSheetView
ref={youtubePlayerRef}
gestureEnabled={true}
hideUnderlay
containerStyle={{ backgroundColor: 'black' }}
indicatorColor={EStyleSheet.value('$primaryWhiteLightBackground')}
onClose={() => {
setYoutubeVideoId(null);
setVideoUrl(null);
}}
>
<VideoPlayerSheet youtubeVideoId={youtubeVideoId} videoUrl={videoUrl} />
</ActionsSheetView>
</Fragment>
);
};
export default CommentBody;

View File

@ -0,0 +1,209 @@
import React from "react";
import { View, ImageBackground } from "react-native";
import EStyleSheet from "react-native-extended-stylesheet";
import RenderHTML, { CustomRendererProps, Element, TNode } from "react-native-render-html";
import { IconButton } from "../../..";
import styles from "./commentBodyStyles";
import { LinkData, parseLinkData } from "./linkDataParser";
interface HtmlRendererProps {
contentWidth:number;
body:string;
setSelectedImage:(imgUrl:string)=>void;
setSelectedLink:(url:string)=>void;
onElementIsImage:(imgUrl:string)=>void;
handleOnPostPress:(permlink:string, authro:string)=>void;
handleOnUserPress:(username:string)=>void;
handleTagPress:(tag:string)=>void;
handleVideoPress:(videoUrl:string)=>void;
handleYoutubePress:(videoId:string)=>void;
}
const HtmlRenderer = ({
contentWidth,
body,
setSelectedImage,
setSelectedLink,
onElementIsImage,
handleOnPostPress,
handleOnUserPress,
handleTagPress,
handleVideoPress,
handleYoutubePress,
}:HtmlRendererProps) => {
//new renderer functions
body = body.replace('<center>', '<div class="text-center">').replace('</center>','</div>');
const _handleOnLinkPress = (data:LinkData) => {
if(!data){
return;
}
const {
type,
href,
author,
permlink,
tag,
videoHref,
} = data;
try {
switch (type) {
case '_external':
case 'markdown-external-link':
setSelectedLink(href);
break;
case 'markdown-author-link':
if (handleOnUserPress) {
handleOnUserPress(author);
}
break;
case 'markdown-post-link':
if (handleOnPostPress) {
handleOnPostPress(permlink, author);
}
break;
case 'markdown-tag-link':
if(handleTagPress){
handleTagPress(tag);
}
break;
case 'markdown-video-link':
if(handleVideoPress){
handleVideoPress(videoHref)
}
break;
case 'markdown-video-link-youtube':
if(handleYoutubePress){
handleYoutubePress(tag)
}
break;
//unused cases
// case 'markdown-witnesses-link':
// break;
// case 'markdown-proposal-link':
// break;
default:
break;
}
} catch (error) {}
};
const _onElement = (element:Element) => {
if(element.tagName === 'img' && element.attribs.src){
const imgUrl = element.attribs.src;
console.log("img element detected", imgUrl);
onElementIsImage(imgUrl)
}
};
const _anchorRenderer = ({
InternalRenderer,
tnode,
...props
}:CustomRendererProps<TNode>) => {
const _onPress = () => {
console.log("Link Pressed:", tnode)
const data = parseLinkData(tnode);
_handleOnLinkPress(data);
};
return (
<InternalRenderer
tnode={tnode}
onPress={_onPress}
{...props}
/>
);
}
const _imageRenderer = ({
InternalRenderer,
tnode,
...props
}:CustomRendererProps<TNode>) => {
const _onPress = () => {
const imgUrl = tnode.attributes.src;
console.log("Image Pressed:", imgUrl)
setSelectedImage(imgUrl);
};
const isVideoThumb = tnode.classes?.indexOf('video-thumbnail') >= 0;
const isAnchored = !(tnode.parent?.classes?.indexOf('markdown-external-link') >= 0)
if(isVideoThumb){
return (
<View pointerEvents={'none'}>
<ImageBackground
source={{uri:tnode.attributes.src}}
style={{...styles.videoThumb, height:contentWidth * 9/16 }}
resizeMode={'cover'}>
<IconButton
style={styles.playButton}
size={44}
name='play-arrow'
color={EStyleSheet.value('$white')}
iconType='MaterialIcons'
/>
</ImageBackground>
</View>
)
}
else {
return (
<InternalRenderer
tnode={tnode}
onPress={isAnchored && _onPress}
{...props}/>
);
}
}
return (
<RenderHTML
contentWidth={contentWidth}
source={{ html:body }}
baseStyle={styles.baseStyle}
classesStyles={{
phishy:styles.phishy,
'text-justify':styles.textJustify,
'text-center':styles.textCenter
}}
tagsStyles={{
body:styles.body,
a:styles.a,
img:styles.img,
th:styles.th,
tr:styles.tr,
td:styles.td,
blockquote:styles.blockquote,
code:styles.code,
}}
domVisitors={{
onElement:_onElement
}}
renderers={{
img:_imageRenderer,
a:_anchorRenderer,
}}
/>
)
}
export default React.memo(HtmlRenderer, (next, prev)=>next.body === prev.body)

View File

@ -0,0 +1,103 @@
import { TNode } from "react-native-render-html";
export interface LinkData {
type:string,
href?:string,
author?:string,
permlink?:string,
tag?:string,
proposal?:string,
videoHref?:string,
}
export const parseLinkData = (tnode:TNode):LinkData => {
if(!tnode){
return null;
}
if(tnode.classes.includes('markdown-external-link')){
return {
type:'markdown-external-link',
href: tnode.attributes['data-href']
}
}
if (tnode.classes.includes('markdown-author-link')) {
var author = tnode.attributes['data-author'];
return {
type: 'markdown-author-link',
author: author
};
}
if (tnode.classes.includes('markdown-post-link')) {
var author = tnode.attributes['data-author'];
var permlink = tnode.attributes['data-permlink'];
//snippets checks if there is anchored post inside permlink and use that instead
const anchoredPostRegex = /(.*?\#\@)(.*)\/(.*)/;
const matchedLink = permlink.match(anchoredPostRegex);
if(matchedLink){
author = matchedLink[2];
permlink = matchedLink[3];
}
return {
type: 'markdown-post-link',
author: author,
permlink: permlink
};
}
if (tnode.classes.includes('markdown-tag-link')) {
var tag = tnode.attributes['data-tag'];
return {
type: 'markdown-tag-link',
tag: tag
};
}
if (tnode.classes.includes('markdown-witnesses-link')) {
return {
type: 'markdown-witnesses-link'
};
}
if (tnode.classes.includes('markdown-proposal-link')) {
var proposal = tnode.attributes['data-proposal'];
return {
type: 'markdown-proposal-link',
proposal: proposal
};
}
if (tnode.classes.includes('markdown-video-link-youtube')) {
var embedUrl = tnode.attributes['data-embed-src'];
if (embedUrl) {
return {
type: 'markdown-video-link-youtube',
tag: embedUrl
};
}
}
if (tnode.classes.includes('markdown-video-link')) {
var videoHref = tnode.attributes['data-embed-src'] || tnode.attributes['data-video-href'];
if (videoHref) {
return {
type: 'markdown-video-link',
videoHref: videoHref
};
}
}
}

View File

@ -25,7 +25,7 @@ import { toastNotification } from '../../../../redux/actions/uiAction';
import { default as ROUTES } from '../../../../constants/routeNames';
import getYoutubeId from '../../../../utils/getYoutubeId';
import isAndroidOreo from '../../../../utils/isAndroidOreo';
import YoutubePlayer from './youtubePlayer';
import VideoPlayerSheet from './videoPlayerSheet';
const WIDTH = Dimensions.get('window').width;
@ -51,7 +51,6 @@ const PostBody = ({
const actionImage = useRef(null);
const actionLink = useRef(null);
const youtubePlayerRef = useRef(null);
// const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
if (selectedLink) {
@ -430,10 +429,12 @@ const PostBody = ({
width: 100%;
height: 240px;
}
.phishy {
display: inline;
color: red;
}
.text-justify {
text-align: justify;
}
@ -471,7 +472,7 @@ const PostBody = ({
setYoutubeVideoId(null);
}}
>
<YoutubePlayer videoId={youtubeVideoId} />
<VideoPlayerSheet youtubeVideoId={youtubeVideoId} />
</ActionSheetView>
<ActionSheet

View File

@ -0,0 +1,78 @@
import React, {useState} from 'react';
import { Dimensions } from 'react-native';
import { View, StyleSheet, ActivityIndicator } from 'react-native';
import AutoHeightWebView from 'react-native-autoheight-webview';
import WebView from 'react-native-webview';
import YoutubeIframe from 'react-native-youtube-iframe';
interface VideoPlayerSheetProps {
youtubeVideoId?:string;
videoUrl?:string;
}
const VideoPlayerSheet = ({youtubeVideoId, videoUrl}: VideoPlayerSheetProps) => {
const PLAYER_HEIGHT = Dimensions.get('screen').width * (9/16);
const [shouldPlay, setShouldPlay] = useState(false);
const [loading, setLoading] = useState(true);
const _onReady = () => {
setLoading(false)
setShouldPlay(true);
}
const _onChangeState = (event:string) => {
setShouldPlay(!(event == 'paused' || event == 'ended'));
}
const _onError = () => {
setLoading(false)
}
return (
<View style={styles.container}>
{youtubeVideoId &&
<YoutubeIframe
height={PLAYER_HEIGHT}
videoId={youtubeVideoId}
onReady={_onReady}
play={shouldPlay}
onChangeState={_onChangeState}
onError={_onError}
/>
}{
videoUrl &&
<View style={{height:PLAYER_HEIGHT}}>
<WebView
scalesPageToFit={true}
bounces={false}
javaScriptEnabled={true}
automaticallyAdjustContentInsets={false}
onLoadEnd={()=>{
setLoading(false);
}}
onLoadStart={()=>{
setLoading(true);
}}
source={{uri:videoUrl}}
/>
</View>
}
{loading && <ActivityIndicator style={styles.activityIndicator}/>}
</View>
);
};
export default VideoPlayerSheet;
const styles = StyleSheet.create({
container: {
paddingVertical:16,
},
activityIndicator: {
position:'absolute', alignItems:'center', justifyContent:'center', top:0, bottom:0, left:0, right:0}
});

View File

@ -1,53 +0,0 @@
import React, {useState} from 'react';
import { View, StyleSheet, ActivityIndicator } from 'react-native';
import YoutubeIframe from 'react-native-youtube-iframe';
interface YoutubePlayerProps {
videoId:string
}
const YoutubePlayer = ({videoId}: YoutubePlayerProps) => {
const [shouldPlay, setShouldPlay] = useState(false);
const [loading, setLoading] = useState(true);
const _onReady = () => {
setLoading(false)
setShouldPlay(true);
}
const _onChangeState = (event:string) => {
setShouldPlay(!(event == 'paused' || event == 'ended'));
}
const _onError = () => {
setLoading(false)
}
return (
<View style={styles.container}>
{videoId &&
<YoutubeIframe
height={250}
videoId={videoId}
onReady={_onReady}
play={shouldPlay}
onChangeState={_onChangeState}
onError={_onError}
/>
}
{loading && <ActivityIndicator style={styles.activityIndicator}/>}
</View>
);
};
export default YoutubePlayer;
const styles = StyleSheet.create({
container: {
paddingVertical:16,
},
activityIndicator: {
position:'absolute', alignItems:'center', justifyContent:'center', top:0, bottom:0, left:0, right:0}
});

223
yarn.lock
View File

@ -1086,19 +1086,6 @@
resolved "https://registry.yarnpkg.com/@esteemapp/react-native-multi-slider/-/react-native-multi-slider-1.1.0.tgz#16ac1df8518147daa4977cec2503caba1fbd96b5"
integrity sha512-NSqnLuyrkO23oTpA2WiL9LrxR84eKYKxBp8OogsjLSmThfyaHJvG87J3GLoy+l/9xXA+BeHS4DF360brZ/lrUA==
"@esteemapp/react-native-render-html@^4.1.5":
version "4.1.5"
resolved "https://registry.yarnpkg.com/@esteemapp/react-native-render-html/-/react-native-render-html-4.1.5.tgz#91b52ac67d6890cb07fcebc25352e7b228340e41"
integrity sha512-C3C/VswCX+59hyenMjfKmbsz5GzX7VLrFUN6Az3W9NXd/iN8I+1P8S18EAmAHbX4hXCRLbDqqOMxxM7CayHcqQ==
dependencies:
buffer "^4.5.1"
events "^1.1.0"
html-entities "^1.2.0"
htmlparser2 "^3.10.1"
react-native-autoheight-webview "^1.3.4"
react-native-lightbox "git+https://github.com/oblador/react-native-lightbox.git"
stream "0.0.2"
"@esteemapp/react-native-slider@^0.12.0":
version "0.12.0"
resolved "https://registry.yarnpkg.com/@esteemapp/react-native-slider/-/react-native-slider-0.12.0.tgz#015d429e22545a176c1c07e7f01ae232302fbab4"
@ -1415,6 +1402,37 @@
"@types/yargs" "^15.0.0"
chalk "^3.0.0"
"@jsamr/counter-style@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@jsamr/counter-style/-/counter-style-2.0.1.tgz#c555adc97ceeee57a929ae90ef5d99bc4783f404"
integrity sha512-ox/fGXtTRWk+si55lcfuM2oIaIxK/vPbugaeR9O++9tI/5Vx31SVkUbtvXIIN27U+thRlR0hz5b/+Geq7zg5NA==
"@jsamr/react-native-li@^2.2.1":
version "2.2.1"
resolved "https://registry.yarnpkg.com/@jsamr/react-native-li/-/react-native-li-2.2.1.tgz#77a737e82899916a25c59fec441595286c7016e5"
integrity sha512-24lfABRzLai11PQSWMdOtwfHAr/2pnWM2adO7npE6aNFJ31u3NCp0+zlYKuo4wdOy32QI5t57KvRDKJjlWvefQ==
"@native-html/css-processor@1.10.2":
version "1.10.2"
resolved "https://registry.yarnpkg.com/@native-html/css-processor/-/css-processor-1.10.2.tgz#b3a214742dc6fa6ada9aab03f841d09b9acd7b05"
integrity sha512-cpcWZ8OcK70UE4TwrIxbaJeSX6hboO7LhAqbalWXp8pkUfEocR72AY+gi1BqQUzAH3sIU0ZUjPmec6brAg2WRQ==
dependencies:
css-to-react-native "^3.0.0"
csstype "^3.0.8"
"@native-html/transient-render-engine@^9.2.2":
version "9.2.2"
resolved "https://registry.yarnpkg.com/@native-html/transient-render-engine/-/transient-render-engine-9.2.2.tgz#00691518926ea47709185c3a25a786472c99a1f0"
integrity sha512-DhJqrOYhyNmTL9ze/bGG4mbHzoJoMCPnkH/TsQT1p+ZHI5LXL8PBisKF0tiSz3B88GbgTKOO8tp1YMj0fjUNKQ==
dependencies:
"@native-html/css-processor" "1.10.2"
"@types/ramda" "^0.27.40"
csstype "^3.0.8"
domelementtype "^2.2.0"
domhandler "^4.2.0"
htmlparser2 "^6.1.0"
ramda "^0.27.1"
"@react-native-community/async-storage@1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@react-native-community/async-storage/-/async-storage-1.5.0.tgz#647ffcd832272068b0be57332e08d73036ed391f"
@ -1774,6 +1792,13 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
"@types/ramda@^0.27.40":
version "0.27.44"
resolved "https://registry.yarnpkg.com/@types/ramda/-/ramda-0.27.44.tgz#ba2283d67fcff366f7e68bd5124a0466e467967f"
integrity sha512-SlEHKcLG36PlU+rLJwp8p4dpC9Hp/LiH6n0REX2m4iEB15PWe1qKQzgNSZrYKhTHDFvkeEM/F2gcYwfighsEuQ==
dependencies:
ts-toolbelt "^6.15.1"
"@types/react-native@>=0.62.0":
version "0.64.12"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.64.12.tgz#1c6a3226c26d7a5949cdf8878e6cfe95fe0951d6"
@ -1804,6 +1829,11 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==
"@types/urijs@^1.19.15":
version "1.19.16"
resolved "https://registry.yarnpkg.com/@types/urijs/-/urijs-1.19.16.tgz#156658c47438fa867db5dce4d2949fe1ca0878e2"
integrity sha512-WgxqcUSEYijGnNWHSln/uqay+AywS3mEhLC+d2PwLsru2fLeMblvxP67Y/SCfB2Pxe+dX/zbIoNNzXY+VKOtNA==
"@types/yargs-parser@*":
version "20.2.0"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9"
@ -2831,7 +2861,7 @@ buffer-xor@^1.0.3:
resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=
buffer@^4.5.1, buffer@^4.9.1:
buffer@^4.9.1:
version "4.9.2"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8"
integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==
@ -2920,6 +2950,11 @@ camelcase@^5.0.0, camelcase@^5.3.1:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
camelize@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b"
integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=
caniuse-lite@^1.0.30001219:
version "1.0.30001228"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz#bfdc5942cd3326fa51ee0b42fbef4da9d492a7fa"
@ -2965,6 +3000,16 @@ chalk@^3.0.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
character-entities-html4@^1.0.0:
version "1.1.4"
resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.4.tgz#0e64b0a3753ddbf1fdc044c5fd01d0199a02e125"
integrity sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==
character-entities-legacy@^1.0.0:
version "1.1.4"
resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1"
integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==
chardet@^0.4.0:
version "0.4.2"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
@ -3458,6 +3503,11 @@ crypto-js@^3.1.9-1:
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.3.0.tgz#846dd1cce2f68aacfa156c8578f926a609b7976b"
integrity sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==
css-color-keywords@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=
css-mediaquery@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0"
@ -3473,6 +3523,15 @@ css-select@^2.0.2:
domutils "^1.7.0"
nth-check "^1.0.2"
css-to-react-native@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.0.0.tgz#62dbe678072a824a689bcfee011fc96e02a7d756"
integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==
dependencies:
camelize "^1.0.0"
css-color-keywords "^1.0.0"
postcss-value-parser "^4.0.2"
css-tree@^1.0.0-alpha.37:
version "1.1.2"
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.2.tgz#9ae393b5dafd7dae8a622475caec78d3d8fbd7b5"
@ -3513,6 +3572,11 @@ csstype@^3.0.2:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b"
integrity sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==
csstype@^3.0.8:
version "3.0.8"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340"
integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==
currency-symbol-map@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/currency-symbol-map/-/currency-symbol-map-4.0.4.tgz#3cfba625974dd3f86822d327ecbd10248695e95e"
@ -3798,12 +3862,21 @@ dom-serializer@0:
domelementtype "^2.0.1"
entities "^2.0.0"
dom-serializer@^1.0.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91"
integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==
dependencies:
domelementtype "^2.0.1"
domhandler "^4.2.0"
entities "^2.0.0"
domain-browser@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
domelementtype@1, domelementtype@^1.3.1:
domelementtype@1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
@ -3813,6 +3886,11 @@ domelementtype@^2.0.1:
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.1.0.tgz#a851c080a6d1c3d94344aed151d99f669edf585e"
integrity sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==
domelementtype@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
domexception@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90"
@ -3820,14 +3898,14 @@ domexception@^1.0.1:
dependencies:
webidl-conversions "^4.0.2"
domhandler@^2.3.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==
domhandler@^4.0.0, domhandler@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059"
integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==
dependencies:
domelementtype "1"
domelementtype "^2.2.0"
domutils@^1.5.1, domutils@^1.7.0:
domutils@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==
@ -3835,6 +3913,15 @@ domutils@^1.5.1, domutils@^1.7.0:
dom-serializer "0"
domelementtype "1"
domutils@^2.5.2:
version "2.7.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.7.0.tgz#8ebaf0c41ebafcf55b0b72ec31c56323712c5442"
integrity sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==
dependencies:
dom-serializer "^1.0.1"
domelementtype "^2.2.0"
domhandler "^4.2.0"
dooboolab-welcome@1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/dooboolab-welcome/-/dooboolab-welcome-1.3.2.tgz#4928595312f0429b4ea1b485ba8767bae6acdab7"
@ -3900,11 +3987,6 @@ elliptic@^6.5.2, elliptic@^6.5.3:
minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1"
emitter-component@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/emitter-component/-/emitter-component-1.1.1.tgz#065e2dbed6959bf470679edabeaf7981d1003ab6"
integrity sha1-Bl4tvtaVm/RwZ57avq95gdEAOrY=
emoji-regex@^7.0.1:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
@ -3939,11 +4021,6 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1:
dependencies:
once "^1.4.0"
entities@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
entities@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
@ -4403,7 +4480,7 @@ eventemitter3@^3.0.0:
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7"
integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==
events@^1.0.0, events@^1.0.2, events@^1.1.0:
events@^1.0.0, events@^1.0.2:
version "1.1.1"
resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=
@ -5273,27 +5350,20 @@ html-encoding-sniffer@^1.0.2:
dependencies:
whatwg-encoding "^1.0.1"
html-entities@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc"
integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==
html-escaper@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
htmlparser2@^3.10.1:
version "3.10.1"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==
htmlparser2@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
dependencies:
domelementtype "^1.3.1"
domhandler "^2.3.0"
domutils "^1.5.1"
entities "^1.1.1"
inherits "^2.0.1"
readable-stream "^3.1.1"
domelementtype "^2.0.1"
domhandler "^4.0.0"
domutils "^2.5.2"
entities "^2.0.0"
http-errors@~1.7.2:
version "1.7.3"
@ -8271,6 +8341,11 @@ posix-character-classes@^0.1.0:
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
postcss-value-parser@^4.0.2:
version "4.1.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb"
integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==
prebuild-install@^5.3.3:
version "5.3.6"
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.6.tgz#7c225568d864c71d89d07f8796042733a3f54291"
@ -8532,6 +8607,11 @@ queue-microtask@^1.2.2:
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
ramda@^0.27.1:
version "0.27.1"
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.27.1.tgz#66fc2df3ef873874ffc2da6aa8984658abacf5c9"
integrity sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
@ -8622,7 +8702,7 @@ react-native-animatable@1.3.3, react-native-animatable@^1.3.3:
dependencies:
prop-types "^15.7.2"
react-native-autoheight-webview@^1.3.4, react-native-autoheight-webview@^1.5.8:
react-native-autoheight-webview@^1.5.8:
version "1.5.8"
resolved "https://registry.yarnpkg.com/react-native-autoheight-webview/-/react-native-autoheight-webview-1.5.8.tgz#afcbe65dfefcce4e2088c9aff9fee23dcd18aadf"
integrity sha512-6+LY0a47AsnfnGgqMP2JzNVgX0/sGnkgq7UV39OKgUf2Im/glFjUOggYm8EiyzmA93gb9tYVB1mRTORElWAiGQ==
@ -8750,12 +8830,6 @@ react-native-level-fs@^3.0.0:
level-filesystem "^1.0.1"
levelup "^0.18.2"
"react-native-lightbox@git+https://github.com/oblador/react-native-lightbox.git":
version "0.8.1"
resolved "git+https://github.com/oblador/react-native-lightbox.git#8db37fda32bfe2f4537b992550bd8d0c27f7ca57"
dependencies:
prop-types "^15.7.2"
react-native-linear-gradient@^2.4.2:
version "2.5.6"
resolved "https://registry.yarnpkg.com/react-native-linear-gradient/-/react-native-linear-gradient-2.5.6.tgz#96215cbc5ec7a01247a20890888aa75b834d44a0"
@ -8835,6 +8909,21 @@ react-native-receive-sharing-intent@ecency/react-native-receive-sharing-intent:
version "1.0.4"
resolved "https://codeload.github.com/ecency/react-native-receive-sharing-intent/tar.gz/02d179b5eed6e18bd887248b8d9d2cb2cad0cb18"
react-native-render-html@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/react-native-render-html/-/react-native-render-html-6.0.5.tgz#b36c020a67760d8aace943e40a4c8b0c61a4759a"
integrity sha512-EpLJ7zeshoRAICnlNDDZD+wc109bo47yBSpXahlnFs0txAw45SL9IfB9KiN15vLrXIq+mneV1GDPKhP8S0e4fw==
dependencies:
"@jsamr/counter-style" "^2.0.1"
"@jsamr/react-native-li" "^2.2.1"
"@native-html/transient-render-engine" "^9.2.2"
"@types/ramda" "^0.27.40"
"@types/urijs" "^1.19.15"
prop-types "^15.5.7"
ramda "^0.27.1"
stringify-entities "^3.1.0"
urijs "^1.19.6"
react-native-restart@0.0.17:
version "0.0.17"
resolved "https://registry.yarnpkg.com/react-native-restart/-/react-native-restart-0.0.17.tgz#c1f38e019d1a2114248d496698e7951e9435ba91"
@ -10112,13 +10201,6 @@ stream-buffers@~2.2.0:
resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4"
integrity sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=
stream@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/stream/-/stream-0.0.2.tgz#7f5363f057f6592c5595f00bc80a27f5cec1f0ef"
integrity sha1-f1Nj8Ff2WSxVlfALyAon9c7B8O8=
dependencies:
emitter-component "^1.1.1"
strict-uri-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
@ -10225,6 +10307,15 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
stringify-entities@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-3.1.0.tgz#b8d3feac256d9ffcc9fa1fefdcf3ca70576ee903"
integrity sha512-3FP+jGMmMV/ffZs86MoghGqAoqXAdxLrJP4GUdrDN1aIScYih5tuIO3eF4To5AJZ79KDZ8Fpdy7QJnK8SsL1Vg==
dependencies:
character-entities-html4 "^1.0.0"
character-entities-legacy "^1.0.0"
xtend "^4.0.0"
stringify-object@^3.2.2:
version "3.3.0"
resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629"
@ -10545,6 +10636,11 @@ tr46@^1.0.1:
dependencies:
punycode "^2.1.0"
ts-toolbelt@^6.15.1:
version "6.15.5"
resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz#cb3b43ed725cb63644782c64fbcad7d8f28c0a83"
integrity sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==
tsconfig-paths@^3.9.0:
version "3.9.0"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b"
@ -10756,6 +10852,11 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
urijs@^1.19.6:
version "1.19.7"
resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.7.tgz#4f594e59113928fea63c00ce688fb395b1168ab9"
integrity sha512-Id+IKjdU0Hx+7Zx717jwLPsPeUqz7rAtuVBRLLs+qn+J2nf9NGITWVCxcijgYxBqe83C7sqsQPs6H1pyz3x9gA==
urix@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"