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}
+ />
+
);
};