mirror of
https://github.com/balzack/databag.git
synced 2025-02-11 19:19:16 +00:00
rendering asset carousel
This commit is contained in:
parent
2cc2419bf9
commit
633ca9248e
@ -30,6 +30,7 @@
|
||||
"react-native-reanimated": "^2.10.0",
|
||||
"react-native-safe-area-context": "^4.3.3",
|
||||
"react-native-safe-area-view": "^1.1.1",
|
||||
"react-native-snap-carousel": "4.0.0-beta.6",
|
||||
"react-native-sqlite-storage": "^6.0.1",
|
||||
"react-native-video": "^5.2.1",
|
||||
"react-native-web": "~0.18.7",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { FlatList, View, Text, TouchableOpacity } from 'react-native';
|
||||
import { FlatList, View, Text, TouchableOpacity, Modal } from 'react-native';
|
||||
import { useTopicItem } from './useTopicItem.hook';
|
||||
import { styles } from './TopicItem.styled';
|
||||
import { Logo } from 'utils/Logo';
|
||||
@ -6,24 +6,47 @@ import Colors from 'constants/Colors';
|
||||
import { VideoThumb } from './videoThumb/VideoThumb';
|
||||
import { AudioThumb } from './audioThumb/AudioThumb';
|
||||
import { ImageThumb } from './imageThumb/ImageThumb';
|
||||
import { ImageAsset } from './imageAsset/ImageAsset';
|
||||
import { AudioAsset } from './audioAsset/AudioAsset';
|
||||
import { VideoAsset } from './videoAsset/VideoAsset';
|
||||
import AntIcons from '@expo/vector-icons/AntDesign';
|
||||
import Carousel from 'react-native-snap-carousel';
|
||||
|
||||
export function TopicItem({ item }) {
|
||||
|
||||
const { state, actions } = useTopicItem(item);
|
||||
|
||||
const renderThumb = (asset) => {
|
||||
if (asset.item.image) {
|
||||
return <ImageThumb topicId={item.topicId} asset={asset.item.image} />
|
||||
}
|
||||
if (asset.item.video) {
|
||||
return <VideoThumb topicId={item.topicId} asset={asset.item.video} />
|
||||
}
|
||||
if (asset.item.audio) {
|
||||
return <AudioThumb topicId={item.topicId} asset={asset.item.audio} />
|
||||
}
|
||||
return <></>
|
||||
};
|
||||
const renderAsset = (asset) => {
|
||||
return (
|
||||
<View style={styles.frame}>
|
||||
{ asset.item.image && (
|
||||
<ImageAsset topicId={item.topicId} asset={asset.item.image} onClearCarousel={() => actions.hideCarousel()} />
|
||||
)}
|
||||
{ asset.item.video && (
|
||||
<VideoAsset topicId={item.topicId} asset={asset.item.video} onClearCarousel={() => actions.hideCarousel()} />
|
||||
)}
|
||||
{ asset.item.audio && (
|
||||
<AudioAsset topicId={item.topicId} asset={asset.item.audio} onClearCarousel={() => actions.hideCarousel()} />
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const renderThumb = (thumb) => {
|
||||
return (
|
||||
<View>
|
||||
{ thumb.item.image && (
|
||||
<ImageThumb topicId={item.topicId} asset={thumb.item.image} onAssetView={() => actions.showCarousel(thumb.index)} />
|
||||
)}
|
||||
{ thumb.item.video && (
|
||||
<VideoThumb topicId={item.topicId} asset={thumb.item.video} onAssetView={() => actions.showCarousel(thumb.index)} />
|
||||
)}
|
||||
{ thumb.item.audio && (
|
||||
<AudioThumb topicId={item.topicId} asset={thumb.item.audio} onAssetView={() => actions.showCarousel(thumb.index)} />
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.item}>
|
||||
@ -55,6 +78,23 @@ export function TopicItem({ item }) {
|
||||
{ state.status !== 'confirmed' && (
|
||||
<AntIcons name="cloudo" size={32} color={Colors.divider} />
|
||||
)}
|
||||
<Modal
|
||||
animationType="fade"
|
||||
transparent={true}
|
||||
visible={state.carousel}
|
||||
supportedOrientations={['portrait', 'landscape']}
|
||||
onRequestClose={actions.hideCarousel}
|
||||
>
|
||||
<View style={styles.modal}>
|
||||
<Carousel
|
||||
data={state.assets}
|
||||
firstItem={state.carouselIndex}
|
||||
renderItem={renderAsset}
|
||||
sliderWidth={state.width}
|
||||
itemWidth={state.width}
|
||||
/>
|
||||
</View>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
@ -30,5 +30,17 @@ export const styles = StyleSheet.create({
|
||||
marginTop: 4,
|
||||
marginBottom: 4,
|
||||
},
|
||||
modal: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: 'rgba(52, 52, 52, 0.8)',
|
||||
},
|
||||
frame: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -0,0 +1,10 @@
|
||||
import { Image, View, TouchableOpacity } from 'react-native';
|
||||
import Colors from 'constants/Colors';
|
||||
|
||||
export function AudioAsset({ topicId, asset, onClearCarousel }) {
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={onClearCarousel} activeOpacity={1} style={{ width: 100, height: 100, backgroundColor: 'yellow' }} onPress={onClearCarousel} />
|
||||
);
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ import { styles } from './AudioThumb.styled';
|
||||
import Colors from 'constants/Colors';
|
||||
import audio from 'images/audio.png';
|
||||
|
||||
export function AudioThumb({ topicId, asset }) {
|
||||
export function AudioThumb({ topicId, asset, onAssetView }) {
|
||||
|
||||
return (
|
||||
<TouchableOpacity activeOpacity={1}>
|
||||
<TouchableOpacity activeOpacity={1} onPress={onAssetView}>
|
||||
<Image source={audio} style={{ borderRadius: 4, width: 92, height: 92, marginRight: 16, backgroundColor: Colors.lightgrey }} resizeMode={'cover'} />
|
||||
{ asset.label && (
|
||||
<View style={styles.overlay}>
|
||||
|
@ -0,0 +1,15 @@
|
||||
import { Image, View, TouchableOpacity } from 'react-native';
|
||||
import { useImageAsset } from './useImageAsset.hook';
|
||||
import { styles } from './ImageAsset.styled';
|
||||
import Colors from 'constants/Colors';
|
||||
|
||||
export function ImageAsset({ topicId, asset, onClearCarousel }) {
|
||||
const { state, actions } = useImageAsset(topicId, asset);
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={onClearCarousel} activeOpacity={1}>
|
||||
<Image source={{ uri: state.url }} style={{ borderRadius: 4, width: state.imageWidth, height: state.imageHeight }} resizeMode={'cover'} />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
import { StyleSheet } from 'react-native';
|
||||
import { Colors } from 'constants/Colors';
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
overlay: {
|
||||
marginRight: 16,
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
padding: 2,
|
||||
borderTopLeftRadius: 4,
|
||||
backgroundColor: Colors.white,
|
||||
borderWidth: 1,
|
||||
borderColor: Colors.divider,
|
||||
},
|
||||
})
|
||||
|
@ -0,0 +1,58 @@
|
||||
import { useState, useRef, useEffect, useContext } from 'react';
|
||||
import { ConversationContext } from 'context/ConversationContext';
|
||||
import { Image } from 'react-native';
|
||||
import { useWindowDimensions } from 'react-native';
|
||||
|
||||
export function useImageAsset(topicId, asset) {
|
||||
|
||||
const [state, setState] = useState({
|
||||
frameWidth: 1,
|
||||
frameHeight: 1,
|
||||
imageRatio: 1,
|
||||
imageWidth: 1,
|
||||
imageHeight: 1,
|
||||
url: null,
|
||||
});
|
||||
|
||||
const conversation = useContext(ConversationContext);
|
||||
const dimensions = useWindowDimensions();
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const frameRatio = state.frameWidth / state.frameHeight;
|
||||
if (frameRatio > state.imageRatio) {
|
||||
//height constrained
|
||||
const height = 0.8 * state.frameHeight;
|
||||
const width = height * state.imageRatio;
|
||||
updateState({ imageWidth: width, imageHeight: height });
|
||||
}
|
||||
else {
|
||||
//width constrained
|
||||
const width = 0.8 * state.frameWidth;
|
||||
const height = width / state.imageRatio;
|
||||
updateState({ imageWidth: width, imageHeight: height });
|
||||
}
|
||||
}, [state.frameWidth, state.frameHeight, state.imageRatio]);
|
||||
|
||||
useEffect(() => {
|
||||
updateState({ frameWidth: dimensions.width, frameHeight: dimensions.height });
|
||||
}, [dimensions]);
|
||||
|
||||
useEffect(() => {
|
||||
const url = conversation.actions.getTopicAssetUrl(topicId, asset.full);
|
||||
if (url) {
|
||||
Image.getSize(url, (width, height) => {
|
||||
updateState({ url, imageRatio: width / height });
|
||||
});
|
||||
}
|
||||
}, [topicId, conversation, asset]);
|
||||
|
||||
const actions = {
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
}
|
||||
|
@ -3,11 +3,11 @@ import { useImageThumb } from './useImageThumb.hook';
|
||||
import { styles } from './ImageThumb.styled';
|
||||
import Colors from 'constants/Colors';
|
||||
|
||||
export function ImageThumb({ topicId, asset }) {
|
||||
export function ImageThumb({ topicId, asset, onAssetView }) {
|
||||
const { state, actions } = useImageThumb(topicId, asset);
|
||||
|
||||
return (
|
||||
<TouchableOpacity activeOpacity={1}>
|
||||
<TouchableOpacity activeOpacity={1} onPress={onAssetView}>
|
||||
<Image source={{ uri: state.url }} style={{ borderRadius: 4, width: 92 * state.ratio, height: 92, marginRight: 16 }} resizeMode={'cover'} />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
|
@ -2,6 +2,7 @@ import { useState, useEffect, useContext } from 'react';
|
||||
import { CardContext } from 'context/CardContext';
|
||||
import { ProfileContext } from 'context/ProfileContext';
|
||||
import moment from 'moment';
|
||||
import { useWindowDimensions } from 'react-native';
|
||||
|
||||
export function useTopicItem(item) {
|
||||
|
||||
@ -11,15 +12,24 @@ export function useTopicItem(item) {
|
||||
logo: null,
|
||||
timestamp: null,
|
||||
message: null,
|
||||
carousel: false,
|
||||
carouselIndex: 0,
|
||||
width: null,
|
||||
height: null,
|
||||
});
|
||||
|
||||
const profile = useContext(ProfileContext);
|
||||
const card = useContext(CardContext);
|
||||
const dimensions = useWindowDimensions();
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
updateState({ width: dimensions.width, height: dimensions.height });
|
||||
}, [dimensions]);
|
||||
|
||||
useEffect(() => {
|
||||
const { topicId, detail } = item;
|
||||
const { guid, data, status, transform } = detail;
|
||||
@ -95,6 +105,12 @@ export function useTopicItem(item) {
|
||||
}, [card, item]);
|
||||
|
||||
const actions = {
|
||||
showCarousel: (index) => {
|
||||
updateState({ carousel: true, carouselIndex: index });
|
||||
},
|
||||
hideCarousel: () => {
|
||||
updateState({ carousel: false });
|
||||
},
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
|
@ -0,0 +1,10 @@
|
||||
import { Image, View, TouchableOpacity } from 'react-native';
|
||||
import Colors from 'constants/Colors';
|
||||
|
||||
export function VideoAsset({ topicId, asset, onClearCarousel }) {
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={onClearCarousel} activeOpacity={1} style={{ width: 100, height: 100, backgroundColor: 'yellow' }} onPress={onClearCarousel} />
|
||||
);
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ import { styles } from './VideoThumb.styled';
|
||||
import Colors from 'constants/Colors';
|
||||
import Ionicons from '@expo/vector-icons/AntDesign';
|
||||
|
||||
export function VideoThumb({ topicId, asset }) {
|
||||
export function VideoThumb({ topicId, asset, onAssetView }) {
|
||||
const { state, actions } = useVideoThumb(topicId, asset);
|
||||
|
||||
return (
|
||||
<TouchableOpacity activeOpacity={1}>
|
||||
<TouchableOpacity activeOpacity={1} onPress={onAssetView}>
|
||||
<Image source={{ uri: state.url }} style={{ borderRadius: 4, width: 92 * state.ratio, height: 92, marginRight: 16 }} resizeMode={'cover'} />
|
||||
<View style={styles.overlay}>
|
||||
<Ionicons name="caretright" size={20} color={Colors.white} />
|
||||
|
10141
app/mobile/yarn.lock
10141
app/mobile/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user