From 976db45b2d536e9a15865bd46f2264f4877d6b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Fridmansk=C3=BD?= Date: Sun, 28 Jan 2024 15:48:51 +0100 Subject: [PATCH 1/3] fix: additional styles for video and image --- README.md | 1 + src/components/Image/index.tsx | 4 ++-- src/components/List/index.tsx | 3 ++- src/core/dto/componentsDTO.ts | 3 +++ src/core/dto/instagramStoriesDTO.ts | 1 + 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b583f8f..d2996e4 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,7 @@ export default YourComponent; `progressColor` | string | '#00000099' | Background color of progress bar item in inactive state `progressActiveColor` | string | '#FFFFFF' | Background color of progress bar item in active state `modalAnimationDuration` | number | 800 | Duration of modal animation in ms (showing/closing instagram stories) + `mediaContainerStyle` | ViewStyle | | Additional styles for media (video or image) container `onShow` | ( id: string ) => void | | Callback when a story is shown. `onHide` | ( id: string ) => void | | Callback when a story is hidden. `onSwipeUp` | ( userId?: string, storyId?: string ) => void| | Callback when user swipes up. diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index 191d4d9..8681a6b 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -11,7 +11,7 @@ import StoryVideo from './video'; const StoryImage: FC = ( { stories, activeStory, defaultImage, isDefaultVideo, paused, videoProps, isActive, - onImageLayout, onLoad, + mediaContainerStyle, onImageLayout, onLoad, } ) => { const [ data, setData ] = useState<{ uri: string | undefined, isVideo?: boolean }>( @@ -99,7 +99,7 @@ const StoryImage: FC = ( { - + {data.uri && ( data.isVideo ? ( = ( { id, stories, index, x, activeUser, activeStory, progress, seenStories, paused, - onLoad, videoProps, progressColor, progressActiveColor, ...props + onLoad, videoProps, progressColor, progressActiveColor, mediaContainerStyle, ...props } ) => { const imageHeight = useSharedValue( HEIGHT ); @@ -47,6 +47,7 @@ const StoryList: FC = ( { paused={paused} isActive={isActive} videoProps={videoProps} + mediaContainerStyle={mediaContainerStyle} /> void; onShow?: ( id: string ) => void; onHide?: ( id: string ) => void; @@ -73,6 +74,7 @@ export interface StoryImageProps { isDefaultVideo: boolean; paused: SharedValue; videoProps?: any; + mediaContainerStyle?: ViewStyle; isActive: SharedValue; onImageLayout: ( height: number ) => void; onLoad: ( duration?: number ) => void; @@ -123,6 +125,7 @@ export interface StoryListProps extends InstagramStoryProps, StoryHeaderProps { videoProps?: any; progressActiveColor?: string; progressColor?: string; + mediaContainerStyle?: ViewStyle; onLoad: ( duration?: number ) => void; } diff --git a/src/core/dto/instagramStoriesDTO.ts b/src/core/dto/instagramStoriesDTO.ts index 1eb18e0..375ee55 100644 --- a/src/core/dto/instagramStoriesDTO.ts +++ b/src/core/dto/instagramStoriesDTO.ts @@ -37,6 +37,7 @@ export interface InstagramStoriesProps { progressActiveColor?: string; progressColor?: string; modalAnimationDuration?: number; + mediaContainerStyle?: ViewStyle; onShow?: ( id: string ) => void; onHide?: ( id: string ) => void; onSwipeUp?: ( userId?: string, storyId?: string ) => void; From 2f0237d23b03dc8981fe5e01866236ddfe84b2af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Fridmansk=C3=BD?= Date: Sun, 28 Jan 2024 16:32:29 +0100 Subject: [PATCH 2/3] fix: content button goes to next story --- src/components/Header/index.tsx | 7 +- src/components/Modal/index.tsx | 129 ++++++++++++++++++-------------- src/core/dto/componentsDTO.ts | 1 - 3 files changed, 75 insertions(+), 62 deletions(-) diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx index c31e1eb..6a7f674 100644 --- a/src/components/Header/index.tsx +++ b/src/components/Header/index.tsx @@ -8,7 +8,7 @@ import { StoryHeaderProps } from '../../core/dto/componentsDTO'; import Close from '../Icon/close'; const StoryHeader: FC = ( { - imgUrl, name, onClose, avatarSize, textStyle, buttonHandled, closeColor, + imgUrl, name, onClose, avatarSize, textStyle, closeColor, } ) => { const styles = { width: avatarSize, height: avatarSize, borderRadius: avatarSize }; @@ -28,11 +28,6 @@ const StoryHeader: FC = ( { onPress={onClose} hitSlop={16} testID="storyCloseButton" - onPressIn={() => { - - buttonHandled.value = true; - - }} > diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx index d01de0d..2c26b78 100644 --- a/src/components/Modal/index.tsx +++ b/src/components/Modal/index.tsx @@ -1,7 +1,7 @@ import React, { forwardRef, memo, useEffect, useImperativeHandle, useState, } from 'react'; -import { Modal } from 'react-native'; +import { GestureResponderEvent, Modal, Pressable } from 'react-native'; import Animated, { cancelAnimation, interpolate, runOnJS, useAnimatedGestureHandler, useAnimatedReaction, useAnimatedStyle, @@ -27,9 +27,11 @@ const StoryModal = forwardRef( ( { const y = useSharedValue( HEIGHT ); const animation = useSharedValue( 0 ); const currentStory = useSharedValue( stories[0]?.stories[0]?.id ); - const buttonHandled = useSharedValue( false ); const paused = useSharedValue( false ); const durationValue = useSharedValue( duration ); + const pressInformation = useSharedValue<{ x: number, y: number, start: number }>( + { x: 0, y: 0, start: 0 }, + ); const userIndex = useDerivedValue( () => Math.round( x.value / WIDTH ) ); const storyIndex = useDerivedValue( () => stories[userIndex.value]?.stories.findIndex( @@ -227,10 +229,6 @@ const StoryModal = forwardRef( ( { onStart: ( e, ctx: GestureContext ) => { ctx.x = x.value; - ctx.pressedX = e.x; - ctx.pressedAt = Date.now(); - stopAnimation(); - paused.value = true; ctx.userId = userId.value; }, @@ -301,29 +299,49 @@ const StoryModal = forwardRef( ( { } - } else if ( ctx.pressedAt + LONG_PRESS_DURATION < Date.now() ) { - - startAnimation( true ); - - } else if ( ctx.pressedX < WIDTH / 2 ) { - - toPreviousStory(); - - } else if ( !buttonHandled.value ) { - - toNextStory(); - } ctx.moving = false; ctx.vertical = false; - buttonHandled.value = false; - paused.value = false; ctx.userId = undefined; }, } ); + const onPressIn = ( { nativeEvent: { locationX, locationY } }: GestureResponderEvent ) => { + + stopAnimation(); + paused.value = true; + pressInformation.value = { x: locationX, y: locationY, start: Date.now() }; + + }; + + const onPressOut = ( { nativeEvent: { locationX, locationY } }: GestureResponderEvent ) => { + + if ( pressInformation.value.x !== locationX || pressInformation.value.y !== locationY ) { + + return; + + } + + if ( pressInformation.value.start + LONG_PRESS_DURATION < Date.now() ) { + + startAnimation( true ); + + } else if ( ( pressInformation.value.x ) < WIDTH / 2 ) { + + toPreviousStory(); + + } else { + + toNextStory(); + + } + + paused.value = false; + + }; + useImperativeHandle( ref, () => ( { show, hide: onClose, @@ -371,42 +389,43 @@ const StoryModal = forwardRef( ( { return ( - - - - - {stories?.map( ( story, index ) => ( - { - - onLoad?.(); - startAnimation( - undefined, - value !== undefined ? ( videoDuration ?? value ) : duration, - ); - - }} - avatarSize={storyAvatarSize} - textStyle={textStyle} - buttonHandled={buttonHandled} - paused={paused} - videoProps={videoProps} - closeColor={closeIconColor} - key={story.id} - {...props} - /> - ) )} + + + + + + {stories?.map( ( story, index ) => ( + { + + onLoad?.(); + startAnimation( + undefined, + value !== undefined ? ( videoDuration ?? value ) : duration, + ); + + }} + avatarSize={storyAvatarSize} + textStyle={textStyle} + paused={paused} + videoProps={videoProps} + closeColor={closeIconColor} + key={story.id} + {...props} + /> + ) )} + - - + + ); diff --git a/src/core/dto/componentsDTO.ts b/src/core/dto/componentsDTO.ts index 85b0557..648cf35 100644 --- a/src/core/dto/componentsDTO.ts +++ b/src/core/dto/componentsDTO.ts @@ -99,7 +99,6 @@ export interface StoryHeaderProps { name?: string; avatarSize: number; textStyle?: TextStyle; - buttonHandled: SharedValue; closeColor: string; onClose: () => void; } From 3ed0455726db284a43331c0bb80d94534707d3e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Fridmansk=C3=BD?= Date: Sun, 28 Jan 2024 16:52:45 +0100 Subject: [PATCH 3/3] feat: image styles --- README.md | 1 + src/components/Image/index.tsx | 4 ++-- src/components/List/index.tsx | 3 ++- src/components/Modal/index.tsx | 5 ++++- src/core/dto/componentsDTO.ts | 5 ++++- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d2996e4..fde2a24 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ export default YourComponent; `progressActiveColor` | string | '#FFFFFF' | Background color of progress bar item in active state `modalAnimationDuration` | number | 800 | Duration of modal animation in ms (showing/closing instagram stories) `mediaContainerStyle` | ViewStyle | | Additional styles for media (video or image) container + `imageStyles` | ImageStyle | { width: WIDTH, aspectRatio: 0.5626 } | Additional styles image component `onShow` | ( id: string ) => void | | Callback when a story is shown. `onHide` | ( id: string ) => void | | Callback when a story is hidden. `onSwipeUp` | ( userId?: string, storyId?: string ) => void| | Callback when user swipes up. diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index 8681a6b..5491cc4 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -11,7 +11,7 @@ import StoryVideo from './video'; const StoryImage: FC = ( { stories, activeStory, defaultImage, isDefaultVideo, paused, videoProps, isActive, - mediaContainerStyle, onImageLayout, onLoad, + mediaContainerStyle, imageStyles, onImageLayout, onLoad, } ) => { const [ data, setData ] = useState<{ uri: string | undefined, isVideo?: boolean }>( @@ -113,7 +113,7 @@ const StoryImage: FC = ( { ) : ( onImageLayout( Math.min( HEIGHT, e.nativeEvent.layout.height ) )} diff --git a/src/components/List/index.tsx b/src/components/List/index.tsx index 7fb42bd..1f076fa 100644 --- a/src/components/List/index.tsx +++ b/src/components/List/index.tsx @@ -12,7 +12,7 @@ import StoryFooter from '../Footer'; const StoryList: FC = ( { id, stories, index, x, activeUser, activeStory, progress, seenStories, paused, - onLoad, videoProps, progressColor, progressActiveColor, mediaContainerStyle, ...props + onLoad, videoProps, progressColor, progressActiveColor, mediaContainerStyle, imageStyles, ...props } ) => { const imageHeight = useSharedValue( HEIGHT ); @@ -48,6 +48,7 @@ const StoryList: FC = ( { isActive={isActive} videoProps={videoProps} mediaContainerStyle={mediaContainerStyle} + imageStyles={imageStyles} /> ( ( { const onPressOut = ( { nativeEvent: { locationX, locationY } }: GestureResponderEvent ) => { - if ( pressInformation.value.x !== locationX || pressInformation.value.y !== locationY ) { + const diffX = Math.abs( pressInformation.value.x - locationX ); + const diffY = Math.abs( pressInformation.value.y - locationY ); + + if ( diffX >= 10 || diffY >= 10 ) { return; diff --git a/src/core/dto/componentsDTO.ts b/src/core/dto/componentsDTO.ts index 648cf35..1aa8996 100644 --- a/src/core/dto/componentsDTO.ts +++ b/src/core/dto/componentsDTO.ts @@ -1,5 +1,5 @@ import { SharedValue } from 'react-native-reanimated'; -import { TextStyle, ViewStyle } from 'react-native'; +import { ImageStyle, TextStyle, ViewStyle } from 'react-native'; import { InstagramStoryProps } from './instagramStoriesDTO'; import { ProgressStorageProps } from './helpersDTO'; @@ -35,6 +35,7 @@ export interface StoryModalProps { progressColor?: string; modalAnimationDuration?: number; mediaContainerStyle?: ViewStyle; + imageStyles?: ImageStyle; onLoad: () => void; onShow?: ( id: string ) => void; onHide?: ( id: string ) => void; @@ -76,6 +77,7 @@ export interface StoryImageProps { videoProps?: any; mediaContainerStyle?: ViewStyle; isActive: SharedValue; + imageStyles?: ImageStyle; onImageLayout: ( height: number ) => void; onLoad: ( duration?: number ) => void; } @@ -125,6 +127,7 @@ export interface StoryListProps extends InstagramStoryProps, StoryHeaderProps { progressActiveColor?: string; progressColor?: string; mediaContainerStyle?: ViewStyle; + imageStyles?: ImageStyle; onLoad: ( duration?: number ) => void; }