Files
swiper/js/enhanced-main.js
2025-06-21 21:44:52 +01:00

233 lines
8.5 KiB
JavaScript

import { showToast, updateImageInfo } from './utils.js';
import SwipeCard from '../components/swipe-card.js';
document.addEventListener('DOMContentLoaded', () => {
// Track total images and processed count for progress bar
const progressState = {
totalImages: 0,
processedImages: 0
};
// Global state
const state = {
currentImageInfo: null,
currentOrientation: 'all',
isLoading: false
};
// DOM elements
const lastActionText = document.getElementById('last-action');
const orientationFilters = document.querySelector('.orientation-filters');
const modal = document.getElementById('fullscreen-modal');
const fullscreenImage = document.getElementById('fullscreen-image');
const closeModal = document.querySelector('.close-modal');
const progressBar = document.getElementById('progress-bar');
// Initialize the enhanced swipe card
const swipeCard = new SwipeCard({
container: document.querySelector('.swipe-container'),
onSwipe: performSwipe,
threshold: 100
});
// Make state available to window for debugging and other components
window.state = state;
window.performSwipe = performSwipe;
function performSwipe(direction) {
if (!state.currentImageInfo) return;
// Update last action text with the action name instead of direction
const actionMap = {
left: 'Discarded',
right: 'Kept',
up: 'Favorited',
down: 'Marked for review'
};
lastActionText.textContent = `Last action: ${actionMap[direction] || 'Unknown'}`;
// Show toast notification
const toastMap = {
left: 'Discarded',
right: 'Kept',
up: 'Favorited',
down: 'Marked for review'
};
showToast(toastMap[direction] || 'Action');
// Record the selection
recordSelection(state.currentImageInfo, direction);
// Update progress
progressState.processedImages++;
updateProgressBar();
// Load new image after animation completes
setTimeout(() => {
loadNewImage();
}, 500);
}
function updateProgressBar() {
if (progressState.totalImages > 0) {
const percentage = (progressState.processedImages / progressState.totalImages) * 100;
progressBar.style.width = `${Math.min(percentage, 100)}%`;
}
}
function recordSelection(imageInfo, action) {
fetch('/selection', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
image_path: imageInfo.path,
resolution: imageInfo.resolution,
action,
}),
}).catch(error => console.error('Error recording selection:', error));
}
function loadNewImage() {
if (state.isLoading) return;
state.isLoading = true;
swipeCard.showLoading();
// First, get the total count if we don't have it yet
if (progressState.totalImages === 0) {
fetch('/image-count')
.then(response => response.json())
.catch(() => ({ count: 100 })) // Fallback if endpoint doesn't exist
.then(data => {
progressState.totalImages = data.count || 100;
updateProgressBar();
});
}
fetch(`/random-image?orientation=${state.currentOrientation}&t=${new Date().getTime()}`)
.then(response => response.json())
.then(data => {
state.isLoading = false;
swipeCard.hideLoading();
if (data && data.path) {
state.currentImageInfo = data;
swipeCard.setImage(data);
updateImageInfo(data);
adjustContainerToImage(data.orientation);
} else {
swipeCard.card.innerHTML = `<div class="no-images-message">${data.message || 'No more images.'}</div>`;
state.currentImageInfo = null;
}
})
.catch(error => {
console.error('Error fetching image:', error);
state.isLoading = false;
swipeCard.hideLoading();
swipeCard.card.innerHTML = '<div class="no-images-message">Error loading image.</div>';
});
}
function adjustContainerToImage(orientation) {
const container = document.querySelector('.swipe-container');
if (window.innerWidth < 992) { // Only on desktop
container.style.transition = 'all 0.5s ease-in-out';
if (orientation === 'landscape') {
container.style.flex = '4';
} else {
container.style.flex = '2';
}
}
}
// Button event listeners
document.getElementById('btn-left').addEventListener('click', () => performSwipe('left'));
document.getElementById('btn-right').addEventListener('click', () => performSwipe('right'));
document.getElementById('btn-up').addEventListener('click', () => performSwipe('up'));
document.getElementById('btn-down').addEventListener('click', () => performSwipe('down'));
// Orientation filter event listeners
orientationFilters.addEventListener('click', (e) => {
if (e.target.tagName === 'BUTTON' && !e.target.classList.contains('active')) {
orientationFilters.querySelector('.active').classList.remove('active');
e.target.classList.add('active');
state.currentOrientation = e.target.dataset.orientation;
loadNewImage();
}
});
// Modal event listeners
swipeCard.card.addEventListener('click', () => {
if (!swipeCard.state.hasMoved && state.currentImageInfo) {
fullscreenImage.src = state.currentImageInfo.path;
document.getElementById('modal-resolution').textContent = `Resolution: ${state.currentImageInfo.resolution}`;
document.getElementById('modal-filename').textContent = `Filename: ${state.currentImageInfo.filename || 'N/A'}`;
document.getElementById('modal-creation-date').textContent = `Creation Date: ${state.currentImageInfo.creation_date || 'N/A'}`;
modal.style.display = 'flex';
// Add animation classes
setTimeout(() => {
modal.classList.add('show');
}, 10);
}
});
closeModal.addEventListener('click', () => {
modal.classList.remove('show');
setTimeout(() => {
modal.style.display = 'none';
}, 400);
});
modal.addEventListener('click', (e) => {
if (e.target === modal) {
modal.classList.remove('show');
setTimeout(() => {
modal.style.display = 'none';
}, 400);
}
});
// Keyboard event listeners
document.addEventListener('keydown', (e) => {
if (modal.style.display === 'flex' && e.key === 'Escape') {
modal.classList.remove('show');
setTimeout(() => {
modal.style.display = 'none';
}, 400);
return;
}
if (modal.style.display !== 'flex') {
switch (e.key) {
case 'ArrowLeft': performSwipe('left'); break;
case 'ArrowRight': performSwipe('right'); break;
case 'ArrowUp': performSwipe('up'); break;
case 'ArrowDown': performSwipe('down'); break;
}
}
});
// Add ripple effect to action buttons
document.querySelectorAll('.action-btn').forEach(button => {
button.addEventListener('click', function(e) {
const ripple = document.createElement('span');
ripple.classList.add('ripple');
this.appendChild(ripple);
const rect = button.getBoundingClientRect();
const size = Math.max(rect.width, rect.height);
ripple.style.width = ripple.style.height = `${size}px`;
ripple.style.left = `${e.clientX - rect.left - size/2}px`;
ripple.style.top = `${e.clientY - rect.top - size/2}px`;
setTimeout(() => {
ripple.remove();
}, 600);
});
});
// Initialize by loading the first image
loadNewImage();
});