Add photo deletion capability to library photo gallery
ADDED: Photo deletion functionality - Added delete button () to each photo in library gallery - Appears on hover with smooth opacity transition - Positioned in top-right corner of photo container FUNCTIONALITY: Complete delete workflow - deletePhoto() function removes photos from localStorage - Confirmation dialog shows photo type and date - Automatic gallery refresh after deletion - Support for both All Photos and Dress Up galleries - Proper index handling for filtered galleries STYLING: Professional delete button design - Red circular button with trash icon - Hover effects with scale animation and shadow - Semi-transparent background for visibility - Positioned with absolute positioning in photo-actions container SAFETY: User confirmation and error handling - Confirmation dialog prevents accidental deletion - Index validation to prevent errors - Success flash message after deletion - Console logging for debugging RESULT: Users can now delete unwanted photos - Hover over any photo to reveal delete button - Click for confirmation dialog with photo details - Gallery automatically updates after deletion - Works for all photo categories in library
This commit is contained in:
parent
3b55de325d
commit
31cfb7cba5
47
index.html
47
index.html
|
|
@ -4837,6 +4837,11 @@
|
|||
<div class="photo-container">
|
||||
<img src="${imageData}" alt="Captured Photo ${index + 1}"
|
||||
onclick="showPhotoPreview('${imageData}', 'Photo ${index + 1}')">
|
||||
<div class="photo-actions">
|
||||
<button class="photo-delete-btn" onclick="deletePhoto(${index})" title="Delete Photo">
|
||||
🗑️
|
||||
</button>
|
||||
</div>
|
||||
<div class="photo-info">
|
||||
<span class="photo-date">${timestamp}</span>
|
||||
<span class="photo-type">${photo.sessionType || 'Training'}</span>
|
||||
|
|
@ -4866,11 +4871,18 @@
|
|||
const imageData = photo.imageData || photo.dataURL; // Support both formats
|
||||
|
||||
if (imageData) {
|
||||
// Find the original index in the full capturedPhotos array
|
||||
const originalIndex = capturedPhotos.findIndex(p => p.imageData === imageData || p.dataURL === imageData);
|
||||
dressUpHtml += `
|
||||
<div class="photo-item" data-index="${index}">
|
||||
<div class="photo-item" data-index="${originalIndex}">
|
||||
<div class="photo-container">
|
||||
<img src="${imageData}" alt="Dress Up Photo ${index + 1}"
|
||||
onclick="showPhotoPreview('${imageData}', 'Dress Up Photo ${index + 1}')">
|
||||
<div class="photo-actions">
|
||||
<button class="photo-delete-btn" onclick="deletePhoto(${originalIndex})" title="Delete Photo">
|
||||
🗑️
|
||||
</button>
|
||||
</div>
|
||||
<div class="photo-info">
|
||||
<span class="photo-date">${timestamp}</span>
|
||||
<span class="photo-type">${photo.sessionType}</span>
|
||||
|
|
@ -4885,6 +4897,39 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Delete a photo from the gallery
|
||||
function deletePhoto(index) {
|
||||
const capturedPhotos = JSON.parse(localStorage.getItem('capturedPhotos') || '[]');
|
||||
|
||||
if (index < 0 || index >= capturedPhotos.length) {
|
||||
console.error('Invalid photo index:', index);
|
||||
return;
|
||||
}
|
||||
|
||||
const photo = capturedPhotos[index];
|
||||
const photoType = photo.sessionType || 'Training';
|
||||
const photoDate = new Date(photo.timestamp || Date.now()).toLocaleDateString();
|
||||
|
||||
// Show confirmation dialog
|
||||
const confirmed = confirm(`Are you sure you want to delete this photo?\n\nType: ${photoType}\nDate: ${photoDate}\n\nThis action cannot be undone.`);
|
||||
|
||||
if (confirmed) {
|
||||
// Remove photo from array
|
||||
capturedPhotos.splice(index, 1);
|
||||
|
||||
// Update localStorage
|
||||
localStorage.setItem('capturedPhotos', JSON.stringify(capturedPhotos));
|
||||
|
||||
// Show success message
|
||||
showFlashMessage(`📸 Photo deleted successfully!`, 'success');
|
||||
|
||||
// Refresh the photo galleries
|
||||
loadLibraryContent();
|
||||
|
||||
console.log(`🗑️ Deleted photo ${index + 1} (${photoType})`);
|
||||
}
|
||||
}
|
||||
|
||||
// Show photo preview in modal
|
||||
function showPhotoPreview(imageData, title) {
|
||||
// Create modal overlay
|
||||
|
|
|
|||
|
|
@ -6470,6 +6470,46 @@ button#start-mirror-btn:disabled {
|
|||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.photo-actions {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.photo-container:hover .photo-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.photo-delete-btn {
|
||||
background: rgba(231, 76, 60, 0.9);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.photo-delete-btn:hover {
|
||||
background: rgba(192, 57, 43, 1);
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.photo-delete-btn:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.photo-info {
|
||||
padding: 12px;
|
||||
background: var(--bg-tertiary);
|
||||
|
|
|
|||
|
|
@ -989,6 +989,7 @@
|
|||
let selectedTrainingMode = null;
|
||||
let videoOpacity = 0.3;
|
||||
let isVideoPlaying = true;
|
||||
let videoControlListenersInitialized = false;
|
||||
|
||||
// Helper function to get format from file path
|
||||
function getFormatFromPath(filePath) {
|
||||
|
|
@ -1317,8 +1318,30 @@
|
|||
setTimeout(() => {
|
||||
updateVideoInfo();
|
||||
updateVideoProgress();
|
||||
|
||||
// Ensure play/pause button state is correct
|
||||
const playPauseBtn = document.getElementById('video-play-pause');
|
||||
if (playPauseBtn) {
|
||||
if (video.paused) {
|
||||
playPauseBtn.textContent = '▶️';
|
||||
playPauseBtn.title = 'Play';
|
||||
} else {
|
||||
playPauseBtn.textContent = '⏸️';
|
||||
playPauseBtn.title = 'Pause';
|
||||
}
|
||||
console.log('🎮 Button state updated on metadata load:', video.paused ? 'Play' : 'Pause');
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
video.onplay = () => {
|
||||
console.log('🎬 Video started playing');
|
||||
const playPauseBtn = document.getElementById('video-play-pause');
|
||||
if (playPauseBtn) {
|
||||
playPauseBtn.textContent = '⏸️';
|
||||
playPauseBtn.title = 'Pause';
|
||||
}
|
||||
};
|
||||
|
||||
video.onerror = (e) => {
|
||||
console.error('❌ Video error:', e);
|
||||
|
|
@ -1341,13 +1364,21 @@
|
|||
|
||||
const video = document.getElementById('backgroundVideo');
|
||||
if (video) {
|
||||
console.log(`🎬 Switching from video paused state: ${video.paused}`);
|
||||
video.src = `file://${nextVideo.fullPath}`;
|
||||
console.log(`🎬 Switched to: ${nextVideo.name}`);
|
||||
console.log(`🎬 After src change, video paused state: ${video.paused}`);
|
||||
|
||||
// Update video info for the new video
|
||||
// Update video info and ensure controls work for the new video
|
||||
video.addEventListener('loadedmetadata', function() {
|
||||
updateVideoInfo();
|
||||
updateVideoProgress();
|
||||
refreshVideoControlState();
|
||||
}, { once: true });
|
||||
|
||||
// Ensure button state updates when new video plays
|
||||
video.addEventListener('play', function() {
|
||||
refreshVideoControlState();
|
||||
}, { once: true });
|
||||
}
|
||||
}
|
||||
|
|
@ -1379,6 +1410,23 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Refresh Video Control State (for video changes)
|
||||
function refreshVideoControlState() {
|
||||
const video = document.getElementById('backgroundVideo');
|
||||
const playPauseBtn = document.getElementById('video-play-pause');
|
||||
|
||||
if (video && playPauseBtn) {
|
||||
if (video.paused) {
|
||||
playPauseBtn.textContent = '▶️';
|
||||
playPauseBtn.title = 'Play';
|
||||
} else {
|
||||
playPauseBtn.textContent = '⏸️';
|
||||
playPauseBtn.title = 'Pause';
|
||||
}
|
||||
console.log('🎮 Control state refreshed:', video.paused ? 'Play' : 'Pause');
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle Video Controls Panel
|
||||
function toggleVideoControls() {
|
||||
const content = document.getElementById('video-control-content');
|
||||
|
|
@ -1397,6 +1445,12 @@
|
|||
|
||||
// Setup Complete Video Control System (from Quick Play)
|
||||
function setupVideoControlListeners() {
|
||||
// Prevent duplicate listener setup
|
||||
if (videoControlListenersInitialized) {
|
||||
console.log('🎮 Video control listeners already initialized, skipping...');
|
||||
return;
|
||||
}
|
||||
|
||||
const video = document.getElementById('backgroundVideo');
|
||||
if (!video) {
|
||||
console.log('⚠️ Background video element not found during control setup');
|
||||
|
|
@ -1407,9 +1461,13 @@
|
|||
|
||||
// Play/Pause control
|
||||
const playPauseBtn = document.getElementById('video-play-pause');
|
||||
console.log('🎮 Play/pause button found:', !!playPauseBtn);
|
||||
if (playPauseBtn) {
|
||||
playPauseBtn.addEventListener('click', async () => {
|
||||
const currentVideo = document.getElementById('backgroundVideo');
|
||||
console.log('🎬 Video element found:', !!currentVideo);
|
||||
console.log('🎬 Video paused state:', currentVideo ? currentVideo.paused : 'no video');
|
||||
|
||||
if (!currentVideo) {
|
||||
console.log('No video element found');
|
||||
return;
|
||||
|
|
@ -1431,6 +1489,8 @@
|
|||
console.error('Video playback error:', error);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.error('❌ Play/pause button not found!');
|
||||
}
|
||||
|
||||
// Rewind 10 seconds
|
||||
|
|
@ -1542,9 +1602,23 @@
|
|||
setTimeout(() => {
|
||||
updateVideoInfo();
|
||||
updateVideoProgress();
|
||||
|
||||
// Set initial play/pause button state
|
||||
const initialPlayPauseBtn = document.getElementById('video-play-pause');
|
||||
if (initialPlayPauseBtn && video) {
|
||||
if (video.paused) {
|
||||
initialPlayPauseBtn.textContent = '▶️';
|
||||
initialPlayPauseBtn.title = 'Play';
|
||||
} else {
|
||||
initialPlayPauseBtn.textContent = '⏸️';
|
||||
initialPlayPauseBtn.title = 'Pause';
|
||||
}
|
||||
console.log('🎮 Initial button state set:', video.paused ? 'Play' : 'Pause');
|
||||
}
|
||||
}, 100);
|
||||
|
||||
console.log('✅ Video control listeners set up successfully');
|
||||
videoControlListenersInitialized = true;
|
||||
}
|
||||
|
||||
function updateVideoProgress() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue