merging refactored conversation

This commit is contained in:
balzack 2023-03-01 16:05:33 -08:00
parent dcc075383c
commit 79d308a627
17 changed files with 805 additions and 4 deletions

View File

@ -567,7 +567,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@ -639,7 +639,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;

View File

@ -320,6 +320,8 @@ PODS:
- React-jsinspector (0.71.3)
- React-logger (0.71.3):
- glog
- react-native-document-picker (8.1.3):
- React-Core
- react-native-rsa-native (2.0.5):
- React
- react-native-safe-area-context (4.5.0):
@ -330,6 +332,11 @@ PODS:
- ReactCommon/turbomodule/core
- react-native-sqlite-storage (6.0.1):
- React-Core
- react-native-video (5.2.1):
- React-Core
- react-native-video/Video (= 5.2.1)
- react-native-video/Video (5.2.1):
- React-Core
- React-perflogger (0.71.3)
- React-RCTActionSheet (0.71.3):
- React-Core/RCTActionSheetHeaders (= 0.71.3)
@ -495,9 +502,11 @@ DEPENDENCIES:
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
- react-native-rsa-native (from `../node_modules/react-native-rsa-native`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- react-native-sqlite-storage (from `../node_modules/react-native-sqlite-storage`)
- react-native-video (from `../node_modules/react-native-video`)
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
- React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
@ -579,12 +588,16 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/jsinspector"
React-logger:
:path: "../node_modules/react-native/ReactCommon/logger"
react-native-document-picker:
:path: "../node_modules/react-native-document-picker"
react-native-rsa-native:
:path: "../node_modules/react-native-rsa-native"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
react-native-sqlite-storage:
:path: "../node_modules/react-native-sqlite-storage"
react-native-video:
:path: "../node_modules/react-native-video"
React-perflogger:
:path: "../node_modules/react-native/ReactCommon/reactperflogger"
React-RCTActionSheet:
@ -665,9 +678,11 @@ SPEC CHECKSUMS:
React-jsiexecutor: 515b703d23ffadeac7687bc2d12fb08b90f0aaa1
React-jsinspector: 9f7c9137605e72ca0343db4cea88006cb94856dd
React-logger: 957e5dc96d9dbffc6e0f15e0ee4d2b42829ff207
react-native-document-picker: 958e2bc82e128be69055be261aeac8d872c8d34c
react-native-rsa-native: 12132eb627797529fdb1f0d22fd0f8f9678df64a
react-native-safe-area-context: 39c2d8be3328df5d437ac1700f4f3a4f75716acc
react-native-sqlite-storage: f6d515e1c446d1e6d026aa5352908a25d4de3261
react-native-video: c26780b224543c62d5e1b2a7244a5cd1b50e8253
React-perflogger: af8a3d31546077f42d729b949925cc4549f14def
React-RCTActionSheet: 57cc5adfefbaaf0aae2cf7e10bccd746f2903673
React-RCTAnimation: 11c61e94da700c4dc915cf134513764d87fc5e2b

View File

@ -26,6 +26,7 @@
"react-native": "0.71.3",
"react-native-base64": "^0.2.1",
"react-native-device-info": "^10.4.0",
"react-native-document-picker": "^8.1.3",
"react-native-gesture-handler": "^2.9.0",
"react-native-image-crop-picker": "^0.39.0",
"react-native-reanimated": "^2.14.4",
@ -34,6 +35,8 @@
"react-native-screens": "^3.20.0",
"react-native-sqlite-storage": "^6.0.1",
"react-native-vector-icons": "^9.2.0",
"react-native-video": "^5.2.1",
"react-native-wheel-color-picker": "^1.2.0",
"react-router-dom": "^6.8.1",
"react-router-native": "^6.8.1"
},

View File

