mirror of
https://github.com/balzack/databag.git
synced 2025-02-14 12:39:17 +00:00
improved asset rendering
This commit is contained in:
parent
92a967210d
commit
55957aeacb
@ -310,7 +310,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 7;
|
CURRENT_PROJECT_VERSION = 8;
|
||||||
DEVELOPMENT_TEAM = 3P65PQ7SUR;
|
DEVELOPMENT_TEAM = 3P65PQ7SUR;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
@ -348,7 +348,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 7;
|
CURRENT_PROJECT_VERSION = 8;
|
||||||
DEVELOPMENT_TEAM = 3P65PQ7SUR;
|
DEVELOPMENT_TEAM = 3P65PQ7SUR;
|
||||||
INFOPLIST_FILE = Databag/Info.plist;
|
INFOPLIST_FILE = Databag/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Databag;
|
INFOPLIST_KEY_CFBundleDisplayName = Databag;
|
||||||
|
@ -97,8 +97,7 @@ export function TopicItem({ item, focused, focus, hosting, remove, update, block
|
|||||||
<VideoAsset topicId={item.topicId} asset={asset.item.video} dismiss={actions.hideCarousel} />
|
<VideoAsset topicId={item.topicId} asset={asset.item.video} dismiss={actions.hideCarousel} />
|
||||||
)}
|
)}
|
||||||
{ asset.item.audio && (
|
{ asset.item.audio && (
|
||||||
<AudioAsset topicId={item.topicId} asset={asset.item.audio} active={state.activeId == asset.dataIndex}
|
<AudioAsset topicId={item.topicId} asset={asset.item.audio} dismiss={actions.hideCarousel} />
|
||||||
setActive={() => actions.setActive(asset.dataIndex)} dismiss={actions.hideCarousel} />
|
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
@ -1,36 +1,38 @@
|
|||||||
import { Text, Image, View, TouchableOpacity } from 'react-native';
|
import { Image, View, Text, TouchableOpacity } from 'react-native';
|
||||||
|
import { useRef } from 'react';
|
||||||
import Colors from 'constants/Colors';
|
import Colors from 'constants/Colors';
|
||||||
|
import { Video, AVPlaybackStatus } from 'expo-av';
|
||||||
import { useAudioAsset } from './useAudioAsset.hook';
|
import { useAudioAsset } from './useAudioAsset.hook';
|
||||||
|
import GestureRecognizer from 'react-native-swipe-gestures';
|
||||||
import { styles } from './AudioAsset.styled';
|
import { styles } from './AudioAsset.styled';
|
||||||
import audio from 'images/audio.png';
|
|
||||||
import Icons from '@expo/vector-icons/MaterialCommunityIcons';
|
import Icons from '@expo/vector-icons/MaterialCommunityIcons';
|
||||||
|
import audio from 'images/audio.png';
|
||||||
|
|
||||||
export function AudioAsset({ topicId, asset, active, setActive, dismiss }) {
|
export function AudioAsset({ topicId, asset, dismiss }) {
|
||||||
|
|
||||||
const { state, actions } = useAudioAsset(topicId, asset);
|
const { state, actions } = useAudioAsset(topicId, asset);
|
||||||
|
|
||||||
const play = () => {
|
const player = useRef(null);
|
||||||
actions.play();
|
|
||||||
setActive();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.background}>
|
<View style={styles.container}>
|
||||||
<Image source={audio} style={{ width: state.length, height: state.length }} resizeMode={'cover'} />
|
<Image source={audio} style={{ width: state.width, height: state.height }} resizeMode={'contain'} />
|
||||||
<Text style={styles.label}>{ asset.label }</Text>
|
<Text style={styles.label}>{ asset.label }</Text>
|
||||||
{ state.playing && active && (
|
{ !state.playing && state.loaded && (
|
||||||
<TouchableOpacity style={styles.control} onPress={actions.pause}>
|
<TouchableOpacity style={styles.control} onPress={actions.play}>
|
||||||
<Icons name="stop-circle-outline" size={92} color={Colors.white} />
|
<Icons name="play-circle-outline" size={92} color={Colors.text} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)}
|
)}
|
||||||
{ (!state.playing || !active) && (
|
{ state.playing && state.loaded && (
|
||||||
<TouchableOpacity style={styles.control} onPress={play}>
|
<TouchableOpacity style={styles.control} onPress={actions.pause}>
|
||||||
<Icons name="play-circle-outline" size={92} color={Colors.white} />
|
<Icons name="pause-circle-outline" size={92} color={Colors.text} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)}
|
)}
|
||||||
<TouchableOpacity style={styles.close} onPress={dismiss}>
|
<TouchableOpacity style={styles.close} onPress={dismiss}>
|
||||||
<Icons name="close" size={24} color={Colors.white} />
|
<Icons name="window-close" size={32} color={Colors.text} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
<Video ref={player} source={{ uri: state.url }} isLooping={true}
|
||||||
|
shouldPlay={state.playing} onLoad={actions.loaded} style={styles.player} />
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,19 @@ import { StyleSheet } from 'react-native';
|
|||||||
import { Colors } from 'constants/Colors';
|
import { Colors } from 'constants/Colors';
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
background: {
|
container: {
|
||||||
backgroundColor: Colors.lightgrey,
|
position: 'relative',
|
||||||
borderRadius: 4,
|
borderRadius: 8,
|
||||||
|
backgroundColor: Colors.formBackground,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
|
control: {
|
||||||
|
position: 'absolute',
|
||||||
|
paddingRight: 8,
|
||||||
|
paddingTop: 4,
|
||||||
|
},
|
||||||
label: {
|
label: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
@ -18,13 +24,17 @@ export const styles = StyleSheet.create({
|
|||||||
paddingLeft: 20,
|
paddingLeft: 20,
|
||||||
paddingRight: 20,
|
paddingRight: 20,
|
||||||
},
|
},
|
||||||
control: {
|
|
||||||
position: 'absolute',
|
|
||||||
},
|
|
||||||
close: {
|
close: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 0,
|
top: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
|
paddingTop: 4,
|
||||||
|
paddingBottom: 4,
|
||||||
|
paddingLeft: 8,
|
||||||
|
paddingRight: 8,
|
||||||
|
},
|
||||||
|
player: {
|
||||||
|
display: 'none',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -2,15 +2,18 @@ import { useState, useRef, useEffect, useContext } from 'react';
|
|||||||
import { ConversationContext } from 'context/ConversationContext';
|
import { ConversationContext } from 'context/ConversationContext';
|
||||||
import { Image } from 'react-native';
|
import { Image } from 'react-native';
|
||||||
import { useWindowDimensions } from 'react-native';
|
import { useWindowDimensions } from 'react-native';
|
||||||
import SoundPlayer from 'react-native-sound-player'
|
|
||||||
|
|
||||||
export function useAudioAsset(topicId, asset) {
|
export function useAudioAsset(topicId, asset) {
|
||||||
|
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
length: null,
|
width: 1,
|
||||||
|
height: 1,
|
||||||
|
url: null,
|
||||||
playing: false,
|
playing: false,
|
||||||
|
loaded: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const closing = useRef(null);
|
||||||
const conversation = useContext(ConversationContext);
|
const conversation = useContext(ConversationContext);
|
||||||
const dimensions = useWindowDimensions();
|
const dimensions = useWindowDimensions();
|
||||||
|
|
||||||
@ -19,29 +22,36 @@ export function useAudioAsset(topicId, asset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (dimensions.width < dimensions.height) {
|
const frameRatio = dimensions.width / dimensions.height;
|
||||||
updateState({ length: 0.8 * dimensions.width });
|
if (frameRatio > 1) {
|
||||||
|
//height constrained
|
||||||
|
const height = 0.9 * dimensions.height;
|
||||||
|
const width = height;
|
||||||
|
updateState({ width, height });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
updateState({ length: 0.8 * dimensions.height });
|
//width constrained
|
||||||
|
const width = 0.9 * dimensions.width;
|
||||||
|
const height = width;
|
||||||
|
updateState({ width, height });
|
||||||
}
|
}
|
||||||
}, [dimensions]);
|
}, [dimensions]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const url = conversation.actions.getTopicAssetUrl(topicId, asset.full);
|
const url = conversation.actions.getTopicAssetUrl(topicId, asset.full);
|
||||||
updateState({ url, playing: false });
|
updateState({ url });
|
||||||
return () => { SoundPlayer.stop() }
|
|
||||||
}, [topicId, conversation, asset]);
|
}, [topicId, conversation, asset]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
play: () => {
|
play: () => {
|
||||||
SoundPlayer.playUrl(state.url);
|
|
||||||
updateState({ playing: true });
|
updateState({ playing: true });
|
||||||
},
|
},
|
||||||
pause: () => {
|
pause: () => {
|
||||||
SoundPlayer.stop();
|
|
||||||
updateState({ playing: false });
|
updateState({ playing: false });
|
||||||
},
|
},
|
||||||
|
loaded: () => {
|
||||||
|
updateState({ loaded: true });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return { state, actions };
|
return { state, actions };
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Image, TouchableOpacity } from 'react-native';
|
import { View, Image, ActivityIndicator, TouchableOpacity } from 'react-native';
|
||||||
import { useImageAsset } from './useImageAsset.hook';
|
import { useImageAsset } from './useImageAsset.hook';
|
||||||
import { styles } from './ImageAsset.styled';
|
import { styles } from './ImageAsset.styled';
|
||||||
import Colors from 'constants/Colors';
|
import Colors from 'constants/Colors';
|
||||||
@ -7,8 +7,13 @@ export function ImageAsset({ topicId, asset, dismiss }) {
|
|||||||
const { state, actions } = useImageAsset(topicId, asset);
|
const { state, actions } = useImageAsset(topicId, asset);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity activeOpacity={1} onPress={dismiss}>
|
<TouchableOpacity style={styles.container} activeOpacity={1} onPress={dismiss}>
|
||||||
<Image source={{ uri: state.url }} style={{ borderRadius: 4, width: state.imageWidth, height: state.imageHeight }} resizeMode={'cover'} />
|
<Image source={{ uri: state.url }} onLoad={actions.loaded} style={{ borderRadius: 4, width: state.imageWidth, height: state.imageHeight }} resizeMode={'cover'} />
|
||||||
|
{ !state.loaded && (
|
||||||
|
<View style={styles.loading}>
|
||||||
|
<ActivityIndicator color={Colors.white} size="large" />
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,14 @@ import { StyleSheet } from 'react-native';
|
|||||||
import { Colors } from 'constants/Colors';
|
import { Colors } from 'constants/Colors';
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
position: 'absolute',
|
||||||
|
},
|
||||||
overlay: {
|
overlay: {
|
||||||
marginRight: 16,
|
marginRight: 16,
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
@ -12,6 +12,7 @@ export function useImageAsset(topicId, asset) {
|
|||||||
imageWidth: 1,
|
imageWidth: 1,
|
||||||
imageHeight: 1,
|
imageHeight: 1,
|
||||||
url: null,
|
url: null,
|
||||||
|
loaded: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const conversation = useContext(ConversationContext);
|
const conversation = useContext(ConversationContext);
|
||||||
@ -51,6 +52,9 @@ export function useImageAsset(topicId, asset) {
|
|||||||
}, [topicId, conversation, asset]);
|
}, [topicId, conversation, asset]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
|
loaded: () => {
|
||||||
|
updateState({ loaded: true });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return { state, actions };
|
return { state, actions };
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { Image, View, TouchableOpacity } from 'react-native';
|
import { ActivityIndicator, Image, View, TouchableOpacity } from 'react-native';
|
||||||
import Colors from 'constants/Colors';
|
import Colors from 'constants/Colors';
|
||||||
import { Video, AVPlaybackStatus } from 'expo-av';
|
import { Video, AVPlaybackStatus } from 'expo-av';
|
||||||
import { useVideoAsset } from './useVideoAsset.hook';
|
import { useVideoAsset } from './useVideoAsset.hook';
|
||||||
import GestureRecognizer from 'react-native-swipe-gestures';
|
|
||||||
import { styles } from './VideoAsset.styled';
|
import { styles } from './VideoAsset.styled';
|
||||||
import Icons from '@expo/vector-icons/MaterialCommunityIcons';
|
import Icons from '@expo/vector-icons/MaterialCommunityIcons';
|
||||||
|
|
||||||
@ -11,18 +10,36 @@ export function VideoAsset({ topicId, asset, dismiss }) {
|
|||||||
const { state, actions } = useVideoAsset(topicId, asset);
|
const { state, actions } = useVideoAsset(topicId, asset);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity activeOpacity={1} onPress={actions.showClose}>
|
<View style={styles.container}>
|
||||||
{ state.url && (
|
{ !state.loaded && (
|
||||||
<Video source={{ uri: state.url }} style={{ width: state.width, height: state.height }} resizeMode={'cover'}
|
<TouchableOpacity onPress={dismiss}>
|
||||||
onReadyForDisplay={(e) => actions.setResolution(e.naturalSize.width, e.naturalSize.height)}
|
<ActivityIndicator color={Colors.white} size="large" />
|
||||||
useNativeControls={state.controls} resizeMode="contain" />
|
|
||||||
)}
|
|
||||||
{ state.closing && (
|
|
||||||
<TouchableOpacity style={styles.close} onPress={dismiss}>
|
|
||||||
<Icons name="close" size={24} color={Colors.white} />
|
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)}
|
)}
|
||||||
</TouchableOpacity>
|
<TouchableOpacity activeOpacity={1} style={{...styles.container, ...state.display}} onPress={actions.showControls}>
|
||||||
|
<Video source={{ uri: state.url }} style={{ width: state.width, height: state.height }} resizeMode={'cover'}
|
||||||
|
onReadyForDisplay={(e) => actions.setResolution(e.naturalSize.width, e.naturalSize.height)}
|
||||||
|
isLooping={true} shouldPlay={state.playing} resizeMode="contain" />
|
||||||
|
{ (!state.playing || state.controls) && (
|
||||||
|
<View style={{ ...styles.overlay, width: state.width, height: state.height }} />
|
||||||
|
)}
|
||||||
|
{ !state.playing && state.loaded && (
|
||||||
|
<TouchableOpacity style={styles.control} onPress={actions.play}>
|
||||||
|
<Icons name="play-circle-outline" size={92} color={Colors.white} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
{ state.controls && state.playing && state.loaded && (
|
||||||
|
<TouchableOpacity style={styles.control} onPress={actions.pause}>
|
||||||
|
<Icons name="pause-circle-outline" size={92} color={Colors.white} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
{ (state.controls || !state.playing) && (
|
||||||
|
<TouchableOpacity style={styles.close} onPress={dismiss}>
|
||||||
|
<Icons name="window-close" size={32} color={Colors.white} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,15 +2,28 @@ import { StyleSheet } from 'react-native';
|
|||||||
import { Colors } from 'constants/Colors';
|
import { Colors } from 'constants/Colors';
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
close: {
|
container: {
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
overlay: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
alignSelf: 'center',
|
backgroundColor: 'rgba(0, 0, 0, 0.4)',
|
||||||
justifySelf: 'center',
|
},
|
||||||
borderBottomLeftRadius: 4,
|
control: {
|
||||||
borderBottomRightRadius: 4,
|
position: 'absolute',
|
||||||
paddingLeft: 4,
|
paddingRight: 8,
|
||||||
paddingRight: 4,
|
paddingTop: 4,
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
paddingTop: 4,
|
||||||
|
paddingBottom: 4,
|
||||||
|
paddingLeft: 8,
|
||||||
|
paddingRight: 8,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -10,13 +10,14 @@ export function useVideoAsset(topicId, asset) {
|
|||||||
frameHeight: 1,
|
frameHeight: 1,
|
||||||
videoRatio: 1,
|
videoRatio: 1,
|
||||||
width: 1,
|
width: 1,
|
||||||
weight: 1,
|
|
||||||
url: null,
|
url: null,
|
||||||
|
playing: false,
|
||||||
|
loaded: false,
|
||||||
controls: false,
|
controls: false,
|
||||||
closing: false,
|
display: { display: 'none' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const closing = useRef(null);
|
const controls = useRef(null);
|
||||||
const conversation = useContext(ConversationContext);
|
const conversation = useContext(ConversationContext);
|
||||||
const dimensions = useWindowDimensions();
|
const dimensions = useWindowDimensions();
|
||||||
|
|
||||||
@ -51,13 +52,20 @@ export function useVideoAsset(topicId, asset) {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
setResolution: (width, height) => {
|
setResolution: (width, height) => {
|
||||||
updateState({ controls: true, videoRatio: width / height });
|
updateState({ loaded: true, display: {}, videoRatio: width / height });
|
||||||
},
|
},
|
||||||
showClose: () => {
|
play: () => {
|
||||||
clearTimeout(closing.current);
|
actions.showControls();
|
||||||
updateState({ closing: true });
|
updateState({ playing: true });
|
||||||
closing.current = setTimeout(() => {
|
},
|
||||||
updateState({ closing: false });
|
pause: () => {
|
||||||
|
updateState({ playing: false });
|
||||||
|
},
|
||||||
|
showControls: () => {
|
||||||
|
clearTimeout(controls.current);
|
||||||
|
updateState({ controls: true });
|
||||||
|
controls.current = setTimeout(() => {
|
||||||
|
updateState({ controls: false });
|
||||||
}, 2000);
|
}, 2000);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user