Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: additional styles for video and image #38

Merged
merged 3 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ 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
`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.
Expand Down
7 changes: 1 addition & 6 deletions src/components/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { StoryHeaderProps } from '../../core/dto/componentsDTO';
import Close from '../Icon/close';

const StoryHeader: FC<StoryHeaderProps> = ( {
imgUrl, name, onClose, avatarSize, textStyle, buttonHandled, closeColor,
imgUrl, name, onClose, avatarSize, textStyle, closeColor,
} ) => {

const styles = { width: avatarSize, height: avatarSize, borderRadius: avatarSize };
Expand All @@ -28,11 +28,6 @@ const StoryHeader: FC<StoryHeaderProps> = ( {
onPress={onClose}
hitSlop={16}
testID="storyCloseButton"
onPressIn={() => {

buttonHandled.value = true;

}}
>
<Close color={closeColor} />
</TouchableOpacity>
Expand Down
6 changes: 3 additions & 3 deletions src/components/Image/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import StoryVideo from './video';

const StoryImage: FC<StoryImageProps> = ( {
stories, activeStory, defaultImage, isDefaultVideo, paused, videoProps, isActive,
onImageLayout, onLoad,
mediaContainerStyle, imageStyles, onImageLayout, onLoad,
} ) => {

const [ data, setData ] = useState<{ uri: string | undefined, isVideo?: boolean }>(
Expand Down Expand Up @@ -99,7 +99,7 @@ const StoryImage: FC<StoryImageProps> = ( {
<View style={ImageStyles.container}>
<Loader loading={loading} color={color} size={50} />
</View>
<View style={ImageStyles.image}>
<View style={[ ImageStyles.image, mediaContainerStyle ]}>
{data.uri && (
data.isVideo ? (
<StoryVideo
Expand All @@ -113,7 +113,7 @@ const StoryImage: FC<StoryImageProps> = ( {
) : (
<Image
source={{ uri: data.uri }}
style={{ width: WIDTH, aspectRatio: 0.5626 }}
style={[ { width: WIDTH, aspectRatio: 0.5626 }, imageStyles ]}
resizeMode="contain"
testID="storyImageComponent"
onLayout={( e ) => onImageLayout( Math.min( HEIGHT, e.nativeEvent.layout.height ) )}
Expand Down
4 changes: 3 additions & 1 deletion src/components/List/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import StoryFooter from '../Footer';

const StoryList: FC<StoryListProps> = ( {
id, stories, index, x, activeUser, activeStory, progress, seenStories, paused,
onLoad, videoProps, progressColor, progressActiveColor, ...props
onLoad, videoProps, progressColor, progressActiveColor, mediaContainerStyle, imageStyles, ...props
} ) => {

const imageHeight = useSharedValue( HEIGHT );
Expand Down Expand Up @@ -47,6 +47,8 @@ const StoryList: FC<StoryListProps> = ( {
paused={paused}
isActive={isActive}
videoProps={videoProps}
mediaContainerStyle={mediaContainerStyle}
imageStyles={imageStyles}
/>
<Progress
active={isActive}
Expand Down
132 changes: 77 additions & 55 deletions src/components/Modal/index.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -27,9 +27,11 @@ const StoryModal = forwardRef<StoryModalPublicMethods, StoryModalProps>( ( {
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(
Expand Down Expand Up @@ -227,10 +229,6 @@ const StoryModal = forwardRef<StoryModalPublicMethods, StoryModalProps>( ( {
onStart: ( e, ctx: GestureContext ) => {

ctx.x = x.value;
ctx.pressedX = e.x;
ctx.pressedAt = Date.now();
stopAnimation();
paused.value = true;
ctx.userId = userId.value;

},
Expand Down Expand Up @@ -301,29 +299,52 @@ const StoryModal = forwardRef<StoryModalPublicMethods, StoryModalProps>( ( {

}

} 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 ) => {

const diffX = Math.abs( pressInformation.value.x - locationX );
const diffY = Math.abs( pressInformation.value.y - locationY );

if ( diffX >= 10 || diffY >= 10 ) {

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,
Expand Down Expand Up @@ -371,42 +392,43 @@ const StoryModal = forwardRef<StoryModalPublicMethods, StoryModalProps>( ( {

return (
<Modal visible={visible} transparent animationType="none" testID="storyRNModal" onRequestClose={onClose}>
<GestureHandler onGestureEvent={onGestureEvent}>
<Animated.View style={ModalStyles.container} testID="storyModal">
<Animated.View style={[ ModalStyles.bgAnimation, backgroundAnimatedStyles ]} />
<Animated.View style={[ ModalStyles.absolute, animatedStyles, containerStyle ]}>
{stories?.map( ( story, index ) => (
<StoryList
{...story}
index={index}
x={x}
activeUser={userId}
activeStory={currentStory}
progress={animation}
seenStories={seenStories}
onClose={onClose}
onLoad={( value ) => {

onLoad?.();
startAnimation(
undefined,
value !== undefined ? ( videoDuration ?? value ) : duration,
);

}}
avatarSize={storyAvatarSize}
textStyle={textStyle}
buttonHandled={buttonHandled}
paused={paused}
videoProps={videoProps}
closeColor={closeIconColor}
key={story.id}
{...props}
/>
) )}
<Pressable onPressIn={onPressIn} onPressOut={onPressOut} style={ModalStyles.container}>
<GestureHandler onGestureEvent={onGestureEvent}>
<Animated.View style={ModalStyles.container} testID="storyModal">
<Animated.View style={[ ModalStyles.bgAnimation, backgroundAnimatedStyles ]} />
<Animated.View style={[ ModalStyles.absolute, animatedStyles, containerStyle ]}>
{stories?.map( ( story, index ) => (
<StoryList
{...story}
index={index}
x={x}
activeUser={userId}
activeStory={currentStory}
progress={animation}
seenStories={seenStories}
onClose={onClose}
onLoad={( value ) => {

onLoad?.();
startAnimation(
undefined,
value !== undefined ? ( videoDuration ?? value ) : duration,
);

}}
avatarSize={storyAvatarSize}
textStyle={textStyle}
paused={paused}
videoProps={videoProps}
closeColor={closeIconColor}
key={story.id}
{...props}
/>
) )}
</Animated.View>
</Animated.View>
</Animated.View>
</GestureHandler>
</GestureHandler>
</Pressable>
</Modal>
);

Expand Down
9 changes: 7 additions & 2 deletions src/core/dto/componentsDTO.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -34,6 +34,8 @@ export interface StoryModalProps {
progressActiveColor?: string;
progressColor?: string;
modalAnimationDuration?: number;
mediaContainerStyle?: ViewStyle;
imageStyles?: ImageStyle;
onLoad: () => void;
onShow?: ( id: string ) => void;
onHide?: ( id: string ) => void;
Expand Down Expand Up @@ -73,7 +75,9 @@ export interface StoryImageProps {
isDefaultVideo: boolean;
paused: SharedValue<boolean>;
videoProps?: any;
mediaContainerStyle?: ViewStyle;
isActive: SharedValue<boolean>;
imageStyles?: ImageStyle;
onImageLayout: ( height: number ) => void;
onLoad: ( duration?: number ) => void;
}
Expand All @@ -97,7 +101,6 @@ export interface StoryHeaderProps {
name?: string;
avatarSize: number;
textStyle?: TextStyle;
buttonHandled: SharedValue<boolean>;
closeColor: string;
onClose: () => void;
}
Expand All @@ -123,6 +126,8 @@ export interface StoryListProps extends InstagramStoryProps, StoryHeaderProps {
videoProps?: any;
progressActiveColor?: string;
progressColor?: string;
mediaContainerStyle?: ViewStyle;
imageStyles?: ImageStyle;
onLoad: ( duration?: number ) => void;
}

Expand Down
1 change: 1 addition & 0 deletions src/core/dto/instagramStoriesDTO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading