import React, { useState, useEffect } from 'react'; const ScreenShareModal = ({ onClose, onSelectSource }) => { const [activeTab, setActiveTab] = useState('applications'); // applications | screens | devices const [sources, setSources] = useState([]); const [loading, setLoading] = useState(true); const [shareAudio, setShareAudio] = useState(true); useEffect(() => { loadSources(); }, []); const loadSources = async () => { setLoading(true); try { // Get screen/window sources from Electron const desktopSources = await window.cryptoAPI.getScreenSources(); // Get video input devices (webcams) const devices = await navigator.mediaDevices.enumerateDevices(); const videoDevices = devices.filter(d => d.kind === 'videoinput'); // Categorize const apps = desktopSources.filter(s => s.id.startsWith('window')); const screens = desktopSources.filter(s => s.id.startsWith('screen')); const formattedDevices = videoDevices.map(d => ({ id: d.deviceId, name: d.label || `Camera ${d.deviceId.substring(0, 4)}...`, isDevice: true, thumbnail: null // Devices don't have static thumbnails easily referencable without opening stream })); setSources({ applications: apps, screens: screens, devices: formattedDevices }); } catch (err) { console.error("Failed to load sources:", err); } finally { setLoading(false); } }; const handleSelect = (source) => { // If device, pass constraints differently (webcams don't have loopback audio) if (source.isDevice) { onSelectSource({ deviceId: source.id, type: 'device', shareAudio: false }); } else { onSelectSource({ sourceId: source.id, type: 'screen', shareAudio }); } onClose(); }; const renderGrid = (items) => { if (!items || items.length === 0) return