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:
dilgenfritz 2025-11-08 11:23:03 -06:00
parent 3b55de325d
commit 31cfb7cba5
3 changed files with 161 additions and 2 deletions

View File

@ -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

View File

@ -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);

View File

@ -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() {