@ -6,6 +6,7 @@ import { styles } from './Conversation.styled';
import { Colors } from 'constants/Colors';
import Ionicons from 'react-native-vector-icons/AntDesign';
import { Logo } from 'utils/Logo';
import { AddTopic } from './addTopic/AddTopic';
export function Conversation({ navigation, cardId, channelId, closeConversation, openDetails }) {
@ -40,7 +41,7 @@ export function Conversation({ navigation, cardId, channelId, closeConversation,
}, [cardId, channelId]);
return (
<View>
<View style={styles.container}>
{ !navigation && (
<View style={styles.header}>
{ ready && (
@ -55,7 +56,12 @@ export function Conversation({ navigation, cardId, channelId, closeConversation,
</TouchableOpacity>
</View>
)}
<Text>Conversation</Text>
<View style={styles.thread}>
<View style={styles.messages}>
<Text>Conversation</Text>
</View>
<AddTopic />
</View>
</View>
);
}

View File

@ -42,5 +42,20 @@ export const styles = StyleSheet.create({
flexGrow: 1,
alignItems: 'flex-end',
},
container: {
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
},
thread: {
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
},
messages: {
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
},
});

View File

@ -0,0 +1,257 @@
import { ActivityIndicator, Modal, Image, FlatList, TextInput, Alert, View, TouchableOpacity, Text, } from 'react-native';
import { useState, useRef } from 'react';
import { useAddTopic } from './useAddTopic.hook';
import { styles } from './AddTopic.styled';
import AntIcons from 'react-native-vector-icons/AntDesign';
import MatIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import Colors from 'constants/Colors';
import { SafeAreaView } from 'react-native-safe-area-context';
import ImagePicker from 'react-native-image-crop-picker'
import DocumentPicker from 'react-native-document-picker'
import ColorPicker from 'react-native-wheel-color-picker'
import { VideoFile } from './videoFile/VideoFile';
import { AudioFile } from './audioFile/AudioFile';
import { ImageFile } from './imageFile/ImageFile';
export function AddTopic({ sealed, sealKey }) {
const { state, actions } = useAddTopic(sealed, sealKey);
const message = useRef();
const addImage = async () => {
try {
const full = await ImagePicker.openPicker({ mediaType: 'photo' });
actions.addImage(full.path);
}
catch (err) {
console.log(err);
}
}
const sendMessage = async () => {
try {
if (state.message || state.assets.length > 0) {
message.current.blur();
await actions.addTopic();
}
}
catch (err) {
console.log(err);
Alert.alert(
'Failed to Send Message',
'Please try again.',
)
}
}
const addVideo = async () => {
try {
const full = await ImagePicker.openPicker({ mediaType: 'video' });
actions.addVideo(full.path);
}
catch (err) {
console.log(err);
}
}
const addAudio = async () => {
try {
const audio = await DocumentPicker.pickSingle({
presentationStyle: 'fullScreen',
copyTo: 'cachesDirectory',
type: DocumentPicker.types.audio,
})
actions.addAudio(audio.fileCopyUri, audio.name.replace(/\.[^/.]+$/, ""));
} catch (err) {
console.log(err);
}
}
const remove = (item) => {
Alert.alert(
`Removing ${item.type} from message.`,
"Confirm?",
[
{ text: "Cancel",
onPress: () => {},
},
{ text: "Remove", onPress: () => {
actions.removeAsset(item.key);
}}
]
);
}
const renderAsset = ({ item }) => {
if (item.type === 'image') {
return (
<ImageFile path={item.data} remove={() => remove(item)} />
);
}
if (item.type === 'video') {
return (
<VideoFile path={item.data}
remove={() => remove(item)}
setPosition={(position) => actions.setVideoPosition(item.key, position)}
/>
)
}
if (item.type === 'audio') {
return (
<AudioFile path={item.data} label={item.label} remove={() => remove(item)}
setLabel={(label) => actions.setAudioLabel(item.key, label)} />
)
}
else {
return (
<View style={styles.asset}></View>
);
}
}
return (
<SafeAreaView style={styles.add} edges={['right']}>
{ !state.uploadError && state.progress && (
<View style={{ height: 0, width: `${state.progress}%`, borderColor: Colors.background, borderWidth: 1 }} />
)}
{ !state.uploadError && !state.progress && (
<View style={{ height: 0, width: '100%', borderColor: Colors.formBackground, borderWidth: 1 }} />
)}
{ state.uploadError && (
<View style={{ height: 0, width: '100%', borderColor: Colors.alert, borderWidth: 1 }} />
)}
{ state.assets.length > 0 && (
<FlatList style={styles.carousel}
data={state.assets}
horizontal={true}
renderItem={renderAsset}
/>
)}
<TextInput style={{ ...styles.input, color: state.color, fontSize: state.textSize }} value={state.message} onChangeText={actions.setMessage} ref={message}
placeholderTextColor={state.color} cursorColor={state.color}
onSubmitEditing={sendMessage} returnKeyType="send"
autoCapitalize="sentences" placeholder="New Message" multiline={true} />
<View style={styles.addButtons}>
{ !sealed && state.enableImage && (
<TouchableOpacity style={styles.addButton} onPress={addImage}>
<AntIcons name="picture" size={20} color={Colors.text} />
</TouchableOpacity>
)}
{ !sealed && state.enableVideo && (
<TouchableOpacity style={styles.addButton} onPress={addVideo}>
<MatIcons name="video-outline" size={24} color={Colors.text} />
</TouchableOpacity>
)}
{ !sealed && state.enableAudio && (
<TouchableOpacity style={styles.addButton} onPress={addAudio}>
<MatIcons name="music-box-outline" size={20} color={Colors.text} />
</TouchableOpacity>
)}
{ !sealed && (
<View style={styles.divider} />
)}
<TouchableOpacity style={styles.addButton} onPress={actions.showFontSize}>
<MatIcons name="format-size" size={20} color={Colors.text} />
</TouchableOpacity>
<TouchableOpacity style={styles.addButton} onPress={actions.showFontColor}>
<MatIcons name="palette-outline" size={20} color={Colors.text} />
</TouchableOpacity>
<View style={styles.space} />
<TouchableOpacity style={styles.addButton} onPress={sendMessage}>
{ state.busy && (
<ActivityIndicator color={Colors.white} />
)}
{ !state.busy && (state.message || state.assets.length > 0) && (
<MatIcons name="send-outline" size={20} color={Colors.text} />
)}
{ !state.busy && !(state.message || state.assets.length > 0) && (
<MatIcons name="send-outline" size={20} color={Colors.lightgrey} />
)}
</TouchableOpacity>
</View>
<Modal
animationType="fade"
transparent={true}
visible={state.fontSize}
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideFontSize}
>
<View style={styles.editWrapper}>
<View style={styles.editContainer}>
<Text style={styles.editHeader}>Font Size:</Text>
<View style={styles.editSize}>
{ state.size === 'small' && (
<View style={styles.selected}>
<Text style={styles.selectedText}>Small</Text>
</View>
)}
{ state.size !== 'small' && (
<TouchableOpacity style={styles.option} onPress={() => actions.setFontSize('small')}>
<Text style={styles.optionText}>Small</Text>
</TouchableOpacity>
)}
{ state.size === 'medium' && (
<View style={styles.selected}>
<Text style={styles.selectedText}>Medium</Text>
</View>
)}
{ state.size !== 'medium' && (
<TouchableOpacity style={styles.option} onPress={() => actions.setFontSize('medium')}>
<Text style={styles.optionText}>Medium</Text>
</TouchableOpacity>
)}
{ state.size === 'large' && (
<View style={styles.selected}>
<Text style={styles.selectedText}>Large</Text>
</View>
)}
{ state.size !== 'large' && (
<TouchableOpacity style={styles.option} onPress={() => actions.setFontSize('large')}>
<Text style={styles.optionText}>Large</Text>
</TouchableOpacity>
)}
</View>
<View style={styles.editControls}>
<View style={styles.selection} />
<TouchableOpacity style={styles.close} onPress={actions.hideFontSize}>
<Text>Close</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
<Modal
animationType="fade"
transparent={true}
visible={state.fontColor}
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideFontColor}
>
<View style={styles.editWrapper}>
<View style={styles.editContainer}>
<Text style={styles.editHeader}>Font Color:</Text>
<View style={styles.editColor}>
<ColorPicker
color={state.color}
onColorChange={actions.setFontColor}
onColorChangeComplete={actions.setFontColor}
swatched={false}
style={{flex: 1, padding: 8}} />
</View>
<View style={styles.editControls}>
<View style={styles.selection}>
<Text>Set Color:</Text>
<View style={{ marginLeft: 6, borderRadius: 4, width: 16, height: 16, backgroundColor: state.color }} />
</View>
<TouchableOpacity style={styles.close} onPress={actions.hideFontColor}>
<Text>Close</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
</SafeAreaView>
);
}

View File

@ -0,0 +1,142 @@
import { StyleSheet } from 'react-native';
import { Colors } from 'constants/Colors';
export const styles = StyleSheet.create({
add: {
borderTopWidth: 1,
borderColor: Colors.divider,
display: 'flex',
flexDirection: 'column',
},
addButtons: {
display: 'flex',
flexDirection: 'row',
marginLeft: 12,
marginRight: 12,
marginBottom: 16,
},
addButton: {
width: 36,
height: 36,
backgroundColor: Colors.white,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderWidth: 1,
borderColor: Colors.divider,
borderRadius: 2,
marginLeft: 4,
marginRight: 4,
},
input: {
marginLeft: 16,
marginRight: 16,
marginTop: 8,
marginBottom: 8,
padding: 8,
borderRadius: 4,
borderWidth: 1,
borderColor: Colors.divider,
backgroundColor: Colors.white,
maxHeight: 96,
minHeight: 52,
},
space: {
height: 32,
flexGrow: 1,
},
divider: {
borderWidth: 1,
borderColor: Colors.divider,
height: 32,
marginLeft: 8,
marginRight: 8,
},
asset: {
width: 92,
height: 92,
marginRight: 8,
backgroundColor: 'yellow',
},
carousel: {
paddingTop: 8,
paddingRight: 16,
paddingLeft: 16,
},
editHeader: {
fontSize: 18,
paddingBottom: 16,
},
editSize: {
width: '100%',
borderWidth: 1,
borderColor: Colors.lightgrey,
borderRadius: 2,
},
editColor: {
width: '100%',
height: 300,
borderWidth: 1,
borderColor: Colors.lightgrey,
borderRadius: 2,
},
editControls: {
display: 'flex',
flexDirection: 'row',
},
editWrapper: {
display: 'flex',
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(52, 52, 52, 0.8)'
},
editContainer: {
backgroundColor: Colors.formBackground,
padding: 16,
width: '80%',
maxWidth: 400,
},
option: {
borderRadius: 8,
margin: 8,
borderColor: Colors.primary,
borderWidth: 1,
},
optionText: {
padding: 8,
color: Colors.primary,
textAlign: 'center',
},
selected: {
borderRadius: 8,
margin: 8,
borderColor: Colors.primary,
borderWidth: 1,
backgroundColor: Colors.primary,
},
selectedText: {
padding: 8,
color: Colors.white,
textAlign: 'center',
},
close: {
borderWidth: 1,
borderColor: Colors.lightgrey,
borderRadius: 4,
padding: 8,
marginTop: 8,
width: 72,
display: 'flex',
alignItems: 'center',
},
selection: {
flexGrow: 1,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
},
})

View File

@ -0,0 +1,13 @@
import { Image, View, TextInput, TouchableOpacity } from 'react-native';
import audio from 'images/audio.png';
import { styles } from './AudioFile.styled';
export function AudioFile({ path, remove, label, setLabel }) {
return (
<TouchableOpacity style={styles.audio} onLongPress={remove}>
<Image source={audio} resizeMode={'cover'} style={styles.image} />
<TextInput style={ styles.input } value={ label } onChangeText={setLabel}
multiline={true} autoCapitalize={'none'} placeholder="Audio Label" />
</TouchableOpacity>
)
}

View File

@ -0,0 +1,24 @@
import { StyleSheet } from 'react-native';
import { Colors } from 'constants/Colors';
export const styles = StyleSheet.create({
audio: {
width: 92,
height: 92,
backgroundColor: Colors.white,
borderRadius: 4,
marginRight: 16,
display: 'flex',
alignItems: 'center',
},
image: {
width: 92,
height: 92,
},
input: {
position: 'absolute',
maxHeight: 50,
textAlign: 'center',
padding: 4,
}
})

View File

@ -0,0 +1,16 @@
import { useRef, useEffect } from 'react';
import { TouchableOpacity, View, Image } from 'react-native';
import { useImageFile } from './useImageFile.hook';
import { styles } from './ImageFile.styled';
import Colors from 'constants/Colors';
export function ImageFile({ path, setPosition, remove }) {
const { state, actions } = useImageFile();
return (
<TouchableOpacity activeOpacity={1} onLongPress={remove}>
<Image source={{ uri: path }} onLoad={actions.loaded} style={{ width: 92 * state.ratio, height: 92, marginRight: 16 }} resizeMode={'cover'} />
</TouchableOpacity>
);
}

View File

@ -0,0 +1,16 @@
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,
},
})

