updated distribution
This commit is contained in:
parent
b9de382bf7
commit
ec45cf69f8
Binary file not shown.
|
|
@ -857,12 +857,38 @@
|
|||
|
||||
imageLibrary = [...unifiedLibrary];
|
||||
console.log(`🖼️ Using unified image library: ${imageLibrary.length} images`);
|
||||
} else {
|
||||
// Check for popup image library data from localStorage
|
||||
const popupImageLibrary = localStorage.getItem('popupImageLibrary');
|
||||
if (popupImageLibrary) {
|
||||
try {
|
||||
let unifiedLibrary = JSON.parse(popupImageLibrary);
|
||||
|
||||
// Filter by selected directories if any are selected
|
||||
if (currentSettings.selectedDirectories.length > 0) {
|
||||
unifiedLibrary = unifiedLibrary.filter(image => {
|
||||
return currentSettings.selectedDirectories.some(selectedDir => {
|
||||
const imagePath = image.path || image.fullPath || '';
|
||||
const normalizedImagePath = imagePath.replace(/\\/g, '/');
|
||||
const normalizedSelectedDir = selectedDir.replace(/\\/g, '/');
|
||||
return normalizedImagePath.startsWith(normalizedSelectedDir);
|
||||
});
|
||||
});
|
||||
console.log(`📁 Filtered popup library to ${unifiedLibrary.length} images from selected directories`);
|
||||
}
|
||||
|
||||
imageLibrary = [...unifiedLibrary];
|
||||
console.log(`🖼️ Using popup image library: ${imageLibrary.length} images`);
|
||||
} catch (error) {
|
||||
console.error('Failed to parse popup image library:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (imageLibrary.length === 0) {
|
||||
const message = currentSettings.selectedDirectories.length > 0
|
||||
? '⚠️ No images found in selected directories'
|
||||
: '⚠️ Image library unavailable - Electron API not accessible';
|
||||
: '⚠️ Image library unavailable - Open from Quick Play to load library';
|
||||
document.getElementById('imageLibraryStatus').innerHTML =
|
||||
`<span style="color: #f39c12;">${message}</span>`;
|
||||
return;
|
||||
|
|
|
|||
513
quick-play.html
513
quick-play.html
|
|
@ -56,8 +56,18 @@
|
|||
<div class="nav-right quick-play-controls">
|
||||
|
||||
<button id="back-to-home" class="btn btn-secondary">🏠 Home</button>
|
||||
<button id="quick-play-webcam-btn" class="btn btn-info" title="Take a photo with webcam">📸 Photo</button>
|
||||
<button id="force-exit" class="btn btn-danger" title="Force close application">❌ Force Exit</button>
|
||||
<button id="open-hypno-gallery" class="btn btn-gallery" title="Open Hypno Gallery in separate window">
|
||||
<span class="btn-icon">🎭</span>
|
||||
<span class="btn-text">Gallery</span>
|
||||
</button>
|
||||
<button id="open-porn-cinema" class="btn btn-cinema" title="Open Porn Cinema in separate window">
|
||||
<span class="btn-icon">🎬</span>
|
||||
<span class="btn-text">Cinema</span>
|
||||
</button>
|
||||
<button id="quick-play-webcam-btn" class="btn btn-photo" title="Take a photo with webcam">
|
||||
<span class="btn-icon">📸</span>
|
||||
<span class="btn-text">Photo</span>
|
||||
</button>
|
||||
<button id="pause-game-btn" class="btn btn-secondary" style="display: none;">⏸️ Pause</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -103,34 +113,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Audio Settings -->
|
||||
<div class="setting-group">
|
||||
<h3>🔊 Audio Experience</h3>
|
||||
<div class="audio-settings">
|
||||
<div class="audio-option">
|
||||
<input type="checkbox" id="enable-background-audio" checked>
|
||||
<label for="enable-background-audio">
|
||||
<span class="option-icon">🎵</span>
|
||||
<span class="option-text">Background Music</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="audio-option">
|
||||
<input type="checkbox" id="enable-ambient-audio" checked>
|
||||
<label for="enable-ambient-audio">
|
||||
<span class="option-icon">🌊</span>
|
||||
<span class="option-text">Ambient Sounds</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="audio-option">
|
||||
<input type="checkbox" id="enable-voice-commands">
|
||||
<label for="enable-voice-commands">
|
||||
<span class="option-icon">🎤</span>
|
||||
<span class="option-text">Voice Commands</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Video Settings -->
|
||||
<div class="setting-group">
|
||||
<h3>🎬 Video Experience</h3>
|
||||
|
|
@ -1424,24 +1406,76 @@
|
|||
|
||||
// Directory handle persistence functions
|
||||
async function storeDirectoryHandle(directoryHandle) {
|
||||
// Modern browsers with Origin Private File System API
|
||||
if ('storage' in navigator && 'persist' in navigator.storage) {
|
||||
try {
|
||||
const opfsRoot = await navigator.storage.getDirectory();
|
||||
const handleFile = await opfsRoot.getFileHandle('webcam-directory-handle', { create: true });
|
||||
const writable = await handleFile.createWritable();
|
||||
await writable.write(JSON.stringify({ name: directoryHandle.name }));
|
||||
await writable.close();
|
||||
return 'opfs-stored';
|
||||
} catch (error) {
|
||||
console.log('OPFS storage failed:', error);
|
||||
}
|
||||
// Store in IndexedDB for more reliable persistence
|
||||
try {
|
||||
const request = indexedDB.open('webcamStorage', 1);
|
||||
request.onupgradeneeded = (event) => {
|
||||
const db = event.target.result;
|
||||
if (!db.objectStoreNames.contains('directoryHandles')) {
|
||||
db.createObjectStore('directoryHandles', { keyPath: 'id' });
|
||||
}
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
request.onsuccess = async (event) => {
|
||||
try {
|
||||
const db = event.target.result;
|
||||
const transaction = db.transaction(['directoryHandles'], 'readwrite');
|
||||
const store = transaction.objectStore('directoryHandles');
|
||||
await store.put({
|
||||
id: 'webcam-directory',
|
||||
handle: directoryHandle,
|
||||
name: directoryHandle.name,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
resolve('indexeddb-stored');
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
};
|
||||
request.onerror = () => reject(request.error);
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('IndexedDB storage failed:', error);
|
||||
}
|
||||
|
||||
// Fallback - just return a reference ID
|
||||
return `handle-${Date.now()}`;
|
||||
}
|
||||
|
||||
async function retrieveDirectoryHandle(handleId) {
|
||||
// Retrieve from IndexedDB
|
||||
try {
|
||||
const request = indexedDB.open('webcamStorage', 1);
|
||||
return new Promise((resolve, reject) => {
|
||||
request.onsuccess = async (event) => {
|
||||
try {
|
||||
const db = event.target.result;
|
||||
const transaction = db.transaction(['directoryHandles'], 'readonly');
|
||||
const store = transaction.objectStore('directoryHandles');
|
||||
const getRequest = store.get('webcam-directory');
|
||||
|
||||
getRequest.onsuccess = () => {
|
||||
const result = getRequest.result;
|
||||
if (result && result.handle) {
|
||||
resolve(result.handle);
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
};
|
||||
getRequest.onerror = () => resolve(null);
|
||||
} catch (error) {
|
||||
resolve(null);
|
||||
}
|
||||
};
|
||||
request.onerror = () => resolve(null);
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('IndexedDB retrieval failed:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadStoredDirectory() {
|
||||
try {
|
||||
// Try to load saved directory name
|
||||
|
|
@ -1450,6 +1484,21 @@
|
|||
quickPlaySettings.webcamOutputDirectory = savedDirectory;
|
||||
document.getElementById('webcam-output-path').value = savedDirectory;
|
||||
console.log('📁 Restored recording directory:', savedDirectory);
|
||||
|
||||
// Try to restore directory handle if available
|
||||
try {
|
||||
const handleId = localStorage.getItem('webcamDirectoryHandleId');
|
||||
if (handleId && typeof retrieveDirectoryHandle !== 'undefined') {
|
||||
const directoryHandle = await retrieveDirectoryHandle(handleId);
|
||||
if (directoryHandle) {
|
||||
quickPlaySettings.webcamDirectoryHandle = directoryHandle;
|
||||
console.log('📁 Restored directory handle for:', savedDirectory);
|
||||
}
|
||||
}
|
||||
} catch (handleError) {
|
||||
console.log('📁 Could not restore directory handle, will use fallback download');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -1490,11 +1539,6 @@
|
|||
}
|
||||
});
|
||||
|
||||
// Apply audio settings
|
||||
document.getElementById('enable-background-audio').checked = quickPlaySettings.enableBackgroundAudio;
|
||||
document.getElementById('enable-ambient-audio').checked = quickPlaySettings.enableAmbientAudio;
|
||||
document.getElementById('enable-voice-commands').checked = quickPlaySettings.enableVoiceCommands;
|
||||
|
||||
// Apply video settings
|
||||
document.getElementById('video-mode').value = quickPlaySettings.videoMode;
|
||||
document.getElementById('enable-video-sound').checked = quickPlaySettings.enableVideoSound;
|
||||
|
|
@ -1524,6 +1568,10 @@
|
|||
checkbox.checked = quickPlaySettings.excludeTags.includes(checkbox.value);
|
||||
});
|
||||
|
||||
// Apply webcam recording settings
|
||||
document.getElementById('enable-session-recording').checked = quickPlaySettings.enableSessionRecording;
|
||||
updateWebcamOptionsVisibility();
|
||||
|
||||
// Show/hide video options based on mode
|
||||
updateVideoOptionsVisibility();
|
||||
}
|
||||
|
|
@ -2323,6 +2371,182 @@
|
|||
} else {
|
||||
console.warn('back-to-home button not found');
|
||||
}
|
||||
|
||||
// Hypno Gallery button
|
||||
const openHypnoGalleryBtn = document.getElementById('open-hypno-gallery');
|
||||
if (openHypnoGalleryBtn) {
|
||||
openHypnoGalleryBtn.addEventListener('click', async (e) => {
|
||||
e.preventDefault();
|
||||
console.log('Opening Hypno Gallery in separate window');
|
||||
|
||||
try {
|
||||
// Try Electron child window first (desktop app)
|
||||
if (window.electronAPI && window.electronAPI.openChildWindow) {
|
||||
console.log('🖥️ Using Electron child window for Hypno Gallery');
|
||||
const result = await window.electronAPI.openChildWindow({
|
||||
url: 'hypno-gallery.html',
|
||||
windowName: 'Hypno Gallery',
|
||||
width: 1200,
|
||||
height: 800
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
// Add visual feedback with animation
|
||||
const originalHTML = openHypnoGalleryBtn.innerHTML;
|
||||
const iconSpan = '<span class="btn-icon">👁️</span>';
|
||||
const textSpan = result.action === 'focused' ? '<span class="btn-text">Focused</span>' : '<span class="btn-text">Opened</span>';
|
||||
|
||||
openHypnoGalleryBtn.innerHTML = iconSpan + textSpan;
|
||||
openHypnoGalleryBtn.disabled = true;
|
||||
openHypnoGalleryBtn.classList.add('success');
|
||||
|
||||
// Reset button after animation
|
||||
const resetTime = result.action === 'focused' ? 2000 : 3000;
|
||||
setTimeout(() => {
|
||||
openHypnoGalleryBtn.innerHTML = originalHTML;
|
||||
openHypnoGalleryBtn.disabled = false;
|
||||
openHypnoGalleryBtn.classList.remove('success');
|
||||
}, resetTime);
|
||||
|
||||
console.log(`✅ Hypno Gallery ${result.action === 'focused' ? 'focused' : 'opened'} successfully`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to browser popup (web version)
|
||||
console.log('🌐 Falling back to browser popup for Hypno Gallery');
|
||||
|
||||
// Transfer media library data to localStorage for the popup window
|
||||
if (window.desktopFileManager && window.desktopFileManager.unifiedImageLibrary) {
|
||||
const imageLibrary = window.desktopFileManager.unifiedImageLibrary;
|
||||
localStorage.setItem('popupImageLibrary', JSON.stringify(imageLibrary));
|
||||
console.log(`📁 Transferred ${imageLibrary.length} images to localStorage for popup`);
|
||||
}
|
||||
|
||||
// Open hypno-gallery.html in a new window
|
||||
const galleryWindow = window.open(
|
||||
'hypno-gallery.html',
|
||||
'hypno-gallery',
|
||||
'width=1200,height=800,scrollbars=yes,resizable=yes,menubar=no,toolbar=no,location=no,status=no'
|
||||
);
|
||||
|
||||
if (galleryWindow) {
|
||||
// Focus the new window
|
||||
galleryWindow.focus();
|
||||
|
||||
// Add visual feedback
|
||||
const originalText = openHypnoGalleryBtn.innerHTML;
|
||||
openHypnoGalleryBtn.innerHTML = '✅ Gallery Opened';
|
||||
openHypnoGalleryBtn.disabled = true;
|
||||
|
||||
// Reset button after 3 seconds
|
||||
setTimeout(() => {
|
||||
openHypnoGalleryBtn.innerHTML = originalText;
|
||||
openHypnoGalleryBtn.disabled = false;
|
||||
}, 3000);
|
||||
|
||||
console.log('Hypno Gallery opened successfully');
|
||||
} else {
|
||||
console.error('Failed to open Hypno Gallery - popup blocked?');
|
||||
alert('Could not open Hypno Gallery. Please check if popups are blocked.');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error opening Hypno Gallery:', error);
|
||||
alert('Failed to open Hypno Gallery. Please try again.');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.warn('open-hypno-gallery button not found');
|
||||
}
|
||||
|
||||
// Porn Cinema button
|
||||
const openPornCinemaBtn = document.getElementById('open-porn-cinema');
|
||||
if (openPornCinemaBtn) {
|
||||
openPornCinemaBtn.addEventListener('click', async (e) => {
|
||||
e.preventDefault();
|
||||
console.log('Opening Porn Cinema in separate window');
|
||||
|
||||
try {
|
||||
// Try Electron child window first (desktop app)
|
||||
if (window.electronAPI && window.electronAPI.openChildWindow) {
|
||||
console.log('🖥️ Using Electron child window for Porn Cinema');
|
||||
const result = await window.electronAPI.openChildWindow({
|
||||
url: 'porn-cinema.html',
|
||||
windowName: 'Porn Cinema',
|
||||
width: 1400,
|
||||
height: 900
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
// Add visual feedback with animation
|
||||
const originalHTML = openPornCinemaBtn.innerHTML;
|
||||
const iconSpan = '<span class="btn-icon">👁️</span>';
|
||||
const textSpan = result.action === 'focused' ? '<span class="btn-text">Focused</span>' : '<span class="btn-text">Opened</span>';
|
||||
|
||||
openPornCinemaBtn.innerHTML = iconSpan + textSpan;
|
||||
openPornCinemaBtn.disabled = true;
|
||||
openPornCinemaBtn.classList.add('success');
|
||||
|
||||
// Reset button after animation
|
||||
const resetTime = result.action === 'focused' ? 2000 : 3000;
|
||||
setTimeout(() => {
|
||||
openPornCinemaBtn.innerHTML = originalHTML;
|
||||
openPornCinemaBtn.disabled = false;
|
||||
openPornCinemaBtn.classList.remove('success');
|
||||
}, resetTime);
|
||||
|
||||
console.log(`✅ Porn Cinema ${result.action === 'focused' ? 'focused' : 'opened'} successfully`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to browser popup (web version)
|
||||
console.log('🌐 Falling back to browser popup for Porn Cinema');
|
||||
|
||||
// Transfer video library data to localStorage for the popup window
|
||||
if (window.desktopFileManager && typeof window.desktopFileManager.getAllVideos === 'function') {
|
||||
const videoLibrary = window.desktopFileManager.getAllVideos();
|
||||
localStorage.setItem('popupVideoLibrary', JSON.stringify(videoLibrary));
|
||||
console.log(`🎬 Transferred ${videoLibrary.length} videos to localStorage for popup`);
|
||||
}
|
||||
|
||||
// Open porn-cinema.html in a new window
|
||||
const cinemaWindow = window.open(
|
||||
'porn-cinema.html',
|
||||
'porn-cinema',
|
||||
'width=1400,height=900,scrollbars=yes,resizable=yes,menubar=no,toolbar=no,location=no,status=no'
|
||||
);
|
||||
|
||||
if (cinemaWindow) {
|
||||
// Focus the new window
|
||||
cinemaWindow.focus();
|
||||
|
||||
// Add visual feedback
|
||||
const originalText = openPornCinemaBtn.innerHTML;
|
||||
openPornCinemaBtn.innerHTML = '✅ Cinema Opened';
|
||||
openPornCinemaBtn.disabled = true;
|
||||
|
||||
// Reset button after 3 seconds
|
||||
setTimeout(() => {
|
||||
openPornCinemaBtn.innerHTML = originalText;
|
||||
openPornCinemaBtn.disabled = false;
|
||||
}, 3000);
|
||||
|
||||
console.log('Porn Cinema opened successfully');
|
||||
} else {
|
||||
console.error('Failed to open Porn Cinema - popup blocked?');
|
||||
alert('Could not open Porn Cinema. Please check if popups are blocked.');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error opening Porn Cinema:', error);
|
||||
alert('Failed to open Porn Cinema. Please try again.');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.warn('open-porn-cinema button not found');
|
||||
}
|
||||
|
||||
const backToHomeResultsBtn = document.getElementById('back-to-home-results');
|
||||
if (backToHomeResultsBtn) {
|
||||
|
|
@ -2335,25 +2559,44 @@
|
|||
|
||||
|
||||
|
||||
// Force exit button
|
||||
const forceExitBtn = document.getElementById('force-exit');
|
||||
if (forceExitBtn) {
|
||||
forceExitBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
console.log('Force exit button clicked');
|
||||
if (confirm('⚠️ Force close the application? This will close the entire window.')) {
|
||||
forceExit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Webcam photo button
|
||||
const webcamBtn = document.getElementById('quick-play-webcam-btn');
|
||||
if (webcamBtn) {
|
||||
webcamBtn.addEventListener('click', (e) => {
|
||||
webcamBtn.addEventListener('click', async (e) => {
|
||||
e.preventDefault();
|
||||
console.log('Webcam photo button clicked');
|
||||
openQuickPlayWebcam();
|
||||
|
||||
// Add visual feedback with animation
|
||||
const originalHTML = webcamBtn.innerHTML;
|
||||
const iconSpan = '<span class="btn-icon">📷</span>';
|
||||
const textSpan = '<span class="btn-text">Opening</span>';
|
||||
|
||||
webcamBtn.innerHTML = iconSpan + textSpan;
|
||||
webcamBtn.disabled = true;
|
||||
webcamBtn.classList.add('success');
|
||||
|
||||
try {
|
||||
await openQuickPlayWebcam();
|
||||
|
||||
// Show success state briefly
|
||||
webcamBtn.innerHTML = '<span class="btn-icon">✅</span><span class="btn-text">Opened</span>';
|
||||
|
||||
setTimeout(() => {
|
||||
webcamBtn.innerHTML = originalHTML;
|
||||
webcamBtn.disabled = false;
|
||||
webcamBtn.classList.remove('success');
|
||||
}, 2000);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Webcam error:', error);
|
||||
webcamBtn.innerHTML = '<span class="btn-icon">❌</span><span class="btn-text">Error</span>';
|
||||
|
||||
setTimeout(() => {
|
||||
webcamBtn.innerHTML = originalHTML;
|
||||
webcamBtn.disabled = false;
|
||||
webcamBtn.classList.remove('success');
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -2450,16 +2693,7 @@
|
|||
});
|
||||
});
|
||||
|
||||
// Audio checkboxes
|
||||
document.getElementById('enable-background-audio').addEventListener('change', (e) => {
|
||||
quickPlaySettings.enableBackgroundAudio = e.target.checked;
|
||||
});
|
||||
document.getElementById('enable-ambient-audio').addEventListener('change', (e) => {
|
||||
quickPlaySettings.enableAmbientAudio = e.target.checked;
|
||||
});
|
||||
document.getElementById('enable-voice-commands').addEventListener('change', (e) => {
|
||||
quickPlaySettings.enableVoiceCommands = e.target.checked;
|
||||
});
|
||||
// Audio controls removed
|
||||
|
||||
// Video settings
|
||||
document.getElementById('video-mode').addEventListener('change', (e) => {
|
||||
|
|
@ -2480,6 +2714,10 @@
|
|||
document.getElementById('enable-session-recording').addEventListener('change', (e) => {
|
||||
quickPlaySettings.enableSessionRecording = e.target.checked;
|
||||
updateWebcamOptionsVisibility();
|
||||
|
||||
// Save settings immediately when recording preference changes
|
||||
localStorage.setItem('quickPlaySettings', JSON.stringify(quickPlaySettings));
|
||||
console.log('💾 Recording preference saved:', e.target.checked);
|
||||
});
|
||||
document.getElementById('select-webcam-directory').addEventListener('click', async () => {
|
||||
try {
|
||||
|
|
@ -2510,6 +2748,10 @@
|
|||
document.getElementById('webcam-output-path').value = directoryPath;
|
||||
console.log('📁 Webcam output directory selected and saved:', directoryPath);
|
||||
|
||||
// Save the complete settings to ensure directory persists
|
||||
localStorage.setItem('quickPlaySettings', JSON.stringify(quickPlaySettings));
|
||||
console.log('💾 Settings saved with new directory');
|
||||
|
||||
if (window.flashMessageManager) {
|
||||
window.flashMessageManager.show(`📁 Recording directory set to: ${directoryPath}`, 'positive');
|
||||
}
|
||||
|
|
@ -3252,11 +3494,6 @@
|
|||
// Initialize flash message system
|
||||
initializeFlashMessages();
|
||||
|
||||
// Trigger welcome message
|
||||
setTimeout(() => {
|
||||
triggerEventFlashMessage('gameStart');
|
||||
}, 3000); // Show after 3 seconds
|
||||
|
||||
// Start timer
|
||||
startGameTimer(config.timeLimit);
|
||||
|
||||
|
|
@ -5182,6 +5419,19 @@
|
|||
document.addEventListener('keydown', (e) => {
|
||||
if (e.target.tagName === 'INPUT') return; // Don't interfere with input fields
|
||||
|
||||
// Ctrl+Shift+F to focus main window
|
||||
if (e.ctrlKey && e.shiftKey && e.key === 'F') {
|
||||
e.preventDefault();
|
||||
if (window.electronAPI && window.electronAPI.focusMainWindow) {
|
||||
window.electronAPI.focusMainWindow().then(result => {
|
||||
if (result.success) {
|
||||
console.log('🎯 Main window focused via keyboard shortcut');
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.key) {
|
||||
case 'Escape':
|
||||
if (isGameRunning) {
|
||||
|
|
@ -10229,13 +10479,114 @@
|
|||
display: none !important;
|
||||
}
|
||||
|
||||
/* Show webcam task overlay when recording */
|
||||
/* Hide webcam task overlay from preview (it will still be rendered on recording canvas) */
|
||||
.webcam-viewer.recording .webcam-task-overlay {
|
||||
display: block !important;
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Floating Webcam Viewer -->
|
||||
|
||||
/* Enhanced Gallery, Cinema, and Photo Button Styles */
|
||||
.btn-gallery, .btn-cinema, .btn-photo {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
text-decoration: none;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn-gallery {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-cinema {
|
||||
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-photo {
|
||||
background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-gallery:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
||||
background: linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%);
|
||||
}
|
||||
|
||||
.btn-cinema:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(245, 87, 108, 0.4);
|
||||
background: linear-gradient(135deg, #e081e9 0%, #e3455a 100%);
|
||||
}
|
||||
|
||||
.btn-photo:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(52, 73, 94, 0.4);
|
||||
background: linear-gradient(135deg, #1a252f 0%, #2c3e50 100%);
|
||||
}
|
||||
|
||||
.btn-gallery:active, .btn-cinema:active, .btn-photo:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.btn-gallery:disabled, .btn-cinema:disabled, .btn-photo:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
font-size: 16px;
|
||||
margin-right: 6px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* Animation for button feedback */
|
||||
.btn-gallery.success, .btn-cinema.success, .btn-photo.success {
|
||||
animation: successPulse 0.6s ease-out;
|
||||
}
|
||||
|
||||
@keyframes successPulse {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.05); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.btn-gallery, .btn-cinema, .btn-photo {
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
font-size: 14px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
|
||||
</style> <!-- Floating Webcam Viewer -->
|
||||
<div id="webcam-viewer" class="webcam-viewer">
|
||||
<div class="recording-indicator">● REC</div>
|
||||
<video id="webcam-preview" autoplay muted></video>
|
||||
|
|
|
|||
110
src/core/main.js
110
src/core/main.js
|
|
@ -114,6 +114,116 @@ async function createWindow() {
|
|||
}
|
||||
}
|
||||
|
||||
// Register all IPC handlers before app is ready
|
||||
function registerIpcHandlers() {
|
||||
console.log('📝 Registering all IPC handlers...');
|
||||
|
||||
// Move the child window handler here for early registration
|
||||
// Child window management
|
||||
let childWindows = new Map();
|
||||
|
||||
console.log('📝 Registering open-child-window IPC handler...');
|
||||
ipcMain.handle('open-child-window', async (event, options) => {
|
||||
console.log('🖥️ Child window requested:', options);
|
||||
try {
|
||||
const { url, windowName, width = 1200, height = 800 } = options;
|
||||
|
||||
// Check if window already exists and focus it instead of creating a new one
|
||||
if (childWindows.has(windowName)) {
|
||||
const existingWindow = childWindows.get(windowName);
|
||||
if (!existingWindow.isDestroyed()) {
|
||||
console.log(`Focusing existing window: ${windowName}`);
|
||||
existingWindow.focus();
|
||||
return { success: true, windowName, action: 'focused' };
|
||||
} else {
|
||||
// Window was destroyed, remove from map
|
||||
childWindows.delete(windowName);
|
||||
}
|
||||
}
|
||||
|
||||
// Create new child window
|
||||
const childWindow = new BrowserWindow({
|
||||
width,
|
||||
height,
|
||||
// Remove parent relationship to prevent focus issues
|
||||
modal: false,
|
||||
resizable: true,
|
||||
minimizable: true,
|
||||
maximizable: true,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true,
|
||||
enableRemoteModule: false,
|
||||
webSecurity: false,
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
allowRunningInsecureContent: true,
|
||||
experimentalFeatures: true
|
||||
},
|
||||
show: true, // Show immediately instead of waiting
|
||||
title: `${windowName} - Gooner Training Academy`
|
||||
});
|
||||
|
||||
// Load the URL - construct full path
|
||||
const fullPath = path.join(__dirname, '..', '..', url);
|
||||
console.log(`Loading child window file: ${fullPath}`);
|
||||
|
||||
try {
|
||||
await childWindow.loadFile(fullPath);
|
||||
console.log(`✅ Successfully loaded: ${fullPath}`);
|
||||
childWindow.focus();
|
||||
} catch (loadError) {
|
||||
console.error(`❌ Failed to load file: ${fullPath}`, loadError);
|
||||
// Try to show the window anyway with an error message
|
||||
childWindow.show();
|
||||
childWindow.focus();
|
||||
}
|
||||
|
||||
// Handle window closed
|
||||
childWindow.on('closed', () => {
|
||||
console.log(`Child window closed: ${windowName}`);
|
||||
childWindows.delete(windowName);
|
||||
});
|
||||
|
||||
// Add error handling
|
||||
childWindow.on('unresponsive', () => {
|
||||
console.warn(`Child window unresponsive: ${windowName}`);
|
||||
});
|
||||
|
||||
childWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL) => {
|
||||
console.error(`Child window failed to load: ${windowName}`, {
|
||||
errorCode,
|
||||
errorDescription,
|
||||
validatedURL
|
||||
});
|
||||
});
|
||||
|
||||
// Store reference
|
||||
childWindows.set(windowName, childWindow);
|
||||
|
||||
console.log(`✅ Created and showing child window: ${windowName} (${url})`);
|
||||
return { success: true, windowName, action: 'created' };
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error creating child window:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add main window focus handler
|
||||
ipcMain.handle('focus-main-window', async () => {
|
||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||
mainWindow.show();
|
||||
mainWindow.focus();
|
||||
mainWindow.moveTop();
|
||||
return { success: true };
|
||||
}
|
||||
return { success: false };
|
||||
});
|
||||
|
||||
// Register IPC handlers
|
||||
registerIpcHandlers();
|
||||
|
||||
app.whenReady().then(createWindow);
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
|||
// Platform info
|
||||
platform: process.platform,
|
||||
|
||||
// Child window management
|
||||
openChildWindow: (options) => ipcRenderer.invoke('open-child-window', options),
|
||||
focusMainWindow: () => ipcRenderer.invoke('focus-main-window'),
|
||||
|
||||
// Version info
|
||||
versions: {
|
||||
node: process.versions.node,
|
||||
|
|
|
|||
|
|
@ -65,7 +65,46 @@ class VideoLibrary {
|
|||
|
||||
async loadVideoLibrary() {
|
||||
try {
|
||||
// First try to get from unified video library (new system)
|
||||
// First check for popup video library data (for windows opened from Quick Play)
|
||||
const popupVideoLibrary = localStorage.getItem('popupVideoLibrary');
|
||||
if (popupVideoLibrary) {
|
||||
console.log('📁 Loading from popup video library...');
|
||||
const popupVideos = JSON.parse(popupVideoLibrary);
|
||||
|
||||
if (popupVideos && popupVideos.length > 0) {
|
||||
console.log(`📁 Loading from popup video library: ${popupVideos.length} videos`);
|
||||
|
||||
// Convert popup library format to VideoLibrary format
|
||||
const allVideos = popupVideos.map(video => ({
|
||||
name: video.name,
|
||||
path: video.path,
|
||||
size: video.size || 0,
|
||||
duration: video.duration || 0,
|
||||
thumbnail: video.thumbnail || null,
|
||||
resolution: video.resolution || 'Unknown',
|
||||
format: video.format || this.getFormatFromPath(video.path),
|
||||
bitrate: video.bitrate || 0,
|
||||
dateAdded: video.dateAdded || new Date().toISOString(),
|
||||
category: video.source === 'individual' ? 'individual' : 'directory',
|
||||
directory: video.directory || video.source || 'Unknown'
|
||||
}));
|
||||
|
||||
this.videos = allVideos;
|
||||
console.log(`📁 Popup video library loaded: ${this.videos.length} videos`);
|
||||
|
||||
if (this.videos.length === 0) {
|
||||
this.displayEmptyLibrary('No videos found. Open from Quick Play to load video library!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply filters and sort before displaying
|
||||
this.applyFiltersAndSort();
|
||||
this.displayLibrary();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Then try to get from unified video library (new system)
|
||||
const unifiedLibrary = JSON.parse(localStorage.getItem('unifiedVideoLibrary') || '{}');
|
||||
if (unifiedLibrary.allVideos && unifiedLibrary.allVideos.length > 0) {
|
||||
console.log(`📁 Loading from unified video library: ${unifiedLibrary.allVideos.length} videos`);
|
||||
|
|
@ -98,6 +137,8 @@ class VideoLibrary {
|
|||
return;
|
||||
}
|
||||
|
||||
// Apply filters and sort before displaying
|
||||
this.applyFiltersAndSort();
|
||||
this.displayLibrary();
|
||||
return;
|
||||
}
|
||||
|
|
@ -359,7 +400,15 @@ class VideoLibrary {
|
|||
}
|
||||
|
||||
displayLibrary() {
|
||||
console.log(`📁 DisplayLibrary called - Videos: ${this.videos.length}, Filtered: ${this.filteredVideos.length}`);
|
||||
|
||||
if (this.filteredVideos.length === 0) {
|
||||
console.log('📁 No filtered videos - applying filter to refresh');
|
||||
this.applyFiltersAndSort(); // Make sure filtering is applied
|
||||
}
|
||||
|
||||
if (this.filteredVideos.length === 0) {
|
||||
console.log('📁 Still no filtered videos after applying filter');
|
||||
this.displayEmptyLibrary('No videos match your search');
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -489,7 +489,7 @@ class DesktopFileManager {
|
|||
await this.updateUnifiedVideoStorage();
|
||||
|
||||
const totalVideos = this.allLinkedVideos.length;
|
||||
this.showNotification(`🔄 Refreshed ${this.externalVideoDirectories.length} directories, found ${totalVideos} videos`, 'success');
|
||||
// Removed notification to avoid startup message clutter
|
||||
}
|
||||
|
||||
async saveLinkedDirectories() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue