185 lines
5.5 KiB
TypeScript
185 lines
5.5 KiB
TypeScript
import React, { RefObject } from 'react';
|
|
import { FlashList, MasonryFlashList } from '@shopify/flash-list';
|
|
import {
|
|
NativeSyntheticEvent,
|
|
NativeScrollEvent,
|
|
StyleSheet,
|
|
} from 'react-native';
|
|
import { useSelector } from 'react-redux';
|
|
import { Divider, HelperText } from 'react-native-paper';
|
|
import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
|
import { Meme } from '../../../database';
|
|
import { RootState } from '../../../state';
|
|
import { VIEW } from '../../../types';
|
|
import { getFlashListItemHeight } from '../../../utilities';
|
|
import MemesMasonryItem from './memesMasonryItem';
|
|
import MemesGridItem from './memesGridItem';
|
|
import MemesListItem from './memesListItem';
|
|
import { AndroidScoped } from 'react-native-file-access';
|
|
|
|
const sharedMemesListStyles = StyleSheet.create({
|
|
flashList: {
|
|
paddingBottom: 100,
|
|
},
|
|
helperText: {
|
|
textAlign: 'center',
|
|
marginVertical: 15,
|
|
},
|
|
});
|
|
|
|
const memesMasonryListStyles = StyleSheet.create({
|
|
flashList: {
|
|
// Needed to prevent fucky MasonryFlashList, see https://github.com/Shopify/flash-list/issues/876
|
|
paddingHorizontal: 0.1,
|
|
},
|
|
});
|
|
|
|
const memesGridListStyles = StyleSheet.create({
|
|
flashList: {
|
|
paddingHorizontal: 2.5,
|
|
},
|
|
});
|
|
|
|
const memesListListStyles = StyleSheet.create({
|
|
flashList: {
|
|
paddingHorizontal: 5,
|
|
},
|
|
});
|
|
|
|
const MemesList = ({
|
|
memes,
|
|
flashListRef,
|
|
flashListPadding,
|
|
handleScroll,
|
|
focusMeme,
|
|
}: {
|
|
memes: Realm.Results<Meme & Realm.Object<Meme>>;
|
|
flashListRef: RefObject<FlashList<Meme>>;
|
|
flashListPadding: number;
|
|
handleScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
focusMeme: (index: number) => void;
|
|
}) => {
|
|
const { height, width } = useSafeAreaFrame();
|
|
const view = useSelector((state: RootState) => state.memes.view);
|
|
const masonryColumns = useSelector(
|
|
(state: RootState) => state.settings.masonryColumns,
|
|
);
|
|
const gridColumns = useSelector(
|
|
(state: RootState) => state.settings.gridColumns,
|
|
);
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
const storageUri = useSelector(
|
|
(state: RootState) => state.settings.storageUri,
|
|
)!;
|
|
|
|
return (
|
|
<>
|
|
{view === VIEW.MASONRY && (
|
|
<MasonryFlashList
|
|
ref={flashListRef}
|
|
data={memes}
|
|
key={masonryColumns}
|
|
estimatedItemSize={getFlashListItemHeight(masonryColumns)}
|
|
estimatedListSize={{
|
|
height,
|
|
width: width * 0.92,
|
|
}}
|
|
numColumns={masonryColumns}
|
|
showsVerticalScrollIndicator={false}
|
|
renderItem={({ item: meme, index }) => (
|
|
<MemesMasonryItem
|
|
meme={meme}
|
|
focusMeme={() => focusMeme(index)}
|
|
uri={AndroidScoped.appendPath(storageUri, meme.filename)}
|
|
columns={masonryColumns}
|
|
/>
|
|
)}
|
|
contentContainerStyle={{
|
|
paddingTop: flashListPadding,
|
|
...sharedMemesListStyles.flashList,
|
|
...memesMasonryListStyles.flashList,
|
|
}}
|
|
ListEmptyComponent={() => (
|
|
<HelperText type={'info'} style={sharedMemesListStyles.helperText}>
|
|
No memes found
|
|
</HelperText>
|
|
)}
|
|
onScroll={handleScroll}
|
|
fadingEdgeLength={100}
|
|
overScrollMode="never"
|
|
/>
|
|
)}
|
|
{view === VIEW.GRID && (
|
|
<FlashList
|
|
ref={flashListRef}
|
|
data={memes}
|
|
key={gridColumns}
|
|
estimatedItemSize={getFlashListItemHeight(gridColumns)}
|
|
estimatedListSize={{
|
|
height: height,
|
|
width: width * 0.92,
|
|
}}
|
|
numColumns={gridColumns}
|
|
showsVerticalScrollIndicator={false}
|
|
renderItem={({ item: meme, index }) => (
|
|
<MemesGridItem
|
|
meme={meme}
|
|
focusMeme={() => focusMeme(index)}
|
|
uri={AndroidScoped.appendPath(storageUri, meme.filename)}
|
|
columns={gridColumns}
|
|
/>
|
|
)}
|
|
contentContainerStyle={{
|
|
paddingTop: flashListPadding,
|
|
...sharedMemesListStyles.flashList,
|
|
...memesGridListStyles.flashList,
|
|
}}
|
|
ListEmptyComponent={() => (
|
|
<HelperText type={'info'} style={sharedMemesListStyles.helperText}>
|
|
No memes found
|
|
</HelperText>
|
|
)}
|
|
onScroll={handleScroll}
|
|
fadingEdgeLength={100}
|
|
overScrollMode="never"
|
|
/>
|
|
)}
|
|
{view === VIEW.LIST && (
|
|
<FlashList
|
|
ref={flashListRef}
|
|
data={memes}
|
|
estimatedItemSize={90}
|
|
estimatedListSize={{
|
|
height: height,
|
|
width: width * 0.92,
|
|
}}
|
|
showsVerticalScrollIndicator={false}
|
|
renderItem={({ item: meme, index }) => (
|
|
<MemesListItem
|
|
meme={meme}
|
|
focusMeme={() => focusMeme(index)}
|
|
uri={AndroidScoped.appendPath(storageUri, meme.filename)}
|
|
/>
|
|
)}
|
|
ItemSeparatorComponent={() => <Divider />}
|
|
contentContainerStyle={{
|
|
paddingTop: flashListPadding,
|
|
...sharedMemesListStyles.flashList,
|
|
...memesListListStyles.flashList,
|
|
}}
|
|
ListEmptyComponent={() => (
|
|
<HelperText type={'info'} style={sharedMemesListStyles.helperText}>
|
|
No memes found
|
|
</HelperText>
|
|
)}
|
|
onScroll={handleScroll}
|
|
fadingEdgeLength={100}
|
|
overScrollMode="never"
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default MemesList;
|