diff --git a/Views/GlobalChat.js b/Views/GlobalChat.js index 5508ab0..16cc12b 100644 --- a/Views/GlobalChat.js +++ b/Views/GlobalChat.js @@ -1,11 +1,34 @@ import React from "react"; -import { View, FlatList, Pressable } from "react-native"; -import { Button, Chip, Text, TextInput } from "react-native-paper"; +import { View, FlatList, Pressable, Animated, PanResponder } from "react-native"; +import { Text, TextInput } from "react-native-paper"; +import { useFocusEffect } from "@react-navigation/native"; +import MaterialIcons from "react-native-vector-icons/MaterialIcons"; import { useSnapshot } from "valtio"; import API from "../API.js"; import GlobalState from "../contexts/GlobalState.js"; import i18n from "../i18nMessages.js"; +const PANEL_WIDTH = 260; + +const CircleIconAction = ({ icon, onPress, color = "#6b7280", disabled = false }) => ( + ({ + width: 36, + height: 36, + borderRadius: 18, + alignItems: "center", + justifyContent: "center", + backgroundColor: disabled ? "#f3f4f6" : (pressed ? "#e5e7eb" : "#f9fafb"), + marginHorizontal: 2, + transform: [{ scale: pressed ? 0.96 : 1 }], + })} + > + + +); + const ChatMessage = ({ item, myProfileId, showOriginal, onPressIn, onPressOut }) => { const isMine = item?.senderProfileId === myProfileId; const isTranslated = !!(item?.textOriginal && item?.text && item.textOriginal !== item.text); @@ -52,6 +75,9 @@ let GlobalChat = () => { const [loading, setLoading] = React.useState(true); const [sending, setSending] = React.useState(false); const [pressedMessageId, setPressedMessageId] = React.useState(""); + const [isOnlinePanelOpen, setIsOnlinePanelOpen] = React.useState(false); + const panelX = React.useRef(new Animated.Value(-PANEL_WIDTH)).current; + const panelOpacity = React.useRef(new Animated.Value(0)).current; const loadMessages = React.useCallback(async () => { const data = await API.getChatMessages(100); @@ -109,60 +135,189 @@ let GlobalChat = () => { setSending(false); }; + const openOnlinePanel = React.useCallback(() => { + setIsOnlinePanelOpen(true); + Animated.parallel([ + Animated.timing(panelX, { + toValue: 0, + duration: 220, + useNativeDriver: true, + }), + Animated.timing(panelOpacity, { + toValue: 1, + duration: 220, + useNativeDriver: true, + }), + ]).start(); + }, [panelOpacity, panelX]); + + const closeOnlinePanel = React.useCallback(() => { + Animated.parallel([ + Animated.timing(panelX, { + toValue: -PANEL_WIDTH, + duration: 220, + useNativeDriver: true, + }), + Animated.timing(panelOpacity, { + toValue: 0, + duration: 220, + useNativeDriver: true, + }), + ]).start(() => setIsOnlinePanelOpen(false)); + }, [panelOpacity, panelX]); + + useFocusEffect( + React.useCallback(() => () => { + setIsOnlinePanelOpen(false); + panelX.setValue(-PANEL_WIDTH); + panelOpacity.setValue(0); + }, [panelOpacity, panelX]) + ); + + const panResponder = React.useMemo(() => PanResponder.create({ + onMoveShouldSetPanResponder: (_, gesture) => { + const isHorizontal = Math.abs(gesture.dx) > 14 && Math.abs(gesture.dy) < 16; + if (!isHorizontal) return false; + if (!isOnlinePanelOpen && gesture.dx > 0) return true; + if (isOnlinePanelOpen && gesture.dx < 0) return true; + return false; + }, + onPanResponderRelease: (_, gesture) => { + if (!isOnlinePanelOpen && gesture.dx > 45) { + openOnlinePanel(); + return; + } + if (isOnlinePanelOpen && gesture.dx < -45) { + closeOnlinePanel(); + } + }, + }), [closeOnlinePanel, isOnlinePanelOpen, openOnlinePanel]); + return ( - - {i18n.t("message.globalChat")} - * {i18n.t("message.chatRoomBeta")} - {i18n.t("message.onlineNow")} ({activeUsers.length}) - - {activeUsers.slice(0, 20).map((user) => ( - - {user?.displayName || "Anonymous"} - - ))} - + + + + + Beta + {i18n.t("message.globalChat")} + + + + {i18n.t("message.onlineNow")} ({activeUsers.length}) + + + - {loading ? ( - {i18n.t("message.loadingChat")} - ) : ( - item?._id?.toString?.() || `${index}-${item?.createdAt || "msg"}`} - renderItem={({ item }) => { - const messageId = item?._id?.toString?.() || ""; - return ( - setPressedMessageId(messageId)} - onPressOut={() => setPressedMessageId("")} - /> - ); + {loading ? ( + {i18n.t("message.loadingChat")} + ) : ( + item?._id?.toString?.() || `${index}-${item?.createdAt || "msg"}`} + renderItem={({ item }) => { + const messageId = item?._id?.toString?.() || ""; + return ( + setPressedMessageId(messageId)} + onPressOut={() => setPressedMessageId("")} + /> + ); + }} + contentContainerStyle={{ paddingBottom: 10 }} + style={{ flex: 1 }} + /> + )} + + - )} - - - - + { }} /> + + + + { }} /> + + + + {isOnlinePanelOpen ? ( + + ) : <>} + + + {i18n.t("message.onlineNow")} ({activeUsers.length}) + + item?.profileId || item?.displayName || `${index}`} + renderItem={({ item }) => ( + + {item?.displayName || "Anonymous"} + + )} + ListEmptyComponent={No users online} + /> + ); };