This commit is contained in:
phamhungd 2025-11-29 21:58:12 +07:00
parent 0485681c76
commit 4a9f6764d9
2 changed files with 90 additions and 71 deletions

View file

@ -1,35 +1,69 @@
import { withCacheBuster } from './utils.js'; import { withCacheBuster } from './utils.js';
import { extractMetadataFromBlob } from './metadata.js'; import { extractMetadataFromBlob } from './metadata.js';
const FILTER_STORAGE_KEY = 'gemini-app-history-filter'; const GALLERY_STATE_KEY = 'gemini-app-gallery-state';
const SEARCH_STORAGE_KEY = 'gemini-app-history-search'; const FILTER_STORAGE_KEY = 'gemini-app-history-filter'; // legacy (single-state)
const SEARCH_STORAGE_KEY = 'gemini-app-history-search'; // legacy (single-state)
const SOURCE_STORAGE_KEY = 'gemini-app-history-source'; const SOURCE_STORAGE_KEY = 'gemini-app-history-source';
const VALID_SOURCES = ['generated', 'uploads']; const VALID_SOURCES = ['generated', 'uploads'];
export function createGallery({ galleryGrid, onSelect }) { export function createGallery({ galleryGrid, onSelect }) {
let currentFilter = 'all';
let searchQuery = '';
let currentSource = 'generated'; let currentSource = 'generated';
let allImages = []; let allImages = [];
let favorites = []; let favorites = [];
let showOnlyFavorites = false; // New toggle state let perSourceState = {
generated: { filter: 'all', search: '', favoritesOnly: false },
uploads: { filter: 'all', search: '', favoritesOnly: false },
};
// Load saved filter and search from localStorage const persistState = () => {
try { try {
const savedFilter = localStorage.getItem(FILTER_STORAGE_KEY); localStorage.setItem(GALLERY_STATE_KEY, JSON.stringify({
if (savedFilter) currentFilter = savedFilter; sourceState: perSourceState,
source: currentSource,
}));
} catch (e) {
console.warn('Failed to persist gallery state', e);
}
};
// Load saved state (with legacy fallback)
try {
const saved = localStorage.getItem(GALLERY_STATE_KEY);
if (saved) {
const parsed = JSON.parse(saved);
if (parsed?.sourceState) {
perSourceState = {
generated: { filter: 'all', search: '', favoritesOnly: false, ...(parsed.sourceState.generated || {}) },
uploads: { filter: 'all', search: '', favoritesOnly: false, ...(parsed.sourceState.uploads || {}) },
};
}
if (parsed?.source && VALID_SOURCES.includes(parsed.source)) {
currentSource = parsed.source;
}
} else {
// Legacy fallback (single state)
const savedFilter = localStorage.getItem(FILTER_STORAGE_KEY);
const savedSearch = localStorage.getItem(SEARCH_STORAGE_KEY); const savedSearch = localStorage.getItem(SEARCH_STORAGE_KEY);
if (savedSearch) searchQuery = savedSearch; if (savedFilter) perSourceState.generated.filter = savedFilter;
if (savedSearch) perSourceState.generated.search = savedSearch;
}
const savedSource = localStorage.getItem(SOURCE_STORAGE_KEY); const savedSource = localStorage.getItem(SOURCE_STORAGE_KEY);
if (savedSource && VALID_SOURCES.includes(savedSource)) { if (savedSource && VALID_SOURCES.includes(savedSource)) {
currentSource = savedSource; currentSource = savedSource;
} }
} catch (e) { } catch (e) {
console.warn('Failed to load history filter/search', e); console.warn('Failed to load gallery state', e);
} }
const getState = (source = currentSource) => {
if (!perSourceState[source]) {
perSourceState[source] = { filter: 'all', search: '', favoritesOnly: false };
}
return perSourceState[source];
};
// Load favorites from backend // Load favorites from backend
async function loadFavorites() { async function loadFavorites() {
try { try {
@ -118,27 +152,29 @@ export function createGallery({ galleryGrid, onSelect }) {
} }
function matchesSearch(imageUrl) { function matchesSearch(imageUrl) {
if (!searchQuery) return true; const { search } = getState();
if (!search) return true;
const filename = imageUrl.split('/').pop().split('?')[0]; const filename = imageUrl.split('/').pop().split('?')[0];
return filename.toLowerCase().includes(searchQuery.toLowerCase()); return filename.toLowerCase().includes(search.toLowerCase());
} }
function shouldShowImage(imageUrl) { function shouldShowImage(imageUrl) {
const state = getState();
// First check text search // First check text search
if (!matchesSearch(imageUrl)) return false; if (!matchesSearch(imageUrl)) return false;
// Check favorites toggle - if enabled, only show favorites // Check favorites toggle - if enabled, only show favorites
if (showOnlyFavorites && !isFavorite(imageUrl)) { if (state.favoritesOnly && !isFavorite(imageUrl)) {
return false; return false;
} }
// Then check date filter // Then check date filter
if (currentFilter === 'all') return true; if (state.filter === 'all') return true;
const timestamp = getFileTimestamp(imageUrl); const timestamp = getFileTimestamp(imageUrl);
if (!timestamp) return currentFilter === 'all'; if (!timestamp) return state.filter === 'all';
switch (currentFilter) { switch (state.filter) {
case 'today': case 'today':
return isToday(timestamp); return isToday(timestamp);
case 'week': case 'week':
@ -305,35 +341,33 @@ export function createGallery({ galleryGrid, onSelect }) {
function setFilter(filterType) { function setFilter(filterType) {
if (currentFilter === filterType) return; if (currentFilter === filterType) return;
currentFilter = filterType; const state = getState();
state.filter = filterType;
// Save to localStorage persistState();
try {
localStorage.setItem(FILTER_STORAGE_KEY, filterType);
} catch (e) {
console.warn('Failed to save history filter', e);
}
renderGallery(); renderGallery();
} }
function setSearch(query) { function setSearch(query) {
searchQuery = query || ''; const state = getState();
state.search = query || '';
// Save to localStorage persistState();
try {
localStorage.setItem(SEARCH_STORAGE_KEY, searchQuery);
} catch (e) {
console.warn('Failed to save history search', e);
}
renderGallery(); renderGallery();
} }
function toggleFavorites() { function toggleFavorites() {
showOnlyFavorites = !showOnlyFavorites; const state = getState();
state.favoritesOnly = !state.favoritesOnly;
persistState();
renderGallery(); renderGallery();
return showOnlyFavorites; return state.favoritesOnly;
}
function setFavoritesActive(active) {
const state = getState();
state.favoritesOnly = Boolean(active);
persistState();
renderGallery();
return state.favoritesOnly;
} }
function setSource(source, { resetFilters = false } = {}) { function setSource(source, { resetFilters = false } = {}) {
@ -345,25 +379,22 @@ export function createGallery({ galleryGrid, onSelect }) {
console.warn('Failed to save history source', e); console.warn('Failed to save history source', e);
} }
if (resetFilters) { if (resetFilters) {
currentFilter = 'all'; const state = getState();
showOnlyFavorites = false; state.filter = 'all';
searchQuery = ''; state.favoritesOnly = false;
try { state.search = '';
localStorage.setItem(FILTER_STORAGE_KEY, currentFilter); persistState();
localStorage.setItem(SEARCH_STORAGE_KEY, searchQuery);
} catch (e) {
console.warn('Failed to reset history filters', e);
}
} }
persistState();
return load(); return load();
} }
function getCurrentFilter() { function getCurrentFilter() {
return currentFilter; return getState().filter;
} }
function getSearchQuery() { function getSearchQuery() {
return searchQuery; return getState().search;
} }
function getCurrentSource() { function getCurrentSource() {
@ -371,13 +402,7 @@ export function createGallery({ galleryGrid, onSelect }) {
} }
function isFavoritesActive() { function isFavoritesActive() {
return showOnlyFavorites; return getState().favoritesOnly;
}
function setFavoritesActive(active) {
showOnlyFavorites = Boolean(active);
renderGallery();
return showOnlyFavorites;
} }
function setSearchQuery(value) { function setSearchQuery(value) {

View file

@ -1713,30 +1713,24 @@ document.addEventListener('DOMContentLoaded', () => {
b.classList.toggle('active', active); b.classList.toggle('active', active);
b.setAttribute('aria-pressed', String(active)); b.setAttribute('aria-pressed', String(active));
}); });
await gallery.setSource(targetSource, { resetFilters: true }); await gallery.setSource(targetSource, { resetFilters: false });
// Reset filters UI to show all when switching source // Sync UI with persisted state (filter, favorites, search)
const activeFilter = gallery.getCurrentFilter ? gallery.getCurrentFilter() : 'all';
historyFilterBtns.forEach(b => { historyFilterBtns.forEach(b => {
if (!b.classList.contains('history-favorites-btn')) { if (!b.classList.contains('history-favorites-btn')) {
b.classList.toggle('active', b.dataset.filter === 'all'); const isFilterActive = b.dataset.filter === activeFilter;
b.classList.toggle('active', isFilterActive);
} }
}); });
// Disable favorites toggle on source change if (historyFavoritesBtn && gallery.isFavoritesActive) {
if (historyFavoritesBtn) { historyFavoritesBtn.classList.toggle('active', gallery.isFavoritesActive());
historyFavoritesBtn.classList.remove('active');
}
if (gallery.setFavoritesActive) {
gallery.setFavoritesActive(false);
} }
// Clear search box
const historySearchInputEl = document.getElementById('history-search-input'); const historySearchInputEl = document.getElementById('history-search-input');
if (historySearchInputEl) { if (historySearchInputEl && gallery.getSearchQuery) {
historySearchInputEl.value = ''; historySearchInputEl.value = gallery.getSearchQuery();
}
if (gallery.setSearchQuery) {
gallery.setSearchQuery('');
} }
}); });
}); });