From c83f9025e13337862c7f38a27d80e320fd5c8e6a Mon Sep 17 00:00:00 2001 From: Sadaqat Ali Date: Fri, 21 Jan 2022 10:45:15 +0500 Subject: [PATCH 01/23] added iframe support --- ios/Podfile.lock | 2 +- package.json | 1 + .../postHtmlRenderer/postHtmlRenderer.tsx | 59 +++++++++++++++++-- yarn.lock | 25 ++++++++ 4 files changed, 81 insertions(+), 6 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index a160089bc..c052bc551 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -772,4 +772,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 9c48318ea254e2c78005a7a0c2d8bfc14ddd783d -COCOAPODS: 1.10.1 +COCOAPODS: 1.11.2 diff --git a/package.json b/package.json index 2595cf0f5..75b70516b 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "@esteemapp/react-native-multi-slider": "^1.1.0", "@esteemapp/react-native-slider": "^0.12.0", "@hiveio/dhive": "^1.0.1", + "@native-html/iframe-plugin": "^2.6.1", "@react-native-community/async-storage": "^1.11.0", "@react-native-community/cameraroll": "^1.3.0", "@react-native-community/cli-platform-ios": "^4.10.1", diff --git a/src/components/postHtmlRenderer/postHtmlRenderer.tsx b/src/components/postHtmlRenderer/postHtmlRenderer.tsx index 1f0bd0e41..b51853058 100644 --- a/src/components/postHtmlRenderer/postHtmlRenderer.tsx +++ b/src/components/postHtmlRenderer/postHtmlRenderer.tsx @@ -1,10 +1,11 @@ -import React, { memo } from "react"; +import React, { memo, } from "react"; import RenderHTML, { CustomRendererProps, Element, TNode } from "react-native-render-html"; import styles from "./postHtmlRendererStyles"; import { LinkData, parseLinkData } from "./linkDataParser"; import VideoThumb from "./videoThumb"; import { AutoHeightImage } from "../autoHeightImage/autoHeightImage"; - +import IframeRenderer, { iframeModel } from '@native-html/iframe-plugin'; +import WebView from "react-native-webview"; interface PostHtmlRendererProps { contentWidth:number; @@ -37,6 +38,14 @@ export const PostHtmlRenderer = memo(({ //new renderer functions body = body.replace(/
/g, '
').replace(/<\/center>/g,'
'); +// body = `

+//

+//

+//
+//

Demo Text

+//
+// +//

` console.log("Comment body:", body); @@ -137,7 +146,30 @@ export const PostHtmlRenderer = memo(({ const data = parseLinkData(tnode); _handleOnLinkPress(data); }; - + console.log("parseLinkData(tnode) : ", parseLinkData(tnode)); + + if (tnode.classes?.indexOf('markdown-video-link') >= 0) { + return ( + { + console.log('load end'); + }} + onLoadStart={() => { + console.log('load start'); + }} + source={{ uri: parseLinkData(tnode).videoHref }} + style={{ width: contentWidth, height: (contentWidth * 9) / 16 }} + startInLoadingState={true} + onShouldStartLoadWithRequest={() => true} + mediaPlaybackRequiresUserAction={true} + allowsInlineMediaPlayback={true} + /> + ); + } if(tnode.classes?.indexOf('markdown-video-link') >= 0){ const imgElement = tnode.children.find((child)=>{ return child.classes.indexOf('video-thumbnail') > 0 ? true:false @@ -156,7 +188,7 @@ export const PostHtmlRenderer = memo(({ onPress={_onPress} {...props} /> - ); + ) } //this method checks if image is a child of table column @@ -264,12 +296,29 @@ export const PostHtmlRenderer = memo(({ renderers={{ img:_imageRenderer, a:_anchorRenderer, - p:_paraRenderer + p:_paraRenderer, + iframe: IframeRenderer }} onHTMLLoaded={onLoaded && onLoaded} defaultTextProps={{ selectable:true }} + customHTMLElementModels={{ + iframe: iframeModel + }} + renderersProps={{ + iframe: { + scalesPageToFit: true, + webViewProps: { + startInLoadingState:true, + onShouldStartLoadWithRequest: () => true , + mediaPlaybackRequiresUserAction: true, + allowsFullscreenVideo: false, + /* Any prop you want to pass to iframe WebViews */ + } + } + }} + WebView={WebView} /> ) }, (next, prev)=>next.body === prev.body) diff --git a/yarn.lock b/yarn.lock index 82d76faf5..f2bb770ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1118,6 +1118,11 @@ resolved "https://registry.yarnpkg.com/@formatjs/intl-utils/-/intl-utils-2.3.0.tgz#2dc8c57044de0340eb53a7ba602e59abf80dc799" integrity sha512-KWk80UPIzPmUg+P0rKh6TqspRw0G6eux1PuJr+zz47ftMaZ9QDwbGzHZbtzWkl5hgayM/qrKRutllRC7D/vVXQ== +"@formidable-webview/webshell@^2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@formidable-webview/webshell/-/webshell-2.6.0.tgz#64704c0b513206e71b23118b3c9d096f0d545005" + integrity sha512-FwQQDajg1xs7W3CUiUNJMvdjgLjKLDGzs0XPzoVg0Dunhold1Jg7w5pihUdvVugFlNtkSpXMA+du9QDHE8lmpg== + "@hapi/address@2.x.x": version "2.1.4" resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" @@ -1412,6 +1417,21 @@ css-to-react-native "^3.0.0" csstype "^3.0.8" +"@native-html/iframe-plugin@^2.6.1": + version "2.6.1" + resolved "https://registry.yarnpkg.com/@native-html/iframe-plugin/-/iframe-plugin-2.6.1.tgz#5b9c36d9d500f82f0bcf654bc005922df4211158" + integrity sha512-PM2vFNT44n/UkCm9+OUn+cNSKgiMjaw7c7/2JnnztHDLVMtPIf52K/86miWNpQpxFoy1ouoLVOvfjFRhoPXjag== + dependencies: + "@formidable-webview/webshell" "^2.6.0" + "@native-html/plugins-core" "1.3.0" + "@types/prop-types" "^15.7.4" + prop-types "^15.7.2" + +"@native-html/plugins-core@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@native-html/plugins-core/-/plugins-core-1.3.0.tgz#f1f24622097551930d9dab0214c4929d00f7446e" + integrity sha512-vce35gqGJKa2oPDZVa2sKjucFFVK+3g8quLayeXiJtj5LzuS8TWGrBFTS5O4ToUtE02AJkCDOLwAguCzK2HWdQ== + "@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" @@ -1784,6 +1804,11 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== +"@types/prop-types@^15.7.4": + version "15.7.4" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" + integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== + "@types/ramda@^0.27.40": version "0.27.44" resolved "https://registry.yarnpkg.com/@types/ramda/-/ramda-0.27.44.tgz#ba2283d67fcff366f7e68bd5124a0466e467967f" From 68a94dd2c13541ab5c11b77430c98f66fc35f9d5 Mon Sep 17 00:00:00 2001 From: Sadaqat Ali Date: Fri, 21 Jan 2022 16:09:30 +0500 Subject: [PATCH 02/23] added custom iframe renderer --- .../postHtmlRenderer/postHtmlRenderer.tsx | 58 ++++++++++++++----- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/src/components/postHtmlRenderer/postHtmlRenderer.tsx b/src/components/postHtmlRenderer/postHtmlRenderer.tsx index b51853058..ef8ee54b2 100644 --- a/src/components/postHtmlRenderer/postHtmlRenderer.tsx +++ b/src/components/postHtmlRenderer/postHtmlRenderer.tsx @@ -4,7 +4,7 @@ import styles from "./postHtmlRendererStyles"; import { LinkData, parseLinkData } from "./linkDataParser"; import VideoThumb from "./videoThumb"; import { AutoHeightImage } from "../autoHeightImage/autoHeightImage"; -import IframeRenderer, { iframeModel } from '@native-html/iframe-plugin'; +import { useHtmlIframeProps,iframeModel } from '@native-html/iframe-plugin'; import WebView from "react-native-webview"; interface PostHtmlRendererProps { @@ -38,15 +38,6 @@ export const PostHtmlRenderer = memo(({ //new renderer functions body = body.replace(/
/g, '
').replace(/<\/center>/g,'
'); -// body = `

-//

-//

-//
-//

Demo Text

-//
-// -//

` - console.log("Comment body:", body); const _handleOnLinkPress = (data:LinkData) => { @@ -266,6 +257,47 @@ export const PostHtmlRenderer = memo(({ ) } + // iframe renderer for rendering iframes in body + const _iframeRenderer = function IframeRenderer(props) { + const iframeProps = useHtmlIframeProps(props); + // console.log('iframeProps : ', iframeProps); + const checkSrcRegex = /(.*?)\.(mp4|webm|ogg)$/gi; + const isVideoType = iframeProps.source.uri.match(checkSrcRegex); + + // check if source contain video source then wrap it with video tag + // else pass the source directly to webview + const src = isVideoType + ? { + html: ` + + `, + } + : { + uri: iframeProps.source.uri, + }; + return ( + { + console.log('load end'); + }} + onLoadStart={() => { + console.log('load start'); + }} + source={src} + style={{ width: contentWidth, height: (contentWidth * 9) / 16 }} + startInLoadingState={true} + onShouldStartLoadWithRequest={() => true} + mediaPlaybackRequiresUserAction={true} + allowsInlineMediaPlayback={true} + /> + ); + }; return ( true , - mediaPlaybackRequiresUserAction: true, - allowsFullscreenVideo: false, /* Any prop you want to pass to iframe WebViews */ } } From 8b4e2ea013c661cb4f03d881e255eb3fdadfd670 Mon Sep 17 00:00:00 2001 From: Sadaqat Ali Date: Fri, 21 Jan 2022 18:30:20 +0500 Subject: [PATCH 03/23] changed uri source to support all videos in anchor renderer --- src/components/postHtmlRenderer/postHtmlRenderer.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/postHtmlRenderer/postHtmlRenderer.tsx b/src/components/postHtmlRenderer/postHtmlRenderer.tsx index ef8ee54b2..88437cb71 100644 --- a/src/components/postHtmlRenderer/postHtmlRenderer.tsx +++ b/src/components/postHtmlRenderer/postHtmlRenderer.tsx @@ -137,9 +137,11 @@ export const PostHtmlRenderer = memo(({ const data = parseLinkData(tnode); _handleOnLinkPress(data); }; - console.log("parseLinkData(tnode) : ", parseLinkData(tnode)); if (tnode.classes?.indexOf('markdown-video-link') >= 0) { + // get video src + let videoHref = tnode.attributes['data-embed-src'] || tnode.attributes['data-video-href'] || tnode.children[0].attributes['src']; + return ( { console.log('load start'); }} - source={{ uri: parseLinkData(tnode).videoHref }} + source={{ uri: videoHref }} style={{ width: contentWidth, height: (contentWidth * 9) / 16 }} startInLoadingState={true} onShouldStartLoadWithRequest={() => true} From 9c3f12e06e4b52dac0c3328382f12dbfc6f828bc Mon Sep 17 00:00:00 2001 From: Sadaqat Ali Date: Sat, 22 Jan 2022 15:32:19 +0500 Subject: [PATCH 04/23] refactored video player --- src/components/index.js | 2 + .../postHtmlRenderer/postHtmlRenderer.tsx | 452 ++++++++---------- .../videoPlayer/videoPlayerStyles.ts | 5 + .../videoPlayer/videoPlayerView.tsx | 98 ++++ 4 files changed, 310 insertions(+), 247 deletions(-) create mode 100644 src/components/videoPlayer/videoPlayerStyles.ts create mode 100644 src/components/videoPlayer/videoPlayerView.tsx diff --git a/src/components/index.js b/src/components/index.js index 459ff3f4c..55747394c 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -93,6 +93,7 @@ import { ForegroundNotification } from './foregroundNotification'; import { PostHtmlRenderer } from './postHtmlRenderer'; import { QuickProfileModal } from './organisms'; import QuickReplyModal from './quickReplyModal/quickReplyModalView'; +import VideoPlayer from './videoPlayer/videoPlayerView'; // Basic UI Elements import { @@ -234,4 +235,5 @@ export { PostHtmlRenderer, QuickProfileModal, QuickReplyModal, + VideoPlayer, }; diff --git a/src/components/postHtmlRenderer/postHtmlRenderer.tsx b/src/components/postHtmlRenderer/postHtmlRenderer.tsx index 88437cb71..2d94b0754 100644 --- a/src/components/postHtmlRenderer/postHtmlRenderer.tsx +++ b/src/components/postHtmlRenderer/postHtmlRenderer.tsx @@ -1,27 +1,31 @@ -import React, { memo, } from "react"; -import RenderHTML, { CustomRendererProps, Element, TNode } from "react-native-render-html"; -import styles from "./postHtmlRendererStyles"; -import { LinkData, parseLinkData } from "./linkDataParser"; -import VideoThumb from "./videoThumb"; -import { AutoHeightImage } from "../autoHeightImage/autoHeightImage"; -import { useHtmlIframeProps,iframeModel } from '@native-html/iframe-plugin'; -import WebView from "react-native-webview"; +import React, { memo } from 'react'; +import RenderHTML, { CustomRendererProps, Element, TNode } from 'react-native-render-html'; +import styles from './postHtmlRendererStyles'; +import { LinkData, parseLinkData } from './linkDataParser'; +import VideoThumb from './videoThumb'; +import { AutoHeightImage } from '../autoHeightImage/autoHeightImage'; +import { useHtmlIframeProps, iframeModel } from '@native-html/iframe-plugin'; +import WebView from 'react-native-webview'; +import { View } from 'react-native'; +import YoutubeIframe from 'react-native-youtube-iframe'; +import { VideoPlayer } from '..'; interface PostHtmlRendererProps { - contentWidth:number; - body:string; - onLoaded?:()=>void; - 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, filter?:string)=>void; - handleVideoPress:(videoUrl:string)=>void; - handleYoutubePress:(videoId:string, startTime:number)=>void; + contentWidth: number; + body: string; + onLoaded?: () => void; + 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, filter?: string) => void; + handleVideoPress: (videoUrl: string) => void; + handleYoutubePress: (videoId: string, startTime: number) => void; } -export const PostHtmlRenderer = memo(({ +export const PostHtmlRenderer = memo( + ({ contentWidth, body, onLoaded, @@ -33,209 +37,174 @@ export const PostHtmlRenderer = memo(({ handleTagPress, handleVideoPress, handleYoutubePress, - }:PostHtmlRendererProps) => { + }: PostHtmlRendererProps) => { + //new renderer functions + body = body.replace(/
/g, '
').replace(/<\/center>/g, '
'); - //new renderer functions - body = body.replace(/
/g, '
').replace(/<\/center>/g,'
'); + console.log('Comment body:', body); - console.log("Comment body:", body); - - const _handleOnLinkPress = (data:LinkData) => { - - if(!data){ - return; - } - - const { - type, - href, - author, - permlink, - tag, - youtubeId, - startTime, - filter, - videoHref, - community - } = 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, filter); - } - break; - - case 'markdown-video-link': - if(handleVideoPress){ - handleVideoPress(videoHref) - } - break; - case 'markdown-video-link-youtube': - if(handleYoutubePress){ - handleYoutubePress(youtubeId, startTime) - } - - break; - - //unused cases - case 'markdown-witnesses-link': - setSelectedLink(href); - break; - - case 'markdown-proposal-link': - setSelectedLink(href); - break; - - case 'markdown-community-link': - //tag press also handles community by default - if(handleTagPress){ - handleTagPress(community, filter) - } - break; - - default: - break; + const _handleOnLinkPress = (data: LinkData) => { + if (!data) { + return; } - } catch (error) {} - }; - - - const _onElement = (element:Element) => { - if(element.tagName === 'img' && element.attribs.src){ + + const { + type, + href, + author, + permlink, + tag, + youtubeId, + startTime, + filter, + videoHref, + community, + } = 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, filter); + } + break; + + case 'markdown-video-link': + if (handleVideoPress) { + handleVideoPress(videoHref); + } + break; + case 'markdown-video-link-youtube': + if (handleYoutubePress) { + handleYoutubePress(youtubeId, startTime); + } + + break; + + //unused cases + case 'markdown-witnesses-link': + setSelectedLink(href); + break; + + case 'markdown-proposal-link': + setSelectedLink(href); + break; + + case 'markdown-community-link': + //tag press also handles community by default + if (handleTagPress) { + handleTagPress(community, filter); + } + 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) + console.log('img element detected', imgUrl); + onElementIsImage(imgUrl); } }; - - const _anchorRenderer = ({ - InternalRenderer, - tnode, - ...props - }:CustomRendererProps) => { - + const _anchorRenderer = ({ InternalRenderer, tnode, ...props }: CustomRendererProps) => { + const parsedTnode = parseLinkData(tnode); const _onPress = () => { - console.log("Link Pressed:", tnode) + console.log('Link Pressed:', tnode); const data = parseLinkData(tnode); _handleOnLinkPress(data); }; - if (tnode.classes?.indexOf('markdown-video-link') >= 0) { - // get video src - let videoHref = tnode.attributes['data-embed-src'] || tnode.attributes['data-video-href'] || tnode.children[0].attributes['src']; - + if (parsedTnode.type === 'markdown-video-link-youtube') { return ( - { - console.log('load end'); - }} - onLoadStart={() => { - console.log('load start'); - }} - source={{ uri: videoHref }} - style={{ width: contentWidth, height: (contentWidth * 9) / 16 }} - startInLoadingState={true} - onShouldStartLoadWithRequest={() => true} - mediaPlaybackRequiresUserAction={true} - allowsInlineMediaPlayback={true} + ); } - if(tnode.classes?.indexOf('markdown-video-link') >= 0){ - const imgElement = tnode.children.find((child)=>{ - return child.classes.indexOf('video-thumbnail') > 0 ? true:false - }) - if(!imgElement){ - return ( - - ) + if (tnode.classes?.indexOf('markdown-video-link') >= 0) { + return ( + + ); + } + if (tnode.classes?.indexOf('markdown-video-link') >= 0) { + const imgElement = tnode.children.find((child) => { + return child.classes.indexOf('video-thumbnail') > 0 ? true : false; + }); + if (!imgElement) { + return ; } } - - - return ( - - ) - } + + return ; + }; //this method checks if image is a child of table column //and calculates img width accordingly, //returns full width if img is not part of table - const getMaxImageWidth = (tnode:TNode)=>{ - + const getMaxImageWidth = (tnode: TNode) => { //return full width if not parent exist - if(!tnode.parent || tnode.parent.tagName === 'body'){ + if (!tnode.parent || tnode.parent.tagName === 'body') { return contentWidth; } //return divided width based on number td tags - if(tnode.parent.tagName === 'td'){ - const cols = tnode.parent.parent.children.length - return contentWidth/cols; + if (tnode.parent.tagName === 'td') { + const cols = tnode.parent.parent.children.length; + return contentWidth / cols; } //check next parent return getMaxImageWidth(tnode.parent); - } - - - const _imageRenderer = ({ - tnode, - }:CustomRendererProps) => { - + }; + + const _imageRenderer = ({ tnode }: CustomRendererProps) => { const imgUrl = tnode.attributes.src; const _onPress = () => { - console.log("Image Pressed:", imgUrl) + console.log('Image Pressed:', imgUrl); setSelectedImage(imgUrl); }; - + const isVideoThumb = tnode.classes?.indexOf('video-thumbnail') >= 0; const isAnchored = tnode.parent?.tagName === 'a'; - - if(isVideoThumb){ - return ; - } - else { + if (isVideoThumb) { + return ; + } else { const maxImgWidth = getMaxImageWidth(tnode); return ( - - ) + ); } - - } - + }; /** * the para renderer is designd to remove margins from para @@ -243,31 +212,18 @@ export const PostHtmlRenderer = memo(({ * a weired misalignment of bullet and content * @returns Default Renderer */ - const _paraRenderer = ({ - TDefaultRenderer, - ...props - }:CustomRendererProps) => { + const _paraRenderer = ({ TDefaultRenderer, ...props }: CustomRendererProps) => { + props.style = props.tnode.parent.tagName === 'li' ? styles.pLi : styles.p; - props.style = props.tnode.parent.tagName === 'li' - ? styles.pLi - : styles.p + return ; + }; - return ( - - ) - } - // iframe renderer for rendering iframes in body const _iframeRenderer = function IframeRenderer(props) { const iframeProps = useHtmlIframeProps(props); - // console.log('iframeProps : ', iframeProps); const checkSrcRegex = /(.*?)\.(mp4|webm|ogg)$/gi; const isVideoType = iframeProps.source.uri.match(checkSrcRegex); - // check if source contain video source then wrap it with video tag - // else pass the source directly to webview const src = isVideoType ? { html: ` @@ -300,55 +256,57 @@ export const PostHtmlRenderer = memo(({ /> ); }; - - return ( - - ) - }, (next, prev)=>next.body === prev.body) + + return ( + + ); + }, + (next, prev) => next.body === prev.body, +); diff --git a/src/components/videoPlayer/videoPlayerStyles.ts b/src/components/videoPlayer/videoPlayerStyles.ts new file mode 100644 index 000000000..b64e4c5cf --- /dev/null +++ b/src/components/videoPlayer/videoPlayerStyles.ts @@ -0,0 +1,5 @@ +import EStyleSheet from 'react-native-extended-stylesheet'; + +export default EStyleSheet.create({ + +}); diff --git a/src/components/videoPlayer/videoPlayerView.tsx b/src/components/videoPlayer/videoPlayerView.tsx new file mode 100644 index 000000000..500aa5fbf --- /dev/null +++ b/src/components/videoPlayer/videoPlayerView.tsx @@ -0,0 +1,98 @@ +import React, { useState } from 'react'; +import style from './videoPlayerStyles'; +import { Dimensions } from 'react-native'; +import { View, StyleSheet, ActivityIndicator } from 'react-native'; +import WebView from 'react-native-webview'; +import YoutubeIframe, { InitialPlayerParams } from 'react-native-youtube-iframe'; + +interface VideoPlayerProps { + youtubeVideoId?: string; + videoUrl?: string; + startTime?: number; + contentWidth?: number; +} + +const VideoPlayer = ({ youtubeVideoId, videoUrl, startTime, contentWidth }: VideoPlayerProps) => { + 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); + console.log('ready'); + }; + + const _onChangeState = (event: string) => { + console.log(event); + setShouldPlay(!(event == 'paused' || event == 'ended')); + }; + + const _onError = () => { + console.log('error!'); + setLoading(false); + }; + + const initialParams: InitialPlayerParams = { + start: startTime, + }; + + return ( + + {youtubeVideoId && ( + + + + )} + {videoUrl && ( + + { + setLoading(false); + }} + onLoadStart={() => { + setLoading(true); + }} + source={{ uri: videoUrl }} + style={{ width: contentWidth, height: (contentWidth * 9) / 16 }} + startInLoadingState={true} + onShouldStartLoadWithRequest={() => true} + mediaPlaybackRequiresUserAction={true} + allowsInlineMediaPlayback={true} + /> + + )} + {loading && } + + ); +}; + +export default VideoPlayer; + +const styles = StyleSheet.create({ + container: { + paddingVertical: 16, + }, + activityIndicator: { + position: 'absolute', + alignItems: 'center', + justifyContent: 'center', + top: 0, + bottom: 0, + left: 0, + right: 0, + }, +}); From ddd4de5b37be593abd9c6df9fb159ef72fe20d73 Mon Sep 17 00:00:00 2001 From: Sadaqat Ali Date: Sat, 22 Jan 2022 16:10:01 +0500 Subject: [PATCH 05/23] changed condition causing crash --- src/components/postHtmlRenderer/postHtmlRenderer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/postHtmlRenderer/postHtmlRenderer.tsx b/src/components/postHtmlRenderer/postHtmlRenderer.tsx index 2d94b0754..3853c94b7 100644 --- a/src/components/postHtmlRenderer/postHtmlRenderer.tsx +++ b/src/components/postHtmlRenderer/postHtmlRenderer.tsx @@ -133,7 +133,7 @@ export const PostHtmlRenderer = memo( _handleOnLinkPress(data); }; - if (parsedTnode.type === 'markdown-video-link-youtube') { + if (tnode.classes?.indexOf('markdown-video-link-youtube') >= 0) { return ( Date: Sun, 23 Jan 2022 01:11:17 +0500 Subject: [PATCH 06/23] unified video player component --- .../body/view/commentBodyView.tsx | 11 ++- .../postElements/body/view/postBodyView.js | 6 +- .../body/view/videoPlayerSheet.tsx | 83 ------------------- .../postHtmlRenderer/postHtmlRenderer.tsx | 52 +++++------- .../videoPlayer/videoPlayerView.tsx | 26 ++++-- 5 files changed, 48 insertions(+), 130 deletions(-) delete mode 100644 src/components/postElements/body/view/videoPlayerSheet.tsx diff --git a/src/components/postElements/body/view/commentBodyView.tsx b/src/components/postElements/body/view/commentBodyView.tsx index bf7b79d29..52b518d5e 100644 --- a/src/components/postElements/body/view/commentBodyView.tsx +++ b/src/components/postElements/body/view/commentBodyView.tsx @@ -13,7 +13,7 @@ import { navigate } from '../../../../navigation/service'; // Constants import { default as ROUTES } from '../../../../constants/routeNames'; -import { PostHtmlRenderer, TextButton } from '../../..'; +import { PostHtmlRenderer, TextButton, VideoPlayer } from '../../..'; // Styles import styles from './commentBodyStyles'; @@ -21,14 +21,12 @@ import styles from './commentBodyStyles'; // Services and Actions import { writeToClipboard } from '../../../../utils/clipboard'; import { toastNotification } from '../../../../redux/actions/uiAction'; -import VideoPlayerSheet from './videoPlayerSheet'; import { LongPressGestureHandler, State } from 'react-native-gesture-handler'; import { useCallback } from 'react'; import { OptionsModal } from '../../../atoms'; import { useAppDispatch } from '../../../../hooks'; import { isCommunity } from '../../../../utils/communityValidation'; import { GLOBAL_POST_FILTERS_VALUE } from '../../../../constants/options/filters'; -import { startsWith } from 'core-js/core/string'; const WIDTH = Dimensions.get('window').width; @@ -368,7 +366,12 @@ const CommentBody = ({ setVideoUrl(null); }} > - + ); diff --git a/src/components/postElements/body/view/postBodyView.js b/src/components/postElements/body/view/postBodyView.js index 052931d6b..8979014ad 100644 --- a/src/components/postElements/body/view/postBodyView.js +++ b/src/components/postElements/body/view/postBodyView.js @@ -15,11 +15,10 @@ import { toastNotification } from '../../../../redux/actions/uiAction'; // Constants import { default as ROUTES } from '../../../../constants/routeNames'; -import VideoPlayerSheet from './videoPlayerSheet'; import { OptionsModal } from '../../../atoms'; import { isCommunity } from '../../../../utils/communityValidation'; import { GLOBAL_POST_FILTERS_VALUE } from '../../../../constants/options/filters'; -import { PostHtmlRenderer } from '../../..'; +import { PostHtmlRenderer, VideoPlayer } from '../../..'; const WIDTH = Dimensions.get('window').width; @@ -294,7 +293,8 @@ const PostBody = ({ navigation, body, dispatch, onLoadEnd }) => { setVideoUrl(null); }} > - { - - 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) - } - - const initialParams:InitialPlayerParams = { - start:startTime - } - - return ( - - - {youtubeVideoId && - - - }{ - videoUrl && - - { - setLoading(false); - }} - onLoadStart={()=>{ - setLoading(true); - }} - source={{uri:videoUrl}} - /> - - - } - {loading && } - - ); -}; - -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} -}); diff --git a/src/components/postHtmlRenderer/postHtmlRenderer.tsx b/src/components/postHtmlRenderer/postHtmlRenderer.tsx index 3853c94b7..a66dfdff9 100644 --- a/src/components/postHtmlRenderer/postHtmlRenderer.tsx +++ b/src/components/postHtmlRenderer/postHtmlRenderer.tsx @@ -218,43 +218,31 @@ export const PostHtmlRenderer = memo( return ; }; + // iframe renderer for rendering iframes in body const _iframeRenderer = function IframeRenderer(props) { const iframeProps = useHtmlIframeProps(props); const checkSrcRegex = /(.*?)\.(mp4|webm|ogg)$/gi; - const isVideoType = iframeProps.source.uri.match(checkSrcRegex); + const isVideoFormat = iframeProps.source.uri.match(checkSrcRegex); - const src = isVideoType - ? { - html: ` - - `, - } - : { - uri: iframeProps.source.uri, - }; - return ( - { - console.log('load end'); - }} - onLoadStart={() => { - console.log('load start'); - }} - source={src} - style={{ width: contentWidth, height: (contentWidth * 9) / 16 }} - startInLoadingState={true} - onShouldStartLoadWithRequest={() => true} - mediaPlaybackRequiresUserAction={true} - allowsInlineMediaPlayback={true} - /> - ); + //this hack help avoid autoplaying fullscreened iframe videos; + const src = isVideoFormat ? + { + html: ` + `, + }:{ + uri: iframeProps.source.uri, + }; + + return ( + + ); }; return ( diff --git a/src/components/videoPlayer/videoPlayerView.tsx b/src/components/videoPlayer/videoPlayerView.tsx index 500aa5fbf..65e9dfc91 100644 --- a/src/components/videoPlayer/videoPlayerView.tsx +++ b/src/components/videoPlayer/videoPlayerView.tsx @@ -1,19 +1,29 @@ import React, { useState } from 'react'; -import style from './videoPlayerStyles'; import { Dimensions } from 'react-native'; import { View, StyleSheet, ActivityIndicator } from 'react-native'; import WebView from 'react-native-webview'; import YoutubeIframe, { InitialPlayerParams } from 'react-native-youtube-iframe'; +import { WebViewSource } from 'react-native-webview/lib/WebViewTypes'; interface VideoPlayerProps { + mode: 'source'|'youtube'|'url'; + contentWidth?: number; youtubeVideoId?: string; videoUrl?: string; startTime?: number; - contentWidth?: number; + source?: WebViewSource; } -const VideoPlayer = ({ youtubeVideoId, videoUrl, startTime, contentWidth }: VideoPlayerProps) => { - const PLAYER_HEIGHT = Dimensions.get('screen').width * (9 / 16); +const VideoPlayer = ({ + youtubeVideoId, + videoUrl, + startTime, + source, + contentWidth = Dimensions.get('screen').width, + mode + }: VideoPlayerProps) => { + + const PLAYER_HEIGHT = contentWidth * (9 / 16); const [shouldPlay, setShouldPlay] = useState(false); const [loading, setLoading] = useState(true); @@ -40,7 +50,7 @@ const VideoPlayer = ({ youtubeVideoId, videoUrl, startTime, contentWidth }: Vide return ( - {youtubeVideoId && ( + {mode === 'youtube' && youtubeVideoId && ( )} - {videoUrl && ( + {((mode === 'source' && source) || (mode === 'url' && videoUrl)) && ( { setLoading(true); }} - source={{ uri: videoUrl }} - style={{ width: contentWidth, height: (contentWidth * 9) / 16 }} + source={source || { uri: videoUrl }} + style={{ width: contentWidth, height: PLAYER_HEIGHT}} startInLoadingState={true} onShouldStartLoadWithRequest={() => true} mediaPlaybackRequiresUserAction={true} From aa963f5f8b219ee5fcb075d4ccf40c05cfe681f4 Mon Sep 17 00:00:00 2001 From: noumantahir Date: Sun, 23 Jan 2022 01:12:11 +0500 Subject: [PATCH 07/23] cleaned up video link processor in anchorRenderer, using sheet based players for comments --- .../body/view/commentBodyView.tsx | 1 + .../postHtmlRenderer/postHtmlRenderer.tsx | 57 +++++++++++-------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/components/postElements/body/view/commentBodyView.tsx b/src/components/postElements/body/view/commentBodyView.tsx index 52b518d5e..730816e4d 100644 --- a/src/components/postElements/body/view/commentBodyView.tsx +++ b/src/components/postElements/body/view/commentBodyView.tsx @@ -335,6 +335,7 @@ const CommentBody = ({ void; setSelectedImage: (imgUrl: string) => void; setSelectedLink: (url: string) => void; @@ -28,6 +27,7 @@ export const PostHtmlRenderer = memo( ({ contentWidth, body, + isComment, onLoaded, setSelectedImage, setSelectedLink, @@ -133,35 +133,42 @@ export const PostHtmlRenderer = memo( _handleOnLinkPress(data); }; - if (tnode.classes?.indexOf('markdown-video-link-youtube') >= 0) { - return ( - - ); - } - if (tnode.classes?.indexOf('markdown-video-link') >= 0) { - return ( - - ); - } - if (tnode.classes?.indexOf('markdown-video-link') >= 0) { - const imgElement = tnode.children.find((child) => { - return child.classes.indexOf('video-thumbnail') > 0 ? true : false; - }); - if (!imgElement) { - return ; + + //process video link + if(tnode.classes?.indexOf('markdown-video-link') >= 0){ + if(isComment){ + const imgElement = tnode.children.find((child) => { + return child.classes.indexOf('video-thumbnail') > 0 ? true : false; + }); + if (!imgElement) { + return ; + } + } + else if(tnode.classes?.indexOf('markdown-video-link-youtube') >= 0){ + return ( + + ); + } else { + return ( + + ); } } + return ; }; + //this method checks if image is a child of table column //and calculates img width accordingly, //returns full width if img is not part of table From 2f167af102872f260e945a7b1077ce02bbcf727b Mon Sep 17 00:00:00 2001 From: noumantahir Date: Sun, 23 Jan 2022 01:22:13 +0500 Subject: [PATCH 08/23] improved player response and refined logic --- .../postHtmlRenderer/postHtmlRenderer.tsx | 15 ++++----------- src/components/videoPlayer/videoPlayerView.tsx | 8 ++++++-- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/components/postHtmlRenderer/postHtmlRenderer.tsx b/src/components/postHtmlRenderer/postHtmlRenderer.tsx index eacb47841..01d7c9430 100644 --- a/src/components/postHtmlRenderer/postHtmlRenderer.tsx +++ b/src/components/postHtmlRenderer/postHtmlRenderer.tsx @@ -143,22 +143,15 @@ export const PostHtmlRenderer = memo( if (!imgElement) { return ; } - } - else if(tnode.classes?.indexOf('markdown-video-link-youtube') >= 0){ - return ( - - ); } else { return ( ); } diff --git a/src/components/videoPlayer/videoPlayerView.tsx b/src/components/videoPlayer/videoPlayerView.tsx index 65e9dfc91..60bd9fb67 100644 --- a/src/components/videoPlayer/videoPlayerView.tsx +++ b/src/components/videoPlayer/videoPlayerView.tsx @@ -12,6 +12,9 @@ interface VideoPlayerProps { videoUrl?: string; startTime?: number; source?: WebViewSource; + + //prop for youtube player + disableAutoplay?:boolean; } const VideoPlayer = ({ @@ -20,7 +23,8 @@ const VideoPlayer = ({ startTime, source, contentWidth = Dimensions.get('screen').width, - mode + mode, + disableAutoplay }: VideoPlayerProps) => { const PLAYER_HEIGHT = contentWidth * (9 / 16); @@ -30,7 +34,7 @@ const VideoPlayer = ({ const _onReady = () => { setLoading(false); - setShouldPlay(true); + setShouldPlay(disableAutoplay ? false : true); console.log('ready'); }; From 153d99e86398eee722cdf12a7cd4c9dae1ec0017 Mon Sep 17 00:00:00 2001 From: noumantahir Date: Sun, 23 Jan 2022 20:31:04 +0500 Subject: [PATCH 09/23] ability to extract word at selection index --- .../markdownEditor/view/markdownEditorView.js | 8 ++++++++ src/utils/editor.ts | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/components/markdownEditor/view/markdownEditorView.js b/src/components/markdownEditor/view/markdownEditorView.js index 6d7241413..2c4419cba 100644 --- a/src/components/markdownEditor/view/markdownEditorView.js +++ b/src/components/markdownEditor/view/markdownEditorView.js @@ -46,6 +46,7 @@ import styles from './markdownEditorStyles'; import applySnippet from './formats/applySnippet'; import { MainButton } from '../../mainButton'; import isAndroidOreo from '../../../utils/isAndroidOreo'; +import { extractWordAtIndex } from '../../../utils/editor'; const MIN_BODY_INPUT_HEIGHT = 300; @@ -104,6 +105,13 @@ const MarkdownEditorView = ({ } }, [onLoadDraftPress]); + useEffect(() => { + if (selection.start === selection.end && text) { + const word = extractWordAtIndex(text, selection.start); + console.log('selection word is: ', word); + } + }, [text, selection]); + useEffect(() => { if (text === '' && draftBody !== '') { _setTextAndSelection({ selection: { start: 0, end: 0 }, text: draftBody }); diff --git a/src/utils/editor.ts b/src/utils/editor.ts index c2c8df62e..c97fde485 100644 --- a/src/utils/editor.ts +++ b/src/utils/editor.ts @@ -44,6 +44,23 @@ export const generatePermlink = (title, random = false) => { return perm; }; +export const extractWordAtIndex = (text:string, index:number) => { + let word = ''; + for(let i = index; i >= 0 && text[i] !== ' '; i--){ + if(text[i]){ + word += text[i]; + } + } + word = word.split('').reverse().join(''); + for(let i = index + 1; i < text.length && text[i] !== ' '; i++){ + if(text[i]){ + word += text[i]; + } + } + return word; + +} + export const generateReplyPermlink = (toAuthor) => { if (!toAuthor) { return ''; From ae34c148702fed26769361f489453906d6e121d8 Mon Sep 17 00:00:00 2001 From: noumantahir Date: Thu, 27 Jan 2022 13:25:35 +0500 Subject: [PATCH 10/23] searching for available users --- .../markdownEditor/view/markdownEditorView.js | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/components/markdownEditor/view/markdownEditorView.js b/src/components/markdownEditor/view/markdownEditorView.js index 2c4419cba..c2153e911 100644 --- a/src/components/markdownEditor/view/markdownEditorView.js +++ b/src/components/markdownEditor/view/markdownEditorView.js @@ -47,6 +47,7 @@ import applySnippet from './formats/applySnippet'; import { MainButton } from '../../mainButton'; import isAndroidOreo from '../../../utils/isAndroidOreo'; import { extractWordAtIndex } from '../../../utils/editor'; +import { searchAccount } from '../../../providers/ecency/ecency'; const MIN_BODY_INPUT_HEIGHT = 300; @@ -82,6 +83,7 @@ const MarkdownEditorView = ({ const [bodyInputHeight, setBodyInputHeight] = useState(MIN_BODY_INPUT_HEIGHT); const [isSnippetsOpen, setIsSnippetsOpen] = useState(false); const [showDraftLoadButton, setShowDraftLoadButton] = useState(false); + const [autoCompleteUsers, setAutoCompleteUsers] = useState([]); const inputRef = useRef(null); const galleryRef = useRef(null); @@ -109,6 +111,9 @@ const MarkdownEditorView = ({ if (selection.start === selection.end && text) { const word = extractWordAtIndex(text, selection.start); console.log('selection word is: ', word); + if(word.startsWith('@')){ + _handleUserSearch(word.substring(1)); + } } }, [text, selection]); @@ -192,6 +197,17 @@ const MarkdownEditorView = ({ dispatch(toggleAccountsBottomSheet(!isVisibleAccountsBottomSheet)); }; + + const _handleUserSearch = async (username) => { + let users = []; + if(username){ + users = await searchAccount(username, 5); + console.log("result users", users) + } + + setAutoCompleteUsers(users); + } + // eslint-disable-next-line react-hooks/exhaustive-deps const _changeText = useCallback((input) => { setText(input); @@ -311,6 +327,16 @@ const MarkdownEditorView = ({ } }; + const _renderLookedUpAccounts = () => { + return { + return {user.name + ' '} + }} + /> + } + const _renderEditorButtons = () => ( @@ -459,6 +485,7 @@ const MarkdownEditorView = ({ {isAndroidOreo() ? _renderEditorWithoutScroll() : _renderEditorWithScroll()} {_renderFloatingDraftButton()} + {_renderLookedUpAccounts()} {!isPreviewActive && _renderEditorButtons()} Date: Thu, 27 Jan 2022 14:16:29 +0500 Subject: [PATCH 11/23] improved word extractor --- src/utils/editor.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/utils/editor.ts b/src/utils/editor.ts index c97fde485..ffabb7aa0 100644 --- a/src/utils/editor.ts +++ b/src/utils/editor.ts @@ -45,18 +45,23 @@ export const generatePermlink = (title, random = false) => { }; export const extractWordAtIndex = (text:string, index:number) => { + const END_REGEX = /[\s,]/ let word = ''; - for(let i = index; i >= 0 && text[i] !== ' '; i--){ + for(let i = index; i >= 0 && (!END_REGEX.test(text[i]) || i === index); i--){ if(text[i]){ word += text[i]; } } word = word.split('').reverse().join(''); - for(let i = index + 1; i < text.length && text[i] !== ' '; i++){ - if(text[i]){ - word += text[i]; + + if(!END_REGEX.test(text[index])){ + for(let i = index + 1; i < text.length && !END_REGEX.test(text[i]); i++){ + if(text[i]){ + word += text[i]; + } } } + return word; } From e75d8d0415db184d4423349479df1f7996e714b1 Mon Sep 17 00:00:00 2001 From: noumantahir Date: Thu, 27 Jan 2022 15:39:57 +0500 Subject: [PATCH 12/23] added users bar component for rendering searched users --- .../markdownEditor/view/usersBar.tsx | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/components/markdownEditor/view/usersBar.tsx diff --git a/src/components/markdownEditor/view/usersBar.tsx b/src/components/markdownEditor/view/usersBar.tsx new file mode 100644 index 000000000..feb7c56b5 --- /dev/null +++ b/src/components/markdownEditor/view/usersBar.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { View, FlatList, Text } from "react-native" +import { TouchableOpacity } from 'react-native-gesture-handler'; +import { UserAvatar } from '../..'; +import styles from './markdownEditorStyles'; + +interface Props { + usernames:Array; + onUserSelect:(username:string)=>void; +} + +export const UsersBar = ({usernames, onUserSelect}:Props) => { + + const _renderItem = ({item}:{item:string}) => { + const username = item; + return ( + {onUserSelect(username)}}> + + + {username} + + + ) + } + + return ( + + + + ) + } From 6422f1d3b8405bb3037d1a943ab844a49af1f95f Mon Sep 17 00:00:00 2001 From: noumantahir Date: Thu, 27 Jan 2022 15:40:05 +0500 Subject: [PATCH 13/23] updated styles --- .../view/markdownEditorStyles.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/components/markdownEditor/view/markdownEditorStyles.js b/src/components/markdownEditor/view/markdownEditorStyles.js index 6a12e7f7e..db5c32267 100644 --- a/src/components/markdownEditor/view/markdownEditorStyles.js +++ b/src/components/markdownEditor/view/markdownEditorStyles.js @@ -110,4 +110,29 @@ export default EStyleSheet.create({ bottom: 56, }, }), + searchAccountsContainer: Platform.select({ + //absolute positioning makes button hide behind keyboard on ios + ios: { + marginBottom: 24, + }, + //on android the appearing of button was causing momentary glitch with ios variant style + android: { + position: 'absolute', + bottom: 56, + }, + }), + userBubble: { + flexDirection: 'row', + alignItems: 'center', + marginHorizontal: 4, + paddingHorizontal: 8, + paddingVertical: 8, + backgroundColor: '$primaryBlue', + borderRadius: 24, + }, + userBubbleText: { + fontSize: 16, + color: '$white', + marginHorizontal: 6, + }, }); From cefa54cb0b7aba4ccb4d86b3b4c1873bf4b83f87 Mon Sep 17 00:00:00 2001 From: noumantahir Date: Thu, 27 Jan 2022 16:00:37 +0500 Subject: [PATCH 14/23] basic end to end implementation --- .../markdownEditor/view/markdownEditorView.js | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/components/markdownEditor/view/markdownEditorView.js b/src/components/markdownEditor/view/markdownEditorView.js index c2153e911..f398da8f0 100644 --- a/src/components/markdownEditor/view/markdownEditorView.js +++ b/src/components/markdownEditor/view/markdownEditorView.js @@ -48,6 +48,7 @@ import { MainButton } from '../../mainButton'; import isAndroidOreo from '../../../utils/isAndroidOreo'; import { extractWordAtIndex } from '../../../utils/editor'; import { searchAccount } from '../../../providers/ecency/ecency'; +import { UsersBar } from './usersBar'; const MIN_BODY_INPUT_HEIGHT = 300; @@ -111,8 +112,10 @@ const MarkdownEditorView = ({ if (selection.start === selection.end && text) { const word = extractWordAtIndex(text, selection.start); console.log('selection word is: ', word); - if(word.startsWith('@')){ + if (word.startsWith('@') && word.length > 3) { _handleUserSearch(word.substring(1)); + } else { + setAutoCompleteUsers([]); } } }, [text, selection]); @@ -197,16 +200,26 @@ const MarkdownEditorView = ({ dispatch(toggleAccountsBottomSheet(!isVisibleAccountsBottomSheet)); }; - const _handleUserSearch = async (username) => { let users = []; - if(username){ + if (username) { users = await searchAccount(username, 5); - console.log("result users", users) + console.log('result users', users); } setAutoCompleteUsers(users); - } + }; + + const _onUserSelect = (username) => { + const word = extractWordAtIndex(text, selection.start); + const from = text.indexOf(word, selection.start - word.length); + const _text = text.slice(0, from) + text.slice(from).replace(word, '@' + username + ' '); + + const sel = from + word.length + 2; + const _selection = { start: sel, end: sel }; + _setTextAndSelection({ selection: _selection, text: _text }); + setAutoCompleteUsers([]); + }; // eslint-disable-next-line react-hooks/exhaustive-deps const _changeText = useCallback((input) => { @@ -327,16 +340,6 @@ const MarkdownEditorView = ({ } }; - const _renderLookedUpAccounts = () => { - return { - return {user.name + ' '} - }} - /> - } - const _renderEditorButtons = () => ( @@ -483,9 +486,12 @@ const MarkdownEditorView = ({ behavior={Platform.OS === 'ios' ? 'padding' : 'height'} > {isAndroidOreo() ? _renderEditorWithoutScroll() : _renderEditorWithScroll()} - + user.name)} + onUserSelect={_onUserSelect} + /> {_renderFloatingDraftButton()} - {_renderLookedUpAccounts()} + {!isPreviewActive && _renderEditorButtons()} Date: Thu, 27 Jan 2022 18:55:01 +0500 Subject: [PATCH 15/23] Organised username insert code --- .../view/formats/applyUsername.ts | 11 ++++++++++ .../markdownEditor/view/markdownEditorView.js | 22 ++++++------------- 2 files changed, 18 insertions(+), 15 deletions(-) create mode 100644 src/components/markdownEditor/view/formats/applyUsername.ts diff --git a/src/components/markdownEditor/view/formats/applyUsername.ts b/src/components/markdownEditor/view/formats/applyUsername.ts new file mode 100644 index 000000000..9ff3454b1 --- /dev/null +++ b/src/components/markdownEditor/view/formats/applyUsername.ts @@ -0,0 +1,11 @@ +import { extractWordAtIndex } from '../../../../utils/editor'; +import {replaceBetween } from './utils'; + +export default async ({ text, selection, setTextAndSelection, username}) => { + const _word = extractWordAtIndex(text, selection.start); + const _insertAt = text.indexOf(_word, selection.start - _word.length); + const _text = replaceBetween(text, {start:_insertAt, end:_insertAt + _word.length}, `@${username} `) + const _newPos = _insertAt + username.length + 2; + const _selection = { start: _newPos, end: _newPos }; + setTextAndSelection({ selection: _selection, text: _text }); +}; \ No newline at end of file diff --git a/src/components/markdownEditor/view/markdownEditorView.js b/src/components/markdownEditor/view/markdownEditorView.js index f398da8f0..269cbf16c 100644 --- a/src/components/markdownEditor/view/markdownEditorView.js +++ b/src/components/markdownEditor/view/markdownEditorView.js @@ -49,6 +49,7 @@ import isAndroidOreo from '../../../utils/isAndroidOreo'; import { extractWordAtIndex } from '../../../utils/editor'; import { searchAccount } from '../../../providers/ecency/ecency'; import { UsersBar } from './usersBar'; +import applyUsername from './formats/applyUsername'; const MIN_BODY_INPUT_HEIGHT = 300; @@ -84,7 +85,7 @@ const MarkdownEditorView = ({ const [bodyInputHeight, setBodyInputHeight] = useState(MIN_BODY_INPUT_HEIGHT); const [isSnippetsOpen, setIsSnippetsOpen] = useState(false); const [showDraftLoadButton, setShowDraftLoadButton] = useState(false); - const [autoCompleteUsers, setAutoCompleteUsers] = useState([]); + const [searchedUsers, setSearchedUsers] = useState([]); const inputRef = useRef(null); const galleryRef = useRef(null); @@ -115,7 +116,7 @@ const MarkdownEditorView = ({ if (word.startsWith('@') && word.length > 3) { _handleUserSearch(word.substring(1)); } else { - setAutoCompleteUsers([]); + setSearchedUsers([]); } } }, [text, selection]); @@ -207,18 +208,12 @@ const MarkdownEditorView = ({ console.log('result users', users); } - setAutoCompleteUsers(users); + setSearchedUsers(users); }; const _onUserSelect = (username) => { - const word = extractWordAtIndex(text, selection.start); - const from = text.indexOf(word, selection.start - word.length); - const _text = text.slice(0, from) + text.slice(from).replace(word, '@' + username + ' '); - - const sel = from + word.length + 2; - const _selection = { start: sel, end: sel }; - _setTextAndSelection({ selection: _selection, text: _text }); - setAutoCompleteUsers([]); + applyUsername(text, selection, _setTextAndSelection, username); + setSearchedUsers([]); }; // eslint-disable-next-line react-hooks/exhaustive-deps @@ -486,10 +481,7 @@ const MarkdownEditorView = ({ behavior={Platform.OS === 'ios' ? 'padding' : 'height'} > {isAndroidOreo() ? _renderEditorWithoutScroll() : _renderEditorWithScroll()} - user.name)} - onUserSelect={_onUserSelect} - /> + user.name)} onUserSelect={_onUserSelect} /> {_renderFloatingDraftButton()} {!isPreviewActive && _renderEditorButtons()} From 07574b6103c00ac06573505bbbe4be71b361bcea Mon Sep 17 00:00:00 2001 From: noumantahir Date: Thu, 27 Jan 2022 18:55:29 +0500 Subject: [PATCH 16/23] improved usersBar styling --- .../view/markdownEditorStyles.js | 3 ++- .../markdownEditor/view/usersBar.tsx | 26 ++++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/components/markdownEditor/view/markdownEditorStyles.js b/src/components/markdownEditor/view/markdownEditorStyles.js index db5c32267..ee0ddd5d5 100644 --- a/src/components/markdownEditor/view/markdownEditorStyles.js +++ b/src/components/markdownEditor/view/markdownEditorStyles.js @@ -113,7 +113,8 @@ export default EStyleSheet.create({ searchAccountsContainer: Platform.select({ //absolute positioning makes button hide behind keyboard on ios ios: { - marginBottom: 24, + marginBottom: 12, + paddingTop: 8, }, //on android the appearing of button was causing momentary glitch with ios variant style android: { diff --git a/src/components/markdownEditor/view/usersBar.tsx b/src/components/markdownEditor/view/usersBar.tsx index feb7c56b5..9548c8c1f 100644 --- a/src/components/markdownEditor/view/usersBar.tsx +++ b/src/components/markdownEditor/view/usersBar.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { View, FlatList, Text } from "react-native" -import { TouchableOpacity } from 'react-native-gesture-handler'; +import { View, FlatList, Text, TouchableOpacity } from "react-native" import { UserAvatar } from '../..'; import styles from './markdownEditorStyles'; @@ -11,7 +10,12 @@ interface Props { export const UsersBar = ({usernames, onUserSelect}:Props) => { + if(!usernames || usernames.length === 0){ + return null; + } + const _renderItem = ({item}:{item:string}) => { + const username = item; return ( {onUserSelect(username)}}> @@ -24,13 +28,15 @@ export const UsersBar = ({usernames, onUserSelect}:Props) => { } return ( - - - + + + ) } From 5d1290dbe3795c4696abdb1ec05e113d8fcd3352 Mon Sep 17 00:00:00 2001 From: noumantahir Date: Thu, 27 Jan 2022 19:02:34 +0500 Subject: [PATCH 17/23] resolved wrong method call applyUsername --- src/components/markdownEditor/view/markdownEditorView.js | 7 ++++++- src/components/markdownEditor/view/usersBar.tsx | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/markdownEditor/view/markdownEditorView.js b/src/components/markdownEditor/view/markdownEditorView.js index 269cbf16c..642e37f8f 100644 --- a/src/components/markdownEditor/view/markdownEditorView.js +++ b/src/components/markdownEditor/view/markdownEditorView.js @@ -212,7 +212,12 @@ const MarkdownEditorView = ({ }; const _onUserSelect = (username) => { - applyUsername(text, selection, _setTextAndSelection, username); + applyUsername({ + text, + selection, + setTextAndSelection: _setTextAndSelection, + username, + }); setSearchedUsers([]); }; diff --git a/src/components/markdownEditor/view/usersBar.tsx b/src/components/markdownEditor/view/usersBar.tsx index 9548c8c1f..65a6363e0 100644 --- a/src/components/markdownEditor/view/usersBar.tsx +++ b/src/components/markdownEditor/view/usersBar.tsx @@ -30,7 +30,6 @@ export const UsersBar = ({usernames, onUserSelect}:Props) => { return ( Date: Thu, 27 Jan 2022 19:32:39 +0500 Subject: [PATCH 18/23] refined user bubbble --- src/components/markdownEditor/view/markdownEditorStyles.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/markdownEditor/view/markdownEditorStyles.js b/src/components/markdownEditor/view/markdownEditorStyles.js index ee0ddd5d5..4adfa8c25 100644 --- a/src/components/markdownEditor/view/markdownEditorStyles.js +++ b/src/components/markdownEditor/view/markdownEditorStyles.js @@ -126,14 +126,15 @@ export default EStyleSheet.create({ flexDirection: 'row', alignItems: 'center', marginHorizontal: 4, - paddingHorizontal: 8, - paddingVertical: 8, + paddingHorizontal: 4, + paddingVertical: 4, backgroundColor: '$primaryBlue', borderRadius: 24, }, userBubbleText: { fontSize: 16, color: '$white', - marginHorizontal: 6, + marginLeft: 6, + marginRight: 8, }, }); From 5cb037bc28efbffc091605213b7d53f8d167ec44 Mon Sep 17 00:00:00 2001 From: noumantahir Date: Thu, 27 Jan 2022 19:42:52 +0500 Subject: [PATCH 19/23] cleaned markdownEditor by moving username search to separate component completely --- .../markdownEditor/view/markdownEditorView.js | 32 +------- .../view/usernameAutofillBar.tsx | 78 +++++++++++++++++++ .../markdownEditor/view/usersBar.tsx | 41 ---------- 3 files changed, 81 insertions(+), 70 deletions(-) create mode 100644 src/components/markdownEditor/view/usernameAutofillBar.tsx delete mode 100644 src/components/markdownEditor/view/usersBar.tsx diff --git a/src/components/markdownEditor/view/markdownEditorView.js b/src/components/markdownEditor/view/markdownEditorView.js index 642e37f8f..78fa5e16c 100644 --- a/src/components/markdownEditor/view/markdownEditorView.js +++ b/src/components/markdownEditor/view/markdownEditorView.js @@ -46,9 +46,7 @@ import styles from './markdownEditorStyles'; import applySnippet from './formats/applySnippet'; import { MainButton } from '../../mainButton'; import isAndroidOreo from '../../../utils/isAndroidOreo'; -import { extractWordAtIndex } from '../../../utils/editor'; -import { searchAccount } from '../../../providers/ecency/ecency'; -import { UsersBar } from './usersBar'; +import { UsernameAutofillBar } from './usernameAutofillBar'; import applyUsername from './formats/applyUsername'; const MIN_BODY_INPUT_HEIGHT = 300; @@ -85,7 +83,6 @@ const MarkdownEditorView = ({ const [bodyInputHeight, setBodyInputHeight] = useState(MIN_BODY_INPUT_HEIGHT); const [isSnippetsOpen, setIsSnippetsOpen] = useState(false); const [showDraftLoadButton, setShowDraftLoadButton] = useState(false); - const [searchedUsers, setSearchedUsers] = useState([]); const inputRef = useRef(null); const galleryRef = useRef(null); @@ -109,18 +106,6 @@ const MarkdownEditorView = ({ } }, [onLoadDraftPress]); - useEffect(() => { - if (selection.start === selection.end && text) { - const word = extractWordAtIndex(text, selection.start); - console.log('selection word is: ', word); - if (word.startsWith('@') && word.length > 3) { - _handleUserSearch(word.substring(1)); - } else { - setSearchedUsers([]); - } - } - }, [text, selection]); - useEffect(() => { if (text === '' && draftBody !== '') { _setTextAndSelection({ selection: { start: 0, end: 0 }, text: draftBody }); @@ -201,24 +186,13 @@ const MarkdownEditorView = ({ dispatch(toggleAccountsBottomSheet(!isVisibleAccountsBottomSheet)); }; - const _handleUserSearch = async (username) => { - let users = []; - if (username) { - users = await searchAccount(username, 5); - console.log('result users', users); - } - - setSearchedUsers(users); - }; - - const _onUserSelect = (username) => { + const _onApplyUsername = (username) => { applyUsername({ text, selection, setTextAndSelection: _setTextAndSelection, username, }); - setSearchedUsers([]); }; // eslint-disable-next-line react-hooks/exhaustive-deps @@ -486,7 +460,7 @@ const MarkdownEditorView = ({ behavior={Platform.OS === 'ios' ? 'padding' : 'height'} > {isAndroidOreo() ? _renderEditorWithoutScroll() : _renderEditorWithScroll()} - user.name)} onUserSelect={_onUserSelect} /> + {_renderFloatingDraftButton()} {!isPreviewActive && _renderEditorButtons()} diff --git a/src/components/markdownEditor/view/usernameAutofillBar.tsx b/src/components/markdownEditor/view/usernameAutofillBar.tsx new file mode 100644 index 000000000..1c5f4bf28 --- /dev/null +++ b/src/components/markdownEditor/view/usernameAutofillBar.tsx @@ -0,0 +1,78 @@ +import React, {useState, useEffect} from 'react'; +import { View, FlatList, Text, TouchableOpacity } from "react-native" +import { UserAvatar } from '../..'; +import { searchAccount } from '../../../providers/ecency/ecency'; +import { extractWordAtIndex } from '../../../utils/editor'; +import styles from './markdownEditorStyles'; + +interface Props { + text:string, + selection:{ + start:number, + end:number + } + onApplyUsername:(username:string)=>void; +} + +export const UsernameAutofillBar = ({text, selection, onApplyUsername}:Props) => { + + const [searchedUsers, setSearchedUsers] = useState([]) + + useEffect(() => { + if (selection.start === selection.end && text) { + const word = extractWordAtIndex(text, selection.start); + console.log('selection word is: ', word); + if (word.startsWith('@') && word.length > 3) { + _handleUserSearch(word.substring(1)); + } else { + setSearchedUsers([]); + } + } + }, [text, selection]) + + + const _handleUserSearch = async (username) => { + let users = []; + if (username) { + users = await searchAccount(username, 5); + console.log('result users', users); + } + setSearchedUsers(users); + }; + + const _onUserSelect = (username) => { + onApplyUsername(username) + setSearchedUsers([]); + }; + + if(!searchedUsers || searchedUsers.length === 0){ + return null; + } + + const _renderItem = ({item}:{item:string}) => { + + const username = item; + return ( + {_onUserSelect(username)}}> + + + {username} + + + ) + } + + const usernames = searchedUsers.map(user=>user.name) + + return ( + + + + ) + } diff --git a/src/components/markdownEditor/view/usersBar.tsx b/src/components/markdownEditor/view/usersBar.tsx deleted file mode 100644 index 65a6363e0..000000000 --- a/src/components/markdownEditor/view/usersBar.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; -import { View, FlatList, Text, TouchableOpacity } from "react-native" -import { UserAvatar } from '../..'; -import styles from './markdownEditorStyles'; - -interface Props { - usernames:Array; - onUserSelect:(username:string)=>void; -} - -export const UsersBar = ({usernames, onUserSelect}:Props) => { - - if(!usernames || usernames.length === 0){ - return null; - } - - const _renderItem = ({item}:{item:string}) => { - - const username = item; - return ( - {onUserSelect(username)}}> - - - {username} - - - ) - } - - return ( - - - - ) - } From ac462d619d8b0f6e6f8c1ef53c3797a84ac74aa0 Mon Sep 17 00:00:00 2001 From: noumantahir Date: Thu, 27 Jan 2022 19:55:31 +0500 Subject: [PATCH 20/23] swapped search method with dhive lookupAccounts method --- .../markdownEditor/view/usernameAutofillBar.tsx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/components/markdownEditor/view/usernameAutofillBar.tsx b/src/components/markdownEditor/view/usernameAutofillBar.tsx index 1c5f4bf28..30c1660b7 100644 --- a/src/components/markdownEditor/view/usernameAutofillBar.tsx +++ b/src/components/markdownEditor/view/usernameAutofillBar.tsx @@ -1,9 +1,10 @@ import React, {useState, useEffect} from 'react'; import { View, FlatList, Text, TouchableOpacity } from "react-native" import { UserAvatar } from '../..'; -import { searchAccount } from '../../../providers/ecency/ecency'; +import { lookupAccounts } from '../../../providers/hive/dhive'; import { extractWordAtIndex } from '../../../utils/editor'; import styles from './markdownEditorStyles'; +import {debounce} from 'lodash'; interface Props { text:string, @@ -31,14 +32,17 @@ export const UsernameAutofillBar = ({text, selection, onApplyUsername}:Props) => }, [text, selection]) - const _handleUserSearch = async (username) => { + + const _handleUserSearch = debounce(async (username) => { let users = []; if (username) { - users = await searchAccount(username, 5); + users = await lookupAccounts(username); console.log('result users', users); } setSearchedUsers(users); - }; + }, 500); + + const _onUserSelect = (username) => { onApplyUsername(username) @@ -62,16 +66,15 @@ export const UsernameAutofillBar = ({text, selection, onApplyUsername}:Props) => ) } - const usernames = searchedUsers.map(user=>user.name) - return ( `searched-user-${item}`} /> ) From 65b6634f74625e2e963aba38881cfcddb16ed9b9 Mon Sep 17 00:00:00 2001 From: noumantahir Date: Thu, 27 Jan 2022 20:27:37 +0500 Subject: [PATCH 21/23] improved show hide behaviour --- .../markdownEditor/view/usernameAutofillBar.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/markdownEditor/view/usernameAutofillBar.tsx b/src/components/markdownEditor/view/usernameAutofillBar.tsx index 30c1660b7..cf2c1f4dd 100644 --- a/src/components/markdownEditor/view/usernameAutofillBar.tsx +++ b/src/components/markdownEditor/view/usernameAutofillBar.tsx @@ -18,6 +18,7 @@ interface Props { export const UsernameAutofillBar = ({text, selection, onApplyUsername}:Props) => { const [searchedUsers, setSearchedUsers] = useState([]) + const [query, setQuery] = useState(''); useEffect(() => { if (selection.start === selection.end && text) { @@ -27,6 +28,7 @@ export const UsernameAutofillBar = ({text, selection, onApplyUsername}:Props) => _handleUserSearch(word.substring(1)); } else { setSearchedUsers([]); + setQuery('') } } }, [text, selection]) @@ -34,22 +36,27 @@ export const UsernameAutofillBar = ({text, selection, onApplyUsername}:Props) => const _handleUserSearch = debounce(async (username) => { + if(query !== username){ let users = []; if (username) { + setQuery(username) users = await lookupAccounts(username); - console.log('result users', users); + console.log('result users for', username, users); } setSearchedUsers(users); + } + }, 500); - + const _onUserSelect = (username) => { onApplyUsername(username) setSearchedUsers([]); + setQuery('') }; - if(!searchedUsers || searchedUsers.length === 0){ + if(!searchedUsers || searchedUsers.length === 0 || query === ''){ return null; } From 14b56ac576303ce6b6ee0559aa4b3d3a250da4d4 Mon Sep 17 00:00:00 2001 From: feruz Date: Thu, 27 Jan 2022 21:16:06 +0200 Subject: [PATCH 22/23] bump version --- android/app/build.gradle | 2 +- ios/Ecency-tvOS/Info.plist | 4 ++-- ios/Ecency-tvOSTests/Info.plist | 4 ++-- ios/Ecency.xcodeproj/project.pbxproj | 4 ++-- ios/Ecency/Info.plist | 2 +- ios/EcencyTests/Info.plist | 4 ++-- ios/eshare/Info.plist | 4 ++-- package.json | 4 ++-- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index af230d579..501cbad02 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -144,7 +144,7 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode versionMajor * 10000 + versionMinor * 100 + versionPatch - versionName "3.0.25" + versionName "3.0.26" resValue "string", "build_config_package", "app.esteem.mobile.android" multiDexEnabled true // react-native-image-crop-picker diff --git a/ios/Ecency-tvOS/Info.plist b/ios/Ecency-tvOS/Info.plist index 657cc0ea6..06f4cd14d 100644 --- a/ios/Ecency-tvOS/Info.plist +++ b/ios/Ecency-tvOS/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 3.0.25 + 3.0.26 CFBundleSignature ???? CFBundleVersion - 2804 + 2805 LSRequiresIPhoneOS NSAppTransportSecurity diff --git a/ios/Ecency-tvOSTests/Info.plist b/ios/Ecency-tvOSTests/Info.plist index 7eff350a0..ae8a18efd 100644 --- a/ios/Ecency-tvOSTests/Info.plist +++ b/ios/Ecency-tvOSTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 3.0.25 + 3.0.26 CFBundleSignature ???? CFBundleVersion - 2804 + 2805 diff --git a/ios/Ecency.xcodeproj/project.pbxproj b/ios/Ecency.xcodeproj/project.pbxproj index 06168e721..c5d32ac9b 100644 --- a/ios/Ecency.xcodeproj/project.pbxproj +++ b/ios/Ecency.xcodeproj/project.pbxproj @@ -1129,7 +1129,7 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2804; + CURRENT_PROJECT_VERSION = 2805; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = 75B6RXTKGT; EXCLUDED_ARCHS = ""; @@ -1208,7 +1208,7 @@ CODE_SIGN_ENTITLEMENTS = Ecency/Ecency.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2804; + CURRENT_PROJECT_VERSION = 2805; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = 75B6RXTKGT; EXCLUDED_ARCHS = ""; diff --git a/ios/Ecency/Info.plist b/ios/Ecency/Info.plist index 24165baf0..6296cf446 100644 --- a/ios/Ecency/Info.plist +++ b/ios/Ecency/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 3.0.25 + 3.0.26 CFBundleSignature ???? CFBundleURLTypes diff --git a/ios/EcencyTests/Info.plist b/ios/EcencyTests/Info.plist index f275b8316..6c797b853 100644 --- a/ios/EcencyTests/Info.plist +++ b/ios/EcencyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 3.0.25 + 3.0.26 CFBundleSignature ???? CFBundleVersion - 2804 + 2805 diff --git a/ios/eshare/Info.plist b/ios/eshare/Info.plist index 026af48ff..499823f0f 100644 --- a/ios/eshare/Info.plist +++ b/ios/eshare/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 3.0.25 + 3.0.26 CFBundleVersion - 2804 + 2805 NSExtension NSExtensionAttributes diff --git a/package.json b/package.json index 8ebc9f0ed..0233d7dd4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ecency", - "version": "3.0.25", + "version": "3.0.26", "displayName": "Ecency", "private": true, "rnpm": { @@ -18,7 +18,7 @@ "test": "node node_modules/jest/bin/jest.js --watch", "lint": "eslint src/", "lint:fix": "eslint src/ --fix", - "format": "prettier --write 'src/**/*.{js,jsx}' && yarn lint:fix --fix", + "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx}' && yarn lint:fix --fix", "lint-staged": "lint-staged", "clear": "watchman watch-del-all && rm -rf $TMPDIR/react-native-packager-cache-* && rm -rf $TMPDIR/metro-bundler-cache-* && rm -rf node_modules/ && yarn && yarn start -- --reset-cache", "bump-patch": "npm version patch --no-git-tag-version", From ef521f5210b3d48cc71a66012c8dd715b83b3d98 Mon Sep 17 00:00:00 2001 From: noumantahir Date: Fri, 28 Jan 2022 20:11:48 +0500 Subject: [PATCH 23/23] reduced debounce interval to 200 ms --- src/components/markdownEditor/view/usernameAutofillBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/markdownEditor/view/usernameAutofillBar.tsx b/src/components/markdownEditor/view/usernameAutofillBar.tsx index cf2c1f4dd..b2e83227b 100644 --- a/src/components/markdownEditor/view/usernameAutofillBar.tsx +++ b/src/components/markdownEditor/view/usernameAutofillBar.tsx @@ -46,7 +46,7 @@ export const UsernameAutofillBar = ({text, selection, onApplyUsername}:Props) => setSearchedUsers(users); } - }, 500); + }, 200);