PlayerGesture.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. import React, { useState, useEffect } from 'react';
  2. import {
  3. View,
  4. Text,
  5. StyleSheet,
  6. Dimensions,
  7. PanResponder,
  8. ScrollView,
  9. Image,
  10. Platform,
  11. StatusBar
  12. } from 'react-native';
  13. import { Slider, Icon } from 'react-native-elements';
  14. import Animated, { Easing } from 'react-native-reanimated';
  15. import { State, PanGestureHandler } from 'react-native-gesture-handler';
  16. import { getStatusBarHeight } from '../utils/StatusBarHeight';
  17. import C from 'rn-class';
  18. import PlayerControls from '../components/PlayerControls';
  19. import PlayerContents from '../components/PlayerContents';
  20. import { getInset } from 'react-native-safe-area-view';
  21. const { width, height } = Dimensions.get('window');
  22. const statusBarHeight = getStatusBarHeight();
  23. const minHeight = height * 0.1;
  24. const midBound = height - height / 2.5;
  25. const upperBound =
  26. height > 560
  27. ?height * 0.75 - getInset('bottom')
  28. :height * 0.70;
  29. const {
  30. Value,
  31. event,
  32. Extrapolate,
  33. cond,
  34. Clock,
  35. eq,
  36. set,
  37. add,
  38. sub,
  39. multiply,
  40. lessThan,
  41. clockRunning,
  42. startClock,
  43. spring,
  44. stopClock,
  45. interpolate,
  46. timing,
  47. neq
  48. } = Animated;
  49. const shadow = {
  50. alignItems: 'center',
  51. shadowColor: 'black',
  52. shadowOffset: { width: 0, height: 0 },
  53. shadowOpacity: 0.18,
  54. shadowRadius: 2
  55. };
  56. const shadow2 = {
  57. alignItems: 'center',
  58. shadowColor: '#000',
  59. shadowOffset: {
  60. width: 0,
  61. height: 7
  62. },
  63. shadowOpacity: 0.41,
  64. shadowRadius: 9.11
  65. //elevation: 14
  66. };
  67. function runSpring(clock, value, dest) {
  68. const state = {
  69. finished: new Value(0),
  70. velocity: new Value(0),
  71. position: new Value(0),
  72. time: new Value(0)
  73. };
  74. const config = {
  75. damping: 20,
  76. mass: 1,
  77. stiffness: 100,
  78. overshootClamping: false,
  79. restSpeedThreshold: 1,
  80. restDisplacementThreshold: 0.5,
  81. toValue: new Value(0)
  82. };
  83. return [
  84. cond(clockRunning(clock), 0, [
  85. set(state.finished, 0),
  86. set(state.velocity, 0),
  87. set(state.position, value),
  88. set(config.toValue, dest),
  89. startClock(clock)
  90. ]),
  91. spring(clock, state, config),
  92. cond(state.finished, stopClock(clock)),
  93. state.position
  94. ];
  95. }
  96. const Player = props => {
  97. const translationY = new Value(0);
  98. const velocityY = new Value(0);
  99. const offsetY = new Value(0);
  100. const offsetY2 = new Value(0);
  101. const gestureState = new Value(State.UNDETERMINED);
  102. const onGestureEvent = event(
  103. [
  104. {
  105. nativeEvent: {
  106. translationY,
  107. velocityY,
  108. state: gestureState
  109. }
  110. }
  111. ],
  112. { useNativeDriver: true }
  113. );
  114. const clockY = new Clock();
  115. const finalTranslateY = add(translationY, multiply(0.2, velocityY));
  116. const snapPoint = cond(
  117. lessThan(finalTranslateY, sub(offsetY, height / 4)),
  118. 0,
  119. upperBound
  120. );
  121. const ty = cond(
  122. eq(gestureState, State.END),
  123. [
  124. set(
  125. translationY,
  126. runSpring(clockY, add(offsetY, translationY), snapPoint)
  127. ),
  128. set(offsetY, translationY),
  129. translationY
  130. ],
  131. [
  132. cond(eq(gestureState, State.BEGAN), stopClock(clockY)),
  133. add(offsetY, translationY)
  134. ]
  135. );
  136. const translateY = add(ty, offsetY2);
  137. const opacity = interpolate(translateY, {
  138. inputRange: [0, midBound - 100],
  139. outputRange: [1, 0],
  140. extrapolate: Extrapolate.CLAMP
  141. });
  142. const statusBarOpacity = interpolate(translateY, {
  143. inputRange: [0, statusBarHeight],
  144. outputRange: [1, 0],
  145. extrapolateLeft: Extrapolate.CLAMP
  146. });
  147. const playContainerWidth = interpolate(translateY, {
  148. inputRange: [0, midBound],
  149. outputRange: [width, width - 16],
  150. extrapolate: Extrapolate.CLAMP
  151. });
  152. const playerContainerHeight = interpolate(translateY, {
  153. inputRange: [0, midBound],
  154. outputRange: [height, 0],
  155. extrapolate: Extrapolate.CLAMP
  156. });
  157. const videoWidth = interpolate(translateY, {
  158. inputRange: [0, midBound, upperBound],
  159. outputRange: [width, width - 16, width / 4],
  160. extrapolate: Extrapolate.CLAMP
  161. });
  162. const videoHeight = interpolate(translateY, {
  163. inputRange: [0, midBound, upperBound],
  164. outputRange: [width / 1.78, minHeight * 1.3, minHeight],
  165. extrapolate: Extrapolate.CLAMP
  166. });
  167. const playerControlOpaciy = interpolate(translateY, {
  168. inputRange: [midBound, upperBound],
  169. outputRange: [0, 1],
  170. extrapolate: Extrapolate.CLAMP
  171. });
  172. const playerBoderRadius = interpolate(translateY, {
  173. inputRange: [midBound, upperBound],
  174. outputRange: [0, 15],
  175. extrapolate: Extrapolate.CLAMP
  176. });
  177. const mainPlayerContainerHeight = interpolate(translateY, {
  178. inputRange: [0, midBound, upperBound],
  179. outputRange: [height, minHeight * 1.3, minHeight],
  180. extrapolate: Extrapolate.CLAMP
  181. });
  182. useEffect(() => {
  183. return () => {};
  184. }, []);
  185. const slideUp = () => {};
  186. return (
  187. <PanGestureHandler
  188. onHandlerStateChange={onGestureEvent}
  189. activeOffsetY={[-10, 10]}
  190. {...{ onGestureEvent }}
  191. >
  192. <Animated.View
  193. style={{
  194. ...StyleSheet.absoluteFillObject,
  195. flex:0.1,
  196. zIndex: 10,
  197. marginTop: statusBarHeight,
  198. transform: [{ translateY }],
  199. alignItems: 'center',
  200. height: mainPlayerContainerHeight,
  201. }}
  202. >
  203. <Animated.View
  204. style={{
  205. padding: 5,
  206. backgroundColor: 'white',
  207. width: playContainerWidth,
  208. borderRadius: playerBoderRadius
  209. }}
  210. >
  211. <Animated.View
  212. style={[
  213. Platform.OS === 'android'
  214. ? { borderColor: '#eee' }
  215. : { borderColor: 'white' },
  216. {
  217. ...StyleSheet.absoluteFillObject,
  218. borderWidth: 1,
  219. borderRadius: 15,
  220. opacity: playerControlOpaciy,
  221. backgroundColor: 'white'
  222. },
  223. shadow2
  224. ]}
  225. >
  226. <PlayerControls
  227. {...props}
  228. title={props.Pages.subtitle}
  229. slideup={slideUp}
  230. closePlayer={props.closePlayer}
  231. />
  232. </Animated.View>
  233. <Animated.View style={{ width: videoWidth, height: videoHeight }}>
  234. <Image
  235. resizeMode="contain"
  236. style={{ flex: 1, width: null, height: null }}
  237. source={props.Pages.img}
  238. />
  239. </Animated.View>
  240. </Animated.View>
  241. <Animated.View
  242. style={{
  243. backgroundColor: 'white',
  244. width: playContainerWidth,
  245. height: playerContainerHeight
  246. }}
  247. >
  248. <Animated.View style={{ opacity }}>
  249. <PlayerContents {...props} />
  250. </Animated.View>
  251. </Animated.View>
  252. </Animated.View>
  253. </PanGestureHandler>
  254. );
  255. };
  256. export default Player;