// UI Controls Module // Handles UI toggle functions, keyboard shortcuts, notifications, and DOM utilities (function() { 'use strict'; AppModules.require('api'); AppModules.register('ui-controls'); // Toast notification system function showToast(message, duration = AppConfig.ui.toastDuration) { const toast = document.getElementById('toast'); if (!toast) return; toast.textContent = message; toast.classList.add('show'); if (duration > 0) { setTimeout(() => { toast.classList.remove('show'); }, duration); } } function hideToast() { const toast = document.getElementById('toast'); if (toast) { toast.classList.remove('show'); } } // Notification badge management function updateNotificationBadge() { const badge = document.getElementById('notificationBadge'); if (badge) { if (AppState.unreadCount > 0) { badge.textContent = AppState.unreadCount > 99 ? '99+' : AppState.unreadCount; badge.classList.add('show'); } else { badge.classList.remove('show'); } } } // Chat toggle functionality function toggleChat() { const chatSection = document.getElementById('chatSection'); const videoSection = document.getElementById('videoSection'); const toggleBtn = document.getElementById('chatToggleText'); if (!chatSection || !videoSection || !toggleBtn) return; AppState.chatCollapsed = !AppState.chatCollapsed; if (AppState.chatCollapsed) { chatSection.classList.add('collapsed'); videoSection.classList.add('expanded'); toggleBtn.textContent = 'Show Chat'; } else { chatSection.classList.remove('collapsed'); videoSection.classList.remove('expanded'); toggleBtn.textContent = 'Hide Chat'; // Clear unread count when reopening AppState.unreadCount = 0; updateNotificationBadge(); } } // Viewer count update function updateViewerCount(count) { const viewerElement = document.getElementById('viewerCount'); if (viewerElement) { viewerElement.textContent = count + (count === 1 ? ' viewer' : ' viewers'); } } // Connection status dot function updateConnectionStatus(online) { const statusDot = document.getElementById('statusDot'); const statusText = document.getElementById('statusText'); if (statusDot && statusText) { if (online) { statusDot.classList.remove('offline'); statusText.textContent = 'Connected'; } else { statusDot.classList.add('offline'); statusText.textContent = 'Reconnecting...'; } } } // Keyboard shortcuts handler function handleKeyboardShortcuts(event) { // Skip if typing in input field if (event.target.matches('input, textarea')) { return; } switch (event.key) { case 'c': case 'C': // Toggle chat event.preventDefault(); toggleChat(); break; case 'f': case 'F': // Toggle fullscreen event.preventDefault(); toggleFullscreen(); break; case '/': // Focus chat input event.preventDefault(); const messageInput = document.getElementById('messageInput'); if (messageInput) { messageInput.focus(); } break; case 'p': case 'P': // Toggle picture-in-picture event.preventDefault(); togglePictureInPicture(); break; } } // Fullscreen functionality function toggleFullscreen() { if (!AppState.player) return; if (AppState.player.isFullscreen()) { AppState.player.exitFullscreen(); } else { AppState.player.requestFullscreen(); } } // Picture-in-picture functionality function togglePictureInPicture() { const video = document.getElementById('video-player'); if (!video || !video.requestPictureInPicture) return; if (document.pictureInPictureElement) { document.exitPictureInPicture(); } else { video.requestPictureInPicture(); } } // Sound notification for new messages function playNotificationSound() { if (!AppState.soundEnabled || !document.hidden) return; try { const audioContext = new (window.AudioContext || window.webkitAudioContext)(); const oscillator = audioContext.createOscillator(); const gainNode = audioContext.createGain(); oscillator.connect(gainNode); gainNode.connect(audioContext.destination); oscillator.frequency.value = 800; oscillator.type = 'sine'; gainNode.gain.value = 0.1; oscillator.start(audioContext.currentTime); oscillator.stop(audioContext.currentTime + 0.1); } catch(e) { AppLogger.log('Audio notification failed:', e); } } // Mobile responsive behavior function handleWindowResize() { const isMobile = window.innerWidth <= AppConfig.ui.mobileBreakpoint; if (isMobile && !AppState.chatCollapsed) { // Auto-collapse chat on mobile for better viewing toggleChat(); } } // Page visibility API handler function handleVisibilityChange() { if (!document.hidden && !AppState.chatCollapsed) { // Clear unread count when page becomes visible AppState.unreadCount = 0; updateNotificationBadge(); } } // DOM utility functions const DOMUtils = { // Add event listener with proper cleanup tracking addEvent: function(element, event, handler) { if (!element) return; element.addEventListener(event, handler); // Store handler for potential cleanup if (!element._handlers) { element._handlers = new Map(); } if (!element._handlers.has(event)) { element._handlers.set(event, []); } element._handlers.get(event).push(handler); }, // Remove event listeners (for cleanup) removeEvent: function(element, event, handler) { if (!element || !element._handlers || !element._handlers.has(event)) return; const handlers = element._handlers.get(event); const index = handlers.indexOf(handler); if (index > -1) { handlers.splice(index, 1); element.removeEventListener(event, handler); } }, // Get element with optional error logging getElement: function(id, required = false) { const element = document.getElementById(id); if (required && !element) { AppLogger.error(`Required element with id '${id}' not found`); } return element; }, // Add/remove classes safely addClass: function(element, className) { if (element) element.classList.add(className); }, removeClass: function(element, className) { if (element) element.classList.remove(className); }, toggleClass: function(element, className) { if (element) element.classList.toggle(className); } }; // Initialize event listeners function initializeEventListeners() { // Keyboard shortcuts DOMUtils.addEvent(document, 'keydown', handleKeyboardShortcuts); // Window resize for mobile responsiveness DOMUtils.addEvent(window, 'resize', handleWindowResize); // Page visibility for notification clearing DOMUtils.addEvent(document, 'visibilitychange', handleVisibilityChange); AppLogger.log('UI controls event listeners initialized'); } // Public API window.UIControls = { showToast: showToast, hideToast: hideToast, toggleChat: toggleChat, toggleFullscreen: toggleFullscreen, togglePictureInPicture: togglePictureInPicture, updateViewerCount: updateViewerCount, updateConnectionStatus: updateConnectionStatus, updateNotificationBadge: updateNotificationBadge, playNotificationSound: playNotificationSound, DOMUtils: DOMUtils }; // Initialize when DOM is ready document.addEventListener('DOMContentLoaded', initializeEventListeners); AppLogger.log('UI Controls module loaded'); })();