UNPKG

stream-chat-react-native-core

Version:

The official React Native and Expo components for Stream Chat, a service for building chat applications

352 lines (349 loc) 19.4 kB
Object.defineProperty(exports, "__esModule", { value: true }); exports.useImageGalleryGestures = exports.clamp = exports.IsSwiping = exports.HasPinched = void 0; var _react = require("react"); var _reactNative = require("react-native"); var _reactNativeGestureHandler = require("react-native-gesture-handler"); var _reactNativeReanimated = require("react-native-reanimated"); var _ImageGalleryContext = require("../../../contexts/imageGalleryContext/ImageGalleryContext"); var _OverlayContext = require("../../../contexts/overlayContext/OverlayContext"); var _native = require("../../../native"); var HasPinched = exports.HasPinched = function (HasPinched) { HasPinched[HasPinched["FALSE"] = 0] = "FALSE"; HasPinched[HasPinched["TRUE"] = 1] = "TRUE"; return HasPinched; }({}); var IsSwiping = exports.IsSwiping = function (IsSwiping) { IsSwiping[IsSwiping["UNDETERMINED"] = 0] = "UNDETERMINED"; IsSwiping[IsSwiping["TRUE"] = 1] = "TRUE"; IsSwiping[IsSwiping["FALSE"] = 2] = "FALSE"; return IsSwiping; }({}); var MARGIN = 32; var useImageGalleryGestures = ({ currentImageHeight, halfScreenHeight, halfScreenWidth, headerFooterVisible, offsetScale, overlayOpacity, scale, screenHeight, screenWidth, translateX, translateY, translationX }) => { var _useImageGalleryConte = (0, _ImageGalleryContext.useImageGalleryContext)(), imageGalleryStateStore = _useImageGalleryConte.imageGalleryStateStore; var currentIndexShared = imageGalleryStateStore.currentIndexShared; var doubleTapRef = (0, _react.useRef)(undefined); var panRef = (0, _react.useRef)(undefined); var pinchRef = (0, _react.useRef)(undefined); var singleTapRef = (0, _react.useRef)(undefined); var _useOverlayContext = (0, _OverlayContext.useOverlayContext)(), overlay = _useOverlayContext.overlay, setOverlay = _useOverlayContext.setOverlay; var isAndroid = _reactNative.Platform.OS === 'android'; var hasHitBottomScale = (0, _reactNativeReanimated.useSharedValue)(1); var hasHitTopScale = (0, _reactNativeReanimated.useSharedValue)(0); var originX = (0, _reactNativeReanimated.useSharedValue)(0); var originY = (0, _reactNativeReanimated.useSharedValue)(0); var oldFocalX = (0, _reactNativeReanimated.useSharedValue)(0); var oldFocalY = (0, _reactNativeReanimated.useSharedValue)(0); var focalX = (0, _reactNativeReanimated.useSharedValue)(0); var focalY = (0, _reactNativeReanimated.useSharedValue)(0); var offsetX = (0, _reactNativeReanimated.useSharedValue)(0); var offsetY = (0, _reactNativeReanimated.useSharedValue)(0); var focalOffsetX = (0, _reactNativeReanimated.useSharedValue)(0); var focalOffsetY = (0, _reactNativeReanimated.useSharedValue)(0); var adjustedFocalX = (0, _reactNativeReanimated.useSharedValue)(0); var adjustedFocalY = (0, _reactNativeReanimated.useSharedValue)(0); var tapX = (0, _reactNativeReanimated.useSharedValue)(0); var tapY = (0, _reactNativeReanimated.useSharedValue)(0); var numberOfPinchFingers = (0, _reactNativeReanimated.useSharedValue)(0); var isSwiping = (0, _reactNativeReanimated.useSharedValue)(0); var isPinch = (0, _reactNativeReanimated.useSharedValue)(false); var hasPinched = (0, _reactNativeReanimated.useSharedValue)(0); var resetTouchValues = () => { 'worklet'; focalX.value = 0; focalY.value = 0; oldFocalX.value = 0; oldFocalY.value = 0; originX.value = 0; originY.value = 0; focalOffsetX.value = 0; focalOffsetY.value = 0; numberOfPinchFingers.value = 0; isPinch.value = false; isSwiping.value = IsSwiping.UNDETERMINED; }; var resetMovementValues = () => { 'worklet'; translateX.value = 0; translateY.value = 0; scale.value = 1; offsetScale.value = 1; }; var assetsLength = imageGalleryStateStore.assets.length; var clearImageGallery = () => { (0, _reactNativeReanimated.runOnJS)(setOverlay)('none'); }; var moveToNextImage = () => { var currentIndex = imageGalleryStateStore.state.getLatestValue().currentIndex; imageGalleryStateStore.currentIndex = currentIndex + 1; }; var moveToPreviousImage = () => { var currentIndex = imageGalleryStateStore.state.getLatestValue().currentIndex; imageGalleryStateStore.currentIndex = currentIndex - 1; }; var pan = _reactNativeGestureHandler.Gesture.Pan().enabled(overlay === 'gallery').maxPointers(isAndroid ? 0 : 1).minDistance(10).onStart(() => { if (!isPinch.value) { (0, _reactNativeReanimated.cancelAnimation)(translateX); (0, _reactNativeReanimated.cancelAnimation)(translateY); (0, _reactNativeReanimated.cancelAnimation)(scale); offsetX.value = translateX.value; offsetY.value = translateY.value; } hasPinched.value = HasPinched.FALSE; }).onChange(event => { if (event.numberOfPointers === 1 && !isPinch.value) { if (isAndroid && hasPinched.value === HasPinched.TRUE) { hasPinched.value = HasPinched.FALSE; isSwiping.value = IsSwiping.FALSE; offsetX.value = translateX.value + event.translationX; offsetY.value = translateY.value - event.translationY; } if (isSwiping.value === IsSwiping.UNDETERMINED) { var maxXYRatio = 0.25; if (Math.abs(event.translationX / event.translationY) > maxXYRatio && (Math.abs(-halfScreenWidth * (scale.value - 1) - offsetX.value) < 3 || Math.abs(halfScreenWidth * (scale.value - 1) - offsetX.value) < 3)) { isSwiping.value = IsSwiping.TRUE; } if (Math.abs(event.translationY) > 25) { isSwiping.value = IsSwiping.FALSE; } } var localEvtScale = scale.value / offsetScale.value; translateX.value = scale.value !== offsetScale.value ? offsetX.value * localEvtScale + event.translationX : offsetX.value + event.translationX; translateY.value = isSwiping.value !== IsSwiping.TRUE ? scale.value !== offsetScale.value ? offsetY.value * localEvtScale + event.translationY : offsetY.value + event.translationY : translateY.value; var imageHeight = currentImageHeight.value; scale.value = imageHeight * offsetScale.value < screenHeight && translateY.value > 0 ? offsetScale.value * (1 - 1 / 3 * (translateY.value / screenHeight)) : imageHeight * offsetScale.value > screenHeight && translateY.value > imageHeight / 2 * offsetScale.value - halfScreenHeight ? offsetScale.value * (1 - 1 / 3 * ((translateY.value - (imageHeight / 2 * offsetScale.value - halfScreenHeight)) / screenHeight)) : scale.value; overlayOpacity.value = localEvtScale; } }).onEnd(event => { if (!isPinch.value && event.numberOfPointers < 2) { var finalXPosition = event.translationX - event.velocityX * 0.3; var finalYPosition = event.translationY + event.velocityY * 0.1; var currentIndex = currentIndexShared.value; if (currentIndex < assetsLength - 1 && Math.abs(halfScreenWidth * (scale.value - 1) + offsetX.value) < 3 && translateX.value < 0 && finalXPosition > halfScreenWidth && isSwiping.value === IsSwiping.TRUE) { (0, _reactNativeReanimated.cancelAnimation)(translationX); translationX.value = (0, _reactNativeReanimated.withTiming)(-(screenWidth + MARGIN) * (currentIndex + 1), { duration: 200, easing: _reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.ease) }, () => { resetMovementValues(); (0, _reactNativeReanimated.runOnJS)(moveToNextImage)(); }); } else if (currentIndex > 0 && Math.abs(-halfScreenWidth * (scale.value - 1) + offsetX.value) < 3 && translateX.value > 0 && finalXPosition < -halfScreenWidth && isSwiping.value === IsSwiping.TRUE) { (0, _reactNativeReanimated.cancelAnimation)(translationX); translationX.value = (0, _reactNativeReanimated.withTiming)(-(screenWidth + MARGIN) * (currentIndex - 1), { duration: 200, easing: _reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.ease) }, () => { resetMovementValues(); (0, _reactNativeReanimated.runOnJS)(moveToPreviousImage)(); }); } translateX.value = scale.value < 1 ? (0, _reactNativeReanimated.withTiming)(0) : translateX.value > halfScreenWidth * (scale.value - 1) ? (0, _reactNativeReanimated.withTiming)(halfScreenWidth * (scale.value - 1), { duration: 200 }) : translateX.value < -halfScreenWidth * (scale.value - 1) ? (0, _reactNativeReanimated.withTiming)(-halfScreenWidth * (scale.value - 1), { duration: 200 }) : (0, _reactNativeReanimated.withDecay)({ clamp: [-halfScreenWidth * (scale.value - 1), halfScreenWidth * (scale.value - 1)], deceleration: 0.99, velocity: -event.velocityX }); var imageHeight = currentImageHeight.value; translateY.value = imageHeight * scale.value < screenHeight ? (0, _reactNativeReanimated.withTiming)(0, { reduceMotion: _reactNativeReanimated.ReduceMotion.Never }) : translateY.value > imageHeight / 2 * scale.value - halfScreenHeight ? (0, _reactNativeReanimated.withTiming)(imageHeight / 2 * scale.value - halfScreenHeight, { reduceMotion: _reactNativeReanimated.ReduceMotion.Never }) : translateY.value < -imageHeight / 2 * scale.value + halfScreenHeight ? (0, _reactNativeReanimated.withTiming)(-imageHeight / 2 * scale.value + halfScreenHeight) : (0, _reactNativeReanimated.withDecay)({ clamp: [-imageHeight / 2 * scale.value + halfScreenHeight, imageHeight / 2 * scale.value - halfScreenHeight], deceleration: 0.99, velocity: event.velocityY }); resetTouchValues(); scale.value = scale.value !== offsetScale.value ? (0, _reactNativeReanimated.withTiming)(offsetScale.value) : offsetScale.value; if (finalYPosition > halfScreenHeight && offsetY.value + 8 >= imageHeight / 2 * scale.value - halfScreenHeight && isSwiping.value !== IsSwiping.TRUE && translateY.value !== 0 && !(Math.abs(halfScreenWidth * (scale.value - 1) + offsetX.value) < 3 && translateX.value < 0 && finalXPosition < -halfScreenWidth) && !(Math.abs(-halfScreenWidth * (scale.value - 1) + offsetX.value) < 3 && translateX.value > 0 && finalXPosition > halfScreenWidth)) { (0, _reactNativeReanimated.cancelAnimation)(translateX); (0, _reactNativeReanimated.cancelAnimation)(translateY); (0, _reactNativeReanimated.cancelAnimation)(scale); overlayOpacity.value = (0, _reactNativeReanimated.withTiming)(0, { duration: 200, easing: _reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.ease) }, () => { (0, _reactNativeReanimated.runOnJS)(clearImageGallery)(); }); scale.value = (0, _reactNativeReanimated.withTiming)(0.6, { duration: 200, easing: _reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.ease) }); translateY.value = event.velocityY > 1000 ? (0, _reactNativeReanimated.withDecay)({ velocity: event.velocityY }) : (0, _reactNativeReanimated.withTiming)(halfScreenHeight + imageHeight / 2 * scale.value, { duration: 200, easing: _reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.ease) }); translateX.value = (0, _reactNativeReanimated.withDecay)({ velocity: -event.velocityX }); } } }).simultaneousWithExternalGesture(pinchRef).withRef(panRef); var triggerHaptic = _native.NativeHandlers.triggerHaptic; var pinch = _reactNativeGestureHandler.Gesture.Pinch().onStart(event => { if (!isAndroid) { (0, _reactNativeReanimated.cancelAnimation)(translateX); (0, _reactNativeReanimated.cancelAnimation)(translateY); (0, _reactNativeReanimated.cancelAnimation)(scale); isPinch.value = true; isSwiping.value = IsSwiping.UNDETERMINED; numberOfPinchFingers.value = event.numberOfPointers; offsetX.value = translateX.value; offsetY.value = translateY.value; adjustedFocalX.value = event.focalX - (halfScreenWidth - offsetX.value); adjustedFocalY.value = event.focalY - (halfScreenHeight + offsetY.value); originX.value = adjustedFocalX.value; originY.value = adjustedFocalY.value; offsetScale.value = scale.value; } hasPinched.value = HasPinched.FALSE; }).onChange(event => { if (!isPinch.value && isAndroid) { hasPinched.value = HasPinched.TRUE; (0, _reactNativeReanimated.cancelAnimation)(translateX); (0, _reactNativeReanimated.cancelAnimation)(translateY); (0, _reactNativeReanimated.cancelAnimation)(scale); isSwiping.value = IsSwiping.UNDETERMINED; numberOfPinchFingers.value = event.numberOfPointers; offsetX.value = translateX.value; offsetY.value = translateY.value; adjustedFocalX.value = event.focalX - (halfScreenWidth - offsetX.value); adjustedFocalY.value = event.focalY - (halfScreenHeight + offsetY.value); originX.value = adjustedFocalX.value; originY.value = adjustedFocalY.value; offsetScale.value = scale.value; } isPinch.value = true; scale.value = clamp(offsetScale.value * event.scale, 1, 8); var localEvtScale = scale.value / offsetScale.value; if (scale.value !== 8 && scale.value !== 1) { hasHitTopScale.value = 0; hasHitBottomScale.value = 0; } else if (scale.value === 8 && hasHitTopScale.value === 0) { hasHitTopScale.value = 1; (0, _reactNativeReanimated.runOnJS)(triggerHaptic)('impactLight'); } else if (scale.value === 1 && hasHitBottomScale.value === 0) { hasHitBottomScale.value = 1; (0, _reactNativeReanimated.runOnJS)(triggerHaptic)('impactLight'); } adjustedFocalX.value = event.focalX - (halfScreenWidth - offsetX.value); adjustedFocalY.value = event.focalY - (halfScreenHeight + offsetY.value); if (numberOfPinchFingers.value !== event.numberOfPointers) { numberOfPinchFingers.value = event.numberOfPointers; if (event.numberOfPointers === 1) { focalOffsetX.value = oldFocalX.value - adjustedFocalX.value; focalOffsetY.value = oldFocalY.value - adjustedFocalY.value; } else if (numberOfPinchFingers.value > 1) { originX.value = originX.value - (oldFocalX.value / localEvtScale - adjustedFocalX.value / localEvtScale); originY.value = originY.value - (oldFocalY.value / localEvtScale - adjustedFocalY.value / localEvtScale); } } if (numberOfPinchFingers.value === 1) { oldFocalX.value = adjustedFocalX.value + focalOffsetX.value; oldFocalY.value = adjustedFocalY.value + focalOffsetY.value; translateX.value = offsetX.value - oldFocalX.value + localEvtScale * originX.value; translateY.value = offsetY.value + oldFocalY.value - localEvtScale * originY.value; } else if (numberOfPinchFingers.value > 1) { oldFocalX.value = adjustedFocalX.value; oldFocalY.value = adjustedFocalY.value; translateX.value = offsetX.value - adjustedFocalX.value + localEvtScale * originX.value; translateY.value = offsetY.value + adjustedFocalY.value - localEvtScale * originY.value; } }).onEnd(() => { if (isPinch.value) { translateX.value = scale.value < 1 ? (0, _reactNativeReanimated.withTiming)(0) : translateX.value > halfScreenWidth * (scale.value - 1) ? (0, _reactNativeReanimated.withTiming)(halfScreenWidth * (scale.value - 1)) : translateX.value < -halfScreenWidth * (scale.value - 1) ? (0, _reactNativeReanimated.withTiming)(-halfScreenWidth * (scale.value - 1)) : translateX.value; var imageHeight = currentImageHeight.value; translateY.value = imageHeight * scale.value < screenHeight ? (0, _reactNativeReanimated.withTiming)(0) : translateY.value > imageHeight / 2 * scale.value - screenHeight / 2 ? (0, _reactNativeReanimated.withTiming)(imageHeight / 2 * scale.value - screenHeight / 2) : translateY.value < -imageHeight / 2 * scale.value + screenHeight / 2 ? (0, _reactNativeReanimated.withTiming)(-imageHeight / 2 * scale.value + screenHeight / 2) : translateY.value; offsetScale.value = scale.value < 1 ? 1 : scale.value; scale.value = scale.value < 1 ? (0, _reactNativeReanimated.withTiming)(1) : scale.value; resetTouchValues(); } }).withRef(pinchRef).simultaneousWithExternalGesture(panRef); var singleTap = _reactNativeGestureHandler.Gesture.Tap().minPointers(1).numberOfTaps(1).onEnd(() => { (0, _reactNativeReanimated.cancelAnimation)(headerFooterVisible); headerFooterVisible.value = headerFooterVisible.value > 0 ? (0, _reactNativeReanimated.withTiming)(0) : (0, _reactNativeReanimated.withTiming)(1); }).requireExternalGestureToFail(panRef, pinchRef, doubleTapRef).withRef(singleTapRef); var doubleTap = _reactNativeGestureHandler.Gesture.Tap().maxDeltaX(8).maxDeltaY(8).maxDistance(8).minPointers(1).numberOfTaps(2).onStart(event => { tapX.value = event.absoluteX; tapY.value = event.absoluteY; }).onEnd(event => { if (Math.abs(tapX.value - event.absoluteX) < 64 && Math.abs(tapY.value - event.absoluteY) < 64) { if (offsetScale.value === 1 && offsetX.value === 0 && offsetY.value === 0) { offsetScale.value = 2; scale.value = (0, _reactNativeReanimated.withTiming)(2, { duration: 200, easing: _reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.ease) }); translateX.value = (0, _reactNativeReanimated.withTiming)(event.absoluteX - halfScreenWidth, { duration: 200, easing: _reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.ease) }); var imageHeight = currentImageHeight.value; if (imageHeight * 2 > screenHeight) { var translateYTopBottom = event.absoluteY > halfScreenHeight ? -(imageHeight * 2 - screenHeight) / 2 : (imageHeight * 2 - screenHeight) / 2; translateY.value = (0, _reactNativeReanimated.withTiming)(translateYTopBottom, { duration: 200, easing: _reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.ease) }); } } else { offsetScale.value = 1; scale.value = (0, _reactNativeReanimated.withTiming)(1, { duration: 200, easing: _reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.ease) }); offsetX.value = 0; offsetY.value = 0; translateX.value = (0, _reactNativeReanimated.withTiming)(0, { duration: 200, easing: _reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.ease) }); translateY.value = (0, _reactNativeReanimated.withTiming)(0, { duration: 200, easing: _reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.ease) }); if (headerFooterVisible.value !== 0) { (0, _reactNativeReanimated.cancelAnimation)(headerFooterVisible); headerFooterVisible.value = (0, _reactNativeReanimated.withTiming)(0); } } } }).withRef(doubleTapRef); return { doubleTap, pan, pinch, singleTap }; }; exports.useImageGalleryGestures = useImageGalleryGestures; var clamp = (value, lowerBound, upperBound) => { 'worklet'; return Math.min(Math.max(lowerBound, value), upperBound); }; exports.clamp = clamp; //# sourceMappingURL=useImageGalleryGestures.js.map