diff --git a/android/build.gradle b/android/build.gradle index 2ffe7ae60..41addf6a6 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -63,6 +63,7 @@ allprojects { includeGroup("com.facebook.fbjni") includeGroup("com.henninghall.android") includeGroup("org.matomo.sdk") + includeModule("com.yqritc", "android-scalablevideoview") } } } diff --git a/ios/Podfile.lock b/ios/Podfile.lock index c67e30b0e..6451ba9a7 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -335,6 +335,11 @@ PODS: - React - react-native-version-number (0.3.6): - React + - react-native-video (5.2.0): + - React-Core + - react-native-video/Video (= 5.2.0) + - react-native-video/Video (5.2.0): + - React-Core - react-native-webview (11.17.1): - React-Core - React-RCTActionSheet (0.63.4): @@ -496,6 +501,7 @@ DEPENDENCIES: - react-native-splash-screen (from `../node_modules/react-native-splash-screen`) - react-native-udp (from `../node_modules/react-native-udp`) - react-native-version-number (from `../node_modules/react-native-version-number`) + - react-native-video (from `../node_modules/react-native-video`) - react-native-webview (from `../node_modules/react-native-webview`) - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) @@ -621,6 +627,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-udp" react-native-version-number: :path: "../node_modules/react-native-version-number" + react-native-video: + :path: "../node_modules/react-native-video" react-native-webview: :path: "../node_modules/react-native-webview" React-RCTActionSheet: @@ -736,6 +744,7 @@ SPEC CHECKSUMS: react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865 react-native-udp: ff9d13e523f2b58e6bc5d4d32321ac60671b5dc9 react-native-version-number: b415bbec6a13f2df62bf978e85bc0d699462f37f + react-native-video: a4c2635d0802f983594b7057e1bce8f442f0ad28 react-native-webview: 162b6453d074e0b1c7025242bb7a939b6f72b9e7 React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336 React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b diff --git a/package.json b/package.json index c369b3509..a4ccdef19 100644 --- a/package.json +++ b/package.json @@ -100,9 +100,10 @@ "react-native-level-fs": "^3.0.0", "react-native-linear-gradient": "^2.4.2", "react-native-matomo-sdk": "feruzm/react-native-matomo-sdk", + "react-native-media-controls": "^2.3.0", "react-native-modal": "^11.5.6", - "react-native-modal-popover": "^2.1.0", "react-native-modal-dropdown": "^1.0.2", + "react-native-modal-popover": "^2.1.0", "react-native-modal-translucent": "^5.0.0", "react-native-navigation-bar-color": "^1.0.0", "react-native-os": "^1.0.1", @@ -118,6 +119,7 @@ "react-native-safe-area-context": "^3.1.9", "react-native-screens": "^2.9.0", "react-native-scrollable-tab-view": "ecency/react-native-scrollable-tab-view", + "react-native-slider": "^0.11.0", "react-native-snap-carousel": "^3.8.0", "react-native-splash-screen": "^3.2.0", "react-native-svg": "^12.1.1", @@ -128,6 +130,7 @@ "react-native-vector-icons": "^6.6.0", "react-native-version": "^4.0.0", "react-native-version-number": "^0.3.5", + "react-native-video": "^5.2.0", "react-native-webview": "^11.17.1", "react-native-youtube-iframe": "^2.1.1", "react-navigation": "^4.0.10", diff --git a/src/components/postElements/body/view/commentBodyView.tsx b/src/components/postElements/body/view/commentBodyView.tsx index 730816e4d..5e0bdd7b5 100644 --- a/src/components/postElements/body/view/commentBodyView.tsx +++ b/src/components/postElements/body/view/commentBodyView.tsx @@ -368,9 +368,9 @@ const CommentBody = ({ }} > diff --git a/src/components/postElements/body/view/postBodyView.js b/src/components/postElements/body/view/postBodyView.js index 8979014ad..d760ce633 100644 --- a/src/components/postElements/body/view/postBodyView.js +++ b/src/components/postElements/body/view/postBodyView.js @@ -294,9 +294,9 @@ const PostBody = ({ navigation, body, dispatch, onLoadEnd }) => { }} > diff --git a/src/components/postHtmlRenderer/postHtmlRenderer.tsx b/src/components/postHtmlRenderer/postHtmlRenderer.tsx index ce677a56d..6ecda43fb 100644 --- a/src/components/postHtmlRenderer/postHtmlRenderer.tsx +++ b/src/components/postHtmlRenderer/postHtmlRenderer.tsx @@ -150,9 +150,9 @@ export const PostHtmlRenderer = memo( } else { return ( - - `, - }:{ - 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 @@ -254,9 +241,10 @@ export const PostHtmlRenderer = memo( ) }else{ return ( + ); diff --git a/src/components/videoPlayer/videoPlayerView.tsx b/src/components/videoPlayer/videoPlayerView.tsx index 60bd9fb67..844752d5c 100644 --- a/src/components/videoPlayer/videoPlayerView.tsx +++ b/src/components/videoPlayer/videoPlayerView.tsx @@ -1,39 +1,47 @@ -import React, { useState } from 'react'; +import React, { useState, useRef } from 'react'; 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'; +import Video from 'react-native-video'; +import MediaControls, { PLAYER_STATES } from 'react-native-media-controls'; +import EStyleSheet from 'react-native-extended-stylesheet'; interface VideoPlayerProps { - mode: 'source'|'youtube'|'url'; + mode: 'uri' | 'youtube'; contentWidth?: number; youtubeVideoId?: string; - videoUrl?: string; startTime?: number; - source?: WebViewSource; - + uri?: string; //prop for youtube player - disableAutoplay?:boolean; + disableAutoplay?: boolean; } -const VideoPlayer = ({ - youtubeVideoId, - videoUrl, - startTime, - source, - contentWidth = Dimensions.get('screen').width, - mode, - disableAutoplay - }: VideoPlayerProps) => { - +const VideoPlayer = ({ + youtubeVideoId, + startTime, + uri, + contentWidth = Dimensions.get('screen').width, + mode, + disableAutoplay, +}: VideoPlayerProps) => { const PLAYER_HEIGHT = contentWidth * (9 / 16); + const checkSrcRegex = /(.*?)\.(mp4|webm|ogg)$/gi; + const isExtensionType = mode === 'uri' ? uri.match(checkSrcRegex) : false; + const videoPlayer = useRef(null); + const [currentTime, setCurrentTime] = useState(0); + const [duration, setDuration] = useState(0); + const [isFullScreen, setIsFullScreen] = useState(false); + const [isLoading, setIsLoading] = useState(true); + const [paused, setPaused] = useState(true); + const [playerState, setPlayerState] = useState(PLAYER_STATES.PAUSED); + const [screenType, setScreenType] = useState('contain'); + + // react-native-youtube-iframe handlers const [shouldPlay, setShouldPlay] = useState(false); - const [loading, setLoading] = useState(true); - const _onReady = () => { - setLoading(false); + setIsLoading(false); setShouldPlay(disableAutoplay ? false : true); console.log('ready'); }; @@ -45,13 +53,101 @@ const VideoPlayer = ({ const _onError = () => { console.log('error!'); - setLoading(false); + setIsLoading(false); }; const initialParams: InitialPlayerParams = { start: startTime, }; + // react-native-video player handlers + const onSeek = (seek) => { + videoPlayer.current.seek(seek); + }; + + const onPaused = (playerState) => { + setPaused(!paused); + setPlayerState(playerState); + }; + + const onReplay = () => { + setPlayerState(PLAYER_STATES.PLAYING); + videoPlayer.current.seek(0); + }; + + const onProgress = (data) => { + if (!isLoading && playerState !== PLAYER_STATES.ENDED) { + setCurrentTime(data.currentTime); + } + }; + + const onLoad = (data) => { + setDuration(data.duration); + videoPlayer.current.seek(0); + setIsLoading(false); + }; + + const onLoadStart = () => setIsLoading(true); + + const onEnd = () => setPlayerState(PLAYER_STATES.ENDED); + + const onError = () => alert('Error while playing'); + + const exitFullScreen = () => { + setIsFullScreen(false); + }; + + const enterFullScreen = () => { + setIsFullScreen(true); + }; + + const onFullScreen = () => { + setIsFullScreen(true); + if (screenType == 'contain') setScreenType('cover'); + else setScreenType('contain'); + }; + + const onSeeking = (currentTime) => setCurrentTime(currentTime); + + const _renderVideoplayerWithControls = () => { + return ( + + + ); + }; return ( {mode === 'youtube' && youtubeVideoId && ( @@ -67,29 +163,35 @@ const VideoPlayer = ({ /> )} - {((mode === 'source' && source) || (mode === 'url' && videoUrl)) && ( - - { - setLoading(false); - }} - onLoadStart={() => { - setLoading(true); - }} - source={source || { uri: videoUrl }} - style={{ width: contentWidth, height: PLAYER_HEIGHT}} - startInLoadingState={true} - onShouldStartLoadWithRequest={() => true} - mediaPlaybackRequiresUserAction={true} - allowsInlineMediaPlayback={true} - /> + {mode === 'uri' && uri && ( + + {isExtensionType ? ( + _renderVideoplayerWithControls() + ) : ( + { + setIsLoading(false); + }} + onLoadStart={() => { + setIsLoading(true); + }} + source={{ uri: uri }} + style={[styles.barkBackground, { width: contentWidth, height: PLAYER_HEIGHT }]} + startInLoadingState={true} + onShouldStartLoadWithRequest={() => true} + mediaPlaybackRequiresUserAction={true} + allowsInlineMediaPlayback={true} + /> + )} )} - {loading && } + {isLoading && ( + + )} ); }; @@ -104,9 +206,30 @@ const styles = StyleSheet.create({ position: 'absolute', alignItems: 'center', justifyContent: 'center', - top: 0, + top: 25, bottom: 0, left: 0, right: 0, }, + toolbar: { + marginTop: 30, + backgroundColor: 'white', + padding: 10, + borderRadius: 5, + }, + playerWrapper: { + backgroundColor: 'black', + }, + mediaPlayer: { + position: 'absolute', + top: 0, + left: 0, + bottom: 0, + right: 0, + backgroundColor: 'black', + justifyContent: 'center', + }, + barkBackground: { + backgroundColor: 'black', + }, }); diff --git a/yarn.lock b/yarn.lock index 571048a46..5c8853eb6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3927,6 +3927,11 @@ elliptic@^6.5.2, elliptic@^6.5.3: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +eme-encryption-scheme-polyfill@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/eme-encryption-scheme-polyfill/-/eme-encryption-scheme-polyfill-2.0.3.tgz#2ca6e06480e06cceb5e50efd27943ac46c959878" + integrity sha512-44CNFMsqzHdKHrzWxlS7xZ8KUHn5XutBqpmCuWzNIynmAyFInHrrD3ozv/RvK9ZhgV6QY6Easx8EWAmxteNodg== + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -6543,6 +6548,11 @@ jsx-ast-utils@^2.2.3: array-includes "^3.1.2" object.assign "^4.1.2" +keymirror@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/keymirror/-/keymirror-0.1.1.tgz#918889ea13f8d0a42e7c557250eee713adc95c35" + integrity sha1-kYiJ6hP40KQufFVyUO7nE63JXDU= + kind-of@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" @@ -8624,6 +8634,11 @@ react-native-matomo-sdk@feruzm/react-native-matomo-sdk: version "0.4.1" resolved "https://codeload.github.com/feruzm/react-native-matomo-sdk/tar.gz/392b1cfca771b28005821ef909ffb9a2082156d9" +react-native-media-controls@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/react-native-media-controls/-/react-native-media-controls-2.3.0.tgz#c36e876a14d12982b7c6fb759201ff439117cbd0" + integrity sha512-N10i12ZO+GIXjmdA9hQk/HuBm5u9xWPIOydG/2SvLEZcnY3xg3D8d2IJXRolzSm2jBRgEGSO4rMgRBU6MpdNMg== + react-native-modal-dropdown@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/react-native-modal-dropdown/-/react-native-modal-dropdown-1.0.2.tgz#3e1efae5a5eacc42f44ac96468ea2f1b5bb0d759" @@ -8759,6 +8774,13 @@ react-native-scrollable-tab-view@ecency/react-native-scrollable-tab-view: prop-types "^15.6.0" react-timer-mixin "^0.13.3" +react-native-slider@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/react-native-slider/-/react-native-slider-0.11.0.tgz#b68a0bc43c8422b24cd57947cc5ac2bcdb58fadc" + integrity sha512-jV9K87eu9uWr0uJIyrSpBLnCKvVlOySC2wynq9TFCdV9oGgjt7Niq8Q1A8R8v+5GHsuBw/s8vEj1AAkkUi+u+w== + dependencies: + prop-types "^15.5.6" + react-native-snap-carousel@^3.8.0: version "3.9.1" resolved "https://registry.yarnpkg.com/react-native-snap-carousel/-/react-native-snap-carousel-3.9.1.tgz#6fd9bd8839546c2c6043a41d2035afbc6fe0443e" @@ -8856,6 +8878,15 @@ react-native-version@^4.0.0: resolve-from "^5.0.0" semver "^7.0.0" +react-native-video@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/react-native-video/-/react-native-video-5.2.0.tgz#c3f2c541775f4fda7e0d26d75a6fb59819b13d5e" + integrity sha512-5SK1lxyzrCkZF+WuxUxLR1Pt65E0rsWB1w1GrGxSLdC9zWYBumcmuHl+wPJ7UQvznjaH2Ze7uU1R3arejI7+WQ== + dependencies: + keymirror "^0.1.1" + prop-types "^15.7.2" + shaka-player "^2.5.9" + 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" @@ -9643,6 +9674,13 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +shaka-player@^2.5.9: + version "2.5.23" + resolved "https://registry.yarnpkg.com/shaka-player/-/shaka-player-2.5.23.tgz#db92d1c6cf2314f0180a2cec11b0e2f2560336f5" + integrity sha512-3MC9k0OXJGw8AZ4n/ZNCZS2yDxx+3as5KgH6Tx4Q5TRboTBBCu6dYPI5vp1DxKeyU12MBN1Zcbs7AKzXv2EnCg== + dependencies: + eme-encryption-scheme-polyfill "^2.0.1" + shallow-clone@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571"