diff --git a/package.json b/package.json index 03f814e0e..525169eef 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "react-native-vector-icons": "^6.6.0", "react-native-version": "^4.0.0", "react-native-version-number": "^0.3.5", - "react-native-webview": "^11.2.1", + "react-native-webview": "^11.17.1", "react-native-youtube-iframe": "^2.1.1", "react-navigation": "^4.0.10", "react-navigation-drawer": "^2.3.3", diff --git a/src/components/checkbox/view/checkboxView.js b/src/components/checkbox/view/checkboxView.js index 52239a213..59c1f0b74 100644 --- a/src/components/checkbox/view/checkboxView.js +++ b/src/components/checkbox/view/checkboxView.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { View, TouchableOpacity } from 'react-native'; import styles from './checkboxStyles'; @@ -6,6 +6,10 @@ import styles from './checkboxStyles'; const CheckBoxView = ({ clicked, value, isChecked, style, locked }) => { const [isCheck, setIsCheck] = useState(false); + useEffect(() => { + setIsCheck(isChecked); + }, [isChecked]); + const _checkClicked = () => { setIsCheck(!isCheck); diff --git a/src/components/dropdownButton/view/dropdownButtonStyles.js b/src/components/dropdownButton/view/dropdownButtonStyles.js index 4de9a3e5b..3b0327c54 100644 --- a/src/components/dropdownButton/view/dropdownButtonStyles.js +++ b/src/components/dropdownButton/view/dropdownButtonStyles.js @@ -82,4 +82,8 @@ export default EStyleSheet.create({ color: '$primaryDarkGray', textAlign: 'left', }, + childrenWrapper: { + flexDirection: 'row', + alignItems: 'center', + }, }); diff --git a/src/components/dropdownButton/view/dropdownButtonView.tsx b/src/components/dropdownButton/view/dropdownButtonView.tsx index bcab9f215..d7a0070b2 100644 --- a/src/components/dropdownButton/view/dropdownButtonView.tsx +++ b/src/components/dropdownButton/view/dropdownButtonView.tsx @@ -97,12 +97,17 @@ const DropdownButtonView = ({ adjustFrame={(style: any) => adjustDropdownFrame(style) } > {isHasChildIcon && !isLoading ? ( - - + + + {defaultText} + + + + ) : ( isHasChildIcon && diff --git a/src/components/markdownEditor/view/formats/applyMediaLink.ts b/src/components/markdownEditor/view/formats/applyMediaLink.ts new file mode 100644 index 000000000..28b5c5ec1 --- /dev/null +++ b/src/components/markdownEditor/view/formats/applyMediaLink.ts @@ -0,0 +1,23 @@ +import {replaceBetween } from './utils'; + +export default async ({ text, selection, setTextAndSelection, items }) => { + const imagePrefix = '!'; + + let newText = text; + let newSelection = selection; + + items.forEach(item => { + if(item.url && item.text){ + const formatedText = `\n${imagePrefix}[${item.text}](${item.url})\n` + newText = replaceBetween(newText, newSelection, formatedText); + const newIndex = newText && newText.indexOf(item.url, newSelection.start) + item.url.length + 2; + newSelection = { + start: newIndex, + end: newIndex + } + } + }); + + + setTextAndSelection({ text: newText, selection: newSelection }); +}; diff --git a/src/components/markdownEditor/view/markdownEditorView.js b/src/components/markdownEditor/view/markdownEditorView.js index c862c78e1..42109fe6a 100644 --- a/src/components/markdownEditor/view/markdownEditorView.js +++ b/src/components/markdownEditor/view/markdownEditorView.js @@ -16,7 +16,7 @@ import { Icon } from '../../icon'; // Utils import Formats from './formats/formats'; -import applyImageLink from './formats/applyWebLinkFormat'; +import applyMediaLink from './formats/applyMediaLink'; // Actions import { toggleAccountsBottomSheet } from '../../../redux/actions/uiAction'; @@ -149,12 +149,11 @@ const MarkdownEditorView = ({ useEffect(() => { if (uploadedImage && uploadedImage.url) { if (uploadedImage.shouldInsert) { - applyImageLink({ + applyMediaLink({ text, selection, setTextAndSelection: _setTextAndSelection, - item: { url: uploadedImage.url, text: uploadedImage.hash }, - isImage: !!uploadedImage, + items: [{ url: uploadedImage.url, text: uploadedImage.hash }], }); } else { uploadsGalleryModalRef.current.showModal(); @@ -267,14 +266,18 @@ const MarkdownEditorView = ({ }); }; - const _handleOnMediaSelect = (mediaInsert) => { - if (mediaInsert && mediaInsert.url) { - applyImageLink({ + const _handleOnMediaSelect = (mediaArray) => { + const items = mediaArray.map((mediaInsert) => ({ + url: mediaInsert.url, + text: mediaInsert.hash, + })); + + if (items.length) { + applyMediaLink({ text, selection, setTextAndSelection: _setTextAndSelection, - item: { url: mediaInsert.url, text: mediaInsert.hash }, - isImage: !!mediaInsert, + items, }); } }; diff --git a/src/components/postHtmlRenderer/postHtmlRenderer.tsx b/src/components/postHtmlRenderer/postHtmlRenderer.tsx index 24eff092c..ce677a56d 100644 --- a/src/components/postHtmlRenderer/postHtmlRenderer.tsx +++ b/src/components/postHtmlRenderer/postHtmlRenderer.tsx @@ -7,6 +7,7 @@ import { AutoHeightImage } from '../autoHeightImage/autoHeightImage'; import { useHtmlIframeProps, iframeModel } from '@native-html/iframe-plugin'; import WebView from 'react-native-webview'; import { VideoPlayer } from '..'; +import { Platform } from 'react-native'; interface PostHtmlRendererProps { contentWidth: number; @@ -136,7 +137,10 @@ export const PostHtmlRenderer = memo( //process video link if(tnode.classes?.indexOf('markdown-video-link') >= 0){ - if(isComment){ + + //TODO: remove android check when fix for react-native-weview scroll crash is available + //ref: https://github.com/react-native-webview/react-native-webview/issues/2364 + if(isComment || Platform.OS === 'android'){ const imgElement = tnode.children.find((child) => { return child.classes.indexOf('video-thumbnail') > 0 ? true : false; }); @@ -225,17 +229,30 @@ export const PostHtmlRenderer = memo( const checkSrcRegex = /(.*?)\.(mp4|webm|ogg)$/gi; const isVideoFormat = iframeProps.source.uri.match(checkSrcRegex); - //this hack help avoid autoplaying fullscreened iframe videos; - const src = isVideoFormat ? - { - html: ` - `, - }:{ - uri: iframeProps.source.uri, - }; + //this hack help avoid autoplaying fullscreened iframe videos; + const src = isVideoFormat ? + { + html: ` + `, + }:{ + uri: iframeProps.source.uri, + }; + //TODO: remove android check logic when fix for react-native-webiew scrollview crash is available + //ref: https://github.com/react-native-webview/react-native-webview/issues/2364 + if(isComment || Platform.OS === 'android'){ + const _onPress = () => { + console.log('iframe thumb Pressed:', iframeProps); + if (handleVideoPress) { + handleVideoPress(iframeProps.source.uri); + } + }; + return ( + + ) + }else{ return ( ); + } + }; return ( diff --git a/src/components/settingsItem/view/settingsItemStyles.js b/src/components/settingsItem/view/settingsItemStyles.js index e49a5de81..2ea14f0c6 100644 --- a/src/components/settingsItem/view/settingsItemStyles.js +++ b/src/components/settingsItem/view/settingsItemStyles.js @@ -19,6 +19,7 @@ export default EStyleSheet.create({ paddingLeft: 16, paddingHorizontal: 14, color: '$primaryDarkGray', + flex: 1, }, rowTextStyle: { fontSize: 12, @@ -43,6 +44,7 @@ export default EStyleSheet.create({ flexGrow: 1, height: 'auto', width: 150, + justifyContent: 'center', }, textStyle: { color: '$primaryBlue', diff --git a/src/components/settingsItem/view/settingsItemView.js b/src/components/settingsItem/view/settingsItemView.js index 82d5d47c1..8f6b1fa6b 100644 --- a/src/components/settingsItem/view/settingsItemView.js +++ b/src/components/settingsItem/view/settingsItemView.js @@ -51,6 +51,7 @@ class SettingsItemView extends PureComponent { textStyle={styles.dropdownText} options={options} onSelect={(e) => handleOnChange(e, type, actionType)} + isHasChildIcon /> ); diff --git a/src/components/uploadsGalleryModal/uploadsGalleryModal.tsx b/src/components/uploadsGalleryModal/uploadsGalleryModal.tsx index 470b64418..7019acb4b 100644 --- a/src/components/uploadsGalleryModal/uploadsGalleryModal.tsx +++ b/src/components/uploadsGalleryModal/uploadsGalleryModal.tsx @@ -2,7 +2,7 @@ import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'rea import { useIntl } from 'react-intl'; import {Text, View, FlatList, RefreshControl, TouchableOpacity, Alert, Platform } from 'react-native'; import FastImage from 'react-native-fast-image'; -import { IconButton } from '..'; +import { CheckBox, MainButton, TextButton } from '..'; import { UploadedMedia } from '../../models'; import { addImage, deleteImage, getImages } from '../../providers/ecency/ecency'; import Modal from '../modal'; @@ -21,7 +21,7 @@ interface MediaInsertData { interface UploadsGalleryModalProps { username:string; - handleOnSelect:(data:MediaInsertData)=>void; + handleOnSelect:(data:Array)=>void; uploadedImage:MediaInsertData; } @@ -30,7 +30,8 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, uploa const [mediaUploads, setMediaUploads] = useState([]); const [isLoading, setIsLoading] = useState(false); - const [showModal, setShowModal] = useState(false); + const [showModal, setShowModal] = useState(false); + const [indices, setIndices] = useState>(new Map()); useImperativeHandle(ref, () => ({ @@ -44,6 +45,12 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, uploa _getMediaUploads(); }, []); + useEffect(()=>{ + if(!showModal){ + setIndices(new Map()); + } + }, [showModal]) + useEffect(() => { if(uploadedImage){ _addUploadedImageToGallery(); @@ -67,11 +74,14 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, uploa // remove image data from user's gallery - const _deleteMediaItem = async (id:string) => { + const _deleteMedia = async () => { try{ setIsLoading(true); - await deleteImage(id) + for (const index of indices.keys()) { + await deleteImage(mediaUploads[index]._id) + } await _getMediaUploads(); + setIndices(new Map()); setIsLoading(false); } catch(err){ console.warn("failed to remove image from gallery", err) @@ -92,45 +102,107 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, uploa setIsLoading(false); } }catch(err){ - console.warn("Failed to get snippets") + console.warn("Failed to get images") setIsLoading(false); } } - - - //render list item for snippet and handle actions; - const _renderItem = ({ item }:{item:UploadedMedia, index:number}) => { - - const _onPress = () => { + //inserts media items in post body + const _insertMedia = async (selectedIndex?:number) => { + const map = selectedIndex ? new Map([[selectedIndex, true]]) : indices; - const data = { - url:item.url, - hash:item.url.split('/').pop() - } + const data = [] + for (const index of map.keys()) { + console.log(index) + const item = mediaUploads[index] + data.push({ + url:item.url, + hash:item.url.split('/').pop() + }) + + } handleOnSelect(data) setShowModal(false); } - const _onRemovePress = async () => { - const _onConfirm = () => { - _deleteMediaItem(item._id) + //renders footer with add snipept button and shows new snippet modal + const _renderFloatingPanel = () => { + + if(!indices.size){ + return null + } + + const _onRemovePress = async () => { + const _onConfirm = () => { + _deleteMedia() + } + Alert.alert( + intl.formatMessage({id:'alert.delete'}), + intl.formatMessage({id:'alert.remove_alert'}), + [{ + text:intl.formatMessage({id:'alert.cancel'}), + style:'cancel' + },{ + text:intl.formatMessage({id:'alert.confirm'}), + onPress:_onConfirm + }] + ) + + } + + return ( + + + + + ); + }; + + + + //render list item for snippet and handle actions; + const _renderItem = ({ item, index }:{item:UploadedMedia, index:number}) => { + + const _onCheckPress = () => { + //update selection indices + if(indices.has(index)){ + indices.delete(index); + }else { + indices.set(index, true); } - Alert.alert( - intl.formatMessage({id:'alert.delete'}), - intl.formatMessage({id:'alert.remove_alert'}), - [{ - text:intl.formatMessage({id:'alert.cancel'}), - style:'cancel' - },{ - text:intl.formatMessage({id:'alert.confirm'}), - onPress:_onConfirm - }] - ) - + + setIndices(new Map([...indices])); } + const _onPress = () => { + + if(indices.size){ + _onCheckPress() + }else { + _insertMedia(index) + } + + + } + + + const thumbUrl = proxifyImageSrc(item.url, 600, 500, Platform.OS === 'ios' ? 'match' : 'webp'); return ( @@ -139,14 +211,11 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, uploa source={{uri:thumbUrl}} style={styles.mediaItem} /> - - + @@ -176,6 +245,7 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, uploa keyExtractor={(item) => `item_${item.url}`} renderItem={_renderItem} ListEmptyComponent={_renderEmptyContent} + extraData={indices} numColumns={2} refreshControl={ + {_renderFloatingPanel()} ) diff --git a/src/components/uploadsGalleryModal/uploadsGalleryModalStyles.ts b/src/components/uploadsGalleryModal/uploadsGalleryModalStyles.ts index d7555dd21..4d28e5a70 100644 --- a/src/components/uploadsGalleryModal/uploadsGalleryModalStyles.ts +++ b/src/components/uploadsGalleryModal/uploadsGalleryModalStyles.ts @@ -22,11 +22,17 @@ export default EStyleSheet.create({ paddingHorizontal:16 }, floatingContainer:{ + flexDirection:'row', position:'absolute', bottom:0, - right:20, + right:0, + left: 0, justifyContent:'flex-end', - zIndex:10 + alignItems:'center', + zIndex:10, + paddingVertical:8, + paddingHorizontal: 16, + backgroundColor:'$primaryBackgroundColor' } as ViewStyle, mediaItem:{ @@ -95,9 +101,14 @@ export default EStyleSheet.create({ } as ViewStyle, - removeItemContainer:{ + checkContainer:{ position:'absolute', - top:16, - right:16 - } as ViewStyle -}) \ No newline at end of file + bottom:20, + right:20 + } as ViewStyle, + + checkStyle:{ + backgroundColor:'$white', + } as ViewStyle, + +}) diff --git a/src/config/locales/en-US.json b/src/config/locales/en-US.json index f44b1b480..7b3c0c2d7 100644 --- a/src/config/locales/en-US.json +++ b/src/config/locales/en-US.json @@ -363,6 +363,8 @@ "title":"Uploaded Images", "title_remove_confirmation":"Delete image", "btn_add":"Image", + "btn_insert":"INSERT", + "btn_delete":"DELETE", "message_failed":"Failed to upload image" }, "pincode": { diff --git a/src/containers/redeemContainer.js b/src/containers/redeemContainer.js index 585f6dc9c..203101120 100644 --- a/src/containers/redeemContainer.js +++ b/src/containers/redeemContainer.js @@ -58,7 +58,7 @@ class RedeemContainer extends Component { permlink, ...specificParam, }); - const uriType = redeemType === 'promote' ? 'esteem_promote' : 'esteem_boost'; + const uriType = redeemType === 'promote' ? 'ecency_promote' : 'ecency_boost'; const uri = `sign/custom-json?authority=active&required_auths=%5B%22${get( user, diff --git a/src/providers/hive/dhive.js b/src/providers/hive/dhive.js index 0993e2f99..d3aa95ac3 100644 --- a/src/providers/hive/dhive.js +++ b/src/providers/hive/dhive.js @@ -1562,7 +1562,7 @@ export const transferPoint = (currentAccount, pinCode, data) => { const privateKey = PrivateKey.fromString(key); const op = { - id: 'esteem_point_transfer', + id: 'ecency_point_transfer', json, required_auths: [username], required_posting_auths: [], @@ -1585,7 +1585,7 @@ export const promote = (currentAccount, pinCode, duration, permlink, author) => const user = get(currentAccount, 'name'); const json = { - id: 'esteem_promote', + id: 'ecency_promote', json: JSON.stringify({ user, author, @@ -1614,7 +1614,7 @@ export const boost = (currentAccount, pinCode, point, permlink, author) => { const user = get(currentAccount, 'name'); const json = { - id: 'esteem_boost', + id: 'ecency_boost', json: JSON.stringify({ user, author, diff --git a/src/screens/transfer/screen/transferScreen.js b/src/screens/transfer/screen/transferScreen.js index 6ca7aa983..f230fcd20 100644 --- a/src/screens/transfer/screen/transferScreen.js +++ b/src/screens/transfer/screen/transferScreen.js @@ -156,7 +156,7 @@ const TransferView = ({ path = `sign/custom-json?authority=active&required_auths=%5B%22${get( selectedAccount, 'name', - )}%22%5D&required_posting_auths=%5B%5D&id=esteem_point_transfer&json=${encodeURIComponent( + )}%22%5D&required_posting_auths=%5B%5D&id=ecency_point_transfer&json=${encodeURIComponent( json, )}`; } else if (transferType === 'transfer_to_savings') { diff --git a/src/screens/transfer/screen/transferTokenScreen.js b/src/screens/transfer/screen/transferTokenScreen.js index 0fc2abfed..40ddb77df 100644 --- a/src/screens/transfer/screen/transferTokenScreen.js +++ b/src/screens/transfer/screen/transferTokenScreen.js @@ -161,7 +161,7 @@ class TransferTokenView extends Component { path = `sign/custom-json?authority=active&required_auths=%5B%22${get( selectedAccount, 'name', - )}%22%5D&required_posting_auths=%5B%5D&id=esteem_point_transfer&json=${encodeURIComponent( + )}%22%5D&required_posting_auths=%5B%5D&id=ecency_point_transfer&json=${encodeURIComponent( json, )}`; } else { diff --git a/yarn.lock b/yarn.lock index c1a4ef4b8..94641bf0f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8856,10 +8856,10 @@ react-native-version@^4.0.0: resolve-from "^5.0.0" semver "^7.0.0" -react-native-webview@^11.2.1: - version "11.2.3" - resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-11.2.3.tgz#1b82685ab60645d4161f2e25e98286493cdffa5d" - integrity sha512-r/K+Lf/O5aij72gRndMX2qsyQ/WLtDPiO75SS57y6JjqSKxedGASVL9Jwl1TM7fCXqUq8dgiwik/LuBHbJXAEg== +react-native-webview@^11.17.1: + version "11.17.1" + resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-11.17.1.tgz#a7c9d995d749539995a4fdad8aa6456bac77fc8f" + integrity sha512-gGdBavATj8Mya2VYZtWtB9cgOAgVJJGlgL5mo/EO8quBeI5L3IBy2ZQolsCyRRGFTUPCc3Ah0OwJal0PjijGqw== dependencies: escape-string-regexp "2.0.0" invariant "2.2.4"