mirror of
https://github.com/balzack/databag.git
synced 2025-02-11 19:19:16 +00:00
merging refactored conversation
This commit is contained in:
parent
dcc075383c
commit
79d308a627
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
},
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
|
257
app/mobile/src/session/conversation/addTopic/AddTopic.jsx
Normal file
257
app/mobile/src/session/conversation/addTopic/AddTopic.jsx
Normal 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>
|
||||
);
|
||||
}
|
||||
|
||||
|
142
app/mobile/src/session/conversation/addTopic/AddTopic.styled.js
Normal file
142
app/mobile/src/session/conversation/addTopic/AddTopic.styled.js
Normal 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',
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
@ -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,
|
||||
}
|
||||
})
|
@ -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>
|
||||
);
|
||||
}
|
@ -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,
|
||||
},
|
||||
})
|
@ -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 };
|
||||
}
|
137
app/mobile/src/session/conversation/addTopic/useAddTopic.hook.js
Normal file
137
app/mobile/src/session/conversation/addTopic/useAddTopic.hook.js
Normal 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 };
|
||||
}
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
@ -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,
|
||||
},
|
||||
})
|
@ -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 };
|
||||
}
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user