Ramble-FE / components / VoiceChatOverlay.tsx
VoiceChatOverlay.tsx
Raw
import { useKeyboardHeight } from "@/hooks";
import React, { useState } from "react";
import { StyleSheet, TextInput, View } from "react-native";
import Animated, { runOnJS, useAnimatedStyle, useSharedValue, withDelay, withSequence, withTiming } from 'react-native-reanimated';
import { useSafeAreaInsets } from "react-native-safe-area-context";
import IconButton from "./ui/IconButton";

interface VoiceChatOverlayProps {
    isMuted: boolean,
    isConnected: boolean,
    toggleMute: () => void,
    toggleVideo: () => void,
    onSend: (message: string) => void,
}

/**
 * Mobile Voice Chat Overlay Component
 */
export default function VoiceChatOverlay({ 
    isConnected, 
    isMuted, 
    toggleMute, 
    toggleVideo, 
    onSend 
}: VoiceChatOverlayProps) {
    const [chatMessage, setChatMessage] = useState("");
    const [chatVisible, setChatVisible] = useState(false);
    const opacity = useSharedValue(0);

    const insets = useSafeAreaInsets();
    const keyboardHeight = useKeyboardHeight();

    const animatedStyle = useAnimatedStyle(() => ({
        opacity: opacity.value,
    }));

    const playAnimation = () => {
        opacity.value = withSequence(
            withTiming(1, { duration: 300 }),
            withDelay(
                10000,
                withTiming(0, { duration: 250 }, (isFinished) => {
                    if (isFinished) {
                        runOnJS(setChatVisible)(false);
                    }
                })
            )
        );
    };

    const handleShowChat = () => {
        setChatVisible(true);
        playAnimation();
    };

    const handleMessageSend = () => {
        if (chatMessage.trim().length > 0) {
            onSend(chatMessage.trim());
            setChatMessage("");
        }
        playAnimation();
    };

    const handleMessageChange = (text: string) => {
        setChatMessage(text);
        playAnimation();
    };

    return (
        <>  
            <View 
                style={[
                    styles.topBar, 
                    { top: insets.top, left: insets.left, right: insets.right }
                ]}
            >
                <IconButton
                    icon="ellipsis-vertical" 
                    onPress={() => { console.log("추후 기능 추가"); }}
                />
            </View>
            <View
                style={[
                    styles.container,
                    { left: insets.left, right: insets.right, bottom: insets.bottom + keyboardHeight }
                ]}
            >
                <IconButton
                    icon={isMuted ? "mic-off" : "mic"}
                    iconColor={isMuted ? "tomato" : "white"}
                    onPress={toggleMute}
                />

                <IconButton
                    icon="sync"
                    onPress={toggleVideo!}
                />

                <Animated.View style={[styles.chatInputContainer, animatedStyle]}>
                    <TextInput
                        style={styles.messageInput}
                        placeholder="Enter your message..."
                        placeholderTextColor="white"
                        value={chatMessage}
                        editable={chatVisible}
                        onChangeText={handleMessageChange}
                        multiline
                    />                        
                </Animated.View>

                <IconButton
                    icon={chatVisible ? "send" : "chatbubble-ellipses"}
                    iconSize={20}
                    backgroundColor={chatVisible ? "rgba(255,255,255,0.6)" : "transparent"}
                    onPress={chatVisible ? handleMessageSend : handleShowChat}  
                />
            </View>
        </>
    );
}

const styles = StyleSheet.create({
    topBar: {
        position: 'absolute',
        flexDirection: "column",
        alignItems: "flex-end",
        padding: 8,
    },
    container: {
        position: 'absolute',
        flexDirection: "row",
        alignItems: "flex-end",
        padding: 8,
        gap: 4,
    },
    chatInputContainer: {
        flex: 1,
        flexDirection: "row",
    },
    messageInput: {
        flex: 1,
        fontSize: 16,
        minHeight: 42,
        maxHeight: 70, 
        borderColor: "white",
        borderWidth: 1.2,
        borderRadius: 20,
        paddingHorizontal: 10,
        backgroundColor: "rgba(0, 0, 0, 0.05)",
        color: "white",
        boxShadow: "0px 0px 8px rgba(0, 0, 0, 0.1)",
    },
});