From 79d308a62767bf24e877debd009d586821e6b3e7 Mon Sep 17 00:00:00 2001 From: balzack Date: Wed, 1 Mar 2023 16:05:33 -0800 Subject: [PATCH] merging refactored conversation --- .../ios/Databag.xcodeproj/project.pbxproj | 4 +- app/mobile/ios/Podfile.lock | 15 + app/mobile/package.json | 3 + .../src/session/conversation/Conversation.jsx | 10 +- .../conversation/Conversation.styled.js | 15 + .../conversation/addTopic/AddTopic.jsx | 257 ++++++++++++++++++ .../conversation/addTopic/AddTopic.styled.js | 142 ++++++++++ .../addTopic/audioFile/AudioFile.jsx | 13 + .../addTopic/audioFile/AudioFile.styled.js | 24 ++ .../addTopic/imageFile/ImageFile.jsx | 16 ++ .../addTopic/imageFile/ImageFile.styled.js | 16 ++ .../addTopic/imageFile/useImageFile.hook.js | 21 ++ .../conversation/addTopic/useAddTopic.hook.js | 137 ++++++++++ .../addTopic/videoFile/VideoFile.jsx | 39 +++ .../addTopic/videoFile/VideoFile.styled.js | 13 + .../addTopic/videoFile/useVideoFile.hook.js | 29 ++ app/mobile/yarn.lock | 55 ++++ 17 files changed, 805 insertions(+), 4 deletions(-) create mode 100644 app/mobile/src/session/conversation/addTopic/AddTopic.jsx create mode 100644 app/mobile/src/session/conversation/addTopic/AddTopic.styled.js create mode 100644 app/mobile/src/session/conversation/addTopic/audioFile/AudioFile.jsx create mode 100644 app/mobile/src/session/conversation/addTopic/audioFile/AudioFile.styled.js create mode 100644 app/mobile/src/session/conversation/addTopic/imageFile/ImageFile.jsx create mode 100644 app/mobile/src/session/conversation/addTopic/imageFile/ImageFile.styled.js create mode 100644 app/mobile/src/session/conversation/addTopic/imageFile/useImageFile.hook.js create mode 100644 app/mobile/src/session/conversation/addTopic/useAddTopic.hook.js create mode 100644 app/mobile/src/session/conversation/addTopic/videoFile/VideoFile.jsx create mode 100644 app/mobile/src/session/conversation/addTopic/videoFile/VideoFile.styled.js create mode 100644 app/mobile/src/session/conversation/addTopic/videoFile/useVideoFile.hook.js diff --git a/app/mobile/ios/Databag.xcodeproj/project.pbxproj b/app/mobile/ios/Databag.xcodeproj/project.pbxproj index e18215b7..d6343f17 100644 --- a/app/mobile/ios/Databag.xcodeproj/project.pbxproj +++ b/app/mobile/ios/Databag.xcodeproj/project.pbxproj @@ -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; diff --git a/app/mobile/ios/Podfile.lock b/app/mobile/ios/Podfile.lock index 1e6d904b..b247937e 100644 --- a/app/mobile/ios/Podfile.lock +++ b/app/mobile/ios/Podfile.lock @@ -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 diff --git a/app/mobile/package.json b/app/mobile/package.json index fdf29b17..ce411ffa 100644 --- a/app/mobile/package.json +++ b/app/mobile/package.json @@ -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" }, diff --git a/app/mobile/src/session/conversation/Conversation.jsx b/app/mobile/src/session/conversation/Conversation.jsx index 79c6104a..f85c6468 100644 --- a/app/mobile/src/session/conversation/Conversation.jsx +++ b/app/mobile/src/session/conversation/Conversation.jsx @@ -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 ( - + { !navigation && ( { ready && ( @@ -55,7 +56,12 @@ export function Conversation({ navigation, cardId, channelId, closeConversation, )} - Conversation + + + Conversation + + + ); } diff --git a/app/mobile/src/session/conversation/Conversation.styled.js b/app/mobile/src/session/conversation/Conversation.styled.js index f0b9c210..f74543ee 100644 --- a/app/mobile/src/session/conversation/Conversation.styled.js +++ b/app/mobile/src/session/conversation/Conversation.styled.js @@ -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, + }, }); diff --git a/app/mobile/src/session/conversation/addTopic/AddTopic.jsx b/app/mobile/src/session/conversation/addTopic/AddTopic.jsx new file mode 100644 index 00000000..0e335847 --- /dev/null +++ b/app/mobile/src/session/conversation/addTopic/AddTopic.jsx @@ -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 ( + remove(item)} /> + ); + } + if (item.type === 'video') { + return ( + remove(item)} + setPosition={(position) => actions.setVideoPosition(item.key, position)} + /> + ) + } + if (item.type === 'audio') { + return ( + remove(item)} + setLabel={(label) => actions.setAudioLabel(item.key, label)} /> + ) + } + else { + return ( + + ); + } + } + + return ( + + { !state.uploadError && state.progress && ( + + )} + { !state.uploadError && !state.progress && ( + + )} + { state.uploadError && ( + + )} + { state.assets.length > 0 && ( + + )} + + + { !sealed && state.enableImage && ( + + + + )} + { !sealed && state.enableVideo && ( + + + + )} + { !sealed && state.enableAudio && ( + + + + )} + { !sealed && ( + + )} + + + + + + + + + { state.busy && ( + + )} + { !state.busy && (state.message || state.assets.length > 0) && ( + + )} + { !state.busy && !(state.message || state.assets.length > 0) && ( + + )} + + + + + + Font Size: + + { state.size === 'small' && ( + + Small + + )} + { state.size !== 'small' && ( + actions.setFontSize('small')}> + Small + + )} + { state.size === 'medium' && ( + + Medium + + )} + { state.size !== 'medium' && ( + actions.setFontSize('medium')}> + Medium + + )} + { state.size === 'large' && ( + + Large + + )} + { state.size !== 'large' && ( + actions.setFontSize('large')}> + Large + + )} + + + + + Close + + + + + + + + + Font Color: + + + + + + Set Color: + + + + Close + + + + + + + ); +} + + diff --git a/app/mobile/src/session/conversation/addTopic/AddTopic.styled.js b/app/mobile/src/session/conversation/addTopic/AddTopic.styled.js new file mode 100644 index 00000000..abe7ff3c --- /dev/null +++ b/app/mobile/src/session/conversation/addTopic/AddTopic.styled.js @@ -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', + }, +}) + + diff --git a/app/mobile/src/session/conversation/addTopic/audioFile/AudioFile.jsx b/app/mobile/src/session/conversation/addTopic/audioFile/AudioFile.jsx new file mode 100644 index 00000000..bbfe58ec --- /dev/null +++ b/app/mobile/src/session/conversation/addTopic/audioFile/AudioFile.jsx @@ -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 ( + + + + + ) +} diff --git a/app/mobile/src/session/conversation/addTopic/audioFile/AudioFile.styled.js b/app/mobile/src/session/conversation/addTopic/audioFile/AudioFile.styled.js new file mode 100644 index 00000000..8a9b54ee --- /dev/null +++ b/app/mobile/src/session/conversation/addTopic/audioFile/AudioFile.styled.js @@ -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, + } +}) diff --git a/app/mobile/src/session/conversation/addTopic/imageFile/ImageFile.jsx b/app/mobile/src/session/conversation/addTopic/imageFile/ImageFile.jsx new file mode 100644 index 00000000..c088ad1e --- /dev/null +++ b/app/mobile/src/session/conversation/addTopic/imageFile/ImageFile.jsx @@ -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 ( + + + + ); +} diff --git a/app/mobile/src/session/conversation/addTopic/imageFile/ImageFile.styled.js b/app/mobile/src/session/conversation/addTopic/imageFile/ImageFile.styled.js new file mode 100644 index 00000000..67cebb57 --- /dev/null +++ b/app/mobile/src/session/conversation/addTopic/imageFile/ImageFile.styled.js @@ -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, + }, +}) diff --git a/app/mobile/src/session/conversation/addTopic/imageFile/useImageFile.hook.js b/app/mobile/src/session/conversation/addTopic/imageFile/useImageFile.hook.js new file mode 100644 index 00000000..51171a23 --- /dev/null +++ b/app/mobile/src/session/conversation/addTopic/imageFile/useImageFile.hook.js @@ -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 }; +} diff --git a/app/mobile/src/session/conversation/addTopic/useAddTopic.hook.js b/app/mobile/src/session/conversation/addTopic/useAddTopic.hook.js new file mode 100644 index 00000000..0b65e0e5 --- /dev/null +++ b/app/mobile/src/session/conversation/addTopic/useAddTopic.hook.js @@ -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 }; +} + diff --git a/app/mobile/src/session/conversation/addTopic/videoFile/VideoFile.jsx b/app/mobile/src/session/conversation/addTopic/videoFile/VideoFile.jsx new file mode 100644 index 00000000..20ec3eb3 --- /dev/null +++ b/app/mobile/src/session/conversation/addTopic/videoFile/VideoFile.jsx @@ -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 ( + + + ); +} diff --git a/app/mobile/src/session/conversation/addTopic/videoFile/VideoFile.styled.js b/app/mobile/src/session/conversation/addTopic/videoFile/VideoFile.styled.js new file mode 100644 index 00000000..4d20175d --- /dev/null +++ b/app/mobile/src/session/conversation/addTopic/videoFile/VideoFile.styled.js @@ -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, + }, +}) diff --git a/app/mobile/src/session/conversation/addTopic/videoFile/useVideoFile.hook.js b/app/mobile/src/session/conversation/addTopic/videoFile/useVideoFile.hook.js new file mode 100644 index 00000000..5c19c3c8 --- /dev/null +++ b/app/mobile/src/session/conversation/addTopic/videoFile/useVideoFile.hook.js @@ -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 }; +} diff --git a/app/mobile/yarn.lock b/app/mobile/yarn.lock index 409f0f1b..b7f1dd07 100644 --- a/app/mobile/yarn.lock +++ b/app/mobile/yarn.lock @@ -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"