import { showToast, updateImageInfo } from './utils.js'; document.addEventListener('DOMContentLoaded', () => { const state = { currentImageInfo: null, currentOrientation: 'all', isLoading: false, isDragging: false, startX: 0, startY: 0, moveX: 0, moveY: 0, touchStartTime: 0, hasMoved: false, }; const card = document.getElementById('current-card'); 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 SWIPE_THRESHOLD = 100; const performSwipe = (direction) => { if (!state.currentImageInfo) return; card.classList.add(`swipe-${direction}`); const actionNameMap = { left: 'Discard', right: 'Keep', up: 'Favorite', down: 'Review' }; const actionName = actionNameMap[direction] || direction; lastActionText.textContent = `Last action: ${actionName}`; const toastMap = { left: 'Discarded', right: 'Kept', up: 'Favorited', down: 'Marked for review' }; showToast(toastMap[direction] || 'Action'); recordSelection(state.currentImageInfo, actionName); setTimeout(() => { card.classList.remove(`swipe-${direction}`); loadNewImage(); }, 500); }; const recordSelection = async (imageInfo, action) => { try { const response = await fetch('/selection', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ image_path: imageInfo.path, action, }), }); if (!response.ok) { console.error('Error recording selection. Status:', response.status); } else { const data = await response.json(); console.log('Selection recorded:', data); } } catch (err) { console.error('Error recording selection:', err); } }; const loadNewImage = () => { if (state.isLoading) return; state.isLoading = true; card.classList.add('loading'); fetch(`/random-image?orientation=${state.currentOrientation}&t=${new Date().getTime()}`) .then(response => response.json()) .then(data => { state.isLoading = false; // card.classList.remove('loading'); // moved to image load handler if (data && data.path) { state.currentImageInfo = data; const cardImage = card.querySelector('img'); // Use load event to ensure indicator hides after image fully loads cardImage.onload = () => { card.classList.remove('loading'); }; cardImage.src = data.path; updateImageInfo(data); adjustContainerToImage(data.orientation); } else { const placeholder = 'static/no-image.png'; const imgEl = card.querySelector('img'); if (imgEl) { imgEl.onload = () => card.classList.remove('loading'); imgEl.src = placeholder; } updateImageInfo({ filename:'No image', creation_date:'', resolution:'', prompt_data:''}); state.currentImageInfo = null; // disables swipe actions } }) .catch(error => { console.error('Error fetching image:', error); state.isLoading = false; card.classList.remove('loading'); card.innerHTML = '
Error loading image.
'; }); }; const 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'; } } }; const handlePointerDown = (x, y) => { state.isDragging = true; state.startX = x; state.startY = y; state.hasMoved = false; state.touchStartTime = Date.now(); card.classList.add('swiping'); }; const handlePointerMove = (x, y) => { if (!state.isDragging) return; state.moveX = x - state.startX; state.moveY = y - state.startY; if (Math.abs(state.moveX) > 10 || Math.abs(state.moveY) > 10) { state.hasMoved = true; } card.style.transform = `translate(${state.moveX}px, ${state.moveY}px) rotate(${state.moveX * 0.05}deg)`; }; const handlePointerUp = () => { if (!state.isDragging) return; state.isDragging = false; card.classList.remove('swiping'); const absX = Math.abs(state.moveX); const absY = Math.abs(state.moveY); if (state.hasMoved && (absX > SWIPE_THRESHOLD || absY > SWIPE_THRESHOLD)) { if (absX > absY) { performSwipe(state.moveX > 0 ? 'right' : 'left'); } else { performSwipe(state.moveY > 0 ? 'down' : 'up'); } } else { card.style.transform = ''; } state.moveX = 0; state.moveY = 0; }; card.addEventListener('mousedown', e => handlePointerDown(e.clientX, e.clientY)); document.addEventListener('mousemove', e => handlePointerMove(e.clientX, e.clientY)); document.addEventListener('mouseup', () => handlePointerUp()); card.addEventListener('touchstart', e => handlePointerDown(e.touches[0].clientX, e.touches[0].clientY), { passive: true }); card.addEventListener('touchmove', e => handlePointerMove(e.touches[0].clientX, e.touches[0].clientY), { passive: true }); card.addEventListener('touchend', () => handlePointerUp()); 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')); 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(); } }); card.addEventListener('click', () => { if (!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'; } }); closeModal.addEventListener('click', () => modal.style.display = 'none'); modal.addEventListener('click', (e) => { if (e.target === modal) { modal.style.display = 'none'; } }); document.addEventListener('keydown', (e) => { if (modal.style.display === 'flex' && e.key === 'Escape') { modal.style.display = 'none'; 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; } } }); loadNewImage(); });