View File

@ -0,0 +1,21 @@
import { useState, useRef, useEffect, useContext } from 'react';
export function useImageFile() {
const [state, setState] = useState({
ratio: 1,
});
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
}
const actions = {
loaded: (e) => {
const { width, height } = e.nativeEvent.source;
updateState({ ratio: width / height });
},
};
return { state, actions };
}

View File

@ -0,0 +1,137 @@
import { useState, useRef, useEffect, useContext } from 'react';
import { ConversationContext } from 'context/ConversationContext';
import { Image } from 'react-native';
import Colors from 'constants/Colors';
export function useAddTopic(sealed, sealKey) {
const [state, setState] = useState({
message: null,
assets: [],
fontSize: false,
fontColor: false,
size: 'medium',
sizeSet: false,
color: Colors.text,
colorSet: false,
busy: false,
textSize: 14,
enableImage: false,
enableAudio: false,
enableVideo: false,
});
const assetId = useRef(0);
const conversation = useContext(ConversationContext);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
}
useEffect(() => {
const { enableVideo, enableAudio, enableImage } = conversation.state.channel?.detail || {};
updateState({ enableImage, enableAudio, enableVideo });
}, [conversation.state]);
const actions = {
setMessage: (message) => {
updateState({ message });
},
addImage: (data) => {
assetId.current++;
Image.getSize(data, (width, height) => {
const asset = { key: assetId.current, type: 'image', data: data, ratio: width/height };
updateState({ assets: [ ...state.assets, asset ] });
});
},
addVideo: (data) => {
assetId.current++;
const asset = { key: assetId.current, type: 'video', data: data, ratio: 1, duration: 0, position: 0 };
updateState({ assets: [ ...state.assets, asset ] });
},
addAudio: (data, label) => {
assetId.current++;
const asset = { key: assetId.current, type: 'audio', data: data, label };
updateState({ assets: [ ...state.assets, asset ] });
},
setVideoPosition: (key, position) => {
updateState({ assets: state.assets.map((item) => {
if(item.key === key) {
return { ...item, position };
}
return item;
})
});
},
setAudioLabel: (key, label) => {
updateState({ assets: state.assets.map((item) => {
if(item.key === key) {
return { ...item, label };
}
return item;
})
});
},
removeAsset: (key) => {
updateState({ assets: state.assets.filter(item => (item.key !== key))});
},
showFontColor: () => {
updateState({ fontColor: true });
},
hideFontColor: () => {
updateState({ fontColor: false });
},
showFontSize: () => {
updateState({ fontSize: true });
},
hideFontSize: () => {
updateState({ fontSize: false });
},
setFontSize: (size) => {
let textSize;
if (size === 'large') {
textSize = 18;
}
else if (size === 'small') {
textSize = 10;
}
else {
textSize = 14;
}
updateState({ size, sizeSet: true, textSize });
},
setFontColor: (color) => {
updateState({ color, colorSet: true });
},
addTopic: async () => {
if (!state.busy) {
try {
updateState({ busy: true });
let message = {
text: state.message,
textColor: state.colorSet ? state.color : null,
textSize: state.sizeSet ? state.size : null,
};
if (sealed) {
await conversation.actions.addSealedTopic(message, sealKey);
}
else {
await conversation.actions.addTopic(message, state.assets);
}
updateState({ busy: false, assets: [], message: null,
size: 'medium', sizeSet: false, textSize: 14,
color: Colors.text, colorSet: false,
});
}
catch(err) {
console.log(err);
updateState({ busy: false });
throw new Error("failed to add message");
}
}
},
};
return { state, actions };
}

