iptv-stream-web/assets/js/ui-controls.js

293 lines
9.6 KiB
JavaScript

// 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;
const isMobile = window.innerWidth <= AppConfig.ui.mobileBreakpoint;
AppState.chatCollapsed = !AppState.chatCollapsed;
if (AppState.chatCollapsed) {
if (isMobile) {
chatSection.classList.remove('mobile-visible');
toggleBtn.textContent = 'Show Chat';
} else {
chatSection.classList.add('collapsed');
videoSection.classList.add('expanded');
toggleBtn.textContent = 'Show Chat';
}
} else {
if (isMobile) {
chatSection.classList.add('mobile-visible');
toggleBtn.textContent = 'Hide 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');
})();