/** * 主入口文件 * 初始化应用,连接各个模块 * SPA架构:connect视图和call视图在同一页面切换 */ import store from './store.js'; import UIRenderer from './renderer.js'; import { showNotification, randomMeetingId } from './utils.js'; import chatMessage from './chatmessage.js'; import { bindConnectViewEvents, initWebSocket, loadUserSettings } from './connectview.js'; import { createInviteController } from './invite-controller.js'; // 全局变量 let connectionId = ""; // 当前视图状态:'connect' 或 'call'(可用于未来扩展) let currentView = 'connect'; function updateConnectionId(nextConnectionId) { connectionId = nextConnectionId || ''; if (connectionId) { localStorage.setItem('connectionId', connectionId); } } /** * 切换到call视图(创建/加入通话后) * @param {string} connectionId - 连接ID */ async function switchToCallView(connectionId) { const connectView = document.getElementById('connectView'); const callView = document.getElementById('callView'); if (connectView) connectView.classList.add('hidden'); if (callView) callView.classList.remove('hidden'); currentView = 'call'; try { // 初始化渲染器 const renderer = new UIRenderer(store); // 加入通话 await store.joinCall(connectionId); // 设置WebRTC连接 await store.setUp(connectionId); renderer.renderHeaderTitle(); // 绑定DOM事件 bindCallViewDomEvents(); console.log('Video call app initialized successfully'); return true; } catch (error) { console.error('Error initializing app:', error); showNotification('初始化失败,请刷新页面重试', 'error'); return false; } } const inviteController = createInviteController({ store, notify: showNotification, onAcceptConnection: switchToCallView, getCurrentView: () => currentView, getConnectionId: () => connectionId, setConnectionId: updateConnectionId }); /** * 处理加入通话 * @param {string} connectionId - 连接ID */ async function handleJoinCall(connectionId) { showNotification(`正在加入通话 (${connectionId})`); updateConnectionId(connectionId); await switchToCallView(connectionId); } /** * 处理创建通话 */ async function handleCreateCall() { showNotification('正在创建通话...'); //const connectionId = 'conn_' + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); const connectionId = randomMeetingId(); updateConnectionId(connectionId); await switchToCallView(connectionId); } /** * 绑定call视图DOM事件 */ function bindCallViewDomEvents() { // 切换侧边栏 window.toggleSidebar = function () { chatMessage.toggleSidebar(); }; // 切换麦克风 window.toggleMute = function () { const state = store.getState(); const currentState = state.session.localUser.mediaState.audio; store.updateLocalMedia('audio', !currentState); }; // 切换视频 window.toggleVideo = function () { const state = store.getState(); const currentState = state.session.localUser.mediaState.video; store.updateLocalMedia('video', !currentState); }; // 切换本地视频(用于悬停控制) window.toggleLocalVideo = function () { window.toggleVideo(); }; // 切换录屏 window.toggleRecording = function () { const state = store.getState(); const currentState = state.session.localUser.mediaState.recording || false; store.updateLocalMedia('recording', !currentState); // 显示录制状态通知 if (!currentState) { showNotification('开始录制'); } else { showNotification('停止录制'); } }; // 更多选项菜单切换 window.toggleMoreOptions = function () { const menu = document.getElementById('moreOptionsMenu'); if (menu) { menu.classList.toggle('hidden'); } }; // 切换视频分辨率 window.changeResolution = function (width, height) { store.changeResolution(width, height); // 关闭菜单 const menu = document.getElementById('moreOptionsMenu'); if (menu) { menu.classList.add('hidden'); } }; // 结束通话 window.endCall = function () { // 显示确认对话框 document.getElementById('endCallDialog').classList.remove('hidden'); }; // 取消结束通话 window.cancelEndCall = function () { document.getElementById('endCallDialog').classList.add('hidden'); }; // 确认结束通话 window.confirmEndCall = function () { document.getElementById('endCallDialog').classList.add('hidden'); store.endCall(); showNotification('通话已结束'); }; // 绑定消息相关事件 chatMessage.bindMessageEvents(); // 键盘快捷键 document.addEventListener('keydown', (event) => { // 空格键静音 if (event.code === 'Space' && !event.target.matches('input, textarea')) { event.preventDefault(); window.toggleMute(); } // Ctrl+V 切换视频 if (event.ctrlKey && event.key === 'v') { event.preventDefault(); window.toggleVideo(); } }); // 绑定对话框事件 const cancelEndCall = document.getElementById('cancelEndCall'); const confirmEndCall = document.getElementById('confirmEndCall'); if (cancelEndCall) cancelEndCall.addEventListener('click', window.cancelEndCall); if (confirmEndCall) confirmEndCall.addEventListener('click', window.confirmEndCall); // 更多选项按钮事件 const moreOptionsBtn = document.getElementById('moreOptionsBtn'); if (moreOptionsBtn) { moreOptionsBtn.addEventListener('click', window.toggleMoreOptions); } // 点击外部关闭更多选项菜单 document.addEventListener('click', function(event) { const moreOptionsMenu = document.getElementById('moreOptionsMenu'); const moreOptionsBtnEl = document.getElementById('moreOptionsBtn'); if (moreOptionsMenu && moreOptionsBtnEl && !moreOptionsMenu.contains(event.target) && !moreOptionsBtnEl.contains(event.target)) { moreOptionsMenu.classList.add('hidden'); } }); inviteController.bindDialogEvents(); } // 页面加载完成后初始化(SPA入口) window.addEventListener('DOMContentLoaded', async () => { try { // 显示connect视图,隐藏call视图 const connectView = document.getElementById('connectView'); const callView = document.getElementById('callView'); if (connectView) connectView.classList.remove('hidden'); if (callView) callView.classList.add('hidden'); currentView = 'connect'; // 加载用户设置 loadUserSettings(); // 初始化WebSocket连接(在connect视图就建立WebSocket) await initWebSocket(); inviteController.bindSignalHandlers(); // 绑定connect视图事件(加入通话、创建通话等) bindConnectViewEvents(handleJoinCall, handleCreateCall); inviteController.bindDialogEvents(); // 检查是否有保存的连接ID,填入输入框 const savedConnectionId = localStorage.getItem('connectionId'); if (savedConnectionId) { updateConnectionId(savedConnectionId); const connectionIdInput = document.getElementById('connectionIdInput'); if (connectionIdInput) connectionIdInput.value = savedConnectionId; } const invitePayload = inviteController.getInvitePayloadFromUrl(); if (invitePayload) { inviteController.showCallRequestDialog(invitePayload); } console.log('SPA initialized, showing connect view'); } catch (error) { console.error('Error initializing SPA:', error); showNotification('初始化失败,请刷新页面重试', 'error'); } }); // 导出全局变量 export { store };