|
@@ -3,7 +3,6 @@ import {
|
|
|
View,
|
|
|
TouchableOpacity,
|
|
|
Image,
|
|
|
- Modal,
|
|
|
Text,
|
|
|
FlatList,
|
|
|
Dimensions,
|
|
@@ -13,8 +12,7 @@ import {
|
|
|
ActivityIndicator,
|
|
|
AppState,
|
|
|
AppStateStatus,
|
|
|
- TextInput,
|
|
|
- Animated
|
|
|
+ TextInput
|
|
|
} from 'react-native';
|
|
|
import {
|
|
|
GiftedChat,
|
|
@@ -33,7 +31,7 @@ import { GestureHandlerRootView, Swipeable } from 'react-native-gesture-handler'
|
|
|
import { AvatarWithInitials, Header, WarningModal } from 'src/components';
|
|
|
import { Colors } from 'src/theme';
|
|
|
import { useFocusEffect, useNavigation } from '@react-navigation/native';
|
|
|
-import { ResizeMode, Video, Audio, AVPlaybackStatus } from 'expo-av';
|
|
|
+import { Audio } from 'expo-av';
|
|
|
import ChatMessageBox from '../Components/ChatMessageBox';
|
|
|
import ReplyMessageBar from '../Components/ReplyMessageBar';
|
|
|
import { useSharedValue, withTiming } from 'react-native-reanimated';
|
|
@@ -50,7 +48,7 @@ import {
|
|
|
usePostReactToMessageMutation,
|
|
|
usePostSendMessageMutation
|
|
|
} from '@api/chat';
|
|
|
-import { CustomMessage, Message, Reaction, Attachement } from '../types';
|
|
|
+import { CustomMessage, Message, Reaction } from '../types';
|
|
|
import { API_HOST, WEBSOCKET_URL } from 'src/constants';
|
|
|
import ReactionBar from '../Components/ReactionBar';
|
|
|
import OptionsMenu from '../Components/OptionsMenu';
|
|
@@ -63,14 +61,16 @@ import { usePushNotification } from 'src/contexts/PushNotificationContext';
|
|
|
import ReactionsListModal from '../Components/ReactionsListModal';
|
|
|
import { dismissChatNotifications } from '../utils';
|
|
|
import { useMessagesStore } from 'src/stores/unreadMessagesStore';
|
|
|
-import * as Location from 'expo-location';
|
|
|
import FileViewer from 'react-native-file-viewer';
|
|
|
import * as FileSystem from 'expo-file-system';
|
|
|
import ImageView from 'better-react-native-image-viewing';
|
|
|
+import * as MediaLibrary from 'expo-media-library';
|
|
|
|
|
|
import BanIcon from 'assets/icons/messages/ban.svg';
|
|
|
import AttachmentsModal from '../Components/AttachmentsModal';
|
|
|
-import ChatOptionsBlock from '../Components/ChatOptionsBlock';
|
|
|
+import RenderMessageVideo from '../Components/renderMessageVideo';
|
|
|
+import MessageLocation from '../Components/MessageLocation';
|
|
|
+import { CACHED_ATTACHMENTS_DIR } from 'src/constants/constants';
|
|
|
|
|
|
const options = {
|
|
|
enableVibrateFallback: true,
|
|
@@ -153,10 +153,6 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
const [hasMoreMessages, setHasMoreMessages] = useState(true);
|
|
|
const updateUnreadMessagesCount = useMessagesStore((state) => state.updateUnreadMessagesCount);
|
|
|
|
|
|
- const [isPlaying, setIsPlaying] = useState(false);
|
|
|
- const [isBuffering, setIsBuffering] = useState(false);
|
|
|
- const videoRef = useRef<Video>(null);
|
|
|
-
|
|
|
const appState = useRef(AppState.currentState);
|
|
|
const textInputRef = useRef<TextInput>(null);
|
|
|
|
|
@@ -177,21 +173,37 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
}, []);
|
|
|
|
|
|
const onSendMedia = useCallback(
|
|
|
- (files: { uri: string; type: 'image' | 'video' }[]) => {
|
|
|
- const newMsgs = files.map((file) => {
|
|
|
- const msg: IMessage = {
|
|
|
+ async (files: { uri: string; type: 'image' | 'video' }[]) => {
|
|
|
+ for (const file of files) {
|
|
|
+ const tempMessage: CustomMessage = {
|
|
|
_id: Date.now() + Math.random(),
|
|
|
text: '',
|
|
|
createdAt: new Date(),
|
|
|
- user: { _id: +currentUserId, name: 'Me' }
|
|
|
+ user: { _id: +currentUserId, name: 'Me' },
|
|
|
+ reactions: {},
|
|
|
+ deleted: false,
|
|
|
+ attachment: {
|
|
|
+ id: -1,
|
|
|
+ filename: file.type,
|
|
|
+ filetype: file.type,
|
|
|
+ attachment_link: file.uri
|
|
|
+ },
|
|
|
+ pending: true,
|
|
|
+ isSending: true,
|
|
|
+ image: file.type === 'image' ? file.uri : undefined,
|
|
|
+ video: file.type === 'video' ? file.uri : undefined
|
|
|
};
|
|
|
|
|
|
- if (file.type === 'image') {
|
|
|
- msg.image = file.uri;
|
|
|
- } else if (file.type === 'video') {
|
|
|
- msg.video = file.uri;
|
|
|
+ if (replyMessage) {
|
|
|
+ tempMessage.replyMessage = {
|
|
|
+ text: replyMessage.text,
|
|
|
+ id: replyMessage._id,
|
|
|
+ name: replyMessage.user._id === id ? userName : 'Me'
|
|
|
+ };
|
|
|
}
|
|
|
|
|
|
+ setMessages((previousMessages) => GiftedChat.append(previousMessages ?? [], [tempMessage]));
|
|
|
+
|
|
|
const messageData = {
|
|
|
token,
|
|
|
to_uid: id,
|
|
@@ -204,35 +216,45 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- console.log('messageData', messageData);
|
|
|
-
|
|
|
- sendMessage(messageData, {
|
|
|
+ const res = await sendMessage(messageData, {
|
|
|
onSuccess: (res) => {
|
|
|
- console.log('res', res);
|
|
|
+ const { attachment, message_id } = res;
|
|
|
+
|
|
|
const newMessage = {
|
|
|
- _id: res.message_id,
|
|
|
+ _id: message_id,
|
|
|
text: '',
|
|
|
- attachment: res.attachment,
|
|
|
- replyMessage: replyMessage
|
|
|
- ? { text: replyMessage.text, id: replyMessage._id, sender: replyMessage.user?._id }
|
|
|
- : undefined
|
|
|
+ attachment,
|
|
|
+ replyMessage: { ...tempMessage.replyMessage, sender: replyMessage?.user?._id },
|
|
|
+ image: file.type === 'image' ? API_HOST + attachment.attachment_full_url : undefined,
|
|
|
+ video: file.type === 'video' ? file.uri : undefined
|
|
|
};
|
|
|
|
|
|
- // setMessages((previousMessages) =>
|
|
|
- // (previousMessages ?? []).map((msg) =>
|
|
|
- // msg._id === msg._id ? { ...msg, _id: res.message_id } : msg
|
|
|
- // )
|
|
|
- // );
|
|
|
+ setMessages((previousMessages) =>
|
|
|
+ (previousMessages ?? []).map((msg) =>
|
|
|
+ msg._id === tempMessage._id
|
|
|
+ ? {
|
|
|
+ ...msg,
|
|
|
+ _id: res.message_id,
|
|
|
+ attachment: res.attachment,
|
|
|
+ isSending: false,
|
|
|
+ image:
|
|
|
+ res.attachment?.attachment_small_url && file.type === 'image'
|
|
|
+ ? API_HOST + res.attachment.attachment_small_url
|
|
|
+ : undefined,
|
|
|
+ video: res.attachment?.attachment_link
|
|
|
+ ? API_HOST + res.attachment.attachment_link
|
|
|
+ : undefined
|
|
|
+ }
|
|
|
+ : msg
|
|
|
+ )
|
|
|
+ );
|
|
|
+
|
|
|
sendWebSocketMessage('new_message', newMessage as unknown as CustomMessage);
|
|
|
- },
|
|
|
- onError: (err) => console.log('err', err)
|
|
|
+ }
|
|
|
});
|
|
|
|
|
|
- return msg;
|
|
|
- });
|
|
|
- clearReplyMessage();
|
|
|
-
|
|
|
- setMessages((prev) => GiftedChat.append(prev, newMsgs));
|
|
|
+ clearReplyMessage();
|
|
|
+ }
|
|
|
},
|
|
|
[replyMessage]
|
|
|
);
|
|
@@ -243,14 +265,33 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
|
|
|
const onSendLocation = useCallback(
|
|
|
(coords: { latitude: number; longitude: number }) => {
|
|
|
- const locMsg: IMessage = {
|
|
|
+ const tempMessage: CustomMessage = {
|
|
|
_id: Date.now() + Math.random(),
|
|
|
- text: `Location: lat=${coords.latitude}, lon=${coords.longitude}`,
|
|
|
+ text: '',
|
|
|
createdAt: new Date(),
|
|
|
user: { _id: +currentUserId, name: 'Me' },
|
|
|
- location: coords
|
|
|
+ pending: true,
|
|
|
+ deleted: false,
|
|
|
+ reactions: {},
|
|
|
+ attachment: {
|
|
|
+ id: -1,
|
|
|
+ filename: 'location.json',
|
|
|
+ filetype: 'nomadmania/location',
|
|
|
+ lat: coords.latitude,
|
|
|
+ lng: coords.longitude
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
+ if (replyMessage) {
|
|
|
+ tempMessage.replyMessage = {
|
|
|
+ text: replyMessage.text,
|
|
|
+ id: replyMessage._id,
|
|
|
+ name: replyMessage.user._id === id ? userName : 'Me'
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ setMessages((previousMessages) => GiftedChat.append(previousMessages ?? [], [tempMessage]));
|
|
|
+
|
|
|
const locationData = JSON.stringify({ lat: coords.latitude, lng: coords.longitude });
|
|
|
|
|
|
const locationFile = {
|
|
@@ -262,37 +303,33 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
const messageData = {
|
|
|
token,
|
|
|
to_uid: id,
|
|
|
- text: locMsg.text,
|
|
|
+ text: tempMessage.text,
|
|
|
reply_to_id: replyMessage ? (replyMessage._id as number) : -1,
|
|
|
attachment: locationFile
|
|
|
};
|
|
|
|
|
|
- console.log('messageData', messageData);
|
|
|
-
|
|
|
sendMessage(messageData, {
|
|
|
onSuccess: (res) => {
|
|
|
- console.log('res', res);
|
|
|
+ const { attachment, message_id } = res;
|
|
|
+
|
|
|
const newMessage = {
|
|
|
- _id: res.message_id,
|
|
|
- text: locMsg.text,
|
|
|
- attachment: res.attachment,
|
|
|
- replyMessage: replyMessage
|
|
|
- ? { text: replyMessage.text, id: replyMessage._id, sender: replyMessage.user?._id }
|
|
|
- : undefined
|
|
|
+ _id: message_id,
|
|
|
+ text: '',
|
|
|
+ attachment,
|
|
|
+ replyMessage: { ...tempMessage.replyMessage, sender: replyMessage?.user?._id }
|
|
|
};
|
|
|
|
|
|
- // setMessages((previousMessages) =>
|
|
|
- // (previousMessages ?? []).map((msg) =>
|
|
|
- // msg._id === locMsg._id ? { ...msg, _id: res.message_id } : msg
|
|
|
- // )
|
|
|
- // );
|
|
|
- // sendWebSocketMessage('new_message', newMessage as unknown as CustomMessage);
|
|
|
- },
|
|
|
- onError: (err) => console.log('err', err)
|
|
|
+ setMessages((previousMessages) =>
|
|
|
+ (previousMessages ?? []).map((msg) =>
|
|
|
+ msg._id === tempMessage._id ? { ...msg, _id: res.message_id } : msg
|
|
|
+ )
|
|
|
+ );
|
|
|
+
|
|
|
+ sendWebSocketMessage('new_message', newMessage as unknown as CustomMessage);
|
|
|
+ }
|
|
|
});
|
|
|
- clearReplyMessage();
|
|
|
|
|
|
- setMessages((prev) => GiftedChat.append(prev, [locMsg]));
|
|
|
+ clearReplyMessage();
|
|
|
},
|
|
|
[replyMessage]
|
|
|
);
|
|
@@ -300,25 +337,38 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
const onSendFile = useCallback(
|
|
|
(files: { uri: string; type: string; name?: string }[]) => {
|
|
|
const newMsgs = files.map((file) => {
|
|
|
- const msg: IMessage = {
|
|
|
+ const msg: CustomMessage = {
|
|
|
_id: Date.now() + Math.random(),
|
|
|
text: '',
|
|
|
createdAt: new Date(),
|
|
|
- user: { _id: +currentUserId, name: 'Me' }
|
|
|
+ user: { _id: +currentUserId, name: 'Me' },
|
|
|
+ deleted: false,
|
|
|
+ reactions: {},
|
|
|
+ isSending: true,
|
|
|
+ attachment: {
|
|
|
+ id: -1,
|
|
|
+ filename: file.name ?? 'File',
|
|
|
+ filetype: file.type,
|
|
|
+ attachment_link: file.uri
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
+ if (replyMessage) {
|
|
|
+ msg.replyMessage = {
|
|
|
+ text: replyMessage.text,
|
|
|
+ id: replyMessage._id,
|
|
|
+ name: replyMessage.user._id === id ? userName : 'Me'
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
if (file.type.includes('image')) {
|
|
|
msg.image = file.uri;
|
|
|
} else if (file.type.includes('video')) {
|
|
|
msg.video = file.uri;
|
|
|
- } else {
|
|
|
- msg.attachment = {
|
|
|
- uri: file.uri,
|
|
|
- type: file.type,
|
|
|
- name: file.name || 'Attachment'
|
|
|
- };
|
|
|
}
|
|
|
|
|
|
+ setMessages((previousMessages) => GiftedChat.append(previousMessages ?? [], [msg]));
|
|
|
+
|
|
|
const messageData = {
|
|
|
token,
|
|
|
to_uid: id,
|
|
@@ -331,46 +381,76 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- console.log('messageData', messageData);
|
|
|
-
|
|
|
sendMessage(messageData, {
|
|
|
onSuccess: (res) => {
|
|
|
- console.log('res', res);
|
|
|
+ const { attachment, message_id } = res;
|
|
|
+
|
|
|
const newMessage = {
|
|
|
- _id: res.message_id,
|
|
|
+ _id: message_id,
|
|
|
text: '',
|
|
|
- attachment: res.attachment,
|
|
|
- replyMessage: replyMessage
|
|
|
- ? { text: replyMessage.text, id: replyMessage._id, sender: replyMessage.user?._id }
|
|
|
- : undefined
|
|
|
+ attachment,
|
|
|
+ replyMessage: { ...msg.replyMessage, sender: replyMessage?.user?._id },
|
|
|
+ image: file.type === 'image' ? API_HOST + attachment.attachment_full_url : undefined,
|
|
|
+ video: file.type === 'video' ? file.uri : undefined
|
|
|
};
|
|
|
|
|
|
- // setMessages((previousMessages) =>
|
|
|
- // (previousMessages ?? []).map((msg) =>
|
|
|
- // msg._id === msg._id ? { ...msg, _id: res.message_id } : msg
|
|
|
- // )
|
|
|
- // );
|
|
|
+ setMessages((previousMessages) =>
|
|
|
+ (previousMessages ?? []).map((prevMsg) =>
|
|
|
+ prevMsg._id === msg._id
|
|
|
+ ? {
|
|
|
+ ...prevMsg,
|
|
|
+ _id: res.message_id,
|
|
|
+ attachment: res.attachment,
|
|
|
+ isSending: false,
|
|
|
+ image:
|
|
|
+ res.attachment?.attachment_small_url && file.type?.startsWith('image')
|
|
|
+ ? API_HOST + res.attachment.attachment_small_url
|
|
|
+ : undefined,
|
|
|
+ video:
|
|
|
+ res.attachment?.attachment_link && file.type?.startsWith('video')
|
|
|
+ ? API_HOST + res.attachment.attachment_link
|
|
|
+ : undefined
|
|
|
+ }
|
|
|
+ : prevMsg
|
|
|
+ )
|
|
|
+ );
|
|
|
+
|
|
|
sendWebSocketMessage('new_message', newMessage as unknown as CustomMessage);
|
|
|
- },
|
|
|
- onError: (err) => console.log('err', err)
|
|
|
+ }
|
|
|
});
|
|
|
|
|
|
return msg;
|
|
|
});
|
|
|
|
|
|
clearReplyMessage();
|
|
|
- setMessages((prev) => GiftedChat.append(prev, newMsgs));
|
|
|
},
|
|
|
[replyMessage]
|
|
|
);
|
|
|
|
|
|
async function openFileInApp(uri: string, fileName: string) {
|
|
|
try {
|
|
|
- // const fileUri = FileSystem.cacheDirectory + encodeURIComponent(fileName);
|
|
|
+ const dirExist = await FileSystem.getInfoAsync(CACHED_ATTACHMENTS_DIR);
|
|
|
+ if (!dirExist.exists) {
|
|
|
+ await FileSystem.makeDirectoryAsync(CACHED_ATTACHMENTS_DIR, { intermediates: true });
|
|
|
+ }
|
|
|
|
|
|
- // const { uri: localUri } = await FileSystem.downloadAsync(uri, fileUri);
|
|
|
+ const fileUri = `${CACHED_ATTACHMENTS_DIR}${fileName}`;
|
|
|
|
|
|
- await FileViewer.open(uri, {
|
|
|
+ const fileExists = await FileSystem.getInfoAsync(fileUri);
|
|
|
+ if (fileExists.exists) {
|
|
|
+ await FileViewer.open(fileUri, {
|
|
|
+ showOpenWithDialog: true,
|
|
|
+ showAppsSuggestions: true
|
|
|
+ });
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const { uri: localUri } = await FileSystem.downloadAsync(uri, fileUri, {
|
|
|
+ headers: { Nmtoken: token }
|
|
|
+ });
|
|
|
+
|
|
|
+ await FileViewer.open(localUri, {
|
|
|
showOpenWithDialog: true,
|
|
|
showAppsSuggestions: true
|
|
|
});
|
|
@@ -380,28 +460,46 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- async function downloadFileToDevice(uri: string, fileName: string) {
|
|
|
+ async function downloadFileToDevice(currentMessage: CustomMessage) {
|
|
|
+ if (!currentMessage.image && !currentMessage.video) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const fileUrl = currentMessage.video
|
|
|
+ ? currentMessage.video
|
|
|
+ : API_HOST + currentMessage.attachment?.attachment_full_url;
|
|
|
+ const fileType = currentMessage.attachment?.filetype || '';
|
|
|
+ const fileExt = fileType.split('/').pop() || '';
|
|
|
+ const fileName = currentMessage.attachment?.filename?.split('.')[0] || 'file';
|
|
|
+ const fileUri = `${FileSystem.cacheDirectory}${fileName}.${fileExt}`;
|
|
|
+
|
|
|
try {
|
|
|
- const downloadFolder = FileSystem.documentDirectory || FileSystem.cacheDirectory;
|
|
|
- const fileUri = downloadFolder + encodeURIComponent(fileName);
|
|
|
+ const { status } = await MediaLibrary.requestPermissionsAsync();
|
|
|
+ if (status !== 'granted') {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- const { uri: localUri } = await FileSystem.downloadAsync(uri, fileUri);
|
|
|
+ const downloadOptions = currentMessage.video ? { headers: { Nmtoken: token } } : undefined;
|
|
|
+ const { uri } = await FileSystem.downloadAsync(fileUrl, fileUri, downloadOptions);
|
|
|
|
|
|
- Alert.alert('File Saved', `File has been saved to:\n${localUri}`);
|
|
|
- } catch (err) {
|
|
|
- console.warn('downloadFileToDevice error:', err);
|
|
|
- Alert.alert('Error', 'Could not download the file.');
|
|
|
+ await MediaLibrary.createAssetAsync(uri);
|
|
|
+
|
|
|
+ Alert.alert(
|
|
|
+ 'Success',
|
|
|
+ `${fileType.startsWith('video') ? 'Video' : 'Image'} saved to gallery.`
|
|
|
+ );
|
|
|
+ } catch (error) {
|
|
|
+ Alert.alert('Error', 'Failed to download the file.');
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
const renderMessageFile = (props: BubbleProps<CustomMessage>) => {
|
|
|
const { currentMessage } = props;
|
|
|
const leftMessage = currentMessage?.user?._id !== +currentUserId;
|
|
|
if (!currentMessage?.attachment) return null;
|
|
|
|
|
|
- // const { uri, type, name } = currentMessage.attachment;
|
|
|
- // const fileName = name ?? 'Attachment';
|
|
|
- const fileName = 'Attachment';
|
|
|
+ const { attachment_link, filename } = currentMessage.attachment;
|
|
|
+ const fileName = filename ?? 'Attachment';
|
|
|
+ const uri = API_HOST + attachment_link;
|
|
|
|
|
|
return (
|
|
|
<TouchableOpacity
|
|
@@ -409,14 +507,24 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
styles.fileContainer,
|
|
|
{ backgroundColor: leftMessage ? 'rgba(15, 63, 79, 0.2)' : 'rgba(244, 244, 244, 0.2)' }
|
|
|
]}
|
|
|
- // onPress={() => openFileInApp(uri, fileName)}
|
|
|
- // onLongPress={() => downloadFileToDevice(uri, fileName)}
|
|
|
+ onPress={() => {
|
|
|
+ openFileInApp(uri, fileName);
|
|
|
+ }}
|
|
|
+ onLongPress={() => handleLongPress(currentMessage, props)}
|
|
|
+ disabled={currentMessage?.isSending}
|
|
|
>
|
|
|
- <MaterialCommunityIcons
|
|
|
- name="file"
|
|
|
- size={32}
|
|
|
- color={leftMessage ? Colors.DARK_BLUE : Colors.FILL_LIGHT}
|
|
|
- />
|
|
|
+ {currentMessage?.isSending ? (
|
|
|
+ <ActivityIndicator
|
|
|
+ size="small"
|
|
|
+ color={leftMessage ? Colors.DARK_BLUE : Colors.FILL_LIGHT}
|
|
|
+ />
|
|
|
+ ) : (
|
|
|
+ <MaterialCommunityIcons
|
|
|
+ name="file"
|
|
|
+ size={32}
|
|
|
+ color={leftMessage ? Colors.DARK_BLUE : Colors.FILL_LIGHT}
|
|
|
+ />
|
|
|
+ )}
|
|
|
<Text
|
|
|
style={[
|
|
|
styles.fileNameText,
|
|
@@ -429,6 +537,30 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
);
|
|
|
};
|
|
|
|
|
|
+ const renderMessageLocation = (props: BubbleProps<CustomMessage>) => {
|
|
|
+ const { currentMessage } = props;
|
|
|
+ if (!currentMessage?.attachment) return null;
|
|
|
+
|
|
|
+ const { lat, lng } = currentMessage.attachment;
|
|
|
+ if (!lat || !lng) return null;
|
|
|
+
|
|
|
+ return (
|
|
|
+ <View
|
|
|
+ style={[
|
|
|
+ {
|
|
|
+ alignItems: 'center',
|
|
|
+ borderRadius: 8,
|
|
|
+ marginVertical: 6,
|
|
|
+ marginHorizontal: 6,
|
|
|
+ width: 220
|
|
|
+ }
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ <MessageLocation props={props} lat={lat} lng={lng} onLongPress={handleLongPress} />
|
|
|
+ </View>
|
|
|
+ );
|
|
|
+ };
|
|
|
+
|
|
|
const onShareLiveLocation = useCallback(() => {
|
|
|
const liveMsg: IMessage = {
|
|
|
_id: 'live-loc-' + Date.now(),
|
|
@@ -440,89 +572,6 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
setMessages((prev) => GiftedChat.append(prev, [liveMsg]));
|
|
|
}, []);
|
|
|
|
|
|
- const renderMessageVideo = (props: any) => {
|
|
|
- const { currentMessage } = props;
|
|
|
- if (!currentMessage?.video) return null;
|
|
|
-
|
|
|
- return (
|
|
|
- <View style={{ width: 200, height: 200, backgroundColor: Colors.DARK_BLUE }}>
|
|
|
- <Video
|
|
|
- ref={videoRef}
|
|
|
- source={{ uri: currentMessage.video, headers: { Nmtoken: token } }}
|
|
|
- style={{ flex: 1 }}
|
|
|
- useNativeControls
|
|
|
- resizeMode={ResizeMode.CONTAIN}
|
|
|
- // isLooping
|
|
|
- isMuted={false}
|
|
|
- volume={1.0}
|
|
|
- shouldCorrectPitch
|
|
|
- onPlaybackStatusUpdate={(playbackStatus) => {
|
|
|
- if (!playbackStatus.isLoaded) {
|
|
|
- setIsPlaying(false);
|
|
|
- setIsBuffering(false);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- setIsPlaying(playbackStatus.isPlaying);
|
|
|
- setIsBuffering(playbackStatus.isBuffering ?? false);
|
|
|
- }}
|
|
|
- />
|
|
|
-
|
|
|
- {isBuffering && (
|
|
|
- <View
|
|
|
- style={{
|
|
|
- position: 'absolute',
|
|
|
- top: 0,
|
|
|
- left: 0,
|
|
|
- right: 0,
|
|
|
- bottom: 0,
|
|
|
- alignItems: 'center',
|
|
|
- justifyContent: 'center'
|
|
|
- }}
|
|
|
- >
|
|
|
- <ActivityIndicator size="large" color="#FFF" />
|
|
|
- </View>
|
|
|
- )}
|
|
|
-
|
|
|
- {isBuffering && (
|
|
|
- <View
|
|
|
- style={{
|
|
|
- position: 'absolute',
|
|
|
- top: 0,
|
|
|
- left: 0,
|
|
|
- right: 0,
|
|
|
- bottom: 0,
|
|
|
- alignItems: 'center',
|
|
|
- justifyContent: 'center'
|
|
|
- }}
|
|
|
- >
|
|
|
- <ActivityIndicator size="large" color="#FFF" />
|
|
|
- </View>
|
|
|
- )}
|
|
|
-
|
|
|
- {!isPlaying && !isBuffering ? (
|
|
|
- <TouchableOpacity
|
|
|
- style={{
|
|
|
- position: 'absolute',
|
|
|
- top: 0,
|
|
|
- left: 0,
|
|
|
- right: 0,
|
|
|
- bottom: 0,
|
|
|
- alignItems: 'center',
|
|
|
- justifyContent: 'center'
|
|
|
- }}
|
|
|
- onPress={async () => {
|
|
|
- await videoRef.current?.presentFullscreenPlayer();
|
|
|
- await videoRef.current?.playAsync();
|
|
|
- }}
|
|
|
- >
|
|
|
- <MaterialCommunityIcons name="play-circle-outline" size={48} color="#FFF" />
|
|
|
- </TouchableOpacity>
|
|
|
- ) : null}
|
|
|
- </View>
|
|
|
- );
|
|
|
- };
|
|
|
-
|
|
|
useEffect(() => {
|
|
|
let unsubscribe: any;
|
|
|
|
|
@@ -756,7 +805,7 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
reply_to: message.replyMessage ?? null,
|
|
|
reactions: message.reactions ?? '{}',
|
|
|
status: 2,
|
|
|
- attachement: -1
|
|
|
+ attachement: message.attachment ? message.attachment : -1
|
|
|
};
|
|
|
}
|
|
|
|
|
@@ -816,12 +865,13 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
sent: message.status === 2,
|
|
|
received: message.status === 3,
|
|
|
deleted: message.status === 4,
|
|
|
+ isSending: false,
|
|
|
video:
|
|
|
- message.attachement !== -1 && message.attachement?.filetype.startsWith('video')
|
|
|
+ message.attachement !== -1 && message.attachement?.filetype?.startsWith('video')
|
|
|
? API_HOST + message.attachement?.attachment_link
|
|
|
: null,
|
|
|
image:
|
|
|
- message.attachement !== -1 && message.attachement?.filetype.startsWith('image')
|
|
|
+ message.attachement !== -1 && message.attachement?.filetype?.startsWith('image')
|
|
|
? API_HOST + message.attachement?.attachment_small_url
|
|
|
: null
|
|
|
};
|
|
@@ -837,7 +887,6 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
useCallback(() => {
|
|
|
if (chatData?.messages) {
|
|
|
const mappedMessages = chatData.messages.map(mapApiMessageToGiftedMessage);
|
|
|
- console.log('mappedMessages', mappedMessages[0]);
|
|
|
|
|
|
if (unreadMessageIndex === null && !isFetching) {
|
|
|
const firstUnreadIndex = mappedMessages.findLastIndex(
|
|
@@ -1035,7 +1084,10 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
text: 'This message was deleted',
|
|
|
pending: false,
|
|
|
sent: false,
|
|
|
- received: false
|
|
|
+ received: false,
|
|
|
+ attachment: null,
|
|
|
+ image: undefined,
|
|
|
+ video: undefined
|
|
|
};
|
|
|
}
|
|
|
return msg;
|
|
@@ -1068,8 +1120,7 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
setIsModalVisible(false);
|
|
|
break;
|
|
|
case 'download':
|
|
|
- console.log('download');
|
|
|
- downloadFileToDevice(selectedMessage.currentMessage?.image, 'Attachment');
|
|
|
+ downloadFileToDevice(selectedMessage.currentMessage);
|
|
|
setIsModalVisible(false);
|
|
|
break;
|
|
|
default:
|
|
@@ -1196,6 +1247,15 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
}}
|
|
|
renderTicks={() => null}
|
|
|
renderTime={renderTimeContainer}
|
|
|
+ renderCustomView={() =>
|
|
|
+ selectedMessage.currentMessage.attachment?.filetype === 'nomadmania/location'
|
|
|
+ ? renderMessageLocation(selectedMessage)
|
|
|
+ : selectedMessage.currentMessage.attachment &&
|
|
|
+ !selectedMessage.currentMessage.image &&
|
|
|
+ !selectedMessage.currentMessage.video
|
|
|
+ ? renderMessageFile(selectedMessage)
|
|
|
+ : null
|
|
|
+ }
|
|
|
/>
|
|
|
</ScrollView>
|
|
|
</View>
|
|
@@ -1251,8 +1311,7 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
)
|
|
|
);
|
|
|
sendWebSocketMessage('new_message', newMessage as unknown as CustomMessage);
|
|
|
- },
|
|
|
- onError: (err) => console.log('err', err)
|
|
|
+ }
|
|
|
}
|
|
|
);
|
|
|
|
|
@@ -1291,8 +1350,7 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
if (message) {
|
|
|
sendWebSocketMessage('new_reaction', message, reaction);
|
|
|
}
|
|
|
- },
|
|
|
- onError: (err) => console.log('err', err)
|
|
|
+ }
|
|
|
}
|
|
|
);
|
|
|
|
|
@@ -1396,13 +1454,34 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
|
|
|
const renderMessageImage = (props: any) => {
|
|
|
const { currentMessage } = props;
|
|
|
+ const leftMessage = currentMessage?.user?._id !== +currentUserId;
|
|
|
+
|
|
|
return (
|
|
|
<TouchableOpacity
|
|
|
onPress={() => setSelectedMedia(API_HOST + currentMessage.attachment.attachment_full_url)}
|
|
|
onLongPress={() => handleLongPress(currentMessage, props)}
|
|
|
style={styles.imageContainer}
|
|
|
+ disabled={currentMessage.isSending}
|
|
|
>
|
|
|
<Image source={{ uri: currentMessage.image }} style={styles.chatImage} resizeMode="cover" />
|
|
|
+ {currentMessage.isSending && (
|
|
|
+ <View
|
|
|
+ style={{
|
|
|
+ position: 'absolute',
|
|
|
+ top: 0,
|
|
|
+ left: 0,
|
|
|
+ right: 0,
|
|
|
+ bottom: 0,
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignItems: 'center'
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <ActivityIndicator
|
|
|
+ size="large"
|
|
|
+ color={leftMessage ? Colors.DARK_BLUE : Colors.FILL_LIGHT}
|
|
|
+ />
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
</TouchableOpacity>
|
|
|
);
|
|
|
};
|
|
@@ -1477,44 +1556,6 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
? Colors.DARK_BLUE
|
|
|
: Colors.FILL_LIGHT;
|
|
|
|
|
|
- if (currentMessage.attachment) {
|
|
|
- return (
|
|
|
- <View
|
|
|
- key={`${currentMessage._id}-${isHighlighted ? 'highlighted' : 'normal'}`}
|
|
|
- ref={(ref) => {
|
|
|
- if (ref && currentMessage) {
|
|
|
- messageRefs.current[currentMessage._id] = ref;
|
|
|
- }
|
|
|
- }}
|
|
|
- collapsable={false}
|
|
|
- >
|
|
|
- <Bubble
|
|
|
- {...props}
|
|
|
- wrapperStyle={{
|
|
|
- right: {
|
|
|
- backgroundColor: backgroundColor
|
|
|
- },
|
|
|
- left: {
|
|
|
- backgroundColor: backgroundColor
|
|
|
- }
|
|
|
- }}
|
|
|
- textStyle={{
|
|
|
- left: {
|
|
|
- color: Colors.DARK_BLUE
|
|
|
- },
|
|
|
- right: {
|
|
|
- color: Colors.FILL_LIGHT
|
|
|
- }
|
|
|
- }}
|
|
|
- onLongPress={() => handleLongPress(currentMessage, props)}
|
|
|
- renderTicks={() => null}
|
|
|
- renderTime={renderTimeContainer}
|
|
|
- renderCustomView={() => renderMessageFile(props)}
|
|
|
- />
|
|
|
- </View>
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
return (
|
|
|
<View
|
|
|
key={`${currentMessage._id}-${isHighlighted ? 'highlighted' : 'normal'}`}
|
|
@@ -1546,6 +1587,13 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
onLongPress={() => handleLongPress(currentMessage, props)}
|
|
|
renderTicks={() => null}
|
|
|
renderTime={renderTimeContainer}
|
|
|
+ renderCustomView={() =>
|
|
|
+ currentMessage.attachment?.filetype === 'nomadmania/location'
|
|
|
+ ? renderMessageLocation(props)
|
|
|
+ : currentMessage.attachment && !currentMessage.image && !currentMessage.video
|
|
|
+ ? renderMessageFile(props)
|
|
|
+ : null
|
|
|
+ }
|
|
|
/>
|
|
|
</View>
|
|
|
);
|
|
@@ -1698,7 +1746,14 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
{!props.text?.trim() && <SendIcon fill={Colors.LIGHT_GRAY} />}
|
|
|
</View>
|
|
|
)}
|
|
|
- renderMessageVideo={renderMessageVideo}
|
|
|
+ renderMessageVideo={(props) => (
|
|
|
+ <RenderMessageVideo
|
|
|
+ props={props}
|
|
|
+ token={token}
|
|
|
+ currentUserId={+currentUserId}
|
|
|
+ onLongPress={handleLongPress}
|
|
|
+ />
|
|
|
+ )}
|
|
|
textInputProps={{
|
|
|
...styles.composer,
|
|
|
selectionColor: Colors.LIGHT_GRAY
|
|
@@ -1755,7 +1810,7 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
|
)}
|
|
|
|
|
|
<ImageView
|
|
|
- images={[{ uri: selectedMedia }]}
|
|
|
+ images={[{ uri: selectedMedia, cache: 'force-cache' }]}
|
|
|
imageIndex={0}
|
|
|
visible={!!selectedMedia}
|
|
|
onRequestClose={() => setSelectedMedia(null)}
|