View File

@ -0,0 +1,39 @@
import { useRef, useEffect } from 'react';
import { TouchableOpacity, View } from 'react-native';
import Video from 'react-native-video';
import { useVideoFile } from './useVideoFile.hook';
import { styles } from './VideoFile.styled';
import MatIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import Colors from 'constants/Colors';
export function VideoFile({ path, setPosition, remove }) {
const { state, actions } = useVideoFile();
const video = useRef();
useEffect(() => {
if (video.current) {
video.current.seek(state.position);
setPosition(state.position);
}
}, [state.position]);
const setInfo = ({ naturalSize, duration }) => {
if (video.current) {
video.current.seek(0);
}
actions.setInfo(naturalSize.width, naturalSize.height, duration);
}
return (
<TouchableOpacity onPress={actions.setNextPosition} onLongPress={remove}>
<Video source={{ uri: path }} style={{ width: 92 * state.ratio, height: 92, marginRight: 16 }} resizeMode={'cover'} paused={true}
onLoad={setInfo} ref={(ref) => video.current = ref}
/>
<View style={styles.overlay}>
<MatIcons name="arrow-right" size={20} color={Colors.white} />
</View>
</TouchableOpacity>
);
}

View File

@ -0,0 +1,13 @@
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,
},
})

View File

@ -0,0 +1,29 @@
import { useState, useRef, useEffect, useContext } from 'react';
export function useVideoFile() {
const [state, setState] = useState({
duration: 0,
position: 0,
ratio: 1,
});
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
}
const actions = {
setInfo: (width, height, duration) => {
updateState({ ratio: width / height, duration: Math.floor(duration) });
},
setNextPosition: () => {
if (state.duration) {
const step = Math.floor(1 + state.duration / 20);
const position = (state.position + step ) % state.duration;
updateState({ position });
}
},
};
return { state, actions };
}

