From 741206df0dafd1659c979f4b0127dbe686386d06 Mon Sep 17 00:00:00 2001 From: wow22831 Date: Mon, 28 Oct 2024 03:26:52 +0700 Subject: [PATCH] yra --- src/components/ExploreContainer.css | 49 ++++-- src/components/ExploreContainer.tsx | 255 ++++++++++++++-------------- 2 files changed, 162 insertions(+), 142 deletions(-) diff --git a/src/components/ExploreContainer.css b/src/components/ExploreContainer.css index 0cfddbf..0d4ebac 100644 --- a/src/components/ExploreContainer.css +++ b/src/components/ExploreContainer.css @@ -2,26 +2,42 @@ display: flex; flex-direction: column; align-items: center; - justify-content: space-around; /* Распределение элементов с равным отступом */ - height: 100vh; /* Высота на весь экран для центрирования */ + justify-content: space-around; + height: 100vh; text-align: center; } .peer-id-container { margin-bottom: 10px; + display: flex; + align-items: center; } .peer-id-text { font-size: 16px; color: #fff; + margin-right: 10px; } .copy-button { background: none; border: none; - color: #007aff; cursor: pointer; + padding: 0; +} + +.copy-notification { + position: fixed; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + background-color: #4caf50; + color: white; + padding: 10px 20px; + border-radius: 5px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); font-size: 16px; + z-index: 1000; } .input-container { @@ -30,7 +46,7 @@ justify-content: center; margin-bottom: 10px; width: 100%; - max-width: 400px; /* Ограничение ширины для компактности */ + max-width: 400px; } .call-info-container { @@ -43,13 +59,13 @@ .call-info-text { font-size: 18px; - margin-bottom: 5px; /* Небольшой отступ снизу для Peer ID */ + margin-bottom: 5px; color: #ffffff; } .call-duration-text { font-size: 18px; - margin-bottom: 15px; /* Отступ снизу для времени */ + margin-bottom: 15px; color: #ffffff; } @@ -66,7 +82,7 @@ } .custom-hang-up-button:hover svg { - transform: scale(1.1); /* Увеличение кнопки при наведении */ + transform: scale(1.1); } .call-button { @@ -76,7 +92,14 @@ cursor: pointer; font-size: 24px; margin-left: 10px; - padding: 10px; /* Увеличение кнопки для удобства */ + padding: 15px; + border-radius: 50%; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + transition: background 0.3s ease; +} + +.call-button:hover { + background: #005bb5; } .panel-optimizer { @@ -89,11 +112,17 @@ display: flex; align-items: center; justify-content: center; - height: 100vh; /* Центрирование всего контента по высоте экрана */ + height: 100vh; } .drone-gif { - width: 300px; /* Задайте нужный размер */ + width: 300px; height: auto; margin-bottom: 20px; +} + +.screen-off { + background-color: #000; + color: #000; + opacity: 0; } \ No newline at end of file diff --git a/src/components/ExploreContainer.tsx b/src/components/ExploreContainer.tsx index 73ce263..af4d4d0 100644 --- a/src/components/ExploreContainer.tsx +++ b/src/components/ExploreContainer.tsx @@ -2,145 +2,100 @@ import React, { useState, useEffect, useCallback } from 'react'; import './ExploreContainer.css'; import InputContainer from './Input'; import { - IonButton, IonContent, IonText, IonModal, IonIcon + IonButton, IonContent, IonFooter, IonToolbar, IonText, IonModal, IonIcon } from '@ionic/react'; import { call as callIcon, close as hangUpIcon } from 'ionicons/icons'; - -const socket = new WebSocket('ws://192.168.0.160:8080'); // Адрес вашего WebSocket сервера +import Peer, { MediaConnection } from 'peerjs'; const ExploreContainer: React.FC = () => { - const [callString, setCallString] = useState(""); // Здесь будет храниться IP-адрес получателя звонка + const [callString, setCallString] = useState(""); const [isEnable, setIsEnable] = useState(true); + const [peer, setPeer] = useState(null); const [localStream, setLocalStream] = useState(null); + const [connectionInfo, setConnectionInfo] = useState(null); const [isLoading, setIsLoading] = useState(false); const [isCallActive, setIsCallActive] = useState(false); const [callDuration, setCallDuration] = useState(0); const [callInterval, setCallInterval] = useState(null); - const [peerConnection, setPeerConnection] = useState(null); - const [remoteStream, setRemoteStream] = useState(null); + const [currentCallId, setCurrentCallId] = useState(null); + const [showCopyNotification, setShowCopyNotification] = useState(false); - // Инициализация WebRTC соединения useEffect(() => { - const pc = new RTCPeerConnection(); - setPeerConnection(pc); + const initializePeer = () => { + const newPeer = new Peer({ debug: 3 }); + setPeer(newPeer); - pc.ontrack = (event) => { - const [stream] = event.streams; - setRemoteStream(stream); - playAudio(stream); + newPeer.on('open', (id) => { + console.log(`Peer успешно открыт с ID: ${id}`); + setConnectionInfo(id); + }); + + newPeer.on('call', (call: MediaConnection) => handleIncomingCall(call)); + newPeer.on('error', (err) => console.error('Ошибка Peer:', err)); + + return () => { + newPeer.destroy(); + }; }; - pc.onicecandidate = (event) => { - if (event.candidate) { - socket.send(JSON.stringify({ - type: 'ice-candidate', - candidate: event.candidate, - target: callString, - })); - } - }; + const cleanup = initializePeer(); + return cleanup; + }, []); - return () => { - pc.close(); - }; - }, [callString]); - - // Обработка входящих сообщений WebSocket - useEffect(() => { - socket.onmessage = async (event) => { - const data = JSON.parse(event.data); - - if (data.type === 'offer') { - await handleIncomingCall(data.offer); - } else if (data.type === 'answer') { - if (peerConnection) { - await peerConnection.setRemoteDescription(new RTCSessionDescription(data.answer)); - } - } else if (data.type === 'ice-candidate' && peerConnection) { - try { - await peerConnection.addIceCandidate(new RTCIceCandidate(data.candidate)); - } catch (error) { - console.error('Ошибка добавления ICE-кандидата', error); - } - } - }; - }, [peerConnection]); - - // Запуск вызова - const makeCall = useCallback(async () => { - if (peerConnection && callString) { - setIsLoading(true); - try { - const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); - setLocalStream(stream); - - stream.getTracks().forEach(track => peerConnection.addTrack(track, stream)); - - const offer = await peerConnection.createOffer(); - await peerConnection.setLocalDescription(offer); - - socket.send(JSON.stringify({ - type: 'offer', - offer: offer, - target: callString, - })); - - setIsLoading(false); - setIsCallActive(true); + const handleIncomingCall = useCallback((call: MediaConnection) => { + console.log('Получен входящий звонок'); + setCurrentCallId(call.peer); + navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => { + setLocalStream(stream); + call.answer(stream); + call.on('stream', (remoteStream: MediaStream) => { + console.log('Получен удалённый поток'); + playAudio(remoteStream); startCallTimer(); - } catch (err) { + setIsCallActive(true); + }); + }).catch((err) => { + console.error('Не удалось получить локальный поток для ответа', err); + }); + }, []); + + const makeCall = useCallback(() => { + if (peer && callString) { + setIsLoading(true); + console.log(`Попытка звонка на: ${callString}`); + navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => { + setLocalStream(stream); + const call = peer.call(callString, stream); + setCurrentCallId(callString); + call.on('stream', (remoteStream: MediaStream) => { + console.log('Получен удалённый поток во время вызова'); + playAudio(remoteStream); + setIsLoading(false); + startCallTimer(); + setIsCallActive(true); + }); + }).catch((err) => { console.error('Не удалось получить локальный поток', err); setIsLoading(false); - } + }); } else { - console.warn('Звонок невозможен: отсутствует соединение или IP-адрес'); + console.warn('Звонок невозможен: отсутствует Peer или callString'); } - }, [peerConnection, callString]); + }, [peer, callString]); - // Принятие входящего звонка - const handleIncomingCall = useCallback(async (offer: RTCSessionDescriptionInit) => { - if (peerConnection) { - try { - await peerConnection.setRemoteDescription(new RTCSessionDescription(offer)); - const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); - setLocalStream(stream); - - stream.getTracks().forEach(track => peerConnection.addTrack(track, stream)); - - const answer = await peerConnection.createAnswer(); - await peerConnection.setLocalDescription(answer); - - socket.send(JSON.stringify({ - type: 'answer', - answer: answer, - target: callString, - })); - - setIsCallActive(true); - startCallTimer(); - } catch (err) { - console.error('Ошибка обработки входящего вызова', err); - } - } - }, [peerConnection, callString]); - - // Завершение звонка const endCall = useCallback(() => { if (localStream) { localStream.getTracks().forEach(track => track.stop()); } - if (peerConnection) { - peerConnection.close(); - } setIsCallActive(false); setIsEnable(true); if (callInterval) { clearInterval(callInterval); } setCallDuration(0); - }, [localStream, peerConnection, callInterval]); + setCurrentCallId(null); + }, [localStream, callInterval]); - // Таймер звонка const startCallTimer = useCallback(() => { const interval = setInterval(() => { setCallDuration(prevDuration => prevDuration + 1); @@ -148,7 +103,6 @@ const ExploreContainer: React.FC = () => { setCallInterval(interval); }, []); - // Воспроизведение аудио потока const playAudio = useCallback((stream: MediaStream) => { const audioElement = document.createElement('audio'); audioElement.srcObject = stream; @@ -159,34 +113,71 @@ const ExploreContainer: React.FC = () => { }); }, []); - return ( - -
-
- - - - -
-
+ const copyPeerId = useCallback(() => { + if (connectionInfo) { + navigator.clipboard.writeText(connectionInfo) + .then(() => { + console.log('Peer ID скопирован в буфер обмена'); + setShowCopyNotification(true); + setTimeout(() => { + setShowCopyNotification(false); + }, 2000); + }) + .catch((err) => { + console.error('Не удалось скопировать Peer ID', err); + }); + } + }, [connectionInfo]); - - -
- Звонок на IP: {callString} - {Math.floor(callDuration / 60)}:{callDuration % 60} - - + return ( + <> + +
+
+ Ваш Peer ID: {connectionInfo} + +
+ {showCopyNotification && ( +
+ Peer ID скопирован +
+ )} +
+ + +
- - - +
+ + {/* Модальное окно для звонка */} + + +
+ {/* Добавляем гифку */} + Monkey with Drone + Peer ID: {currentCallId} + {Math.floor(callDuration / 60)}:{callDuration % 60} + +
+
+
+
+ ); }; -export default ExploreContainer; +export default ExploreContainer; \ No newline at end of file