From ac7303588f2a429d7920ff50db8624083558613a Mon Sep 17 00:00:00 2001 From: phamhungd Date: Sat, 29 Nov 2025 22:27:10 +0700 Subject: [PATCH] fillter history fix --- static/modules/gallery.js | 141 +++++++++++++++++++++++++++++--------- static/script.js | 52 ++++++-------- 2 files changed, 130 insertions(+), 63 deletions(-) diff --git a/static/modules/gallery.js b/static/modules/gallery.js index b99e730..2021a59 100644 --- a/static/modules/gallery.js +++ b/static/modules/gallery.js @@ -3,33 +3,97 @@ import { extractMetadataFromBlob } from './metadata.js'; const FILTER_STORAGE_KEY = 'gemini-app-history-filter'; const SEARCH_STORAGE_KEY = 'gemini-app-history-search'; +const FAVORITES_STORAGE_KEY = 'gemini-app-history-favorites'; const SOURCE_STORAGE_KEY = 'gemini-app-history-source'; const VALID_SOURCES = ['generated', 'uploads']; +const DEFAULT_STATE = { + filter: 'all', + search: '', + favorites: false, +}; + +function createStateMap(fallback) { + return { + generated: fallback, + uploads: fallback, + }; +} + +function parseStoredMap(key, fallback) { + const defaultMap = createStateMap(fallback); + let raw; + try { + raw = localStorage.getItem(key); + if (!raw) return defaultMap; + const parsed = JSON.parse(raw); + if (parsed && typeof parsed === 'object') { + return { + generated: parsed.generated ?? parsed.default ?? fallback, + uploads: parsed.uploads ?? parsed.default ?? fallback, + }; + } + // Backward compatibility: single value string or number + return createStateMap(raw); + } catch (e) { + // If parsing failed but raw exists, treat it as a primitive single value + if (raw) { + return createStateMap(raw); + } + console.warn('Failed to load history state', e); + return defaultMap; + } +} + +function persistStateMap(key, map) { + try { + localStorage.setItem(key, JSON.stringify(map)); + } catch (e) { + console.warn('Failed to save history state', e); + } +} export function createGallery({ galleryGrid, onSelect }) { - let currentFilter = 'all'; - let searchQuery = ''; + let currentFilter = DEFAULT_STATE.filter; + let searchQuery = DEFAULT_STATE.search; let currentSource = 'generated'; let allImages = []; let favorites = []; - let showOnlyFavorites = false; // New toggle state + let showOnlyFavorites = DEFAULT_STATE.favorites; + const stateBySource = { + generated: { ...DEFAULT_STATE }, + uploads: { ...DEFAULT_STATE }, + }; + + // Load saved filter, search and favorites from localStorage (per source) + const savedFilters = parseStoredMap(FILTER_STORAGE_KEY, DEFAULT_STATE.filter); + const savedSearches = parseStoredMap(SEARCH_STORAGE_KEY, DEFAULT_STATE.search); + const savedFavorites = parseStoredMap(FAVORITES_STORAGE_KEY, DEFAULT_STATE.favorites); + + stateBySource.generated.filter = savedFilters.generated; + stateBySource.uploads.filter = savedFilters.uploads; + stateBySource.generated.search = savedSearches.generated; + stateBySource.uploads.search = savedSearches.uploads; + stateBySource.generated.favorites = savedFavorites.generated; + stateBySource.uploads.favorites = savedFavorites.uploads; - // Load saved filter and search from localStorage try { - const savedFilter = localStorage.getItem(FILTER_STORAGE_KEY); - if (savedFilter) currentFilter = savedFilter; - - const savedSearch = localStorage.getItem(SEARCH_STORAGE_KEY); - if (savedSearch) searchQuery = savedSearch; - const savedSource = localStorage.getItem(SOURCE_STORAGE_KEY); if (savedSource && VALID_SOURCES.includes(savedSource)) { currentSource = savedSource; } } catch (e) { - console.warn('Failed to load history filter/search', e); + console.warn('Failed to load history source', e); } + function applySourceState(source) { + const state = stateBySource[source] || DEFAULT_STATE; + currentFilter = state.filter ?? DEFAULT_STATE.filter; + searchQuery = state.search ?? DEFAULT_STATE.search; + showOnlyFavorites = state.favorites ?? DEFAULT_STATE.favorites; + } + + applySourceState(currentSource); + // Load favorites from backend async function loadFavorites() { try { @@ -306,32 +370,35 @@ export function createGallery({ galleryGrid, onSelect }) { function setFilter(filterType) { if (currentFilter === filterType) return; currentFilter = filterType; + stateBySource[currentSource].filter = filterType; - // Save to localStorage - try { - localStorage.setItem(FILTER_STORAGE_KEY, filterType); - } catch (e) { - console.warn('Failed to save history filter', e); - } + persistStateMap(FILTER_STORAGE_KEY, { + generated: stateBySource.generated.filter, + uploads: stateBySource.uploads.filter, + }); renderGallery(); } function setSearch(query) { searchQuery = query || ''; + stateBySource[currentSource].search = searchQuery; - // Save to localStorage - try { - localStorage.setItem(SEARCH_STORAGE_KEY, searchQuery); - } catch (e) { - console.warn('Failed to save history search', e); - } + persistStateMap(SEARCH_STORAGE_KEY, { + generated: stateBySource.generated.search, + uploads: stateBySource.uploads.search, + }); renderGallery(); } function toggleFavorites() { showOnlyFavorites = !showOnlyFavorites; + stateBySource[currentSource].favorites = showOnlyFavorites; + persistStateMap(FAVORITES_STORAGE_KEY, { + generated: stateBySource.generated.favorites, + uploads: stateBySource.uploads.favorites, + }); renderGallery(); return showOnlyFavorites; } @@ -345,16 +412,21 @@ export function createGallery({ galleryGrid, onSelect }) { console.warn('Failed to save history source', e); } if (resetFilters) { - currentFilter = 'all'; - showOnlyFavorites = false; - searchQuery = ''; - try { - localStorage.setItem(FILTER_STORAGE_KEY, currentFilter); - localStorage.setItem(SEARCH_STORAGE_KEY, searchQuery); - } catch (e) { - console.warn('Failed to reset history filters', e); - } + stateBySource[currentSource] = { ...DEFAULT_STATE }; + persistStateMap(FILTER_STORAGE_KEY, { + generated: stateBySource.generated.filter, + uploads: stateBySource.uploads.filter, + }); + persistStateMap(SEARCH_STORAGE_KEY, { + generated: stateBySource.generated.search, + uploads: stateBySource.uploads.search, + }); + persistStateMap(FAVORITES_STORAGE_KEY, { + generated: stateBySource.generated.favorites, + uploads: stateBySource.uploads.favorites, + }); } + applySourceState(currentSource); return load(); } @@ -376,6 +448,11 @@ export function createGallery({ galleryGrid, onSelect }) { function setFavoritesActive(active) { showOnlyFavorites = Boolean(active); + stateBySource[currentSource].favorites = showOnlyFavorites; + persistStateMap(FAVORITES_STORAGE_KEY, { + generated: stateBySource.generated.favorites, + uploads: stateBySource.uploads.favorites, + }); renderGallery(); return showOnlyFavorites; } diff --git a/static/script.js b/static/script.js index d48b1b6..2c08899 100644 --- a/static/script.js +++ b/static/script.js @@ -1701,6 +1701,24 @@ document.addEventListener('DOMContentLoaded', () => { const historySourceBtns = document.querySelectorAll('.history-source-btn'); const initialSource = gallery.getCurrentSource ? gallery.getCurrentSource() : 'generated'; + function syncHistoryControlsFromGallery() { + const activeFilter = gallery.getCurrentFilter ? gallery.getCurrentFilter() : 'all'; + historyFilterBtns.forEach(btn => { + if (btn.classList.contains('history-favorites-btn')) return; + const isActive = btn.dataset.filter === activeFilter; + btn.classList.toggle('active', isActive); + }); + + if (historyFavoritesBtn && gallery.isFavoritesActive) { + historyFavoritesBtn.classList.toggle('active', gallery.isFavoritesActive()); + } + + const historySearchInputEl = document.getElementById('history-search-input'); + if (historySearchInputEl && gallery.getSearchQuery) { + historySearchInputEl.value = gallery.getSearchQuery(); + } + } + historySourceBtns.forEach(btn => { const isActive = btn.dataset.source === initialSource; btn.classList.toggle('active', isActive); @@ -1713,41 +1731,13 @@ document.addEventListener('DOMContentLoaded', () => { b.classList.toggle('active', active); b.setAttribute('aria-pressed', String(active)); }); - await gallery.setSource(targetSource, { resetFilters: true }); - - // Reset filters UI to show all when switching source - historyFilterBtns.forEach(b => { - if (!b.classList.contains('history-favorites-btn')) { - b.classList.toggle('active', b.dataset.filter === 'all'); - } - }); - - // Disable favorites toggle on source change - if (historyFavoritesBtn) { - historyFavoritesBtn.classList.remove('active'); - } - if (gallery.setFavoritesActive) { - gallery.setFavoritesActive(false); - } - - // Clear search box - const historySearchInputEl = document.getElementById('history-search-input'); - if (historySearchInputEl) { - historySearchInputEl.value = ''; - } - if (gallery.setSearchQuery) { - gallery.setSearchQuery(''); - } + await gallery.setSource(targetSource, { resetFilters: false }); + syncHistoryControlsFromGallery(); }); }); // Set initial active state based on saved filter - const currentFilter = gallery.getCurrentFilter(); - historyFilterBtns.forEach(btn => { - if (btn.dataset.filter === currentFilter && !btn.classList.contains('history-favorites-btn')) { - btn.classList.add('active'); - } - }); + syncHistoryControlsFromGallery(); // Handle favorites button as toggle if (historyFavoritesBtn) {