View File

@ -3072,6 +3072,15 @@ depd@2.0.0:
resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz"
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
deprecated-react-native-prop-types@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz#c10c6ee75ff2b6de94bb127f142b814e6e08d9ab"
integrity sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA==
dependencies:
"@react-native/normalize-color" "*"
invariant "*"
prop-types "*"
deprecated-react-native-prop-types@^3.0.1:
version "3.0.1"
resolved "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-3.0.1.tgz"
@ -3132,6 +3141,11 @@ electron-to-chromium@^1.4.284:
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.296.tgz"
integrity sha512-i/6Q+Y9bluDa2a0NbMvdtG5TuS/1Fr3TKK8L+7UUL9QjRS5iFJzCC3r70xjyOnLiYG8qGV4/mMpe6HuAbdJW4w==
eme-encryption-scheme-polyfill@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/eme-encryption-scheme-polyfill/-/eme-encryption-scheme-polyfill-2.1.1.tgz#91c823ed584e8ec5a9f03a6a676def8f80c57a4c"
integrity sha512-njD17wcUrbqCj0ArpLu5zWXtaiupHb/2fIUQGdInf83GlI+Q6mmqaPGLdrke4savKAu15J/z1Tg/ivDgl14g0g==
emittery@^0.13.1:
version "0.13.1"
resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz"
@ -5050,6 +5064,11 @@ jsonfile@^4.0.0:
array-includes "^3.1.5"
object.assign "^4.1.3"
keymirror@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/keymirror/-/keymirror-0.1.1.tgz#918889ea13f8d0a42e7c557250eee713adc95c35"
integrity sha512-vIkZAFWoDijgQT/Nvl2AHCMmnegN2ehgTPYuyy2hWQkQSntI0S7ESYqdLkoSe1HyEBFHHkCgSIvVdSEiWwKvCg==
kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
version "3.2.2"
resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz"
@ -6222,6 +6241,18 @@ react-native-device-info@^10.4.0:
resolved "https://registry.npmjs.org/react-native-device-info/-/react-native-device-info-10.4.0.tgz"
integrity sha512-Z37e0HtpBvfkPRgv4xN7lXpvmJyzjwCXSFTXEkw6m2UgnnIsWlOD02Avu4hJXBlIMMazaW3ZLKal3o9h3AYvCw==
react-native-document-picker@^8.1.3:
version "8.1.3"
resolved "https://registry.yarnpkg.com/react-native-document-picker/-/react-native-document-picker-8.1.3.tgz#200b47c182d2d654747b5e41b5843fd378ac9d2e"
integrity sha512-lC+SZnzqIEE30x2CSHeZT+f7FzhQOTJprCNMRPpFVl4mLV9dDCJ/wZAmMByJFT79oQMPrzjlhhJlmjm+sVRUWQ==
dependencies:
invariant "^2.2.4"
react-native-elevation@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/react-native-elevation/-/react-native-elevation-1.0.0.tgz#2a091c688290ac9b08b5842d1a8e8a00fc84233e"
integrity sha512-BWIKcEYtzjRV6GpkX0Km5/w2E7fgIcywiQOT7JZTc5NSbv/YI9kpFinB9lRFsOoRVGmiqq/O3VfP/oH2clIiBA==
react-native-gesture-handler@^2.9.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-2.9.0.tgz#2f63812e523c646f25b9ad660fc6f75948e51241"
@ -6287,6 +6318,23 @@ react-native-vector-icons@^9.2.0:
prop-types "^15.7.2"
yargs "^16.1.1"
react-native-video@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/react-native-video/-/react-native-video-5.2.1.tgz#a17e856759d7e17eee9cbd9df0d05ba22e88d457"
integrity sha512-aJlr9MeTuQ0LpZ4n+EC9RvhoKeiPbLtI2Rxy8u7zo/wzGevbRpWHSBj9xZ5YDBXnAVXzuqyNIkGhdw7bfdIBZw==
dependencies:
deprecated-react-native-prop-types "^2.2.0"
keymirror "^0.1.1"
prop-types "^15.7.2"
shaka-player "^2.5.9"
react-native-wheel-color-picker@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/react-native-wheel-color-picker/-/react-native-wheel-color-picker-1.2.0.tgz#56ba38fc57411edececb0fb6a8f049e91160b015"
integrity sha512-j4IcN7so9dZAkXyrPTTaPqCKsjkGBZkd5F7HqLo0OTRB1EZX3Ww5VMKsKjloxv6Omv193wGOhwfG20ec2KnxJQ==
dependencies:
react-native-elevation "^1.0.0"
react-native@0.71.3:
version "0.71.3"
resolved "https://registry.npmjs.org/react-native/-/react-native-0.71.3.tgz"
@ -6709,6 +6757,13 @@ setprototypeof@1.2.0:
resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz"
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
shaka-player@^2.5.9:
version "2.5.23"
resolved "https://registry.yarnpkg.com/shaka-player/-/shaka-player-2.5.23.tgz#db92d1c6cf2314f0180a2cec11b0e2f2560336f5"
integrity sha512-3MC9k0OXJGw8AZ4n/ZNCZS2yDxx+3as5KgH6Tx4Q5TRboTBBCu6dYPI5vp1DxKeyU12MBN1Zcbs7AKzXv2EnCg==
dependencies:
eme-encryption-scheme-polyfill "^2.0.1"
shallow-clone@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz"