feat: enhance state management for image generation settings and restore functionality

This commit is contained in:
Yusuf İpek
2026-01-21 18:35:15 +03:00
parent 7a688e2730
commit d8f7a2c909
+66 -43
View File
@@ -90,9 +90,9 @@ const ImagenDB = {
const state = { const state = {
apiKey: localStorage.getItem('imagen_api_key') || '', apiKey: localStorage.getItem('imagen_api_key') || '',
selectedModel: localStorage.getItem('imagen_model') || 'google/gemini-2.5-flash-image', selectedModel: localStorage.getItem('imagen_model') || 'google/gemini-2.5-flash-image',
imageSize: '1024x1024', imageSize: localStorage.getItem('imagen_size') || '1024x1024',
imageQuality: '1K', imageQuality: localStorage.getItem('imagen_quality') || '1K',
aspectRatio: '1:1', aspectRatio: localStorage.getItem('imagen_aspect_ratio') || '1:1',
imageCount: 1, imageCount: 1,
references: [], // Dynamic array - unlimited references references: [], // Dynamic array - unlimited references
images: [], // Will be loaded from IndexedDB images: [], // Will be loaded from IndexedDB
@@ -251,6 +251,22 @@ async function init() {
} }
} }
// Restore saved image quality/size
document.querySelectorAll('.btn-toggle').forEach(btn => {
btn.classList.remove('active');
if (btn.dataset.quality === state.imageQuality) {
btn.classList.add('active');
}
});
// Restore saved aspect ratio
document.querySelectorAll('.btn-aspect').forEach(btn => {
btn.classList.remove('active');
if (btn.dataset.ratio === state.aspectRatio) {
btn.classList.add('active');
}
});
// Load images from IndexedDB // Load images from IndexedDB
try { try {
state.images = await ImagenDB.getAllImages(); state.images = await ImagenDB.getAllImages();
@@ -303,6 +319,8 @@ function setupEventListeners() {
btn.classList.add('active'); btn.classList.add('active');
state.imageSize = btn.dataset.size; state.imageSize = btn.dataset.size;
state.imageQuality = btn.dataset.quality; state.imageQuality = btn.dataset.quality;
localStorage.setItem('imagen_size', state.imageSize);
localStorage.setItem('imagen_quality', state.imageQuality);
}); });
}); });
@@ -312,6 +330,7 @@ function setupEventListeners() {
document.querySelectorAll('.btn-aspect').forEach(b => b.classList.remove('active')); document.querySelectorAll('.btn-aspect').forEach(b => b.classList.remove('active'));
btn.classList.add('active'); btn.classList.add('active');
state.aspectRatio = btn.dataset.ratio; state.aspectRatio = btn.dataset.ratio;
localStorage.setItem('imagen_aspect_ratio', state.aspectRatio);
}); });
}); });
@@ -528,60 +547,59 @@ async function generateImages() {
elements.generateBtn.disabled = true; elements.generateBtn.disabled = true;
elements.loadingContainer.style.display = 'flex'; elements.loadingContainer.style.display = 'flex';
try { const modelConfig = MODEL_CONFIGS[state.selectedModel];
const modelConfig = MODEL_CONFIGS[state.selectedModel]; const currentReferences = state.references.length > 0 ? [...state.references] : [];
const promises = []; console.log('Generating with references:', currentReferences.length, currentReferences);
let successCount = 0;
let failCount = 0;
for (let i = 0; i < state.imageCount; i++) { // Generate images and display each one as it completes
promises.push(generateSingleImage(prompt, modelConfig)); const generateAndDisplay = async (index) => {
} try {
const result = await generateSingleImage(prompt, modelConfig);
const results = await Promise.allSettled(promises); if (result) {
let successCount = 0;
const newImages = [];
results.forEach((result, index) => {
if (result.status === 'fulfilled' && result.value) {
const imageData = { const imageData = {
id: Date.now() + index, id: Date.now() + index,
url: result.value, url: result,
prompt: prompt, prompt: prompt,
model: state.selectedModel, model: state.selectedModel,
modelName: modelConfig.name, modelName: modelConfig.name,
size: state.imageSize, size: state.imageSize,
quality: state.imageQuality, quality: state.imageQuality,
aspectRatio: state.aspectRatio, aspectRatio: state.aspectRatio,
references: state.references.length > 0 ? [...state.references] : [], references: currentReferences,
createdAt: new Date().toISOString() createdAt: new Date().toISOString()
}; };
newImages.push(imageData);
state.images.unshift(imageData); state.images.unshift(imageData);
renderGallery();
successCount++; successCount++;
} else {
console.error('Failed to generate image:', result.reason); // Save to IndexedDB in background
ImagenDB.saveImage(imageData).catch(e => console.error('Failed to save to IndexedDB:', e));
} }
}); } catch (error) {
console.error('Failed to generate image:', error);
if (successCount > 0) { failCount++;
// Render gallery immediately so user sees results
renderGallery();
showToast(`${successCount} image(s) generated!`, 'success');
// Save to IndexedDB in background (don't block UI)
Promise.all(newImages.map(img => ImagenDB.saveImage(img)))
.catch(dbError => console.error('Failed to save to IndexedDB:', dbError));
} else {
showToast('Failed to generate images. Check console for details.', 'error');
} }
};
} catch (error) { // Start all generations in parallel, each will render when done
console.error('Generation error:', error); const promises = [];
showToast(`Error: ${error.message}`, 'error'); for (let i = 0; i < state.imageCount; i++) {
} finally { promises.push(generateAndDisplay(i));
state.isGenerating = false; }
elements.generateBtn.disabled = false;
elements.loadingContainer.style.display = 'none'; // Wait for all to complete to update final UI state
await Promise.allSettled(promises);
state.isGenerating = false;
elements.generateBtn.disabled = false;
elements.loadingContainer.style.display = 'none';
if (successCount > 0) {
showToast(`${successCount} image(s) generated!`, 'success');
} else {
showToast('Failed to generate images. Check console for details.', 'error');
} }
} }
@@ -838,11 +856,16 @@ function recreateImage() {
} }
}); });
// Restore references // Restore references (always update the UI, even if empty to clear previous refs)
console.log('Recreate - image references:', state.currentImage.references);
if (state.currentImage.references && state.currentImage.references.length > 0) { if (state.currentImage.references && state.currentImage.references.length > 0) {
state.references = [...state.currentImage.references]; state.references = [...state.currentImage.references];
renderReferenceSlots(); console.log('Restored references:', state.references.length);
} else {
state.references = [];
console.log('No references to restore');
} }
renderReferenceSlots();
closeModal(); closeModal();
showToast('Settings restored. Click Generate to recreate.', 'success'); showToast('Settings restored. Click Generate to recreate.', 'success');