Skip to content

Commit

Permalink
Merge branch 'main' into pr/123
Browse files Browse the repository at this point in the history
  • Loading branch information
LukasFridmansky committed Oct 15, 2024
2 parents a4f4c29 + 87a488b commit 3ab6594
Show file tree
Hide file tree
Showing 13 changed files with 231 additions and 62 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

### 1.3.8 (2024-10-12)

### 1.3.7 (2024-10-08)

### 1.3.6 (2024-10-08)

### 1.3.5 (2024-08-10)

### 1.3.4 (2024-07-30)
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ npm install react-native-gesture-handler
npm install @birdwingo/react-native-instagram-stories
```

## Integration with Storage and Video
## Integration with Storage, Flashlist and Video

The component offers an option to save and track the progress of seen stories using `saveProgress`. If you use `saveProgress`, please make sure you have `@react-native-async-storage/async-storage` installed.

If you have installed Flashlist, it will be automatically used for avatars list.

If you use video in your stories, please make sure you have `react-native-video` installed.

## Usage
Expand Down Expand Up @@ -97,7 +99,7 @@ export default YourComponent;
`avatarSeenBorderColors` | string[] | [ '#2A2A2C' ] | An array of string colors representing the border colors of seen story avatars.
`avatarSize` | number | 60 | The size of the story avatars.
`storyAvatarSize` | number | 25 | The size of the avatars shown in the header of each story.
`avatarListContainerStyle` | ScrollViewProps['contentContainerStyle'] | | Additional styles for the avatar scroll list container.
`avatarListContainerStyle` | ScrollViewProps['contentContainerStyle'], FlashListProps | | Additional styles for the avatar scroll list container.
`avatarListContainerProps` | ScrollViewProps | | Props to be passed to the avatar list ScrollView component.
`containerStyle` | ViewStyle | | Additional styles for the story container.
`textStyle` | TextStyle | | Additional styles for text elements.
Expand All @@ -122,7 +124,7 @@ export default YourComponent;
`progressContainerStyle` | ViewStyle | | Additional styles for the story progress container
`hideAvatarList` | boolean | false | A boolean indicating whether to hide avatar scroll list
`hideElementsOnLongPress` | boolean | false | A boolean indicating whether to hide all elements when story is paused by long press
| `hideOverlayOnLongPress` | `boolean` | (Optional) Controls whether the image overlay hides when `hideElementOnLongPress` is set to `true`. If `true`, the overlay will hide along with other elements on long press. If `false`, only the other elements (e.g., header, progress bar) will hide, and the overlay will remain visible. Default is the value of `hideElementOnLongPress`. |
`hideOverlayOnLongPress` | `boolean` | The value of `hideElementOnLongPress` | Controls whether the image overlay hides when `hideElementOnLongPress` is set to `true`. If `true`, the overlay will hide along with other elements on long press. If `false`, only the other elements (e.g., header, progress bar) will hide, and the overlay will remain visible.
`loopingStories` | `'none'` | `'onlyLast'` | `'all'` | `'none'` | A string indicating whether to continue stories after last story was shown. If set to `'none'` modal will be closed after all stories were played, if set to `'onlyLast'` stories will loop on last user only after all stories were played. If set to `'all'` stories will play from beginning after all stories were played.
`statusBarTranslucent` | boolean | false | A property passed to React native Modal component
`footerComponent` | ReactNode | | A custom component, such as a floating element, that can be added to the modal.
Expand All @@ -148,6 +150,7 @@ export default YourComponent;
`goToPreviousStory` | () => void | Goes to previous story item
`goToNextStory` | () => void | Goes to next story item
`getCurrentStory` | () => {userId?: string, storyId?: string} | Returns current userId and storyId
`goToSpecificStory` | ( userId: string, index: number ) => void | Change current playing story to defined index if index not exist then start playing first story
## Types
Expand Down
17 changes: 17 additions & 0 deletions jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,20 @@ jest.mock('./src/components/Image/video', () => {
return <View testID="storyVideo" />;
};
});

jest.mock('@shopify/flash-list', () => {

const React = require('react');
const { ScrollView } = require('react-native');

return {FlashList: ({ data, renderItem, ...props }) => {

return (
<ScrollView {...props}>
{data.map(( item, index ) => renderItem({ item, index }))}
</ScrollView>
)

}};

});
81 changes: 63 additions & 18 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@birdwingo/react-native-instagram-stories",
"version": "1.3.5",
"version": "1.3.8",
"description": "A versatile and captivating React Native component that empowers developers to seamlessly integrate Instagram-style stories into their mobile applications, fostering an engaging and interactive user experience.",
"main": "src/index.tsx",
"source": "src/index.tsx",
Expand Down Expand Up @@ -45,6 +45,7 @@
"@commitlint/cli": "^17.6.7",
"@commitlint/config-conventional": "^17.6.7",
"@react-native-async-storage/async-storage": "^1.19.2",
"@shopify/flash-list": "^1.7.1",
"@testing-library/jest-native": "^5.4.2",
"@testing-library/react-native": "^12.1.3",
"@tsconfig/react-native": "^3.0.0",
Expand Down
68 changes: 68 additions & 0 deletions src/components/AvatarList/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React, { FC, memo } from 'react';
import { ScrollView } from 'react-native';
import StoryAvatar from '../Avatar';
import { StoryAvatarListProps } from '~/core/dto/componentsDTO';
import { InstagramStoryProps } from '~/core/dto/instagramStoriesDTO';

let FlashList: any;

try {

// eslint-disable-next-line global-require
FlashList = require( '@shopify/flash-list' ).FlashList;

} catch ( error ) {

FlashList = null;

}

const StoryAvatarList: FC<StoryAvatarListProps> = ( {
stories, loadingStory, seenStories, colors, seenColors, size,
showName, nameTextStyle, nameTextProps, listContainerProps, listContainerStyle,
avatarListContainerProps, avatarListContainerStyle, onPress,
} ) => {

const renderItem = ( story: InstagramStoryProps ) => story.renderAvatar?.()
?? ( ( story.avatarSource || story.imgUrl ) && (
<StoryAvatar
{...story}
loadingStory={loadingStory}
seenStories={seenStories}
onPress={() => onPress( story.id )}
colors={colors}
seenColors={seenColors}
size={size}
showName={showName}
nameTextStyle={nameTextStyle}
nameTextProps={nameTextProps}
key={`avatar${story.id}`}
/>
) );

if ( FlashList ) {

return (
<FlashList
horizontal
{...listContainerProps}
{...avatarListContainerProps}
data={stories}
renderItem={( { item } : { item: InstagramStoryProps } ) => renderItem( item )}
keyExtractor={( item: InstagramStoryProps ) => item.id}
contentContainerStyle={[ listContainerStyle, avatarListContainerStyle ]}
testID="storiesList"
/>
);

}

return (
<ScrollView horizontal {...listContainerProps} {...avatarListContainerProps} contentContainerStyle={[ listContainerStyle, avatarListContainerStyle ]} testID="storiesList">
{stories.map( renderItem )}
</ScrollView>
);

};

export default memo( StoryAvatarList );
39 changes: 19 additions & 20 deletions src/components/InstagramStories/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import React, {
forwardRef, useImperativeHandle, useState, useEffect, useRef, memo,
} from 'react';
import { useSharedValue } from 'react-native-reanimated';
import { Image, ScrollView } from 'react-native';
import StoryAvatar from '../Avatar';
import { Image } from 'react-native';
import { clearProgressStorage, getProgressStorage, setProgressStorage } from '../../core/helpers/storage';
import { InstagramStoriesProps, InstagramStoriesPublicMethods } from '../../core/dto/instagramStoriesDTO';
import { ProgressStorageProps } from '../../core/dto/helpersDTO';
Expand All @@ -13,6 +12,7 @@ import {
} from '../../core/constants';
import StoryModal from '../Modal';
import { StoryModalPublicMethods } from '../../core/dto/componentsDTO';
import StoryAvatarList from '../AvatarList';

const InstagramStories = forwardRef<InstagramStoriesPublicMethods, InstagramStoriesProps>( ( {
stories,
Expand Down Expand Up @@ -175,6 +175,7 @@ const InstagramStories = forwardRef<InstagramStoriesPublicMethods, InstagramStor

},
clearProgressStorage,
goToSpecificStory: ( userId, index ) => modalRef.current?.goToSpecificStory( userId, index ),
hide: () => modalRef.current?.hide(),
show: ( id ) => {

Expand Down Expand Up @@ -227,24 +228,22 @@ const InstagramStories = forwardRef<InstagramStoriesPublicMethods, InstagramStor
return (
<>
{!hideAvatarList && (
<ScrollView horizontal {...listContainerProps} {...avatarListContainerProps} contentContainerStyle={[ listContainerStyle, avatarListContainerStyle ]} testID="storiesList">
{data.map( ( story ) => story.renderAvatar?.()
?? ( ( story.avatarSource || story.imgUrl ) && (
<StoryAvatar
{...story}
loadingStory={loadingStory}
seenStories={seenStories}
onPress={() => onPress( story.id )}
colors={avatarBorderColors}
seenColors={avatarSeenBorderColors}
size={avatarSize}
showName={showName}
nameTextStyle={nameTextStyle}
nameTextProps={nameTextProps}
key={`avatar${story.id}`}
/>
) ) )}
</ScrollView>
<StoryAvatarList
stories={data}
loadingStory={loadingStory}
seenStories={seenStories}
colors={avatarBorderColors}
seenColors={avatarSeenBorderColors}
size={avatarSize}
showName={showName}
nameTextStyle={nameTextStyle}
nameTextProps={nameTextProps}
listContainerProps={listContainerProps}
listContainerStyle={listContainerStyle}
avatarListContainerProps={avatarListContainerProps}
avatarListContainerStyle={avatarListContainerStyle}
onPress={onPress}
/>
)}
<StoryModal
ref={modalRef}
Expand Down
Loading

0 comments on commit 3ab6594

Please sign in to comment.