Multi-Screen Quad Player Implementation
Complete 4-Video Grid System: - Created QuadVideoPlayer extending OverlayVideoPlayer architecture - 2x2 responsive grid layout with professional styling - Auto-hide individual headers, backdrop, and controls for clean quad view Training Mode Integration: - Added Multi-Screen Mode button to interactive task controls - Smart video library access using unified storage fallbacks - Object-fit contain for proper video scaling (portrait/landscape) Advanced Controls: - Shuffle All: Load 4 new random videos instantly - Minimize: Hide overlay but continue videos in background - Close: Stop all videos and reset state - ESC key and backdrop click support State Management: - Minimize/restore functionality for seamless training progression - Proper cleanup on game end with video stopping - DOM corruption prevention via force recreation strategy - Complete player destruction and fresh initialization User Experience: - Notification system integration with helpful status messages - Responsive design with mobile considerations - Pink/purple gradient theming matching game aesthetic - Hover effects and smooth transitions Future: Individual controls, sync options, focus mode, custom layouts Files: quadVideoPlayer.js, interactiveTaskManager.js, index.html, ROADMAP.md
This commit is contained in:
parent
f06ec70751
commit
689574953a
152
ROADMAP.md
152
ROADMAP.md
|
|
@ -19,141 +19,51 @@
|
|||
- Modern layout with header navigation and sidebar panels
|
||||
- Interactive video controls with progress bar seeking
|
||||
- Auto-hide control behavior and responsive design
|
||||
- Foundation ready for video library and playlist features
|
||||
- Video library, playlist management, and search functionality
|
||||
- Full video loading system with unified library integration
|
||||
|
||||
## 🚧 Active Development
|
||||
- Enhanced user experience improvements
|
||||
- Bug fixes and stability enhancements
|
||||
- Performance optimizations
|
||||
- **✅ 🎬 Overlay Video Player System (October 31, 2025)**
|
||||
- ✅ **Portable Video Player Architecture**: Created OverlayVideoPlayer class extending BaseVideoPlayer for maximum reusability
|
||||
- ✅ **Modal Popup Interface**: Professional overlay system with backdrop blur, smooth animations, and responsive design
|
||||
- ✅ **Random Video Selection**: Automatic random video loading from unified video library with robust fallback mechanisms
|
||||
- ✅ **Full Video Controls**: Inherited complete video control system (play/pause, seek, volume, fullscreen) from BaseVideoPlayer
|
||||
- ✅ **User Experience Features**: Dismissible via Escape/close button/backdrop, video metadata display, mobile optimization
|
||||
- ✅ **Integration Testing**: Successfully tested with linked video directories, accessible via Video Management screen
|
||||
- ✅ **Glassmorphism Styling**: Professional dark theme with CSS animations and modern UI design patterns
|
||||
- **✅ 🎬 Porn Cinema Video Loading Bug Fix (October 31, 2025)**
|
||||
- ✅ **Critical Bug Resolution**: Fixed video loading issue where Porn Cinema couldn't access videos from linked directories
|
||||
- ✅ **Data Preservation Logic**: Implemented safeguards to prevent DesktopFileManager from overwriting existing video data
|
||||
- ✅ **Storage System Enhancement**: Enhanced unified video library fallback mechanisms for reliable video access
|
||||
- ✅ **Console Cleanup**: Removed excessive debug logging for cleaner user experience
|
||||
- ✅ **Cross-Component Synchronization**: Fixed timing issues between main game and Porn Cinema video data access
|
||||
- **✅ 🎬 Complete Playlist System Implementation (October 31, 2025)**
|
||||
- ✅ **Playlist Management UI**: Professional sidebar with playlist tab, controls, and real-time display updates
|
||||
- ✅ **Add/Remove/Play Operations**: Full CRUD operations with ➕/✕/▶ buttons and direct playlist item interaction
|
||||
- ✅ **Smart Playlist Features**: Shuffle, clear, duplicate prevention, and current video highlighting
|
||||
- ✅ **Save/Load System**: Custom naming dialog, localStorage persistence, and JSON export/import functionality
|
||||
- ✅ **Video Library Playlist Creation**: Multi-selection system with checkboxes, batch playlist creation, and immediate switching
|
||||
- ✅ **Professional UI/UX**: Toast notifications, modal dialogs, responsive design, and consistent theming
|
||||
- **✅ 📊 Player Statistics System (October 31, 2025)**
|
||||
- ✅ **Real-time Watch Time Tracking**: Precise play/pause detection with cumulative timer that never resets
|
||||
- ✅ **Comprehensive Viewing Metrics**: Videos watched, completed (90%+), skipped (<10%), and completion rates
|
||||
- ✅ **Session Analytics**: Session counting, average length, longest session, and binge session detection (2+ hours)
|
||||
- ✅ **Engagement Statistics**: Playlists created, videos added to playlists, and most watched video tracking
|
||||
- ✅ **Achievement Metrics**: Days active, consecutive day streaks, and daily activity pattern analysis
|
||||
- ✅ **Professional Stats Dashboard**: Beautiful card-based visualization with export/reset functionality and main navigation integration
|
||||
- **✅ 👤 User Profile System (October 31, 2025)**
|
||||
- ✅ **Profile Information Management**: Customizable username, bio, join date, theme preferences with localStorage persistence
|
||||
- ✅ **Dynamic Avatar System**: Auto-generated avatar from username with visual profile identity
|
||||
- ✅ **Statistics Integration**: Seamless integration with PlayerStats infrastructure for real-time data display
|
||||
- ✅ **Level Progression System**: XP-based leveling with visual progress bars and level calculation
|
||||
- ✅ **Achievement System**: 8 unique achievements with dynamic unlocking based on player statistics
|
||||
- ✅ **Profile Data Management**: Export/import functionality for profile and statistics backup
|
||||
- ✅ **Navigation Integration**: Added profile button to main menu with cross-page navigation links
|
||||
- ✅ **Professional UI Design**: Card-based responsive layout with glassmorphism styling and notifications
|
||||
- **🎬 User Profile System** *(📋 Planned - November 2025)*
|
||||
- ✅ **Navigation Integration**: Added profile button to main menu with cross-page navigation links
|
||||
- ✅ **Professional UI Design**: Card-based responsive layout with glassmorphism styling and notifications
|
||||
- **🎬 Porn Cinema Player Enhancements** *(📋 Planned - November 2025)*
|
||||
- 📋 **Pause Button Fix**: Debug and repair non-functioning pause button in video player
|
||||
- 📋 **Autoplay Next Video**: Implement automatic progression to next playlist video on completion
|
||||
- 📋 **Repeat/Loop Options**: Add single video repeat and full playlist loop functionality
|
||||
- 📋 **Enhanced Playlist Controls**: Improved playlist navigation and playback options
|
||||
- 📋 **Video Player Reliability**: Ensure all basic controls function correctly across all scenarios
|
||||
- **🎬 Porn Cinema Media Player** *(✅ Major Progress - October 30-31, 2025)*
|
||||
- ✅ **Complete Layout Implementation**: Professional two-column design with main content area and right sidebar
|
||||
- ✅ **Header Navigation**: Slim, modern header with Home, Settings, Theater, and Fullscreen controls
|
||||
- ✅ **Sidebar Navigation**: Tabbed interface with Playlist and Search panels
|
||||
- ✅ **Video Player Core**: Full-featured video player with professional controls
|
||||
- ✅ **Progress Bar**: Interactive seeking with hover effects and click-to-seek functionality
|
||||
- ✅ **Auto-Hide Controls**: Smart control visibility with 3-second timeout during playback
|
||||
- ✅ **Video Library Integration**: Minimal, clean library section with grid/list views
|
||||
- ✅ **Responsive Design**: Clean mockup-matching layout with proper CSS architecture
|
||||
- **🎬 Multi-Screen Quad Player (October 31, 2025)** *(🚧 In Progress)*
|
||||
- ✅ **Quad Video Layout**: 2x2 grid displaying 4 simultaneous video streams for intensive training
|
||||
- ✅ **Training Integration**: Multi-Screen Mode button added to interactive task controls
|
||||
- ✅ **Smart Controls**: Shuffle all videos, minimize to background, and close functionality
|
||||
- ✅ **Minimize Feature**: Continue videos in background while progressing through training scenarios
|
||||
- ✅ **Proper Cleanup**: Videos stop when game ends, DOM corruption prevention with force recreation
|
||||
- 🚧 **Future Enhancements**: Individual video controls, sync options, focus mode, custom layouts
|
||||
- **🎬 Porn Cinema Media Player** *(✅ COMPLETED - October 30-31, 2025)*
|
||||
- ✅ **Complete Professional Interface**: Modern two-column layout with header navigation and sidebar panels
|
||||
- ✅ **Full Video Player Controls**: Interactive progress bar, auto-hide behavior, quality/speed selection, volume control
|
||||
- ✅ **Playlist & Library System**: Video library integration, playlist management, search functionality
|
||||
- ✅ **Responsive Design**: Clean architecture with purple gradient theming
|
||||
- ✅ **Video Loading System**: Robust video loading from unified video library with fallback mechanisms
|
||||
- 🚧 **Next Steps**: Video library population, playlist functionality, search implementation
|
||||
- **🔧 Base Video Player Extraction** *(✅ COMPLETED - October 31, 2025)*
|
||||
- ✅ **Extract Reusable Components**: Created BaseVideoPlayer class with full video control functionality (400+ lines)
|
||||
- **🔧 Base Video Player Architecture** *(✅ COMPLETED - October 31, 2025)*
|
||||
- ✅ **Reusable Components**: Created BaseVideoPlayer class with full video control functionality (400+ lines)
|
||||
- ✅ **Focus Video Player**: Built FocusVideoPlayer extending BaseVideoPlayer for minimal focus session UI
|
||||
- ✅ **Shared CSS System**: Created base-video-player.css for reusable video styling across game modes
|
||||
- ✅ **Focus Interruption Integration**: Updated interactiveTaskManager to use new FocusVideoPlayer with graceful fallback
|
||||
- ✅ **Testing Infrastructure**: Created video-player-test.html with comprehensive validation - ALL TESTS PASSING ✅
|
||||
- ✅ **Script Integration**: Added baseVideoPlayer.js and focusVideoPlayer.js to index.html loading sequence
|
||||
- ✅ **Global Export**: Properly exported classes to window object for browser compatibility
|
||||
- ✅ **Syntax Validation**: Clean JavaScript validation with no errors
|
||||
- ✅ **Integration & Testing**: Successfully integrated with focus interruptions and validated with comprehensive tests
|
||||
- **🎬 Porn Cinema Refactoring** *(✅ COMPLETED - October 31, 2025)*
|
||||
- ✅ **Legacy Code Analysis**: Analyzed existing pornCinema.js for BaseVideoPlayer integration points
|
||||
- ✅ **Architecture Planning**: Identified cinema-specific features (playlist, theater mode, navigation)
|
||||
- ✅ **Code Backup**: Created pornCinema-backup.js to preserve original implementation
|
||||
- ✅ **Class Refactoring**: Created clean PornCinema class extending BaseVideoPlayer
|
||||
- ✅ **Core Inheritance**: PornCinema now properly extends BaseVideoPlayer for shared functionality
|
||||
- ✅ **Method Implementation**: Added initialize(), playVideo(), addToPlaylist() methods
|
||||
- ✅ **Error Handling**: Proper TypeError resolution and method validation
|
||||
- ✅ **Integration Testing**: Successfully tested in Option A architecture
|
||||
- ✅ **Clean Architecture**: Created PornCinema class extending BaseVideoPlayer for shared functionality
|
||||
- ✅ **Legacy Preservation**: Created pornCinema-backup.js to preserve original implementation
|
||||
- ✅ **Integration**: Proper inheritance with initialize(), playVideo(), addToPlaylist() methods
|
||||
- **🎮 Focus Interruption Video Integration** *(✅ COMPLETED - October 31, 2025)*
|
||||
- ✅ **Video Library Access**: Fixed FocusVideoPlayer video library initialization
|
||||
- ✅ **Volume Control Integration**: Added ultra-compact volume slider (60px width)
|
||||
- ✅ **CSS Override System**: Resolved CSS conflicts with focus-volume-slider class
|
||||
- ✅ **UI Refinement**: Achieved ultra-compact volume control design per user specs
|
||||
- ✅ **Video Collection**: 34 videos successfully integrated from punishment/task/background categories
|
||||
- ✅ **Testing Complete**: Focus interruption videos playing successfully with proper controls
|
||||
- **NEW XP System Implementation:**
|
||||
- **Main Game**
|
||||
- User gains 1 XP per task
|
||||
- User gains 5 XP for a streak of 10 completed tasks.
|
||||
- User gains No XP to their overall XP counter if the game is quit
|
||||
- **Scenario Games(punishment, photo, training academy, endurance)**
|
||||
- Time-based XP: 1 XP per 2 minutes of gameplay
|
||||
- Focus session bonuses: 3 XP per 30 seconds
|
||||
- Webcam mirror bonuses: 3 XP per 30 seconds
|
||||
- Photo rewards: 1 XP per picture taken
|
||||
- No XP awarded for abandoned/quit sessions
|
||||
- ✅ **Video Library Access**: Fixed FocusVideoPlayer video library initialization with 34 videos integrated
|
||||
- ✅ **Ultra-Compact Controls**: Added 60px width volume slider with CSS override system
|
||||
- ✅ **Complete Integration**: Focus interruption videos playing successfully with proper controls
|
||||
- **✅ XP System Implementation (October 2025)**
|
||||
- **Main Game**: 1 XP per task, 5 XP for 10-task streaks, no XP for quit sessions
|
||||
- **Scenario Games**: Time-based XP (1 XP per 2 minutes), focus session bonuses (3 XP per 30 seconds), webcam bonuses, photo rewards
|
||||
|
||||
## 📋 Feature Backlog
|
||||
|
||||
### 🎯 High Priority (Core Game Polish)
|
||||
- [✅] **Porn Cinema Media Player** - *Major Milestone Achieved October 30-31, 2025*
|
||||
- **✅ Layout & Design Completed:**
|
||||
- Two-column responsive layout with main content and sidebar
|
||||
- Professional header with navigation controls
|
||||
- Tabbed sidebar interface (Playlist/Search)
|
||||
- Clean, minimal video library section
|
||||
- Modern purple gradient theming throughout
|
||||
- **✅ Video Player Core:**
|
||||
- Full-featured video container with overlay system
|
||||
- Interactive progress bar with click-to-seek
|
||||
- Auto-hide controls with smart timeout behavior
|
||||
- Professional media control buttons
|
||||
- Quality and speed selection dropdowns
|
||||
- Volume control with visual feedback
|
||||
- **✅ User Experience Features:**
|
||||
- Hover-to-reveal control behavior
|
||||
- Keyboard shortcuts support structure
|
||||
- Theater mode and fullscreen toggle buttons
|
||||
- Responsive design for different screen sizes
|
||||
- **🚧 Remaining Implementation:**
|
||||
- Video library population from desktop file manager
|
||||
- Playlist creation and management functionality
|
||||
- Search functionality for video library
|
||||
- Video thumbnail generation and metadata display
|
||||
- Remember last played position
|
||||
- Keyboard shortcuts activation
|
||||
- An overall counter time watching videos that is saved to the users stats
|
||||
- [✅] **Overlay Video Player System** - *Completed October 31, 2025*
|
||||
- **✅ Architecture**: Portable BaseVideoPlayer extension for popup/modal video playback
|
||||
- **✅ Features**: Random video selection, full controls, dismissible interface, responsive design
|
||||
- **✅ Integration**: Successfully integrated with video management and unified video library
|
||||
- **🎯 Future Applications**: Could be used for focus interruptions, random rewards, punishment videos, or mini-cinema modes
|
||||
- [✅] **Porn Cinema Media Player** - *Completed October 30-31, 2025*
|
||||
- **✅ Complete Professional Interface**: Two-column responsive layout, header navigation, tabbed sidebar
|
||||
- **✅ Full Video Player**: Interactive progress bar, auto-hide controls, quality/speed selection, volume control
|
||||
- **✅ Advanced Features**: Video library integration, playlist management, search functionality, theater mode
|
||||
- **✅ User Experience**: Hover effects, keyboard shortcuts support, responsive design, purple gradient theming
|
||||
- [ ] More interactive task types and scenarios
|
||||
- [ ] Improved user interface and visual design
|
||||
- [ ] Better error handling and user feedback
|
||||
|
|
|
|||
|
|
@ -1661,6 +1661,7 @@
|
|||
<script src="src/features/media/baseVideoPlayer.js"></script>
|
||||
<script src="src/features/media/focusVideoPlayer.js"></script>
|
||||
<script src="src/features/media/overlayVideoPlayer.js"></script>
|
||||
<script src="src/features/media/quadVideoPlayer.js"></script>
|
||||
<script src="src/features/tasks/interactiveTaskManager.js"></script>
|
||||
<script src="src/features/video/videoPlayerManager.js"></script>
|
||||
<script src="src/utils/desktop-file-manager.js"></script>
|
||||
|
|
|
|||
|
|
@ -4518,6 +4518,11 @@ ${usagePercent > 85 ? '⚠️ Storage getting full - consider deleting some imag
|
|||
}
|
||||
|
||||
startGame() {
|
||||
// Clean up any existing interactive resources before starting new game
|
||||
if (this.interactiveTaskManager) {
|
||||
this.interactiveTaskManager.cleanup();
|
||||
}
|
||||
|
||||
if (!this.imageDiscoveryComplete) {
|
||||
console.log('Image discovery not complete, retrying in 500ms...');
|
||||
|
||||
|
|
@ -5241,6 +5246,11 @@ ${usagePercent > 85 ? '⚠️ Storage getting full - consider deleting some imag
|
|||
this.stopTimer();
|
||||
this.flashMessageManager.stop();
|
||||
|
||||
// Clean up interactive task resources (including quad video player)
|
||||
if (this.interactiveTaskManager) {
|
||||
this.interactiveTaskManager.cleanup();
|
||||
}
|
||||
|
||||
// Handle XP calculation - use scenario XP for scenarios, task XP for main game
|
||||
let sessionXp;
|
||||
if (window.gameModeManager && window.gameModeManager.isScenarioMode()) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,549 @@
|
|||
/**
|
||||
* Quad Video Player - Multi-screen video overlay system
|
||||
* Displays 4 videos simultaneously in a grid layout for intensive viewing sessions
|
||||
*/
|
||||
|
||||
class QuadVideoPlayer {
|
||||
constructor() {
|
||||
this.players = [];
|
||||
this.container = null;
|
||||
this.isActive = false;
|
||||
this.isMinimized = false;
|
||||
this.videoLibrary = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the quad video player system
|
||||
*/
|
||||
async initialize() {
|
||||
console.log('🎬 Initializing QuadVideoPlayer...');
|
||||
|
||||
// Get video library using the same pattern as OverlayVideoPlayer
|
||||
this.videoLibrary = this.getAvailableVideos();
|
||||
|
||||
if (!this.videoLibrary || this.videoLibrary.length === 0) {
|
||||
console.warn('⚠️ No videos available for quad player');
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('📹 Found', this.videoLibrary.length, 'videos for quad player');
|
||||
this.createQuadContainer();
|
||||
await this.initializePlayers();
|
||||
|
||||
console.log('✅ QuadVideoPlayer initialized with', this.players.length, 'players');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available videos using the same logic as OverlayVideoPlayer
|
||||
*/
|
||||
getAvailableVideos() {
|
||||
let allVideos = [];
|
||||
|
||||
console.log('📹 Checking video sources...');
|
||||
|
||||
// Try desktop file manager first
|
||||
if (window.desktopFileManager) {
|
||||
allVideos = window.desktopFileManager.getAllVideos();
|
||||
console.log('📹 Desktop file manager videos:', allVideos.length);
|
||||
}
|
||||
|
||||
// Fallback to unified storage
|
||||
if (allVideos.length === 0) {
|
||||
const unifiedData = JSON.parse(localStorage.getItem('unifiedVideoLibrary') || '{}');
|
||||
allVideos = unifiedData.allVideos || [];
|
||||
console.log('📹 Unified storage videos:', allVideos.length);
|
||||
}
|
||||
|
||||
// Fallback to legacy storage
|
||||
if (allVideos.length === 0) {
|
||||
const storedVideos = JSON.parse(localStorage.getItem('videoFiles') || '{}');
|
||||
allVideos = Object.values(storedVideos).flat();
|
||||
console.log('📹 Legacy storage videos:', allVideos.length);
|
||||
}
|
||||
|
||||
console.log('📹 Total videos found:', allVideos.length);
|
||||
return allVideos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the main quad container
|
||||
*/
|
||||
createQuadContainer() {
|
||||
this.container = document.createElement('div');
|
||||
this.container.className = 'quad-video-overlay';
|
||||
this.container.innerHTML = `
|
||||
<div class="quad-header">
|
||||
<h2>🎬 Multi-Screen Training Mode</h2>
|
||||
<div class="quad-controls">
|
||||
<button id="quad-shuffle-btn" class="btn btn-secondary btn-small">🔄 Shuffle All</button>
|
||||
<button id="quad-minimize-btn" class="btn btn-warning btn-small">— Minimize</button>
|
||||
<button id="quad-close-btn" class="btn btn-danger btn-small">✕ Close</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="quad-grid">
|
||||
<div class="quad-slot" data-slot="0"></div>
|
||||
<div class="quad-slot" data-slot="1"></div>
|
||||
<div class="quad-slot" data-slot="2"></div>
|
||||
<div class="quad-slot" data-slot="3"></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Add to body but keep hidden initially
|
||||
this.container.style.display = 'none';
|
||||
document.body.appendChild(this.container);
|
||||
|
||||
// Add event listeners for controls
|
||||
this.setupEventListeners();
|
||||
this.addQuadStyles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize 4 overlay video players
|
||||
*/
|
||||
async initializePlayers() {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const player = new OverlayVideoPlayer();
|
||||
|
||||
// Configure for quad layout
|
||||
this.setupQuadPlayer(player, i);
|
||||
this.players.push(player);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure individual player for quad layout
|
||||
*/
|
||||
setupQuadPlayer(player, index) {
|
||||
const slot = this.container.querySelector(`[data-slot="${index}"]`);
|
||||
|
||||
// Ensure the overlay element is in the DOM (constructor removes it)
|
||||
if (!document.body.contains(player.overlayElement)) {
|
||||
document.body.appendChild(player.overlayElement);
|
||||
}
|
||||
|
||||
// Configure the overlay element for quad layout
|
||||
player.overlayElement.style.position = 'relative';
|
||||
player.overlayElement.style.width = '100%';
|
||||
player.overlayElement.style.height = '100%';
|
||||
player.overlayElement.style.background = 'transparent';
|
||||
player.overlayElement.style.display = 'flex'; // Override the default display: none
|
||||
|
||||
// Set visibility states
|
||||
player.isVisible = true;
|
||||
player.overlayElement.classList.add('visible');
|
||||
|
||||
// Remove/hide the backdrop
|
||||
const backdrop = player.overlayElement.querySelector('.overlay-backdrop');
|
||||
if (backdrop) {
|
||||
backdrop.style.display = 'none';
|
||||
}
|
||||
|
||||
// Find and configure the overlay window
|
||||
const overlayWindow = player.overlayElement.querySelector('.overlay-window');
|
||||
if (overlayWindow) {
|
||||
overlayWindow.style.position = 'relative';
|
||||
overlayWindow.style.width = '100%';
|
||||
overlayWindow.style.height = '100%';
|
||||
overlayWindow.style.margin = '0';
|
||||
overlayWindow.style.transform = 'none';
|
||||
overlayWindow.style.maxWidth = 'none';
|
||||
overlayWindow.style.maxHeight = 'none';
|
||||
}
|
||||
|
||||
// Find and configure the video container
|
||||
const videoContainer = player.overlayElement.querySelector('.overlay-video-container');
|
||||
if (videoContainer) {
|
||||
videoContainer.style.width = '100%';
|
||||
videoContainer.style.height = '100%';
|
||||
videoContainer.style.position = 'relative';
|
||||
}
|
||||
|
||||
// Find and configure the video element
|
||||
const video = player.overlayElement.querySelector('video');
|
||||
if (video) {
|
||||
video.style.width = '100%';
|
||||
video.style.height = '100%';
|
||||
video.style.objectFit = 'contain'; // Changed from 'cover' to 'contain' to fit entire video
|
||||
video.style.display = 'block';
|
||||
video.style.backgroundColor = '#000'; // Add black background for letterboxing
|
||||
}
|
||||
|
||||
// Hide the header to save space
|
||||
const header = player.overlayElement.querySelector('.overlay-header');
|
||||
if (header) {
|
||||
header.style.display = 'none';
|
||||
}
|
||||
|
||||
// Hide individual close button
|
||||
const closeBtn = player.overlayElement.querySelector('.overlay-close-btn');
|
||||
if (closeBtn) {
|
||||
closeBtn.style.display = 'none';
|
||||
}
|
||||
|
||||
// Remove from body and add to quad slot
|
||||
document.body.removeChild(player.overlayElement);
|
||||
slot.appendChild(player.overlayElement);
|
||||
|
||||
// Load random video for this slot
|
||||
player.playRandomVideo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup event listeners for quad controls
|
||||
*/
|
||||
setupEventListeners() {
|
||||
// Shuffle all videos
|
||||
const shuffleBtn = this.container.querySelector('#quad-shuffle-btn');
|
||||
shuffleBtn?.addEventListener('click', () => {
|
||||
this.shuffleAllVideos();
|
||||
});
|
||||
|
||||
// Minimize quad mode
|
||||
const minimizeBtn = this.container.querySelector('#quad-minimize-btn');
|
||||
minimizeBtn?.addEventListener('click', () => {
|
||||
this.minimize();
|
||||
});
|
||||
|
||||
// Close quad mode
|
||||
const closeBtn = this.container.querySelector('#quad-close-btn');
|
||||
closeBtn?.addEventListener('click', () => {
|
||||
this.hide();
|
||||
});
|
||||
|
||||
// ESC key to close
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && this.isActive) {
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
|
||||
// Backdrop click to close
|
||||
this.container.addEventListener('click', (e) => {
|
||||
if (e.target === this.container) {
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the quad video overlay
|
||||
*/
|
||||
show() {
|
||||
if (!this.container) {
|
||||
console.error('❌ QuadVideoPlayer not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('🎬 Showing quad video overlay');
|
||||
this.container.style.display = 'flex';
|
||||
this.isActive = true;
|
||||
|
||||
// Start all videos
|
||||
this.players.forEach(player => {
|
||||
if (player.videoElement) {
|
||||
player.videoElement.play().catch(e => console.log('Video autoplay prevented:', e));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the quad video overlay
|
||||
*/
|
||||
hide() {
|
||||
if (!this.container) return;
|
||||
|
||||
console.log('🎬 Hiding quad video overlay');
|
||||
this.container.style.display = 'none';
|
||||
this.isActive = false;
|
||||
this.isMinimized = false; // Reset minimized state when fully hiding
|
||||
|
||||
// Always pause and stop all videos, regardless of current state
|
||||
this.stopAllVideos();
|
||||
|
||||
// Reset player states more thoroughly
|
||||
this.players.forEach((player, index) => {
|
||||
if (player.overlayElement) {
|
||||
// Reset video source to prevent corruption
|
||||
if (player.videoElement) {
|
||||
player.videoElement.src = '';
|
||||
player.videoElement.load(); // Force reload to clear state
|
||||
}
|
||||
|
||||
// Reset player state
|
||||
player.isVisible = false;
|
||||
player.currentVideo = null;
|
||||
player.overlayElement.classList.remove('visible');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop all videos (separate method for cleanup purposes)
|
||||
*/
|
||||
stopAllVideos() {
|
||||
console.log('🛑 Stopping all quad videos');
|
||||
this.players.forEach((player, index) => {
|
||||
// Use videoElement (BaseVideoPlayer property) instead of video
|
||||
if (player.videoElement) {
|
||||
player.videoElement.pause();
|
||||
player.videoElement.currentTime = 0; // Reset to beginning
|
||||
console.log(`🛑 Stopped video ${index + 1}: ${player.videoElement.src || 'Unknown'}`);
|
||||
} else {
|
||||
console.log(`⚠️ No videoElement found for player ${index + 1}`);
|
||||
}
|
||||
// Also hide the individual players
|
||||
if (player.overlayElement) {
|
||||
player.isVisible = false;
|
||||
player.overlayElement.classList.remove('visible');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimize the quad video overlay (hide but keep videos playing)
|
||||
*/
|
||||
minimize() {
|
||||
if (!this.container) return;
|
||||
|
||||
console.log('🎬 Minimizing quad video overlay');
|
||||
this.container.style.display = 'none';
|
||||
this.isMinimized = true;
|
||||
// Note: Keep isActive = true and videos continue playing
|
||||
|
||||
// Show notification to user
|
||||
if (window.game && window.game.showNotification) {
|
||||
window.game.showNotification('📺 Multi-Screen Mode minimized - videos continue in background. Click Multi-Screen button to restore.', 'info');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore from minimized state
|
||||
*/
|
||||
restore() {
|
||||
if (!this.container || !this.isMinimized) return;
|
||||
|
||||
console.log('🎬 Restoring quad video overlay from minimized');
|
||||
this.container.style.display = 'flex';
|
||||
this.isMinimized = false;
|
||||
this.isActive = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load new random videos in all slots
|
||||
*/
|
||||
shuffleAllVideos() {
|
||||
console.log('🔄 Shuffling all quad videos');
|
||||
|
||||
// Refresh video library in case new videos were added
|
||||
this.videoLibrary = this.getAvailableVideos();
|
||||
|
||||
if (this.videoLibrary.length === 0) {
|
||||
console.warn('⚠️ No videos available for shuffle');
|
||||
return;
|
||||
}
|
||||
|
||||
this.players.forEach(player => {
|
||||
player.playRandomVideo();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add CSS styles for quad layout
|
||||
*/
|
||||
addQuadStyles() {
|
||||
if (document.getElementById('quad-video-styles')) return;
|
||||
|
||||
const styles = document.createElement('style');
|
||||
styles.id = 'quad-video-styles';
|
||||
styles.textContent = `
|
||||
.quad-video-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0.95);
|
||||
z-index: 10000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.quad-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
margin-bottom: 20px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.quad-header h2 {
|
||||
margin: 0;
|
||||
color: #ff6b9d;
|
||||
text-shadow: 0 2px 4px rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
.quad-controls {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.quad-controls .btn {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.quad-controls .btn:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.quad-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
gap: 15px;
|
||||
width: 100%;
|
||||
height: calc(100vh - 120px);
|
||||
max-width: 1200px;
|
||||
max-height: 800px;
|
||||
}
|
||||
|
||||
.quad-slot {
|
||||
position: relative;
|
||||
background: #000;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
border: 2px solid #333;
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.quad-slot:hover {
|
||||
border-color: #ff6b9d;
|
||||
transform: scale(1.02);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* Force overlay elements to display properly in quad layout */
|
||||
.quad-slot .video-overlay-popup {
|
||||
position: relative !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
background: transparent !important;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.quad-slot .overlay-window {
|
||||
position: relative !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
margin: 0 !important;
|
||||
transform: none !important;
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.quad-slot .overlay-video-container {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.quad-slot video {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
object-fit: contain !important; /* Ensure entire video is visible */
|
||||
display: block !important;
|
||||
background-color: #000 !important; /* Black background for letterboxing */
|
||||
}
|
||||
|
||||
/* Responsive design for smaller screens */
|
||||
@media (max-width: 768px) {
|
||||
.quad-grid {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: repeat(4, 1fr);
|
||||
gap: 10px;
|
||||
max-height: 90vh;
|
||||
}
|
||||
|
||||
.quad-header {
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.quad-video-overlay {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.quad-grid {
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
document.head.appendChild(styles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup resources
|
||||
*/
|
||||
destroy() {
|
||||
console.log('🧹 Destroying QuadVideoPlayer...');
|
||||
|
||||
// Stop all videos first
|
||||
this.stopAllVideos();
|
||||
|
||||
// Destroy individual players
|
||||
this.players.forEach((player, index) => {
|
||||
console.log(`🧹 Destroying player ${index + 1}`);
|
||||
|
||||
// Remove event listeners and clean up player
|
||||
if (player.overlayElement) {
|
||||
// Remove from DOM
|
||||
if (player.overlayElement.parentNode) {
|
||||
player.overlayElement.parentNode.removeChild(player.overlayElement);
|
||||
}
|
||||
}
|
||||
|
||||
// Call destroy method if it exists
|
||||
if (typeof player.destroy === 'function') {
|
||||
player.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
// Remove container
|
||||
if (this.container && this.container.parentNode) {
|
||||
this.container.parentNode.removeChild(this.container);
|
||||
}
|
||||
|
||||
// Reset state
|
||||
this.players = [];
|
||||
this.container = null;
|
||||
this.isActive = false;
|
||||
this.isMinimized = false;
|
||||
|
||||
// Remove styles
|
||||
const styles = document.getElementById('quad-video-styles');
|
||||
if (styles) {
|
||||
styles.remove();
|
||||
}
|
||||
|
||||
console.log('✅ QuadVideoPlayer destroyed');
|
||||
}
|
||||
}
|
||||
|
||||
// Export for use in other modules
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = QuadVideoPlayer;
|
||||
}
|
||||
|
||||
// Make available globally
|
||||
window.QuadVideoPlayer = QuadVideoPlayer;
|
||||
|
|
@ -192,7 +192,9 @@ class InteractiveTaskManager {
|
|||
<button id="interactive-give-up-btn" class="btn btn-danger interactive-btn">
|
||||
Give Up
|
||||
</button>
|
||||
|
||||
<button id="multi-screen-btn" class="btn btn-primary interactive-btn">
|
||||
🎬 Multi-Screen Mode
|
||||
</button>
|
||||
`;
|
||||
|
||||
actionButtons.appendChild(interactiveControls);
|
||||
|
|
@ -206,6 +208,7 @@ class InteractiveTaskManager {
|
|||
this.completeInteractiveTask();
|
||||
});
|
||||
document.getElementById('interactive-give-up-btn').addEventListener('click', () => this.giveUpInteractiveTask());
|
||||
document.getElementById('multi-screen-btn').addEventListener('click', () => this.openMultiScreenMode());
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -3763,6 +3766,74 @@ class InteractiveTaskManager {
|
|||
|
||||
document.head.appendChild(styles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open multi-screen mode overlay for intensive training
|
||||
*/
|
||||
async openMultiScreenMode() {
|
||||
console.log('🎬 Opening Multi-Screen Mode...');
|
||||
|
||||
try {
|
||||
// Check if quad player exists and is minimized
|
||||
if (this.quadPlayer && this.quadPlayer.isMinimized) {
|
||||
console.log('🎬 Restoring minimized QuadVideoPlayer');
|
||||
this.quadPlayer.restore();
|
||||
return;
|
||||
}
|
||||
|
||||
// If quad player exists but might be corrupted, destroy and recreate
|
||||
if (this.quadPlayer) {
|
||||
console.log('🎬 Recreating QuadVideoPlayer to prevent corruption');
|
||||
this.quadPlayer.destroy();
|
||||
this.quadPlayer = null;
|
||||
}
|
||||
|
||||
// Create new quad player
|
||||
this.quadPlayer = new QuadVideoPlayer();
|
||||
const initialized = await this.quadPlayer.initialize();
|
||||
|
||||
if (!initialized) {
|
||||
console.error('❌ Failed to initialize QuadVideoPlayer');
|
||||
// Show user-friendly error
|
||||
if (this.game && this.game.showNotification) {
|
||||
this.game.showNotification('⚠️ No videos available for multi-screen mode', 'warning');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Show the quad overlay
|
||||
this.quadPlayer.show();
|
||||
|
||||
// Log for user feedback
|
||||
if (this.game && this.game.showNotification) {
|
||||
this.game.showNotification('🎬 Multi-Screen Mode activated! Press ESC to close, — to minimize', 'info');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error opening multi-screen mode:', error);
|
||||
if (this.game && this.game.showNotification) {
|
||||
this.game.showNotification('❌ Failed to open multi-screen mode', 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up quad video player and other resources
|
||||
*/
|
||||
cleanup() {
|
||||
if (this.quadPlayer) {
|
||||
console.log('🧹 Cleaning up QuadVideoPlayer...');
|
||||
|
||||
// Always stop all videos during cleanup
|
||||
this.quadPlayer.stopAllVideos();
|
||||
|
||||
// Fully destroy the quad player to prevent DOM corruption
|
||||
this.quadPlayer.destroy();
|
||||
this.quadPlayer = null;
|
||||
|
||||
console.log('✅ QuadVideoPlayer fully cleaned up');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Export for use in other modules
|
||||
|
|
|
|||
Loading…
Reference in New Issue