Cleanup code structure, code smells, rename paramter, break out more granular managers
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
using System.Collections.Generic;
|
||||
using Core;
|
||||
using Core.Lifecycle;
|
||||
using Minigames.StatueDressup.Data;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using Utils;
|
||||
|
||||
namespace Minigames.StatueDressup.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton manager for decoration data loading and caching.
|
||||
/// Loads all DecorationData assets once via Addressables and provides shared access.
|
||||
/// Used by both minigame and town map to avoid duplicate loading.
|
||||
/// </summary>
|
||||
public class DecorationDataManager : ManagedBehaviour
|
||||
{
|
||||
public static DecorationDataManager Instance { get; private set; }
|
||||
|
||||
private Dictionary<string, DecorationData> decorationDataDict;
|
||||
private AsyncOperationHandle<System.Collections.Generic.IList<DecorationData>> decorationDataHandle;
|
||||
private bool isLoaded;
|
||||
|
||||
/// <summary>
|
||||
/// Check if data is loaded and ready
|
||||
/// </summary>
|
||||
public bool IsLoaded => isLoaded;
|
||||
|
||||
/// <summary>
|
||||
/// Get all decoration data as dictionary
|
||||
/// </summary>
|
||||
public Dictionary<string, DecorationData> AllData => decorationDataDict;
|
||||
|
||||
internal override void OnManagedAwake()
|
||||
{
|
||||
base.OnManagedAwake();
|
||||
|
||||
// Singleton pattern
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Logging.Warning("[DecorationDataManager] Duplicate instance detected. Destroying duplicate.");
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
internal override async void OnManagedStart()
|
||||
{
|
||||
base.OnManagedStart();
|
||||
|
||||
await LoadAllDecorationData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load all DecorationData assets via Addressables
|
||||
/// </summary>
|
||||
private async System.Threading.Tasks.Task LoadAllDecorationData()
|
||||
{
|
||||
if (isLoaded)
|
||||
{
|
||||
Logging.Warning("[DecorationDataManager] Data already loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
var settings = StatueDressupSettings.Instance?.Settings;
|
||||
string label = settings?.DecorationDataLabel;
|
||||
|
||||
if (string.IsNullOrEmpty(label))
|
||||
{
|
||||
Logging.Error("[DecorationDataManager] Decoration data label not set in settings!");
|
||||
return;
|
||||
}
|
||||
|
||||
Logging.Debug($"[DecorationDataManager] Loading DecorationData with label '{label}'...");
|
||||
|
||||
// Use utility to load all DecorationData and create dictionary by ID
|
||||
var result = await AddressablesUtility.LoadAssetsByLabelAsync<DecorationData, string>(
|
||||
label,
|
||||
data => data.DecorationId
|
||||
);
|
||||
|
||||
decorationDataDict = result.dictionary;
|
||||
decorationDataHandle = result.handle;
|
||||
isLoaded = true;
|
||||
|
||||
Logging.Debug($"[DecorationDataManager] Loaded {decorationDataDict.Count} DecorationData assets");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get decoration data by ID
|
||||
/// </summary>
|
||||
public DecorationData GetData(string decorationId)
|
||||
{
|
||||
if (!isLoaded)
|
||||
{
|
||||
Logging.Warning("[DecorationDataManager] Data not loaded yet!");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(decorationId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
decorationDataDict.TryGetValue(decorationId, out DecorationData data);
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try get decoration data by ID
|
||||
/// </summary>
|
||||
public bool TryGetData(string decorationId, out DecorationData data)
|
||||
{
|
||||
data = null;
|
||||
|
||||
if (!isLoaded || string.IsNullOrEmpty(decorationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return decorationDataDict.TryGetValue(decorationId, out data);
|
||||
}
|
||||
|
||||
internal override void OnManagedDestroy()
|
||||
{
|
||||
base.OnManagedDestroy();
|
||||
|
||||
// Release Addressables handle
|
||||
AddressablesUtility.ReleaseHandle(decorationDataHandle);
|
||||
|
||||
if (Instance == this)
|
||||
{
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afa56ec5b1f84b32ba014a91d9d9a0a0
|
||||
timeCreated: 1764240174
|
||||
@@ -13,6 +13,8 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
public class DecorationMenuController : ManagedBehaviour
|
||||
{
|
||||
public static DecorationMenuController Instance { get; private set; }
|
||||
|
||||
[Header("References")]
|
||||
[SerializeField] private DecorationGridIcon iconPrefab;
|
||||
[SerializeField] private DecorationDraggableInstance draggablePrefab;
|
||||
@@ -20,36 +22,36 @@ namespace Minigames.StatueDressup.Controllers
|
||||
[SerializeField] private Transform draggableContainer; // Parent for spawned draggables
|
||||
[SerializeField] private Button nextPageButton;
|
||||
[SerializeField] private Button previousPageButton;
|
||||
[SerializeField] private StatueDecorationController statueController; // Controller for registration
|
||||
[SerializeField] private Image statueOutline; // Outline image shown during drag to indicate valid drop area
|
||||
|
||||
[Header("Layout")]
|
||||
[SerializeField] private GridLayoutGroup gridLayout;
|
||||
|
||||
private int _currentPage;
|
||||
private int _totalPages;
|
||||
private List<DecorationGridIcon> _spawnedIcons = new List<DecorationGridIcon>();
|
||||
private AppleHills.Core.Settings.IStatueDressupSettings _settings;
|
||||
private int currentPage;
|
||||
private int totalPages;
|
||||
private List<DecorationGridIcon> spawnedIcons = new List<DecorationGridIcon>();
|
||||
|
||||
// Properties
|
||||
public int CurrentPage => _currentPage;
|
||||
public int TotalPages => _totalPages;
|
||||
public int CurrentPage => currentPage;
|
||||
public int TotalPages => totalPages;
|
||||
|
||||
/// <summary>
|
||||
/// Early initialization - get settings reference
|
||||
/// Early initialization - singleton setup
|
||||
/// </summary>
|
||||
internal override void OnManagedAwake()
|
||||
{
|
||||
base.OnManagedAwake();
|
||||
|
||||
// Get settings early
|
||||
_settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>();
|
||||
|
||||
if (_settings == null)
|
||||
// Singleton pattern
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Logging.Error("[DecorationMenuController] Failed to load StatueDressupSettings!");
|
||||
Logging.Warning("[DecorationMenuController] Duplicate instance detected. Destroying duplicate.");
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
|
||||
// Ensure outline starts hidden (do this early so it's ready for saved decorations)
|
||||
if (statueOutline != null)
|
||||
{
|
||||
@@ -64,27 +66,29 @@ namespace Minigames.StatueDressup.Controllers
|
||||
{
|
||||
base.OnManagedStart();
|
||||
|
||||
if (_settings == null)
|
||||
var settings = StatueDressupSettings.Instance?.Settings;
|
||||
|
||||
if (settings == null)
|
||||
{
|
||||
Logging.Error("[DecorationMenuController] Cannot initialize without settings!");
|
||||
return;
|
||||
}
|
||||
|
||||
var allDecorations = _settings.AllDecorations;
|
||||
int itemsPerPage = _settings.ItemsPerPage;
|
||||
var allDecorations = settings.AllDecorations;
|
||||
int itemsPerPage = settings.ItemsPerPage;
|
||||
|
||||
Logging.Debug($"[DecorationMenuController] Initializing with {allDecorations?.Count ?? 0} decorations");
|
||||
|
||||
// Calculate total pages
|
||||
if (allDecorations != null && allDecorations.Count > 0)
|
||||
{
|
||||
_totalPages = Mathf.CeilToInt((float)allDecorations.Count / itemsPerPage);
|
||||
Logging.Debug($"[DecorationMenuController] Total pages: {_totalPages}");
|
||||
totalPages = Mathf.CeilToInt((float)allDecorations.Count / itemsPerPage);
|
||||
Logging.Debug($"[DecorationMenuController] Total pages: {totalPages}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Warning("[DecorationMenuController] No decorations found in settings!");
|
||||
_totalPages = 0;
|
||||
totalPages = 0;
|
||||
}
|
||||
|
||||
// Setup buttons
|
||||
@@ -110,10 +114,11 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private void PopulateCurrentPage()
|
||||
{
|
||||
if (_settings == null) return;
|
||||
var settings = StatueDressupSettings.Instance?.Settings;
|
||||
if (settings == null) return;
|
||||
|
||||
var allDecorations = _settings.AllDecorations;
|
||||
int itemsPerPage = _settings.ItemsPerPage;
|
||||
var allDecorations = settings.AllDecorations;
|
||||
int itemsPerPage = settings.ItemsPerPage;
|
||||
|
||||
if (allDecorations == null || allDecorations.Count == 0)
|
||||
{
|
||||
@@ -121,13 +126,13 @@ namespace Minigames.StatueDressup.Controllers
|
||||
return;
|
||||
}
|
||||
|
||||
Logging.Debug($"[DecorationMenuController] Populating page {_currentPage + 1}/{_totalPages}");
|
||||
Logging.Debug($"[DecorationMenuController] Populating page {currentPage + 1}/{totalPages}");
|
||||
|
||||
// Clear existing icons
|
||||
ClearIcons();
|
||||
|
||||
// Calculate range for current page
|
||||
int startIndex = _currentPage * itemsPerPage;
|
||||
int startIndex = currentPage * itemsPerPage;
|
||||
int endIndex = Mathf.Min(startIndex + itemsPerPage, allDecorations.Count);
|
||||
|
||||
Logging.Debug($"[DecorationMenuController] Spawning icons {startIndex} to {endIndex - 1}");
|
||||
@@ -156,7 +161,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
DecorationGridIcon icon = Instantiate(iconPrefab, itemsContainer);
|
||||
icon.Initialize(data, this);
|
||||
|
||||
_spawnedIcons.Add(icon);
|
||||
spawnedIcons.Add(icon);
|
||||
|
||||
Logging.Debug($"[DecorationMenuController] Spawned icon: {data.DecorationName}");
|
||||
}
|
||||
@@ -167,7 +172,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
public DecorationDraggableInstance SpawnDraggableInstance(DecorationData data, Vector3 screenPosition)
|
||||
{
|
||||
if (draggablePrefab == null || statueController == null)
|
||||
if (draggablePrefab == null || StatueDecorationController.Instance == null)
|
||||
{
|
||||
Logging.Warning("[DecorationMenuController] Missing draggable prefab or statue controller");
|
||||
return null;
|
||||
@@ -185,18 +190,21 @@ namespace Minigames.StatueDressup.Controllers
|
||||
// Get outline RectTransform for overlap detection
|
||||
RectTransform outlineRect = statueOutline != null ? statueOutline.rectTransform : null;
|
||||
|
||||
// Initialize with references including outline callbacks
|
||||
instance.Initialize(
|
||||
// Create context for new drag
|
||||
var context = DecorationDragContext.CreateForNewDrag(
|
||||
data,
|
||||
outlineRect,
|
||||
statueController.StatueParent,
|
||||
statueController,
|
||||
_settings,
|
||||
StatueDecorationController.Instance.StatueParent,
|
||||
StatueDecorationController.Instance,
|
||||
StatueDressupSettings.Instance.Settings,
|
||||
OnDraggableFinished,
|
||||
ShowStatueOutline, // Show outline when picking up from statue
|
||||
HideStatueOutline // Hide outline when drag ends
|
||||
ShowStatueOutline,
|
||||
HideStatueOutline
|
||||
);
|
||||
|
||||
// Initialize with context
|
||||
instance.InitializeWithContext(context);
|
||||
|
||||
// Position at cursor (in local space)
|
||||
Canvas canvas = GetComponentInParent<Canvas>();
|
||||
if (canvas != null)
|
||||
@@ -261,7 +269,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private void ClearIcons()
|
||||
{
|
||||
foreach (var icon in _spawnedIcons)
|
||||
foreach (var icon in spawnedIcons)
|
||||
{
|
||||
if (icon != null)
|
||||
{
|
||||
@@ -269,7 +277,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
_spawnedIcons.Clear();
|
||||
spawnedIcons.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -277,11 +285,11 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private void OnNextPage()
|
||||
{
|
||||
if (_currentPage < _totalPages - 1)
|
||||
if (currentPage < totalPages - 1)
|
||||
{
|
||||
_currentPage++;
|
||||
currentPage++;
|
||||
PopulateCurrentPage();
|
||||
Logging.Debug($"[DecorationMenuController] Next page: {_currentPage + 1}/{_totalPages}");
|
||||
Logging.Debug($"[DecorationMenuController] Next page: {currentPage + 1}/{totalPages}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,11 +298,11 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private void OnPreviousPage()
|
||||
{
|
||||
if (_currentPage > 0)
|
||||
if (currentPage > 0)
|
||||
{
|
||||
_currentPage--;
|
||||
currentPage--;
|
||||
PopulateCurrentPage();
|
||||
Logging.Debug($"[DecorationMenuController] Previous page: {_currentPage + 1}/{_totalPages}");
|
||||
Logging.Debug($"[DecorationMenuController] Previous page: {currentPage + 1}/{totalPages}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,14 +311,14 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private void UpdateNavigationButtons()
|
||||
{
|
||||
if (previousPageButton != null)
|
||||
{
|
||||
previousPageButton.interactable = _currentPage > 0;
|
||||
}
|
||||
|
||||
if (nextPageButton != null)
|
||||
{
|
||||
nextPageButton.interactable = _currentPage < _totalPages - 1;
|
||||
nextPageButton.interactable = currentPage < totalPages - 1;
|
||||
}
|
||||
|
||||
if (previousPageButton != null)
|
||||
{
|
||||
previousPageButton.interactable = currentPage > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,6 +342,12 @@ namespace Minigames.StatueDressup.Controllers
|
||||
|
||||
// Cleanup icons
|
||||
ClearIcons();
|
||||
|
||||
// Singleton cleanup
|
||||
if (Instance == this)
|
||||
{
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Utils;
|
||||
|
||||
namespace Minigames.StatueDressup.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Minimal test for photo capture - just capture and save to disk
|
||||
/// </summary>
|
||||
public class PhotoCaptureTestController : MonoBehaviour
|
||||
{
|
||||
[Header("Required")]
|
||||
[SerializeField] private RectTransform captureArea;
|
||||
[SerializeField] private Button captureButton;
|
||||
|
||||
[Header("Optional - UI to hide during capture")]
|
||||
[SerializeField] private GameObject[] hideTheseObjects;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (captureButton != null)
|
||||
{
|
||||
captureButton.onClick.AddListener(OnCaptureClicked);
|
||||
}
|
||||
|
||||
Debug.Log($"[PhotoCaptureTest] Ready. Photo save path: {PhotoManager.GetCaptureDirectory(CaptureType.StatueMinigame)}");
|
||||
}
|
||||
|
||||
private void OnCaptureClicked()
|
||||
{
|
||||
if (captureArea == null)
|
||||
{
|
||||
Debug.LogError("[PhotoCaptureTest] Capture Area not assigned!");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("[PhotoCaptureTest] Starting capture...");
|
||||
StartCoroutine(CaptureCoroutine());
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator CaptureCoroutine()
|
||||
{
|
||||
// Use new PhotoManager plug-and-play coroutine
|
||||
yield return PhotoManager.CaptureAndSaveCoroutine(
|
||||
CaptureType.StatueMinigame,
|
||||
captureArea,
|
||||
hideTheseObjects,
|
||||
onSuccess: (photoId) =>
|
||||
{
|
||||
string path = $"{PhotoManager.GetCaptureDirectory(CaptureType.StatueMinigame)}/{photoId}.png";
|
||||
Debug.Log($"[PhotoCaptureTest] ✅ SUCCESS! Photo saved: {path}");
|
||||
|
||||
// Load back to verify
|
||||
Texture2D loadedPhoto = PhotoManager.LoadPhoto(CaptureType.StatueMinigame, photoId);
|
||||
if (loadedPhoto != null)
|
||||
{
|
||||
Debug.Log($"[PhotoCaptureTest] Photo size: {loadedPhoto.width}x{loadedPhoto.height}");
|
||||
}
|
||||
},
|
||||
onFailure: (error) =>
|
||||
{
|
||||
Debug.LogError($"[PhotoCaptureTest] ❌ Failed: {error}");
|
||||
},
|
||||
metadata: 0
|
||||
);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (captureButton != null)
|
||||
captureButton.onClick.RemoveListener(OnCaptureClicked);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: deab1758ddef4bdea0e2c50554eaf568
|
||||
timeCreated: 1764077035
|
||||
@@ -1,163 +0,0 @@
|
||||
using Core;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using Utils;
|
||||
|
||||
namespace Minigames.StatueDressup.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages enlarged photo preview display.
|
||||
/// Handles backdrop, preview spawning, and click-to-dismiss.
|
||||
/// Similar to CardEnlargeController but simpler (no state machine).
|
||||
/// </summary>
|
||||
public class PhotoEnlargeController
|
||||
{
|
||||
private readonly GameObject _backdrop;
|
||||
private readonly Transform _enlargedContainer;
|
||||
private readonly float _animationDuration;
|
||||
|
||||
private GameObject _currentEnlargedPreview;
|
||||
private PhotoGridItem _currentSourceItem;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public PhotoEnlargeController(GameObject backdrop, Transform enlargedContainer, float animationDuration = 0.3f)
|
||||
{
|
||||
_backdrop = backdrop;
|
||||
_enlargedContainer = enlargedContainer;
|
||||
_animationDuration = animationDuration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a photo is currently enlarged
|
||||
/// </summary>
|
||||
public bool IsPhotoEnlarged => _currentEnlargedPreview != null;
|
||||
|
||||
/// <summary>
|
||||
/// Enlarge a photo from a grid item
|
||||
/// </summary>
|
||||
public void EnlargePhoto(PhotoGridItem sourceItem, GameObject previewPrefab, Texture2D photoTexture, float enlargedScale)
|
||||
{
|
||||
if (sourceItem == null || previewPrefab == null || photoTexture == null)
|
||||
{
|
||||
Logging.Error("[PhotoEnlargeController] Invalid parameters for EnlargePhoto");
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't allow multiple enlargements
|
||||
if (_currentEnlargedPreview != null)
|
||||
{
|
||||
Logging.Warning("[PhotoEnlargeController] Photo already enlarged");
|
||||
return;
|
||||
}
|
||||
|
||||
_currentSourceItem = sourceItem;
|
||||
|
||||
// Show backdrop
|
||||
if (_backdrop != null)
|
||||
{
|
||||
_backdrop.SetActive(true);
|
||||
}
|
||||
|
||||
// Spawn preview clone
|
||||
_currentEnlargedPreview = Object.Instantiate(previewPrefab, _enlargedContainer);
|
||||
_currentEnlargedPreview.transform.SetAsLastSibling();
|
||||
|
||||
// Position at source item's world position
|
||||
_currentEnlargedPreview.transform.position = sourceItem.transform.position;
|
||||
_currentEnlargedPreview.transform.localScale = sourceItem.transform.localScale;
|
||||
|
||||
// Set photo texture on preview
|
||||
var previewImage = _currentEnlargedPreview.GetComponent<UnityEngine.UI.Image>();
|
||||
if (previewImage != null)
|
||||
{
|
||||
// Create sprite from texture
|
||||
Sprite photoSprite = Sprite.Create(
|
||||
photoTexture,
|
||||
new Rect(0, 0, photoTexture.width, photoTexture.height),
|
||||
new Vector2(0.5f, 0.5f)
|
||||
);
|
||||
previewImage.sprite = photoSprite;
|
||||
}
|
||||
|
||||
// Add click handler to preview
|
||||
var clickHandler = _currentEnlargedPreview.GetComponent<EventTrigger>();
|
||||
if (clickHandler == null)
|
||||
{
|
||||
clickHandler = _currentEnlargedPreview.AddComponent<EventTrigger>();
|
||||
}
|
||||
|
||||
var pointerClickEntry = new EventTrigger.Entry { eventID = EventTriggerType.PointerClick };
|
||||
pointerClickEntry.callback.AddListener((_) => { ShrinkPhoto(); });
|
||||
clickHandler.triggers.Add(pointerClickEntry);
|
||||
|
||||
// Animate to center and scale up
|
||||
TweenAnimationUtility.AnimateLocalPosition(_currentEnlargedPreview.transform, Vector3.zero, _animationDuration);
|
||||
TweenAnimationUtility.AnimateScale(_currentEnlargedPreview.transform, Vector3.one * enlargedScale, _animationDuration);
|
||||
|
||||
// Play audio feedback
|
||||
AudioManager.Instance.LoadAndPlayUIAudio("card_albumdrop_deep", false);
|
||||
|
||||
Logging.Debug("[PhotoEnlargeController] Photo enlarged");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shrink the currently enlarged photo back to grid
|
||||
/// </summary>
|
||||
public void ShrinkPhoto()
|
||||
{
|
||||
if (_currentEnlargedPreview == null || _currentSourceItem == null)
|
||||
{
|
||||
Logging.Warning("[PhotoEnlargeController] No photo to shrink");
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide backdrop
|
||||
if (_backdrop != null)
|
||||
{
|
||||
_backdrop.SetActive(false);
|
||||
}
|
||||
|
||||
// Get target position from source item
|
||||
Vector3 targetWorldPos = _currentSourceItem.transform.position;
|
||||
Vector3 targetScale = _currentSourceItem.transform.localScale;
|
||||
|
||||
GameObject previewToDestroy = _currentEnlargedPreview;
|
||||
|
||||
// Animate back to source position
|
||||
Pixelplacement.Tween.Position(previewToDestroy.transform, targetWorldPos, _animationDuration, 0f, Pixelplacement.Tween.EaseInOut);
|
||||
TweenAnimationUtility.AnimateScale(previewToDestroy.transform, targetScale, _animationDuration, () =>
|
||||
{
|
||||
// Destroy preview after animation
|
||||
Object.Destroy(previewToDestroy);
|
||||
});
|
||||
|
||||
// Clear references
|
||||
_currentEnlargedPreview = null;
|
||||
_currentSourceItem = null;
|
||||
|
||||
Logging.Debug("[PhotoEnlargeController] Photo shrunk");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup - call when gallery is closed
|
||||
/// </summary>
|
||||
public void Cleanup()
|
||||
{
|
||||
if (_currentEnlargedPreview != null)
|
||||
{
|
||||
Object.Destroy(_currentEnlargedPreview);
|
||||
_currentEnlargedPreview = null;
|
||||
}
|
||||
|
||||
if (_backdrop != null)
|
||||
{
|
||||
_backdrop.SetActive(false);
|
||||
}
|
||||
|
||||
_currentSourceItem = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ba20462f9a647ee90389c7480147d2e
|
||||
timeCreated: 1764151481
|
||||
@@ -1,79 +0,0 @@
|
||||
using Core;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace Minigames.StatueDressup.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Individual photo thumbnail in the gallery grid.
|
||||
/// Handles click to show enlarged view.
|
||||
/// </summary>
|
||||
public class PhotoGridItem : MonoBehaviour, IPointerClickHandler
|
||||
{
|
||||
[Header("References")]
|
||||
[SerializeField] private Image thumbnailImage;
|
||||
[SerializeField] private GameObject loadingIndicator;
|
||||
|
||||
private string _photoId;
|
||||
private StatuePhotoGalleryController _galleryController;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize grid item with photo ID
|
||||
/// </summary>
|
||||
public void Initialize(string photoId, StatuePhotoGalleryController controller)
|
||||
{
|
||||
_photoId = photoId;
|
||||
_galleryController = controller;
|
||||
|
||||
// Show loading state
|
||||
if (loadingIndicator != null)
|
||||
loadingIndicator.SetActive(true);
|
||||
|
||||
if (thumbnailImage != null)
|
||||
thumbnailImage.enabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the thumbnail texture
|
||||
/// </summary>
|
||||
public void SetThumbnail(Texture2D thumbnail)
|
||||
{
|
||||
if (thumbnail == null)
|
||||
{
|
||||
Logging.Warning($"[PhotoGridItem] Null thumbnail for photo: {_photoId}");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create sprite from thumbnail
|
||||
Sprite thumbnailSprite = Sprite.Create(
|
||||
thumbnail,
|
||||
new Rect(0, 0, thumbnail.width, thumbnail.height),
|
||||
new Vector2(0.5f, 0.5f)
|
||||
);
|
||||
|
||||
if (thumbnailImage != null)
|
||||
{
|
||||
thumbnailImage.sprite = thumbnailSprite;
|
||||
thumbnailImage.enabled = true;
|
||||
}
|
||||
|
||||
// Hide loading indicator
|
||||
if (loadingIndicator != null)
|
||||
loadingIndicator.SetActive(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle click to enlarge/shrink photo
|
||||
/// </summary>
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
if (_galleryController != null && !string.IsNullOrEmpty(_photoId))
|
||||
{
|
||||
Logging.Debug($"[PhotoGridItem] Clicked: {_photoId}");
|
||||
_galleryController.OnGridItemClicked(this, _photoId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: acd8d97ee2f744d984a9507e75309be0
|
||||
timeCreated: 1764065014
|
||||
@@ -17,10 +17,11 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
public class StatueDecorationController : ManagedBehaviour
|
||||
{
|
||||
public static StatueDecorationController Instance { get; private set; }
|
||||
|
||||
[Header("References")]
|
||||
[SerializeField] private RectTransform statueArea; // Statue area for overlap detection
|
||||
[SerializeField] private Transform statueParent; // Parent for placed decorations
|
||||
[SerializeField] private DecorationMenuController menuController;
|
||||
[SerializeField] private Button takePhotoButton;
|
||||
[SerializeField] private GameObject statue;
|
||||
[SerializeField] private DecorationDraggableInstance draggablePrefab; // Prefab for spawning decorations
|
||||
@@ -36,38 +37,71 @@ namespace Minigames.StatueDressup.Controllers
|
||||
[Header("Photo Settings")]
|
||||
[SerializeField] private RectTransform photoArea; // Area to capture
|
||||
|
||||
private List<DecorationDraggableInstance> _placedDecorations = new List<DecorationDraggableInstance>();
|
||||
private bool _minigameCompleted;
|
||||
private AppleHills.Core.Settings.IStatueDressupSettings _settings;
|
||||
private Dictionary<string, DecorationData> _decorationDataDict;
|
||||
private UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle<System.Collections.Generic.IList<DecorationData>> _decorationDataHandle;
|
||||
private List<DecorationDraggableInstance> placedDecorations = new List<DecorationDraggableInstance>();
|
||||
private bool minigameCompleted;
|
||||
|
||||
// Public property for menu controller
|
||||
// Public properties
|
||||
public Transform StatueParent => statueParent;
|
||||
public RectTransform StatueArea => statueArea;
|
||||
|
||||
/// <summary>
|
||||
/// Early initialization - get settings reference
|
||||
/// Early initialization - singleton setup
|
||||
/// </summary>
|
||||
internal override void OnManagedAwake()
|
||||
{
|
||||
base.OnManagedAwake();
|
||||
|
||||
// Get settings early
|
||||
_settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>();
|
||||
// Singleton pattern
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Logging.Warning("[StatueDecorationController] Duplicate instance detected. Destroying duplicate.");
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Main initialization after all managers are ready
|
||||
/// </summary>
|
||||
internal override async void OnManagedStart()
|
||||
internal override void OnManagedStart()
|
||||
{
|
||||
base.OnManagedStart();
|
||||
|
||||
Logging.Debug("[StatueDecorationController] Initializing minigame");
|
||||
|
||||
// Load all DecorationData via Addressables first
|
||||
await LoadDecorationDataAsync();
|
||||
// DecorationDataManager exists (initialized in OnManagedAwake) but data loads async in OnManagedStart
|
||||
// Wait for data to finish loading before initializing
|
||||
if (!DecorationDataManager.Instance.IsLoaded)
|
||||
{
|
||||
Logging.Debug("[StatueDecorationController] Waiting for DecorationData to load...");
|
||||
StartCoroutine(WaitForDataAndInitialize());
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeMinigame();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wait for data manager to finish loading data before initializing
|
||||
/// </summary>
|
||||
private System.Collections.IEnumerator WaitForDataAndInitialize()
|
||||
{
|
||||
while (!DecorationDataManager.Instance.IsLoaded)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
Logging.Debug("[StatueDecorationController] DecorationData loaded, initializing minigame");
|
||||
InitializeMinigame();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the minigame after data is ready
|
||||
/// </summary>
|
||||
private void InitializeMinigame()
|
||||
{
|
||||
// TODO: If ever picture gallery
|
||||
// Setup UI pages (DISABLED - kept for future gallery integration)
|
||||
// if (playAreaPage != null && UIPageController.Instance != null)
|
||||
@@ -89,45 +123,10 @@ namespace Minigames.StatueDressup.Controllers
|
||||
// openGalleryButton.onClick.AddListener(OnOpenGallery);
|
||||
// }
|
||||
|
||||
// Subscribe to menu controller for tracking placed items
|
||||
// Items will manage their own placement via overlap detection
|
||||
if (menuController != null)
|
||||
{
|
||||
// Menu controller will handle spawning replacements
|
||||
Logging.Debug("[StatueDecorationController] Menu controller connected");
|
||||
}
|
||||
|
||||
// Load saved state if exists
|
||||
LoadStatueState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load all DecorationData assets via Addressables and build lookup dictionary
|
||||
/// </summary>
|
||||
private async System.Threading.Tasks.Task LoadDecorationDataAsync()
|
||||
{
|
||||
string label = _settings?.DecorationDataLabel;
|
||||
|
||||
if (string.IsNullOrEmpty(label))
|
||||
{
|
||||
Logging.Error("[StatueDecorationController] Decoration data label not set in settings!");
|
||||
return;
|
||||
}
|
||||
|
||||
Logging.Debug($"[StatueDecorationController] Loading DecorationData with label '{label}'...");
|
||||
|
||||
// Use utility to load all DecorationData and create dictionary by ID
|
||||
var result = await AddressablesUtility.LoadAssetsByLabelAsync<DecorationData, string>(
|
||||
label,
|
||||
data => data.DecorationId
|
||||
);
|
||||
|
||||
_decorationDataDict = result.dictionary;
|
||||
_decorationDataHandle = result.handle;
|
||||
|
||||
Logging.Debug($"[StatueDecorationController] Loaded {_decorationDataDict.Count} DecorationData assets");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open photo gallery
|
||||
/// </summary>
|
||||
@@ -149,9 +148,9 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
public void RegisterDecoration(DecorationDraggableInstance decoration)
|
||||
{
|
||||
if (decoration != null && !_placedDecorations.Contains(decoration))
|
||||
if (decoration != null && !placedDecorations.Contains(decoration))
|
||||
{
|
||||
_placedDecorations.Add(decoration);
|
||||
placedDecorations.Add(decoration);
|
||||
Logging.Debug($"[StatueDecorationController] Decoration placed: {decoration.Data?.DecorationName}");
|
||||
|
||||
// Auto-save state
|
||||
@@ -164,9 +163,9 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
public void UnregisterDecoration(DecorationDraggableInstance decoration)
|
||||
{
|
||||
if (decoration != null && _placedDecorations.Contains(decoration))
|
||||
if (decoration != null && placedDecorations.Contains(decoration))
|
||||
{
|
||||
_placedDecorations.Remove(decoration);
|
||||
placedDecorations.Remove(decoration);
|
||||
Logging.Debug($"[StatueDecorationController] Decoration removed: {decoration.Data?.DecorationName}");
|
||||
|
||||
// Auto-save state
|
||||
@@ -179,7 +178,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private void OnTakePhoto()
|
||||
{
|
||||
if (_minigameCompleted)
|
||||
if (minigameCompleted)
|
||||
{
|
||||
Logging.Debug("[StatueDecorationController] Minigame already completed");
|
||||
return;
|
||||
@@ -196,7 +195,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private System.Collections.IEnumerator CapturePhotoCoroutine()
|
||||
{
|
||||
int decorationCount = _placedDecorations.Count;
|
||||
int decorationCount = placedDecorations.Count;
|
||||
bool captureSuccess = false;
|
||||
string savedPhotoId = null;
|
||||
|
||||
@@ -244,7 +243,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
// Show completion feedback
|
||||
ShowCompletionFeedback();
|
||||
|
||||
_minigameCompleted = true;
|
||||
minigameCompleted = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -306,13 +305,13 @@ namespace Minigames.StatueDressup.Controllers
|
||||
StatueDecorationData data = new StatueDecorationData
|
||||
{
|
||||
photoId = photoId,
|
||||
timestamp = System.DateTime.Now.ToString("o"),
|
||||
timestamp = DateTime.Now.ToString("o"),
|
||||
coordinateSystem = isUIRectTransform ? CoordinateSystemType.UIRectTransform : CoordinateSystemType.WorldSpace,
|
||||
sourceStatueSize = statueSize
|
||||
};
|
||||
|
||||
// Collect all decoration placements
|
||||
foreach (var decoration in _placedDecorations)
|
||||
foreach (var decoration in placedDecorations)
|
||||
{
|
||||
if (decoration == null || decoration.Data == null) continue;
|
||||
|
||||
@@ -343,8 +342,10 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private void SaveStatueState()
|
||||
{
|
||||
var settings = StatueDressupSettings.Instance?.Settings;
|
||||
|
||||
// Check if persistence is enabled
|
||||
if (_settings == null || !_settings.EnableStatePersistence)
|
||||
if (settings == null || !settings.EnableStatePersistence)
|
||||
{
|
||||
Logging.Debug("[StatueDecorationController] State persistence disabled");
|
||||
return;
|
||||
@@ -354,7 +355,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
// Save decoration ID + position + rotation for each placed item
|
||||
// Respect MaxSavedDecorations limit
|
||||
|
||||
Logging.Debug($"[StatueDecorationController] State saved to {_settings.StateSaveKey} (TODO: implement persistence)");
|
||||
Logging.Debug($"[StatueDecorationController] State saved to {settings.StateSaveKey} (TODO: implement persistence)");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -362,15 +363,17 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private void LoadStatueState()
|
||||
{
|
||||
var settings = StatueDressupSettings.Instance?.Settings;
|
||||
|
||||
// Check if persistence is enabled
|
||||
if (_settings == null || !_settings.EnableStatePersistence)
|
||||
if (settings == null || !settings.EnableStatePersistence)
|
||||
{
|
||||
Logging.Debug("[StatueDecorationController] State persistence disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if DecorationData is loaded
|
||||
if (_decorationDataDict == null || _decorationDataDict.Count == 0)
|
||||
if (DecorationDataManager.Instance == null || !DecorationDataManager.Instance.IsLoaded)
|
||||
{
|
||||
Logging.Warning("[StatueDecorationController] DecorationData not loaded yet. Cannot restore state.");
|
||||
return;
|
||||
@@ -405,8 +408,8 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private bool SpawnSavedDecoration(DecorationPlacement placement)
|
||||
{
|
||||
// Look up DecorationData from dictionary
|
||||
if (!_decorationDataDict.TryGetValue(placement.decorationId, out DecorationData decorationData))
|
||||
// Look up DecorationData from manager
|
||||
if (!DecorationDataManager.Instance.TryGetData(placement.decorationId, out DecorationData decorationData))
|
||||
{
|
||||
Logging.Warning($"[StatueDecorationController] DecorationData not found for ID: {placement.decorationId}");
|
||||
return false;
|
||||
@@ -425,23 +428,24 @@ namespace Minigames.StatueDressup.Controllers
|
||||
Transform canvasParent = statueParent.parent; // Typically the canvas or draggable container
|
||||
|
||||
// Create callbacks for outline show/hide
|
||||
Logging.Debug($"[StatueDecorationController] MenuController is null: {menuController == null}");
|
||||
System.Action showOutlineCallback = menuController != null ? (System.Action)menuController.ShowStatueOutline : null;
|
||||
System.Action hideOutlineCallback = menuController != null ? (System.Action)menuController.HideStatueOutline : null;
|
||||
Logging.Debug($"[StatueDecorationController] Show outline callback is null: {showOutlineCallback == null}");
|
||||
System.Action showOutlineCallback = DecorationMenuController.Instance != null ? (System.Action)DecorationMenuController.Instance.ShowStatueOutline : null;
|
||||
System.Action hideOutlineCallback = DecorationMenuController.Instance != null ? (System.Action)DecorationMenuController.Instance.HideStatueOutline : null;
|
||||
|
||||
// Initialize in "placed" state (skip drag logic)
|
||||
instance.InitializeAsPlaced(
|
||||
// Create context for placed decoration
|
||||
var context = DecorationDragContext.CreateForPlaced(
|
||||
decorationData,
|
||||
this,
|
||||
_settings,
|
||||
statueArea, // Pass statue outline for overlap detection
|
||||
canvasParent, // Pass canvas parent for reparenting during pickup
|
||||
showOutlineCallback, // Show outline when picking up
|
||||
hideOutlineCallback, // Hide outline when drag ends
|
||||
hideOutlineCallback // Also use hide callback for onFinished
|
||||
StatueDressupSettings.Instance.Settings,
|
||||
statueArea,
|
||||
canvasParent,
|
||||
showOutlineCallback,
|
||||
hideOutlineCallback,
|
||||
hideOutlineCallback
|
||||
);
|
||||
|
||||
// Initialize in "placed" state (skip drag logic)
|
||||
instance.InitializeWithContext(context);
|
||||
|
||||
// Apply saved transform
|
||||
instance.transform.localPosition = placement.localPosition;
|
||||
instance.transform.localScale = placement.localScale;
|
||||
@@ -479,9 +483,6 @@ namespace Minigames.StatueDressup.Controllers
|
||||
{
|
||||
base.OnManagedDestroy();
|
||||
|
||||
// Release Addressables handle
|
||||
AddressablesUtility.ReleaseHandle(_decorationDataHandle);
|
||||
|
||||
// Cleanup button listeners
|
||||
if (takePhotoButton != null)
|
||||
{
|
||||
@@ -494,6 +495,12 @@ namespace Minigames.StatueDressup.Controllers
|
||||
// {
|
||||
// openGalleryButton.onClick.RemoveListener(OnOpenGallery);
|
||||
// }
|
||||
|
||||
// Singleton cleanup
|
||||
if (Instance == this)
|
||||
{
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
public async void ExitToAppleHills()
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
using Core;
|
||||
using Core.Lifecycle;
|
||||
|
||||
namespace Minigames.StatueDressup.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton manager for StatueDressup settings access.
|
||||
/// Loads settings once and provides global access point.
|
||||
/// </summary>
|
||||
public class StatueDressupSettings : ManagedBehaviour
|
||||
{
|
||||
public static StatueDressupSettings Instance { get; private set; }
|
||||
|
||||
private AppleHills.Core.Settings.IStatueDressupSettings settings;
|
||||
|
||||
/// <summary>
|
||||
/// Get the settings instance
|
||||
/// </summary>
|
||||
public AppleHills.Core.Settings.IStatueDressupSettings Settings => settings;
|
||||
|
||||
internal override void OnManagedAwake()
|
||||
{
|
||||
base.OnManagedAwake();
|
||||
|
||||
// Singleton pattern
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Logging.Warning("[StatueDressupSettings] Duplicate instance detected. Destroying duplicate.");
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
|
||||
// Load settings once
|
||||
settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>();
|
||||
|
||||
if (settings == null)
|
||||
{
|
||||
Logging.Error("[StatueDressupSettings] Failed to load StatueDressupSettings!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Debug("[StatueDressupSettings] Settings loaded successfully");
|
||||
}
|
||||
}
|
||||
|
||||
internal override void OnManagedDestroy()
|
||||
{
|
||||
base.OnManagedDestroy();
|
||||
|
||||
if (Instance == this)
|
||||
{
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: acf5624b19664ce5900f1a7c1328edbc
|
||||
timeCreated: 1764240158
|
||||
@@ -15,6 +15,8 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
public class StatuePhotoGalleryController : ManagedBehaviour
|
||||
{
|
||||
public static StatuePhotoGalleryController Instance { get; private set; }
|
||||
|
||||
[Header("Gallery UI")]
|
||||
[SerializeField] private Transform gridContainer;
|
||||
[SerializeField] private PhotoGridItem gridItemPrefab;
|
||||
@@ -29,25 +31,33 @@ namespace Minigames.StatueDressup.Controllers
|
||||
[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;
|
||||
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>();
|
||||
// Singleton pattern
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Logging.Warning("[StatuePhotoGalleryController] Duplicate instance detected. Destroying duplicate.");
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
|
||||
var settings = StatueDressupSettings.Instance?.Settings;
|
||||
|
||||
// Initialize enlarge controller
|
||||
_enlargeController = new PhotoEnlargeController(backdrop, enlargedContainer, _settings?.GalleryAnimationDuration ?? 0.3f);
|
||||
enlargeController = new PhotoEnlargeController(backdrop, enlargedContainer, settings?.GalleryAnimationDuration ?? 0.3f);
|
||||
|
||||
// Setup page navigation buttons
|
||||
if (previousPageButton != null)
|
||||
@@ -76,10 +86,10 @@ namespace Minigames.StatueDressup.Controllers
|
||||
ClearGrid();
|
||||
|
||||
// Get all photo IDs
|
||||
_allPhotoIds = PhotoManager.GetAllPhotoIds(CaptureType.StatueMinigame);
|
||||
_currentPage = 0;
|
||||
allPhotoIds = PhotoManager.GetAllPhotoIds(CaptureType.StatueMinigame);
|
||||
currentPage = 0;
|
||||
|
||||
Logging.Debug($"[StatuePhotoGalleryController] Gallery refreshed: {_allPhotoIds.Count} photos");
|
||||
Logging.Debug($"[StatuePhotoGalleryController] Gallery refreshed: {allPhotoIds.Count} photos");
|
||||
|
||||
// Display first page
|
||||
DisplayCurrentPage();
|
||||
@@ -90,18 +100,18 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private void DisplayCurrentPage()
|
||||
{
|
||||
if (_isLoadingPage) return;
|
||||
if (isLoadingPage) return;
|
||||
|
||||
_isLoadingPage = true;
|
||||
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);
|
||||
int itemsPerPage = StatueDressupSettings.Instance?.Settings?.GalleryItemsPerPage ?? 20;
|
||||
List<string> pagePhotoIds = PhotoManager.GetPhotoIdsPage(CaptureType.StatueMinigame, currentPage, itemsPerPage);
|
||||
|
||||
Logging.Debug($"[StatuePhotoGalleryController] Displaying page {_currentPage + 1}: {pagePhotoIds.Count} items");
|
||||
Logging.Debug($"[StatuePhotoGalleryController] Displaying page {currentPage + 1}: {pagePhotoIds.Count} items");
|
||||
|
||||
// Spawn grid items for this page
|
||||
foreach (string photoId in pagePhotoIds)
|
||||
@@ -113,10 +123,10 @@ namespace Minigames.StatueDressup.Controllers
|
||||
UpdatePageButtons();
|
||||
|
||||
// Update status text
|
||||
int totalPages = Mathf.CeilToInt((float)_allPhotoIds.Count / itemsPerPage);
|
||||
UpdateStatusText($"Page {_currentPage + 1}/{totalPages} ({_allPhotoIds.Count} photos)");
|
||||
int totalPages = Mathf.CeilToInt((float)allPhotoIds.Count / itemsPerPage);
|
||||
UpdateStatusText($"Page {currentPage + 1}/{totalPages} ({allPhotoIds.Count} photos)");
|
||||
|
||||
_isLoadingPage = false;
|
||||
isLoadingPage = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -124,19 +134,19 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private void UpdatePageButtons()
|
||||
{
|
||||
int itemsPerPage = _settings?.GalleryItemsPerPage ?? 20;
|
||||
int totalPages = Mathf.CeilToInt((float)_allPhotoIds.Count / itemsPerPage);
|
||||
int itemsPerPage = StatueDressupSettings.Instance?.Settings?.GalleryItemsPerPage ?? 20;
|
||||
int totalPages = Mathf.CeilToInt((float)allPhotoIds.Count / itemsPerPage);
|
||||
|
||||
// Enable/disable previous button
|
||||
if (previousPageButton != null)
|
||||
{
|
||||
previousPageButton.interactable = _currentPage > 0;
|
||||
previousPageButton.interactable = currentPage > 0;
|
||||
}
|
||||
|
||||
// Enable/disable next button
|
||||
if (nextPageButton != null)
|
||||
{
|
||||
nextPageButton.interactable = _currentPage < totalPages - 1;
|
||||
nextPageButton.interactable = currentPage < totalPages - 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,11 +155,11 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private void OnPreviousPageClicked()
|
||||
{
|
||||
if (_currentPage > 0)
|
||||
if (currentPage > 0)
|
||||
{
|
||||
_currentPage--;
|
||||
currentPage--;
|
||||
DisplayCurrentPage();
|
||||
Logging.Debug($"[StatuePhotoGalleryController] Navigated to previous page: {_currentPage}");
|
||||
Logging.Debug($"[StatuePhotoGalleryController] Navigated to previous page: {currentPage}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,14 +168,14 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private void OnNextPageClicked()
|
||||
{
|
||||
int itemsPerPage = _settings?.GalleryItemsPerPage ?? 20;
|
||||
int totalPages = Mathf.CeilToInt((float)_allPhotoIds.Count / itemsPerPage);
|
||||
int itemsPerPage = StatueDressupSettings.Instance?.Settings?.GalleryItemsPerPage ?? 20;
|
||||
int totalPages = Mathf.CeilToInt((float)allPhotoIds.Count / itemsPerPage);
|
||||
|
||||
if (_currentPage < totalPages - 1)
|
||||
if (currentPage < totalPages - 1)
|
||||
{
|
||||
_currentPage++;
|
||||
currentPage++;
|
||||
DisplayCurrentPage();
|
||||
Logging.Debug($"[StatuePhotoGalleryController] Navigated to next page: {_currentPage}");
|
||||
Logging.Debug($"[StatuePhotoGalleryController] Navigated to next page: {currentPage}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +184,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
private void SpawnGridItem(string photoId)
|
||||
{
|
||||
if (_activeGridItems.ContainsKey(photoId))
|
||||
if (activeGridItems.ContainsKey(photoId))
|
||||
{
|
||||
Logging.Warning($"[StatuePhotoGalleryController] Grid item already exists: {photoId}");
|
||||
return;
|
||||
@@ -183,7 +193,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
PhotoGridItem gridItem = Instantiate(gridItemPrefab, gridContainer);
|
||||
gridItem.Initialize(photoId, this);
|
||||
|
||||
_activeGridItems[photoId] = gridItem;
|
||||
activeGridItems[photoId] = gridItem;
|
||||
|
||||
// Load thumbnail asynchronously
|
||||
StartCoroutine(LoadThumbnailAsync(photoId, gridItem));
|
||||
@@ -195,7 +205,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
private IEnumerator LoadThumbnailAsync(string photoId, PhotoGridItem gridItem)
|
||||
{
|
||||
// Check cache first
|
||||
if (_thumbnailCache.TryGetValue(photoId, out Texture2D cachedThumbnail))
|
||||
if (thumbnailCache.TryGetValue(photoId, out Texture2D cachedThumbnail))
|
||||
{
|
||||
gridItem.SetThumbnail(cachedThumbnail);
|
||||
yield break;
|
||||
@@ -214,7 +224,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
}
|
||||
|
||||
// Create thumbnail
|
||||
int thumbSize = _settings?.GalleryThumbnailSize ?? 256;
|
||||
int thumbSize = StatueDressupSettings.Instance?.Settings?.GalleryThumbnailSize ?? 256;
|
||||
Texture2D thumbnail = PhotoManager.CreateThumbnail(fullPhoto, thumbSize);
|
||||
|
||||
// Destroy full photo immediately (we only need thumbnail)
|
||||
@@ -236,19 +246,19 @@ namespace Minigames.StatueDressup.Controllers
|
||||
private void CacheThumbnail(string photoId, Texture2D thumbnail)
|
||||
{
|
||||
// Add to cache
|
||||
_thumbnailCache[photoId] = thumbnail;
|
||||
_thumbnailCacheOrder.Enqueue(photoId);
|
||||
thumbnailCache[photoId] = thumbnail;
|
||||
thumbnailCacheOrder.Enqueue(photoId);
|
||||
|
||||
// Evict oldest if over limit
|
||||
int maxCached = _settings?.GalleryMaxCachedThumbnails ?? 50;
|
||||
while (_thumbnailCache.Count > maxCached && _thumbnailCacheOrder.Count > 0)
|
||||
int maxCached = StatueDressupSettings.Instance?.Settings?.GalleryMaxCachedThumbnails ?? 50;
|
||||
while (thumbnailCache.Count > maxCached && thumbnailCacheOrder.Count > 0)
|
||||
{
|
||||
string oldestId = _thumbnailCacheOrder.Dequeue();
|
||||
string oldestId = thumbnailCacheOrder.Dequeue();
|
||||
|
||||
if (_thumbnailCache.TryGetValue(oldestId, out Texture2D oldThumbnail))
|
||||
if (thumbnailCache.TryGetValue(oldestId, out Texture2D oldThumbnail))
|
||||
{
|
||||
Destroy(oldThumbnail);
|
||||
_thumbnailCache.Remove(oldestId);
|
||||
thumbnailCache.Remove(oldestId);
|
||||
Logging.Debug($"[StatuePhotoGalleryController] Evicted thumbnail from cache: {oldestId}");
|
||||
}
|
||||
}
|
||||
@@ -259,28 +269,28 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
public void OnGridItemClicked(PhotoGridItem gridItem, string photoId)
|
||||
{
|
||||
if (_enlargeController == null)
|
||||
if (enlargeController == null)
|
||||
{
|
||||
Logging.Error("[StatuePhotoGalleryController] Enlarge controller not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
// If already enlarged, shrink it
|
||||
if (_enlargeController.IsPhotoEnlarged)
|
||||
if (enlargeController.IsPhotoEnlarged)
|
||||
{
|
||||
_enlargeController.ShrinkPhoto();
|
||||
enlargeController.ShrinkPhoto();
|
||||
return;
|
||||
}
|
||||
|
||||
Logging.Debug($"[StatuePhotoGalleryController] Enlarging photo: {photoId}");
|
||||
|
||||
float enlargedScale = _settings?.GalleryEnlargedScale ?? 2.5f;
|
||||
float enlargedScale = StatueDressupSettings.Instance?.Settings?.GalleryEnlargedScale ?? 2.5f;
|
||||
|
||||
// Check cache first
|
||||
if (_fullPhotoCache.TryGetValue(photoId, out Texture2D fullPhoto))
|
||||
if (fullPhotoCache.TryGetValue(photoId, out Texture2D fullPhoto))
|
||||
{
|
||||
// Use cached photo
|
||||
_enlargeController.EnlargePhoto(gridItem, enlargedPreviewPrefab != null ? enlargedPreviewPrefab : gridItem.gameObject, fullPhoto, enlargedScale);
|
||||
enlargeController.EnlargePhoto(gridItem, enlargedPreviewPrefab != null ? enlargedPreviewPrefab : gridItem.gameObject, fullPhoto, enlargedScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -294,12 +304,12 @@ namespace Minigames.StatueDressup.Controllers
|
||||
}
|
||||
|
||||
// Cache it (limited cache)
|
||||
if (_fullPhotoCache.Count < 10) // Keep only recent 10 full photos
|
||||
if (fullPhotoCache.Count < 10) // Keep only recent 10 full photos
|
||||
{
|
||||
_fullPhotoCache[photoId] = fullPhoto;
|
||||
fullPhotoCache[photoId] = fullPhoto;
|
||||
}
|
||||
|
||||
_enlargeController.EnlargePhoto(gridItem, enlargedPreviewPrefab != null ? enlargedPreviewPrefab : gridItem.gameObject, fullPhoto, enlargedScale);
|
||||
enlargeController.EnlargePhoto(gridItem, enlargedPreviewPrefab != null ? enlargedPreviewPrefab : gridItem.gameObject, fullPhoto, enlargedScale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,20 +318,20 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// </summary>
|
||||
public void CleanupGallery()
|
||||
{
|
||||
if (_enlargeController != null)
|
||||
if (enlargeController != null)
|
||||
{
|
||||
_enlargeController.Cleanup();
|
||||
enlargeController.Cleanup();
|
||||
}
|
||||
|
||||
// Clean up cached full photos
|
||||
foreach (var photo in _fullPhotoCache.Values)
|
||||
foreach (var photo in fullPhotoCache.Values)
|
||||
{
|
||||
if (photo != null)
|
||||
{
|
||||
Destroy(photo);
|
||||
}
|
||||
}
|
||||
_fullPhotoCache.Clear();
|
||||
fullPhotoCache.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -341,12 +351,12 @@ namespace Minigames.StatueDressup.Controllers
|
||||
private void ClearGrid()
|
||||
{
|
||||
// Destroy grid items
|
||||
foreach (var gridItem in _activeGridItems.Values)
|
||||
foreach (var gridItem in activeGridItems.Values)
|
||||
{
|
||||
if (gridItem != null)
|
||||
Destroy(gridItem.gameObject);
|
||||
}
|
||||
_activeGridItems.Clear();
|
||||
activeGridItems.Clear();
|
||||
|
||||
Logging.Debug("[StatuePhotoGalleryController] Grid cleared");
|
||||
}
|
||||
@@ -359,13 +369,13 @@ namespace Minigames.StatueDressup.Controllers
|
||||
ClearGrid();
|
||||
|
||||
// Clear thumbnail cache
|
||||
foreach (var thumbnail in _thumbnailCache.Values)
|
||||
foreach (var thumbnail in thumbnailCache.Values)
|
||||
{
|
||||
if (thumbnail != null)
|
||||
Destroy(thumbnail);
|
||||
}
|
||||
_thumbnailCache.Clear();
|
||||
_thumbnailCacheOrder.Clear();
|
||||
thumbnailCache.Clear();
|
||||
thumbnailCacheOrder.Clear();
|
||||
|
||||
Logging.Debug("[StatuePhotoGalleryController] Gallery fully cleared");
|
||||
}
|
||||
@@ -374,7 +384,13 @@ namespace Minigames.StatueDressup.Controllers
|
||||
{
|
||||
base.OnManagedDestroy();
|
||||
|
||||
// Cleanup
|
||||
// Singleton cleanup
|
||||
if (Instance == this)
|
||||
{
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
// Clean up cached textures
|
||||
ClearGallery();
|
||||
CleanupGallery();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user