Files
AppleHillsProduction/Assets/Scripts/Minigames/StatueDressup/Controllers/StatuePhotoGalleryController.cs
Michal Pikulski 5bab6d9596 stash work
2025-11-27 11:29:45 +01:00

391 lines
14 KiB
C#

using System.Collections;
using System.Collections.Generic;
using Core;
using Core.Lifecycle;
using UnityEngine;
using UnityEngine.UI;
using Utils;
namespace Minigames.StatueDressup.Controllers
{
/// <summary>
/// Manages photo gallery display with optimized memory usage.
/// Loads photos in pages and caches thumbnails to avoid loading 1000+ photos at once.
/// Supports grid view with thumbnail preview and enlarged view on selection.
/// </summary>
public class StatuePhotoGalleryController : ManagedBehaviour
{
[Header("Gallery UI")]
[SerializeField] private Transform gridContainer;
[SerializeField] private PhotoGridItem gridItemPrefab;
[Header("Enlarged View")]
[SerializeField] private Transform enlargedContainer; // Container for enlarged preview (top layer)
[SerializeField] private GameObject backdrop; // Dark backdrop for enlarged view
[SerializeField] private GameObject enlargedPreviewPrefab; // Prefab for enlarged preview (same as grid item)
[Header("Pagination")]
[SerializeField] private Button previousPageButton;
[SerializeField] private Button nextPageButton;
[SerializeField] private Text pageStatusText;
private AppleHills.Core.Settings.IStatueDressupSettings _settings;
private int _currentPage;
private List<string> _allPhotoIds = new List<string>();
private Dictionary<string, PhotoGridItem> _activeGridItems = new Dictionary<string, PhotoGridItem>();
private Dictionary<string, Texture2D> _thumbnailCache = new Dictionary<string, Texture2D>();
private Dictionary<string, Texture2D> _fullPhotoCache = new Dictionary<string, Texture2D>(); // Cache full photos for enlargement
private Queue<string> _thumbnailCacheOrder = new Queue<string>();
private bool _isLoadingPage;
private PhotoEnlargeController _enlargeController;
internal override void OnManagedStart()
{
base.OnManagedStart();
// Get settings
_settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>();
// Initialize enlarge controller
_enlargeController = new PhotoEnlargeController(backdrop, enlargedContainer, _settings?.GalleryAnimationDuration ?? 0.3f);
// Setup page navigation buttons
if (previousPageButton != null)
previousPageButton.onClick.AddListener(OnPreviousPageClicked);
if (nextPageButton != null)
nextPageButton.onClick.AddListener(OnNextPageClicked);
// Hide backdrop initially
if (backdrop != null)
backdrop.SetActive(false);
// Clear grid initially (in case there are leftover items from scene setup)
ClearGrid();
// Load first page
RefreshGallery();
}
/// <summary>
/// Refresh the entire gallery from scratch
/// </summary>
public void RefreshGallery()
{
// Clear existing items
ClearGrid();
// Get all photo IDs
_allPhotoIds = PhotoManager.GetAllPhotoIds(CaptureType.StatueMinigame);
_currentPage = 0;
Logging.Debug($"[StatuePhotoGalleryController] Gallery refreshed: {_allPhotoIds.Count} photos");
// Display first page
DisplayCurrentPage();
}
/// <summary>
/// Display the current page of photos (clears grid and shows only current page)
/// </summary>
private void DisplayCurrentPage()
{
if (_isLoadingPage) return;
_isLoadingPage = true;
// Clear current grid
ClearGrid();
// Get photos for current page
int itemsPerPage = _settings?.GalleryItemsPerPage ?? 20;
List<string> pagePhotoIds = PhotoManager.GetPhotoIdsPage(CaptureType.StatueMinigame, _currentPage, itemsPerPage);
Logging.Debug($"[StatuePhotoGalleryController] Displaying page {_currentPage + 1}: {pagePhotoIds.Count} items");
// Spawn grid items for this page
foreach (string photoId in pagePhotoIds)
{
SpawnGridItem(photoId);
}
// Update button states
UpdatePageButtons();
// Update status text
int totalPages = Mathf.CeilToInt((float)_allPhotoIds.Count / itemsPerPage);
UpdateStatusText($"Page {_currentPage + 1}/{totalPages} ({_allPhotoIds.Count} photos)");
_isLoadingPage = false;
}
/// <summary>
/// Update page navigation button states
/// </summary>
private void UpdatePageButtons()
{
int itemsPerPage = _settings?.GalleryItemsPerPage ?? 20;
int totalPages = Mathf.CeilToInt((float)_allPhotoIds.Count / itemsPerPage);
// Enable/disable previous button
if (previousPageButton != null)
{
previousPageButton.interactable = _currentPage > 0;
}
// Enable/disable next button
if (nextPageButton != null)
{
nextPageButton.interactable = _currentPage < totalPages - 1;
}
}
/// <summary>
/// Navigate to previous page
/// </summary>
private void OnPreviousPageClicked()
{
if (_currentPage > 0)
{
_currentPage--;
DisplayCurrentPage();
Logging.Debug($"[StatuePhotoGalleryController] Navigated to previous page: {_currentPage}");
}
}
/// <summary>
/// Navigate to next page
/// </summary>
private void OnNextPageClicked()
{
int itemsPerPage = _settings?.GalleryItemsPerPage ?? 20;
int totalPages = Mathf.CeilToInt((float)_allPhotoIds.Count / itemsPerPage);
if (_currentPage < totalPages - 1)
{
_currentPage++;
DisplayCurrentPage();
Logging.Debug($"[StatuePhotoGalleryController] Navigated to next page: {_currentPage}");
}
}
/// <summary>
/// Spawn a grid item for a photo
/// </summary>
private void SpawnGridItem(string photoId)
{
if (_activeGridItems.ContainsKey(photoId))
{
Logging.Warning($"[StatuePhotoGalleryController] Grid item already exists: {photoId}");
return;
}
PhotoGridItem gridItem = Instantiate(gridItemPrefab, gridContainer);
gridItem.Initialize(photoId, this);
_activeGridItems[photoId] = gridItem;
// Load thumbnail asynchronously
StartCoroutine(LoadThumbnailAsync(photoId, gridItem));
}
/// <summary>
/// Load thumbnail for grid item (async to avoid frame hitches)
/// </summary>
private IEnumerator LoadThumbnailAsync(string photoId, PhotoGridItem gridItem)
{
// Check cache first
if (_thumbnailCache.TryGetValue(photoId, out Texture2D cachedThumbnail))
{
gridItem.SetThumbnail(cachedThumbnail);
yield break;
}
// Yield to avoid loading all thumbnails in one frame
yield return null;
// Load full photo
Texture2D fullPhoto = PhotoManager.LoadPhoto(CaptureType.StatueMinigame, photoId);
if (fullPhoto == null)
{
Logging.Warning($"[StatuePhotoGalleryController] Failed to load photo: {photoId}");
yield break;
}
// Create thumbnail
int thumbSize = _settings?.GalleryThumbnailSize ?? 256;
Texture2D thumbnail = PhotoManager.CreateThumbnail(fullPhoto, thumbSize);
// Destroy full photo immediately (we only need thumbnail)
Destroy(fullPhoto);
// Cache thumbnail
CacheThumbnail(photoId, thumbnail);
// Set on grid item
if (gridItem != null)
{
gridItem.SetThumbnail(thumbnail);
}
}
/// <summary>
/// Cache thumbnail with LRU eviction
/// </summary>
private void CacheThumbnail(string photoId, Texture2D thumbnail)
{
// Add to cache
_thumbnailCache[photoId] = thumbnail;
_thumbnailCacheOrder.Enqueue(photoId);
// Evict oldest if over limit
int maxCached = _settings?.GalleryMaxCachedThumbnails ?? 50;
while (_thumbnailCache.Count > maxCached && _thumbnailCacheOrder.Count > 0)
{
string oldestId = _thumbnailCacheOrder.Dequeue();
if (_thumbnailCache.TryGetValue(oldestId, out Texture2D oldThumbnail))
{
Destroy(oldThumbnail);
_thumbnailCache.Remove(oldestId);
Logging.Debug($"[StatuePhotoGalleryController] Evicted thumbnail from cache: {oldestId}");
}
}
}
/// <summary>
/// Enlarge a photo (called by PhotoGridItem)
/// </summary>
public void OnGridItemClicked(PhotoGridItem gridItem, string photoId)
{
if (_enlargeController == null)
{
Logging.Error("[StatuePhotoGalleryController] Enlarge controller not initialized");
return;
}
// If already enlarged, shrink it
if (_enlargeController.IsPhotoEnlarged)
{
_enlargeController.ShrinkPhoto();
return;
}
Logging.Debug($"[StatuePhotoGalleryController] Enlarging photo: {photoId}");
float enlargedScale = _settings?.GalleryEnlargedScale ?? 2.5f;
// Check cache first
if (_fullPhotoCache.TryGetValue(photoId, out Texture2D fullPhoto))
{
// Use cached photo
_enlargeController.EnlargePhoto(gridItem, enlargedPreviewPrefab != null ? enlargedPreviewPrefab : gridItem.gameObject, fullPhoto, enlargedScale);
}
else
{
// Load full-size photo
fullPhoto = PhotoManager.LoadPhoto(CaptureType.StatueMinigame, photoId);
if (fullPhoto == null)
{
Logging.Error($"[StatuePhotoGalleryController] Failed to load photo: {photoId}");
return;
}
// Cache it (limited cache)
if (_fullPhotoCache.Count < 10) // Keep only recent 10 full photos
{
_fullPhotoCache[photoId] = fullPhoto;
}
_enlargeController.EnlargePhoto(gridItem, enlargedPreviewPrefab != null ? enlargedPreviewPrefab : gridItem.gameObject, fullPhoto, enlargedScale);
}
}
/// <summary>
/// Cleanup when gallery is closed
/// </summary>
public void CleanupGallery()
{
if (_enlargeController != null)
{
_enlargeController.Cleanup();
}
// Clean up cached full photos
foreach (var photo in _fullPhotoCache.Values)
{
if (photo != null)
{
Destroy(photo);
}
}
_fullPhotoCache.Clear();
}
/// <summary>
/// Update status text
/// </summary>
private void UpdateStatusText(string message)
{
if (pageStatusText != null)
pageStatusText.text = message;
Logging.Debug($"[StatuePhotoGalleryController] Status: {message}");
}
/// <summary>
/// Clear only the grid items (used when switching pages)
/// </summary>
private void ClearGrid()
{
// Destroy grid items
foreach (var gridItem in _activeGridItems.Values)
{
if (gridItem != null)
Destroy(gridItem.gameObject);
}
_activeGridItems.Clear();
Logging.Debug("[StatuePhotoGalleryController] Grid cleared");
}
/// <summary>
/// Clear all grid items and cached data (full cleanup)
/// </summary>
private void ClearGallery()
{
ClearGrid();
// Clear thumbnail cache
foreach (var thumbnail in _thumbnailCache.Values)
{
if (thumbnail != null)
Destroy(thumbnail);
}
_thumbnailCache.Clear();
_thumbnailCacheOrder.Clear();
Logging.Debug("[StatuePhotoGalleryController] Gallery fully cleared");
}
internal override void OnManagedDestroy()
{
base.OnManagedDestroy();
// Cleanup
ClearGallery();
CleanupGallery();
// Unsubscribe buttons
if (previousPageButton != null)
previousPageButton.onClick.RemoveListener(OnPreviousPageClicked);
if (nextPageButton != null)
nextPageButton.onClick.RemoveListener(OnNextPageClicked);
}
}
}