Cleanup code structure, code smells, rename paramter, break out more granular managers

This commit is contained in:
Michal Pikulski
2025-11-27 12:10:25 +01:00
parent d083c2873e
commit a57fca63bf
23 changed files with 1738 additions and 453 deletions

View File

@@ -15,7 +15,7 @@ MonoBehaviour:
m_DefaultGroup: 6f3207429a65b3e4b83935ac19791077 m_DefaultGroup: 6f3207429a65b3e4b83935ac19791077
m_currentHash: m_currentHash:
serializedVersion: 2 serializedVersion: 2
Hash: 027dc5937f1a989438d4c39629cbe46f Hash: b9c3c669d28f187e4cec7b0693d59a99
m_OptimizeCatalogSize: 0 m_OptimizeCatalogSize: 0
m_BuildRemoteCatalog: 0 m_BuildRemoteCatalog: 0
m_CatalogRequestsTimeout: 0 m_CatalogRequestsTimeout: 0
@@ -65,6 +65,7 @@ MonoBehaviour:
- {fileID: 11400000, guid: efe7e1728e73e9546ac5dfee2eff524f, type: 2} - {fileID: 11400000, guid: efe7e1728e73e9546ac5dfee2eff524f, type: 2}
- {fileID: 11400000, guid: 6e4927e7e19eef34b93dc2baa9e9e8e2, type: 2} - {fileID: 11400000, guid: 6e4927e7e19eef34b93dc2baa9e9e8e2, type: 2}
- {fileID: 11400000, guid: 4186fdd83f912a14b97fbf4644266b0d, type: 2} - {fileID: 11400000, guid: 4186fdd83f912a14b97fbf4644266b0d, type: 2}
- {fileID: 11400000, guid: fd8b6934620e3a54a818495e62a103e0, type: 2}
- {fileID: 11400000, guid: e25c7672a65b5974bb354fcfb2a8400c, type: 2} - {fileID: 11400000, guid: e25c7672a65b5974bb354fcfb2a8400c, type: 2}
- {fileID: 11400000, guid: 7fcc03e584505ed4381983b6ebb1179d, type: 2} - {fileID: 11400000, guid: 7fcc03e584505ed4381983b6ebb1179d, type: 2}
m_BuildSettings: m_BuildSettings:
@@ -107,6 +108,7 @@ MonoBehaviour:
m_LabelNames: m_LabelNames:
- default - default
- BlokkemonCard - BlokkemonCard
- StatueDecorations
m_SchemaTemplates: [] m_SchemaTemplates: []
m_GroupTemplateObjects: m_GroupTemplateObjects:
- {fileID: 11400000, guid: ea0a5135f5495eb4693a23d94617fe92, type: 2} - {fileID: 11400000, guid: ea0a5135f5495eb4693a23d94617fe92, type: 2}

File diff suppressed because one or more lines are too long

View File

@@ -3186,6 +3186,12 @@ PrefabInstance:
- targetCorrespondingSourceObject: {fileID: 7404622075362872657, guid: f44866deaba5f5c4a90f0330dd9957f0, type: 3} - targetCorrespondingSourceObject: {fileID: 7404622075362872657, guid: f44866deaba5f5c4a90f0330dd9957f0, type: 3}
insertIndex: -1 insertIndex: -1
addedObject: {fileID: 1460027146} addedObject: {fileID: 1460027146}
- targetCorrespondingSourceObject: {fileID: 7404622075362872657, guid: f44866deaba5f5c4a90f0330dd9957f0, type: 3}
insertIndex: -1
addedObject: {fileID: 1460027150}
- targetCorrespondingSourceObject: {fileID: 7404622075362872657, guid: f44866deaba5f5c4a90f0330dd9957f0, type: 3}
insertIndex: -1
addedObject: {fileID: 1460027149}
m_SourcePrefab: {fileID: 100100000, guid: f44866deaba5f5c4a90f0330dd9957f0, type: 3} m_SourcePrefab: {fileID: 100100000, guid: f44866deaba5f5c4a90f0330dd9957f0, type: 3}
--- !u!4 &1460027142 stripped --- !u!4 &1460027142 stripped
Transform: Transform:
@@ -3206,7 +3212,32 @@ MonoBehaviour:
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Display.StatueDecorationLoader m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Display.StatueDecorationLoader
statueSpriteRenderer: {fileID: 831113526} statueSpriteRenderer: {fileID: 831113526}
specificPhotoId: specificPhotoId:
applyPivotOffset: 1
showDebugInfo: 1 showDebugInfo: 1
--- !u!114 &1460027149
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 175866977}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: acf5624b19664ce5900f1a7c1328edbc, type: 3}
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Controllers.StatueDressupSettings
--- !u!114 &1460027150
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 175866977}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: afa56ec5b1f84b32ba014a91d9d9a0a0, type: 3}
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Controllers.DecorationDataManager
--- !u!4 &1572710089 stripped --- !u!4 &1572710089 stripped
Transform: Transform:
m_CorrespondingSourceObject: {fileID: 5507990123417429516, guid: afbb486e5456a20479aee4cf8bc949b6, type: 3} m_CorrespondingSourceObject: {fileID: 5507990123417429516, guid: afbb486e5456a20479aee4cf8bc949b6, type: 3}

View File

@@ -1163,7 +1163,6 @@ MonoBehaviour:
draggableContainer: {fileID: 1217454518} draggableContainer: {fileID: 1217454518}
nextPageButton: {fileID: 2071711339} nextPageButton: {fileID: 2071711339}
previousPageButton: {fileID: 194466356} previousPageButton: {fileID: 194466356}
statueController: {fileID: 1647993458}
statueOutline: {fileID: 1325274732} statueOutline: {fileID: 1325274732}
gridLayout: {fileID: 699865156} gridLayout: {fileID: 699865156}
--- !u!1 &435994659 --- !u!1 &435994659
@@ -2076,6 +2075,152 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1140141871} m_GameObject: {fileID: 1140141871}
m_CullTransparentMesh: 1 m_CullTransparentMesh: 1
--- !u!1 &1181815683
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1181815686}
- component: {fileID: 1181815685}
- component: {fileID: 1181815684}
m_Layer: 0
m_Name: SFXManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1181815684
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1181815683}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 242e6101be071f44fb14c3c12641c833, type: 3}
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::AppleAudioSource
audioSourceType: 3
audioSource: {fileID: 0}
clipPriority: 0
sourcePriority: 0
--- !u!82 &1181815685
AudioSource:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1181815683}
m_Enabled: 1
serializedVersion: 4
OutputAudioMixerGroup: {fileID: 0}
m_audioClip: {fileID: 0}
m_Resource: {fileID: 0}
m_PlayOnAwake: 0
m_Volume: 1
m_Pitch: 1
Loop: 0
Mute: 0
Spatialize: 0
SpatializePostEffects: 0
Priority: 128
DopplerLevel: 1
MinDistance: 1
MaxDistance: 500
Pan2D: 0
rolloffMode: 0
BypassEffects: 0
BypassListenerEffects: 0
BypassReverbZones: 0
rolloffCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
panLevelCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
spreadCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
reverbZoneMixCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
--- !u!4 &1181815686
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1181815683}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 1218.915, y: 722.89856, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1217454514 --- !u!1 &1217454514
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -2719,6 +2864,8 @@ GameObject:
m_Component: m_Component:
- component: {fileID: 1647993459} - component: {fileID: 1647993459}
- component: {fileID: 1647993458} - component: {fileID: 1647993458}
- component: {fileID: 1647993461}
- component: {fileID: 1647993460}
m_Layer: 0 m_Layer: 0
m_Name: StatueDecorationController m_Name: StatueDecorationController
m_TagString: Untagged m_TagString: Untagged
@@ -2740,7 +2887,6 @@ MonoBehaviour:
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Controllers.StatueDecorationController m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Controllers.StatueDecorationController
statueArea: {fileID: 65358845} statueArea: {fileID: 65358845}
statueParent: {fileID: 166400579} statueParent: {fileID: 166400579}
menuController: {fileID: 403667980}
takePhotoButton: {fileID: 37633367} takePhotoButton: {fileID: 37633367}
statue: {fileID: 1078270173} statue: {fileID: 1078270173}
draggablePrefab: {fileID: 8998709565229564215, guid: 064cd4d021ea13e47860a59bbe8224aa, type: 3} draggablePrefab: {fileID: 8998709565229564215, guid: 064cd4d021ea13e47860a59bbe8224aa, type: 3}
@@ -2764,6 +2910,30 @@ Transform:
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1647993460
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1647993457}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: afa56ec5b1f84b32ba014a91d9d9a0a0, type: 3}
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Controllers.DecorationDataManager
--- !u!114 &1647993461
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1647993457}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: acf5624b19664ce5900f1a7c1328edbc, type: 3}
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Controllers.StatueDressupSettings
--- !u!1 &1685271989 --- !u!1 &1685271989
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -3297,6 +3467,7 @@ SceneRoots:
- {fileID: 951788} - {fileID: 951788}
- {fileID: 1542794369} - {fileID: 1542794369}
- {fileID: 1647993459} - {fileID: 1647993459}
- {fileID: 1181815686}
- {fileID: 1217454518} - {fileID: 1217454518}
- {fileID: 1126329096} - {fileID: 1126329096}
- {fileID: 483064112} - {fileID: 483064112}

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: afa56ec5b1f84b32ba014a91d9d9a0a0
timeCreated: 1764240174

View File

@@ -13,6 +13,8 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
public class DecorationMenuController : ManagedBehaviour public class DecorationMenuController : ManagedBehaviour
{ {
public static DecorationMenuController Instance { get; private set; }
[Header("References")] [Header("References")]
[SerializeField] private DecorationGridIcon iconPrefab; [SerializeField] private DecorationGridIcon iconPrefab;
[SerializeField] private DecorationDraggableInstance draggablePrefab; [SerializeField] private DecorationDraggableInstance draggablePrefab;
@@ -20,36 +22,36 @@ namespace Minigames.StatueDressup.Controllers
[SerializeField] private Transform draggableContainer; // Parent for spawned draggables [SerializeField] private Transform draggableContainer; // Parent for spawned draggables
[SerializeField] private Button nextPageButton; [SerializeField] private Button nextPageButton;
[SerializeField] private Button previousPageButton; [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 [SerializeField] private Image statueOutline; // Outline image shown during drag to indicate valid drop area
[Header("Layout")] [Header("Layout")]
[SerializeField] private GridLayoutGroup gridLayout; [SerializeField] private GridLayoutGroup gridLayout;
private int _currentPage; private int currentPage;
private int _totalPages; private int totalPages;
private List<DecorationGridIcon> _spawnedIcons = new List<DecorationGridIcon>(); private List<DecorationGridIcon> spawnedIcons = new List<DecorationGridIcon>();
private AppleHills.Core.Settings.IStatueDressupSettings _settings;
// Properties // Properties
public int CurrentPage => _currentPage; public int CurrentPage => currentPage;
public int TotalPages => _totalPages; public int TotalPages => totalPages;
/// <summary> /// <summary>
/// Early initialization - get settings reference /// Early initialization - singleton setup
/// </summary> /// </summary>
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {
base.OnManagedAwake(); base.OnManagedAwake();
// Get settings early // Singleton pattern
_settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>(); if (Instance != null && Instance != this)
if (_settings == null)
{ {
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) // Ensure outline starts hidden (do this early so it's ready for saved decorations)
if (statueOutline != null) if (statueOutline != null)
{ {
@@ -64,27 +66,29 @@ namespace Minigames.StatueDressup.Controllers
{ {
base.OnManagedStart(); base.OnManagedStart();
if (_settings == null) var settings = StatueDressupSettings.Instance?.Settings;
if (settings == null)
{ {
Logging.Error("[DecorationMenuController] Cannot initialize without settings!"); Logging.Error("[DecorationMenuController] Cannot initialize without settings!");
return; return;
} }
var allDecorations = _settings.AllDecorations; var allDecorations = settings.AllDecorations;
int itemsPerPage = _settings.ItemsPerPage; int itemsPerPage = settings.ItemsPerPage;
Logging.Debug($"[DecorationMenuController] Initializing with {allDecorations?.Count ?? 0} decorations"); Logging.Debug($"[DecorationMenuController] Initializing with {allDecorations?.Count ?? 0} decorations");
// Calculate total pages // Calculate total pages
if (allDecorations != null && allDecorations.Count > 0) if (allDecorations != null && allDecorations.Count > 0)
{ {
_totalPages = Mathf.CeilToInt((float)allDecorations.Count / itemsPerPage); totalPages = Mathf.CeilToInt((float)allDecorations.Count / itemsPerPage);
Logging.Debug($"[DecorationMenuController] Total pages: {_totalPages}"); Logging.Debug($"[DecorationMenuController] Total pages: {totalPages}");
} }
else else
{ {
Logging.Warning("[DecorationMenuController] No decorations found in settings!"); Logging.Warning("[DecorationMenuController] No decorations found in settings!");
_totalPages = 0; totalPages = 0;
} }
// Setup buttons // Setup buttons
@@ -110,10 +114,11 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
private void PopulateCurrentPage() private void PopulateCurrentPage()
{ {
if (_settings == null) return; var settings = StatueDressupSettings.Instance?.Settings;
if (settings == null) return;
var allDecorations = _settings.AllDecorations; var allDecorations = settings.AllDecorations;
int itemsPerPage = _settings.ItemsPerPage; int itemsPerPage = settings.ItemsPerPage;
if (allDecorations == null || allDecorations.Count == 0) if (allDecorations == null || allDecorations.Count == 0)
{ {
@@ -121,13 +126,13 @@ namespace Minigames.StatueDressup.Controllers
return; return;
} }
Logging.Debug($"[DecorationMenuController] Populating page {_currentPage + 1}/{_totalPages}"); Logging.Debug($"[DecorationMenuController] Populating page {currentPage + 1}/{totalPages}");
// Clear existing icons // Clear existing icons
ClearIcons(); ClearIcons();
// Calculate range for current page // Calculate range for current page
int startIndex = _currentPage * itemsPerPage; int startIndex = currentPage * itemsPerPage;
int endIndex = Mathf.Min(startIndex + itemsPerPage, allDecorations.Count); int endIndex = Mathf.Min(startIndex + itemsPerPage, allDecorations.Count);
Logging.Debug($"[DecorationMenuController] Spawning icons {startIndex} to {endIndex - 1}"); Logging.Debug($"[DecorationMenuController] Spawning icons {startIndex} to {endIndex - 1}");
@@ -156,7 +161,7 @@ namespace Minigames.StatueDressup.Controllers
DecorationGridIcon icon = Instantiate(iconPrefab, itemsContainer); DecorationGridIcon icon = Instantiate(iconPrefab, itemsContainer);
icon.Initialize(data, this); icon.Initialize(data, this);
_spawnedIcons.Add(icon); spawnedIcons.Add(icon);
Logging.Debug($"[DecorationMenuController] Spawned icon: {data.DecorationName}"); Logging.Debug($"[DecorationMenuController] Spawned icon: {data.DecorationName}");
} }
@@ -167,7 +172,7 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
public DecorationDraggableInstance SpawnDraggableInstance(DecorationData data, Vector3 screenPosition) 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"); Logging.Warning("[DecorationMenuController] Missing draggable prefab or statue controller");
return null; return null;
@@ -185,18 +190,21 @@ namespace Minigames.StatueDressup.Controllers
// Get outline RectTransform for overlap detection // Get outline RectTransform for overlap detection
RectTransform outlineRect = statueOutline != null ? statueOutline.rectTransform : null; RectTransform outlineRect = statueOutline != null ? statueOutline.rectTransform : null;
// Initialize with references including outline callbacks // Create context for new drag
instance.Initialize( var context = DecorationDragContext.CreateForNewDrag(
data, data,
outlineRect, outlineRect,
statueController.StatueParent, StatueDecorationController.Instance.StatueParent,
statueController, StatueDecorationController.Instance,
_settings, StatueDressupSettings.Instance.Settings,
OnDraggableFinished, OnDraggableFinished,
ShowStatueOutline, // Show outline when picking up from statue ShowStatueOutline,
HideStatueOutline // Hide outline when drag ends HideStatueOutline
); );
// Initialize with context
instance.InitializeWithContext(context);
// Position at cursor (in local space) // Position at cursor (in local space)
Canvas canvas = GetComponentInParent<Canvas>(); Canvas canvas = GetComponentInParent<Canvas>();
if (canvas != null) if (canvas != null)
@@ -261,7 +269,7 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
private void ClearIcons() private void ClearIcons()
{ {
foreach (var icon in _spawnedIcons) foreach (var icon in spawnedIcons)
{ {
if (icon != null) if (icon != null)
{ {
@@ -269,7 +277,7 @@ namespace Minigames.StatueDressup.Controllers
} }
} }
_spawnedIcons.Clear(); spawnedIcons.Clear();
} }
/// <summary> /// <summary>
@@ -277,11 +285,11 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
private void OnNextPage() private void OnNextPage()
{ {
if (_currentPage < _totalPages - 1) if (currentPage < totalPages - 1)
{ {
_currentPage++; currentPage++;
PopulateCurrentPage(); 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> /// </summary>
private void OnPreviousPage() private void OnPreviousPage()
{ {
if (_currentPage > 0) if (currentPage > 0)
{ {
_currentPage--; currentPage--;
PopulateCurrentPage(); 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> /// </summary>
private void UpdateNavigationButtons() private void UpdateNavigationButtons()
{ {
if (previousPageButton != null)
{
previousPageButton.interactable = _currentPage > 0;
}
if (nextPageButton != null) 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 // Cleanup icons
ClearIcons(); ClearIcons();
// Singleton cleanup
if (Instance == this)
{
Instance = null;
}
} }
} }
} }

View File

@@ -17,10 +17,11 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
public class StatueDecorationController : ManagedBehaviour public class StatueDecorationController : ManagedBehaviour
{ {
public static StatueDecorationController Instance { get; private set; }
[Header("References")] [Header("References")]
[SerializeField] private RectTransform statueArea; // Statue area for overlap detection [SerializeField] private RectTransform statueArea; // Statue area for overlap detection
[SerializeField] private Transform statueParent; // Parent for placed decorations [SerializeField] private Transform statueParent; // Parent for placed decorations
[SerializeField] private DecorationMenuController menuController;
[SerializeField] private Button takePhotoButton; [SerializeField] private Button takePhotoButton;
[SerializeField] private GameObject statue; [SerializeField] private GameObject statue;
[SerializeField] private DecorationDraggableInstance draggablePrefab; // Prefab for spawning decorations [SerializeField] private DecorationDraggableInstance draggablePrefab; // Prefab for spawning decorations
@@ -36,38 +37,71 @@ namespace Minigames.StatueDressup.Controllers
[Header("Photo Settings")] [Header("Photo Settings")]
[SerializeField] private RectTransform photoArea; // Area to capture [SerializeField] private RectTransform photoArea; // Area to capture
private List<DecorationDraggableInstance> _placedDecorations = new List<DecorationDraggableInstance>(); private List<DecorationDraggableInstance> placedDecorations = new List<DecorationDraggableInstance>();
private bool _minigameCompleted; 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;
// Public property for menu controller // Public properties
public Transform StatueParent => statueParent; public Transform StatueParent => statueParent;
public RectTransform StatueArea => statueArea;
/// <summary> /// <summary>
/// Early initialization - get settings reference /// Early initialization - singleton setup
/// </summary> /// </summary>
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {
base.OnManagedAwake(); base.OnManagedAwake();
// Get settings early // Singleton pattern
_settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>(); if (Instance != null && Instance != this)
{
Logging.Warning("[StatueDecorationController] Duplicate instance detected. Destroying duplicate.");
Destroy(gameObject);
return;
}
Instance = this;
} }
/// <summary> /// <summary>
/// Main initialization after all managers are ready /// Main initialization after all managers are ready
/// </summary> /// </summary>
internal override async void OnManagedStart() internal override void OnManagedStart()
{ {
base.OnManagedStart(); base.OnManagedStart();
Logging.Debug("[StatueDecorationController] Initializing minigame"); Logging.Debug("[StatueDecorationController] Initializing minigame");
// Load all DecorationData via Addressables first // DecorationDataManager exists (initialized in OnManagedAwake) but data loads async in OnManagedStart
await LoadDecorationDataAsync(); // 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 // TODO: If ever picture gallery
// Setup UI pages (DISABLED - kept for future gallery integration) // Setup UI pages (DISABLED - kept for future gallery integration)
// if (playAreaPage != null && UIPageController.Instance != null) // if (playAreaPage != null && UIPageController.Instance != null)
@@ -89,45 +123,10 @@ namespace Minigames.StatueDressup.Controllers
// openGalleryButton.onClick.AddListener(OnOpenGallery); // 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 // Load saved state if exists
LoadStatueState(); 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> /// <summary>
/// Open photo gallery /// Open photo gallery
/// </summary> /// </summary>
@@ -149,9 +148,9 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
public void RegisterDecoration(DecorationDraggableInstance decoration) 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}"); Logging.Debug($"[StatueDecorationController] Decoration placed: {decoration.Data?.DecorationName}");
// Auto-save state // Auto-save state
@@ -164,9 +163,9 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
public void UnregisterDecoration(DecorationDraggableInstance decoration) 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}"); Logging.Debug($"[StatueDecorationController] Decoration removed: {decoration.Data?.DecorationName}");
// Auto-save state // Auto-save state
@@ -179,7 +178,7 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
private void OnTakePhoto() private void OnTakePhoto()
{ {
if (_minigameCompleted) if (minigameCompleted)
{ {
Logging.Debug("[StatueDecorationController] Minigame already completed"); Logging.Debug("[StatueDecorationController] Minigame already completed");
return; return;
@@ -196,7 +195,7 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
private System.Collections.IEnumerator CapturePhotoCoroutine() private System.Collections.IEnumerator CapturePhotoCoroutine()
{ {
int decorationCount = _placedDecorations.Count; int decorationCount = placedDecorations.Count;
bool captureSuccess = false; bool captureSuccess = false;
string savedPhotoId = null; string savedPhotoId = null;
@@ -244,7 +243,7 @@ namespace Minigames.StatueDressup.Controllers
// Show completion feedback // Show completion feedback
ShowCompletionFeedback(); ShowCompletionFeedback();
_minigameCompleted = true; minigameCompleted = true;
} }
/// <summary> /// <summary>
@@ -306,13 +305,13 @@ namespace Minigames.StatueDressup.Controllers
StatueDecorationData data = new StatueDecorationData StatueDecorationData data = new StatueDecorationData
{ {
photoId = photoId, photoId = photoId,
timestamp = System.DateTime.Now.ToString("o"), timestamp = DateTime.Now.ToString("o"),
coordinateSystem = isUIRectTransform ? CoordinateSystemType.UIRectTransform : CoordinateSystemType.WorldSpace, coordinateSystem = isUIRectTransform ? CoordinateSystemType.UIRectTransform : CoordinateSystemType.WorldSpace,
sourceStatueSize = statueSize sourceStatueSize = statueSize
}; };
// Collect all decoration placements // Collect all decoration placements
foreach (var decoration in _placedDecorations) foreach (var decoration in placedDecorations)
{ {
if (decoration == null || decoration.Data == null) continue; if (decoration == null || decoration.Data == null) continue;
@@ -343,8 +342,10 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
private void SaveStatueState() private void SaveStatueState()
{ {
var settings = StatueDressupSettings.Instance?.Settings;
// Check if persistence is enabled // Check if persistence is enabled
if (_settings == null || !_settings.EnableStatePersistence) if (settings == null || !settings.EnableStatePersistence)
{ {
Logging.Debug("[StatueDecorationController] State persistence disabled"); Logging.Debug("[StatueDecorationController] State persistence disabled");
return; return;
@@ -354,7 +355,7 @@ namespace Minigames.StatueDressup.Controllers
// Save decoration ID + position + rotation for each placed item // Save decoration ID + position + rotation for each placed item
// Respect MaxSavedDecorations limit // 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> /// <summary>
@@ -362,15 +363,17 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
private void LoadStatueState() private void LoadStatueState()
{ {
var settings = StatueDressupSettings.Instance?.Settings;
// Check if persistence is enabled // Check if persistence is enabled
if (_settings == null || !_settings.EnableStatePersistence) if (settings == null || !settings.EnableStatePersistence)
{ {
Logging.Debug("[StatueDecorationController] State persistence disabled"); Logging.Debug("[StatueDecorationController] State persistence disabled");
return; return;
} }
// Check if DecorationData is loaded // 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."); Logging.Warning("[StatueDecorationController] DecorationData not loaded yet. Cannot restore state.");
return; return;
@@ -405,8 +408,8 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
private bool SpawnSavedDecoration(DecorationPlacement placement) private bool SpawnSavedDecoration(DecorationPlacement placement)
{ {
// Look up DecorationData from dictionary // Look up DecorationData from manager
if (!_decorationDataDict.TryGetValue(placement.decorationId, out DecorationData decorationData)) if (!DecorationDataManager.Instance.TryGetData(placement.decorationId, out DecorationData decorationData))
{ {
Logging.Warning($"[StatueDecorationController] DecorationData not found for ID: {placement.decorationId}"); Logging.Warning($"[StatueDecorationController] DecorationData not found for ID: {placement.decorationId}");
return false; return false;
@@ -425,23 +428,24 @@ namespace Minigames.StatueDressup.Controllers
Transform canvasParent = statueParent.parent; // Typically the canvas or draggable container Transform canvasParent = statueParent.parent; // Typically the canvas or draggable container
// Create callbacks for outline show/hide // Create callbacks for outline show/hide
Logging.Debug($"[StatueDecorationController] MenuController is null: {menuController == null}"); System.Action showOutlineCallback = DecorationMenuController.Instance != null ? (System.Action)DecorationMenuController.Instance.ShowStatueOutline : null;
System.Action showOutlineCallback = menuController != null ? (System.Action)menuController.ShowStatueOutline : null; System.Action hideOutlineCallback = DecorationMenuController.Instance != null ? (System.Action)DecorationMenuController.Instance.HideStatueOutline : null;
System.Action hideOutlineCallback = menuController != null ? (System.Action)menuController.HideStatueOutline : null;
Logging.Debug($"[StatueDecorationController] Show outline callback is null: {showOutlineCallback == null}");
// Initialize in "placed" state (skip drag logic) // Create context for placed decoration
instance.InitializeAsPlaced( var context = DecorationDragContext.CreateForPlaced(
decorationData, decorationData,
this, this,
_settings, StatueDressupSettings.Instance.Settings,
statueArea, // Pass statue outline for overlap detection statueArea,
canvasParent, // Pass canvas parent for reparenting during pickup canvasParent,
showOutlineCallback, // Show outline when picking up showOutlineCallback,
hideOutlineCallback, // Hide outline when drag ends hideOutlineCallback,
hideOutlineCallback // Also use hide callback for onFinished hideOutlineCallback
); );
// Initialize in "placed" state (skip drag logic)
instance.InitializeWithContext(context);
// Apply saved transform // Apply saved transform
instance.transform.localPosition = placement.localPosition; instance.transform.localPosition = placement.localPosition;
instance.transform.localScale = placement.localScale; instance.transform.localScale = placement.localScale;
@@ -479,9 +483,6 @@ namespace Minigames.StatueDressup.Controllers
{ {
base.OnManagedDestroy(); base.OnManagedDestroy();
// Release Addressables handle
AddressablesUtility.ReleaseHandle(_decorationDataHandle);
// Cleanup button listeners // Cleanup button listeners
if (takePhotoButton != null) if (takePhotoButton != null)
{ {
@@ -494,6 +495,12 @@ namespace Minigames.StatueDressup.Controllers
// { // {
// openGalleryButton.onClick.RemoveListener(OnOpenGallery); // openGalleryButton.onClick.RemoveListener(OnOpenGallery);
// } // }
// Singleton cleanup
if (Instance == this)
{
Instance = null;
}
} }
public async void ExitToAppleHills() public async void ExitToAppleHills()

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: acf5624b19664ce5900f1a7c1328edbc
timeCreated: 1764240158

View File

@@ -15,6 +15,8 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
public class StatuePhotoGalleryController : ManagedBehaviour public class StatuePhotoGalleryController : ManagedBehaviour
{ {
public static StatuePhotoGalleryController Instance { get; private set; }
[Header("Gallery UI")] [Header("Gallery UI")]
[SerializeField] private Transform gridContainer; [SerializeField] private Transform gridContainer;
[SerializeField] private PhotoGridItem gridItemPrefab; [SerializeField] private PhotoGridItem gridItemPrefab;
@@ -29,25 +31,33 @@ namespace Minigames.StatueDressup.Controllers
[SerializeField] private Button nextPageButton; [SerializeField] private Button nextPageButton;
[SerializeField] private Text pageStatusText; [SerializeField] private Text pageStatusText;
private AppleHills.Core.Settings.IStatueDressupSettings _settings; private int currentPage;
private int _currentPage; private List<string> allPhotoIds = new List<string>();
private List<string> _allPhotoIds = new List<string>(); private Dictionary<string, PhotoGridItem> activeGridItems = new Dictionary<string, PhotoGridItem>();
private Dictionary<string, PhotoGridItem> _activeGridItems = new Dictionary<string, PhotoGridItem>(); private Dictionary<string, Texture2D> thumbnailCache = new Dictionary<string, Texture2D>();
private Dictionary<string, Texture2D> _thumbnailCache = new Dictionary<string, Texture2D>(); private Dictionary<string, Texture2D> fullPhotoCache = new Dictionary<string, Texture2D>(); // Cache full photos for enlargement
private Dictionary<string, Texture2D> _fullPhotoCache = new Dictionary<string, Texture2D>(); // Cache full photos for enlargement private Queue<string> thumbnailCacheOrder = new Queue<string>();
private Queue<string> _thumbnailCacheOrder = new Queue<string>(); private bool isLoadingPage;
private bool _isLoadingPage; private PhotoEnlargeController enlargeController;
private PhotoEnlargeController _enlargeController;
internal override void OnManagedStart() internal override void OnManagedStart()
{ {
base.OnManagedStart(); base.OnManagedStart();
// Get settings // Singleton pattern
_settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>(); 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 // 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 // Setup page navigation buttons
if (previousPageButton != null) if (previousPageButton != null)
@@ -76,10 +86,10 @@ namespace Minigames.StatueDressup.Controllers
ClearGrid(); ClearGrid();
// Get all photo IDs // Get all photo IDs
_allPhotoIds = PhotoManager.GetAllPhotoIds(CaptureType.StatueMinigame); allPhotoIds = PhotoManager.GetAllPhotoIds(CaptureType.StatueMinigame);
_currentPage = 0; currentPage = 0;
Logging.Debug($"[StatuePhotoGalleryController] Gallery refreshed: {_allPhotoIds.Count} photos"); Logging.Debug($"[StatuePhotoGalleryController] Gallery refreshed: {allPhotoIds.Count} photos");
// Display first page // Display first page
DisplayCurrentPage(); DisplayCurrentPage();
@@ -90,18 +100,18 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
private void DisplayCurrentPage() private void DisplayCurrentPage()
{ {
if (_isLoadingPage) return; if (isLoadingPage) return;
_isLoadingPage = true; isLoadingPage = true;
// Clear current grid // Clear current grid
ClearGrid(); ClearGrid();
// Get photos for current page // Get photos for current page
int itemsPerPage = _settings?.GalleryItemsPerPage ?? 20; int itemsPerPage = StatueDressupSettings.Instance?.Settings?.GalleryItemsPerPage ?? 20;
List<string> pagePhotoIds = PhotoManager.GetPhotoIdsPage(CaptureType.StatueMinigame, _currentPage, itemsPerPage); 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 // Spawn grid items for this page
foreach (string photoId in pagePhotoIds) foreach (string photoId in pagePhotoIds)
@@ -113,10 +123,10 @@ namespace Minigames.StatueDressup.Controllers
UpdatePageButtons(); UpdatePageButtons();
// Update status text // Update status text
int totalPages = Mathf.CeilToInt((float)_allPhotoIds.Count / itemsPerPage); int totalPages = Mathf.CeilToInt((float)allPhotoIds.Count / itemsPerPage);
UpdateStatusText($"Page {_currentPage + 1}/{totalPages} ({_allPhotoIds.Count} photos)"); UpdateStatusText($"Page {currentPage + 1}/{totalPages} ({allPhotoIds.Count} photos)");
_isLoadingPage = false; isLoadingPage = false;
} }
/// <summary> /// <summary>
@@ -124,19 +134,19 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
private void UpdatePageButtons() private void UpdatePageButtons()
{ {
int itemsPerPage = _settings?.GalleryItemsPerPage ?? 20; int itemsPerPage = StatueDressupSettings.Instance?.Settings?.GalleryItemsPerPage ?? 20;
int totalPages = Mathf.CeilToInt((float)_allPhotoIds.Count / itemsPerPage); int totalPages = Mathf.CeilToInt((float)allPhotoIds.Count / itemsPerPage);
// Enable/disable previous button // Enable/disable previous button
if (previousPageButton != null) if (previousPageButton != null)
{ {
previousPageButton.interactable = _currentPage > 0; previousPageButton.interactable = currentPage > 0;
} }
// Enable/disable next button // Enable/disable next button
if (nextPageButton != null) if (nextPageButton != null)
{ {
nextPageButton.interactable = _currentPage < totalPages - 1; nextPageButton.interactable = currentPage < totalPages - 1;
} }
} }
@@ -145,11 +155,11 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
private void OnPreviousPageClicked() private void OnPreviousPageClicked()
{ {
if (_currentPage > 0) if (currentPage > 0)
{ {
_currentPage--; currentPage--;
DisplayCurrentPage(); 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> /// </summary>
private void OnNextPageClicked() private void OnNextPageClicked()
{ {
int itemsPerPage = _settings?.GalleryItemsPerPage ?? 20; int itemsPerPage = StatueDressupSettings.Instance?.Settings?.GalleryItemsPerPage ?? 20;
int totalPages = Mathf.CeilToInt((float)_allPhotoIds.Count / itemsPerPage); int totalPages = Mathf.CeilToInt((float)allPhotoIds.Count / itemsPerPage);
if (_currentPage < totalPages - 1) if (currentPage < totalPages - 1)
{ {
_currentPage++; currentPage++;
DisplayCurrentPage(); 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> /// </summary>
private void SpawnGridItem(string photoId) private void SpawnGridItem(string photoId)
{ {
if (_activeGridItems.ContainsKey(photoId)) if (activeGridItems.ContainsKey(photoId))
{ {
Logging.Warning($"[StatuePhotoGalleryController] Grid item already exists: {photoId}"); Logging.Warning($"[StatuePhotoGalleryController] Grid item already exists: {photoId}");
return; return;
@@ -183,7 +193,7 @@ namespace Minigames.StatueDressup.Controllers
PhotoGridItem gridItem = Instantiate(gridItemPrefab, gridContainer); PhotoGridItem gridItem = Instantiate(gridItemPrefab, gridContainer);
gridItem.Initialize(photoId, this); gridItem.Initialize(photoId, this);
_activeGridItems[photoId] = gridItem; activeGridItems[photoId] = gridItem;
// Load thumbnail asynchronously // Load thumbnail asynchronously
StartCoroutine(LoadThumbnailAsync(photoId, gridItem)); StartCoroutine(LoadThumbnailAsync(photoId, gridItem));
@@ -195,7 +205,7 @@ namespace Minigames.StatueDressup.Controllers
private IEnumerator LoadThumbnailAsync(string photoId, PhotoGridItem gridItem) private IEnumerator LoadThumbnailAsync(string photoId, PhotoGridItem gridItem)
{ {
// Check cache first // Check cache first
if (_thumbnailCache.TryGetValue(photoId, out Texture2D cachedThumbnail)) if (thumbnailCache.TryGetValue(photoId, out Texture2D cachedThumbnail))
{ {
gridItem.SetThumbnail(cachedThumbnail); gridItem.SetThumbnail(cachedThumbnail);
yield break; yield break;
@@ -214,7 +224,7 @@ namespace Minigames.StatueDressup.Controllers
} }
// Create thumbnail // Create thumbnail
int thumbSize = _settings?.GalleryThumbnailSize ?? 256; int thumbSize = StatueDressupSettings.Instance?.Settings?.GalleryThumbnailSize ?? 256;
Texture2D thumbnail = PhotoManager.CreateThumbnail(fullPhoto, thumbSize); Texture2D thumbnail = PhotoManager.CreateThumbnail(fullPhoto, thumbSize);
// Destroy full photo immediately (we only need thumbnail) // Destroy full photo immediately (we only need thumbnail)
@@ -236,19 +246,19 @@ namespace Minigames.StatueDressup.Controllers
private void CacheThumbnail(string photoId, Texture2D thumbnail) private void CacheThumbnail(string photoId, Texture2D thumbnail)
{ {
// Add to cache // Add to cache
_thumbnailCache[photoId] = thumbnail; thumbnailCache[photoId] = thumbnail;
_thumbnailCacheOrder.Enqueue(photoId); thumbnailCacheOrder.Enqueue(photoId);
// Evict oldest if over limit // Evict oldest if over limit
int maxCached = _settings?.GalleryMaxCachedThumbnails ?? 50; int maxCached = StatueDressupSettings.Instance?.Settings?.GalleryMaxCachedThumbnails ?? 50;
while (_thumbnailCache.Count > maxCached && _thumbnailCacheOrder.Count > 0) 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); Destroy(oldThumbnail);
_thumbnailCache.Remove(oldestId); thumbnailCache.Remove(oldestId);
Logging.Debug($"[StatuePhotoGalleryController] Evicted thumbnail from cache: {oldestId}"); Logging.Debug($"[StatuePhotoGalleryController] Evicted thumbnail from cache: {oldestId}");
} }
} }
@@ -259,28 +269,28 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
public void OnGridItemClicked(PhotoGridItem gridItem, string photoId) public void OnGridItemClicked(PhotoGridItem gridItem, string photoId)
{ {
if (_enlargeController == null) if (enlargeController == null)
{ {
Logging.Error("[StatuePhotoGalleryController] Enlarge controller not initialized"); Logging.Error("[StatuePhotoGalleryController] Enlarge controller not initialized");
return; return;
} }
// If already enlarged, shrink it // If already enlarged, shrink it
if (_enlargeController.IsPhotoEnlarged) if (enlargeController.IsPhotoEnlarged)
{ {
_enlargeController.ShrinkPhoto(); enlargeController.ShrinkPhoto();
return; return;
} }
Logging.Debug($"[StatuePhotoGalleryController] Enlarging photo: {photoId}"); Logging.Debug($"[StatuePhotoGalleryController] Enlarging photo: {photoId}");
float enlargedScale = _settings?.GalleryEnlargedScale ?? 2.5f; float enlargedScale = StatueDressupSettings.Instance?.Settings?.GalleryEnlargedScale ?? 2.5f;
// Check cache first // Check cache first
if (_fullPhotoCache.TryGetValue(photoId, out Texture2D fullPhoto)) if (fullPhotoCache.TryGetValue(photoId, out Texture2D fullPhoto))
{ {
// Use cached photo // Use cached photo
_enlargeController.EnlargePhoto(gridItem, enlargedPreviewPrefab != null ? enlargedPreviewPrefab : gridItem.gameObject, fullPhoto, enlargedScale); enlargeController.EnlargePhoto(gridItem, enlargedPreviewPrefab != null ? enlargedPreviewPrefab : gridItem.gameObject, fullPhoto, enlargedScale);
} }
else else
{ {
@@ -294,12 +304,12 @@ namespace Minigames.StatueDressup.Controllers
} }
// Cache it (limited cache) // 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> /// </summary>
public void CleanupGallery() public void CleanupGallery()
{ {
if (_enlargeController != null) if (enlargeController != null)
{ {
_enlargeController.Cleanup(); enlargeController.Cleanup();
} }
// Clean up cached full photos // Clean up cached full photos
foreach (var photo in _fullPhotoCache.Values) foreach (var photo in fullPhotoCache.Values)
{ {
if (photo != null) if (photo != null)
{ {
Destroy(photo); Destroy(photo);
} }
} }
_fullPhotoCache.Clear(); fullPhotoCache.Clear();
} }
/// <summary> /// <summary>
@@ -341,12 +351,12 @@ namespace Minigames.StatueDressup.Controllers
private void ClearGrid() private void ClearGrid()
{ {
// Destroy grid items // Destroy grid items
foreach (var gridItem in _activeGridItems.Values) foreach (var gridItem in activeGridItems.Values)
{ {
if (gridItem != null) if (gridItem != null)
Destroy(gridItem.gameObject); Destroy(gridItem.gameObject);
} }
_activeGridItems.Clear(); activeGridItems.Clear();
Logging.Debug("[StatuePhotoGalleryController] Grid cleared"); Logging.Debug("[StatuePhotoGalleryController] Grid cleared");
} }
@@ -359,13 +369,13 @@ namespace Minigames.StatueDressup.Controllers
ClearGrid(); ClearGrid();
// Clear thumbnail cache // Clear thumbnail cache
foreach (var thumbnail in _thumbnailCache.Values) foreach (var thumbnail in thumbnailCache.Values)
{ {
if (thumbnail != null) if (thumbnail != null)
Destroy(thumbnail); Destroy(thumbnail);
} }
_thumbnailCache.Clear(); thumbnailCache.Clear();
_thumbnailCacheOrder.Clear(); thumbnailCacheOrder.Clear();
Logging.Debug("[StatuePhotoGalleryController] Gallery fully cleared"); Logging.Debug("[StatuePhotoGalleryController] Gallery fully cleared");
} }
@@ -374,7 +384,13 @@ namespace Minigames.StatueDressup.Controllers
{ {
base.OnManagedDestroy(); base.OnManagedDestroy();
// Cleanup // Singleton cleanup
if (Instance == this)
{
Instance = null;
}
// Clean up cached textures
ClearGallery(); ClearGallery();
CleanupGallery(); CleanupGallery();

View File

@@ -1,9 +1,8 @@
using System.Collections.Generic; using Core;
using Core;
using Core.Lifecycle; using Core.Lifecycle;
using Minigames.StatueDressup.Controllers;
using Minigames.StatueDressup.Data; using Minigames.StatueDressup.Data;
using UnityEngine; using UnityEngine;
using UnityEngine.ResourceManagement.AsyncOperations;
using Utils; using Utils;
namespace Minigames.StatueDressup.Display namespace Minigames.StatueDressup.Display
@@ -27,10 +26,6 @@ namespace Minigames.StatueDressup.Display
[Header("Debug")] [Header("Debug")]
[SerializeField] private bool showDebugInfo = true; [SerializeField] private bool showDebugInfo = true;
private Dictionary<string, DecorationData> decorationDataDict;
private AsyncOperationHandle<IList<DecorationData>> decorationDataHandle;
private AppleHills.Core.Settings.IStatueDressupSettings settings;
internal override void OnManagedStart() internal override void OnManagedStart()
{ {
base.OnManagedStart(); base.OnManagedStart();
@@ -44,81 +39,40 @@ namespace Minigames.StatueDressup.Display
return; return;
} }
// Get settings // DecorationDataManager exists (initialized in OnManagedAwake) but data loads async
settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>(); // Wait for data to finish loading before displaying decorations
StartCoroutine(WaitForDataAndDisplay());
// Start async loading via coroutine wrapper
StartCoroutine(LoadAndDisplayDecorationsCoroutine());
} }
/// <summary> /// <summary>
/// Coroutine wrapper for async loading and display /// Wait for DecorationDataManager to finish loading data before displaying decorations
/// </summary> /// </summary>
private System.Collections.IEnumerator LoadAndDisplayDecorationsCoroutine() private System.Collections.IEnumerator WaitForDataAndDisplay()
{ {
// Convert async Task to coroutine-compatible operation // Wait for data to load (manager is guaranteed to exist)
var loadTask = LoadDecorationDataAsync(); while (!DecorationDataManager.Instance.IsLoaded)
// Wait for async operation to complete
while (!loadTask.IsCompleted)
{ {
yield return null; yield return null;
} }
// Check for exceptions if (showDebugInfo)
if (loadTask.IsFaulted)
{ {
Logging.Error($"[StatueDecorationLoader] Failed to load decoration data: {loadTask.Exception?.GetBaseException().Message}"); Logging.Debug("[StatueDecorationLoader] DecorationData loaded, displaying decorations");
yield break;
} }
// Load and display decorations // Load and display decorations
LoadAndDisplayDecorations(); LoadAndDisplayDecorations();
} }
/// <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("[StatueDecorationLoader] Decoration data label not set in settings!");
return;
}
if (showDebugInfo)
{
Logging.Debug($"[StatueDecorationLoader] 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, // Key selector: use DecorationId as key
progress => { /* Optional: could show loading bar */ }
);
decorationDataDict = result.dictionary;
decorationDataHandle = result.handle;
if (showDebugInfo)
{
Logging.Debug($"[StatueDecorationLoader] Loaded {decorationDataDict.Count} DecorationData assets");
}
}
/// <summary> /// <summary>
/// Load decoration metadata and spawn decorations /// Load decoration metadata and spawn decorations
/// </summary> /// </summary>
public void LoadAndDisplayDecorations() public void LoadAndDisplayDecorations()
{ {
// Check if DecorationData is loaded // Check if DecorationData is loaded via manager
if (decorationDataDict == null || decorationDataDict.Count == 0) if (DecorationDataManager.Instance == null || !DecorationDataManager.Instance.IsLoaded)
{ {
Logging.Warning("[StatueDecorationLoader] DecorationData not loaded yet. Cannot display decorations."); Logging.Warning("[StatueDecorationLoader] DecorationDataManager not ready. Cannot display decorations.");
return; return;
} }
@@ -206,12 +160,12 @@ namespace Minigames.StatueDressup.Display
/// <summary> /// <summary>
/// Spawn a single decoration from placement data /// Spawn a single decoration from placement data
/// Looks up DecorationData from pre-loaded dictionary and applies coordinate conversion /// Looks up DecorationData from manager and applies coordinate conversion
/// </summary> /// </summary>
private bool SpawnDecoration(DecorationPlacement placement, float conversionFactor, Vector2 sourceStatueSize, Vector2 targetStatueWorldSize) private bool SpawnDecoration(DecorationPlacement placement, float conversionFactor, Vector2 sourceStatueSize, Vector2 targetStatueWorldSize)
{ {
// Look up DecorationData from dictionary // Look up DecorationData from manager
if (!decorationDataDict.TryGetValue(placement.decorationId, out DecorationData decorationData)) if (!DecorationDataManager.Instance.TryGetData(placement.decorationId, out DecorationData decorationData))
{ {
Logging.Warning($"[StatueDecorationLoader] DecorationData not found for ID: {placement.decorationId}"); Logging.Warning($"[StatueDecorationLoader] DecorationData not found for ID: {placement.decorationId}");
return false; return false;
@@ -375,14 +329,7 @@ namespace Minigames.StatueDressup.Display
} }
} }
/// <summary> // Cleanup handled by DecorationDataManager - no need for OnDestroy here
/// Cleanup - release Addressables handle
/// </summary>
private void OnDestroy()
{
// Release DecorationData handle
AddressablesUtility.ReleaseHandle(decorationDataHandle);
}
/// <summary> /// <summary>
/// Reload decorations (useful for testing) /// Reload decorations (useful for testing)

View File

@@ -0,0 +1,117 @@
using Minigames.StatueDressup.Data;
using UnityEngine;
namespace Minigames.StatueDressup.DragDrop
{
/// <summary>
/// Context object for initializing draggable decorations.
/// Consolidates multiple parameters into a single, cohesive object.
/// </summary>
public class DecorationDragContext
{
/// <summary>
/// The decoration data to display
/// </summary>
public DecorationData Data { get; set; }
/// <summary>
/// The statue outline area for overlap detection
/// </summary>
public RectTransform StatueOutline { get; set; }
/// <summary>
/// Parent transform for decorations placed on statue
/// </summary>
public Transform StatueParent { get; set; }
/// <summary>
/// Parent transform for dragging (usually canvas or draggable container)
/// </summary>
public Transform CanvasParent { get; set; }
/// <summary>
/// Controller for registering/unregistering decorations
/// </summary>
public Controllers.StatueDecorationController Controller { get; set; }
/// <summary>
/// Settings for the minigame
/// </summary>
public AppleHills.Core.Settings.IStatueDressupSettings Settings { get; set; }
/// <summary>
/// Callback when drag operation finishes (success or failure)
/// </summary>
public System.Action OnFinished { get; set; }
/// <summary>
/// Callback to show statue outline during drag
/// </summary>
public System.Action OnShowOutline { get; set; }
/// <summary>
/// Callback to hide statue outline after drag
/// </summary>
public System.Action OnHideOutline { get; set; }
/// <summary>
/// Whether this decoration is being initialized as already placed (from saved state)
/// </summary>
public bool IsPlaced { get; set; }
/// <summary>
/// Create a context for a new decoration being dragged from menu
/// </summary>
public static DecorationDragContext CreateForNewDrag(
DecorationData data,
RectTransform statueOutline,
Transform statueParent,
Controllers.StatueDecorationController controller,
AppleHills.Core.Settings.IStatueDressupSettings settings,
System.Action onFinished,
System.Action onShowOutline,
System.Action onHideOutline)
{
return new DecorationDragContext
{
Data = data,
StatueOutline = statueOutline,
StatueParent = statueParent,
Controller = controller,
Settings = settings,
OnFinished = onFinished,
OnShowOutline = onShowOutline,
OnHideOutline = onHideOutline,
IsPlaced = false
};
}
/// <summary>
/// Create a context for a decoration being loaded from saved state
/// </summary>
public static DecorationDragContext CreateForPlaced(
DecorationData data,
Controllers.StatueDecorationController controller,
AppleHills.Core.Settings.IStatueDressupSettings settings,
RectTransform statueOutline = null,
Transform canvasParent = null,
System.Action onShowOutline = null,
System.Action onHideOutline = null,
System.Action onFinished = null)
{
return new DecorationDragContext
{
Data = data,
StatueOutline = statueOutline,
CanvasParent = canvasParent,
Controller = controller,
Settings = settings,
OnShowOutline = onShowOutline,
OnHideOutline = onHideOutline,
OnFinished = onFinished,
IsPlaced = true
};
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8f2a2c34f6ce482ba117f39cb669e11f
timeCreated: 1764240188

View File

@@ -20,36 +20,36 @@ namespace Minigames.StatueDressup.DragDrop
[SerializeField] private Image decorationImage; [SerializeField] private Image decorationImage;
[SerializeField] private CanvasGroup canvasGroup; [SerializeField] private CanvasGroup canvasGroup;
private DecorationData _decorationData; private DecorationData decorationData;
private RectTransform _rectTransform; private RectTransform rectTransform;
private Canvas _canvas; private Canvas canvas;
private Transform _canvasParent; // Parent transform for dragging (usually canvas or draggable container) private Transform canvasParent; // Parent transform for dragging (usually canvas or draggable container)
private RectTransform _statueOutline; private RectTransform statueOutline;
private Transform _statueParent; private Transform statueParent;
private StatueDecorationController _controller; private StatueDecorationController controller;
private AppleHills.Core.Settings.IStatueDressupSettings _settings; private AppleHills.Core.Settings.IStatueDressupSettings settings;
private System.Action _onFinishedCallback; private System.Action onFinishedCallback;
private System.Action _onShowOutlineCallback; private System.Action onShowOutlineCallback;
private System.Action _onHideOutlineCallback; private System.Action onHideOutlineCallback;
private bool _isDragging; private bool isDragging;
private bool _isPlacedOnStatue; private bool isPlacedOnStatue;
private Vector3 _dragOffset; private Vector3 dragOffset;
private bool _dragStarted; // Track if drag actually started (vs just a click) private bool dragStarted; // Track if drag actually started (vs just a click)
// Properties // Properties
public DecorationData Data => _decorationData; public DecorationData Data => decorationData;
public bool IsPlacedOnStatue => _isPlacedOnStatue; public bool IsPlacedOnStatue => isPlacedOnStatue;
private void Awake() private void Awake()
{ {
_rectTransform = GetComponent<RectTransform>(); rectTransform = GetComponent<RectTransform>();
_canvas = GetComponentInParent<Canvas>(); canvas = GetComponentInParent<Canvas>();
// Store initial parent for dragging context // Store initial parent for dragging context
if (transform.parent != null) if (transform.parent != null)
{ {
_canvasParent = transform.parent; canvasParent = transform.parent;
} }
if (canvasGroup == null) if (canvasGroup == null)
@@ -65,87 +65,87 @@ namespace Minigames.StatueDressup.DragDrop
} }
/// <summary> /// <summary>
/// Initialize the draggable instance /// Initialize with context object (preferred method)
/// </summary> /// </summary>
public void Initialize(DecorationData data, RectTransform statueOutline, Transform statueParent, public void InitializeWithContext(DecorationDragContext context)
StatueDecorationController controller, AppleHills.Core.Settings.IStatueDressupSettings settings,
System.Action onFinishedCallback, System.Action onShowOutline = null, System.Action onHideOutline = null)
{ {
_decorationData = data; if (context == null)
_statueOutline = statueOutline; {
_statueParent = statueParent; Logging.Error("[DecorationDraggableInstance] Null context provided!");
_controller = controller; return;
_settings = settings; }
_onFinishedCallback = onFinishedCallback;
_onShowOutlineCallback = onShowOutline; decorationData = context.Data;
_onHideOutlineCallback = onHideOutline; statueOutline = context.StatueOutline;
statueParent = context.StatueParent;
controller = context.Controller;
settings = context.Settings;
onFinishedCallback = context.OnFinished;
onShowOutlineCallback = context.OnShowOutline;
onHideOutlineCallback = context.OnHideOutline;
// Handle placed vs new drag
if (context.IsPlaced)
{
isPlacedOnStatue = true;
isDragging = false;
statueParent = transform.parent; // Already parented to statue
if (context.CanvasParent != null)
{
canvasParent = context.CanvasParent;
}
}
// Set sprite // Set sprite
if (decorationImage != null && data != null && data.DecorationSprite != null) if (decorationImage != null && context.Data != null && context.Data.DecorationSprite != null)
{ {
decorationImage.sprite = data.DecorationSprite; decorationImage.sprite = context.Data.DecorationSprite;
} }
// Set authored size // Set authored size
if (_rectTransform != null && data != null) if (rectTransform != null && context.Data != null)
{ {
_rectTransform.sizeDelta = data.AuthoredSize; rectTransform.sizeDelta = context.Data.AuthoredSize;
} }
Logging.Debug($"[DecorationDraggableInstance] Initialized: {data?.DecorationName}"); // Make interactive if placed (so it can be picked up)
} if (context.IsPlaced && canvasGroup != null)
/// <summary>
/// Initialize as already placed decoration (from saved state)
/// Skips drag logic and sets up as if already placed on statue
/// </summary>
public void InitializeAsPlaced(DecorationData data, StatueDecorationController controller,
AppleHills.Core.Settings.IStatueDressupSettings settings, RectTransform statueOutline = null,
Transform canvasParent = null, System.Action onShowOutline = null, System.Action onHideOutline = null,
System.Action onFinished = null)
{
_decorationData = data;
_controller = controller;
_settings = settings;
_isPlacedOnStatue = true;
_isDragging = false;
// Store references needed for pickup
_statueOutline = statueOutline;
_statueParent = transform.parent; // Already parented to statue when this is called
if (canvasParent != null)
{
_canvasParent = canvasParent;
}
// Store outline callbacks for when picking up from statue
_onShowOutlineCallback = onShowOutline;
_onHideOutlineCallback = onHideOutline;
_onFinishedCallback = onFinished;
Logging.Debug($"[DecorationDraggableInstance] InitializeAsPlaced - Show outline callback is null: {_onShowOutlineCallback == null}");
Logging.Debug($"[DecorationDraggableInstance] InitializeAsPlaced - Hide outline callback is null: {_onHideOutlineCallback == null}");
Logging.Debug($"[DecorationDraggableInstance] InitializeAsPlaced - Finished callback is null: {_onFinishedCallback == null}");
// Set sprite
if (decorationImage != null && data != null && data.DecorationSprite != null)
{
decorationImage.sprite = data.DecorationSprite;
}
// Set authored size
if (_rectTransform != null && data != null)
{
_rectTransform.sizeDelta = data.AuthoredSize;
}
// Make interactive so it can be picked up
if (canvasGroup != null)
{ {
canvasGroup.blocksRaycasts = true; canvasGroup.blocksRaycasts = true;
} }
Logging.Debug($"[DecorationDraggableInstance] Initialized as placed: {data?.DecorationName}"); Logging.Debug($"[DecorationDraggableInstance] Initialized with context: {context.Data?.DecorationName}, isPlaced={context.IsPlaced}");
}
/// <summary>
/// Initialize the draggable instance (legacy method - prefer InitializeWithContext)
/// </summary>
[System.Obsolete("Use InitializeWithContext instead")]
public void Initialize(DecorationData data, RectTransform pStatueOutline, Transform pStatueParent,
StatueDecorationController pController, AppleHills.Core.Settings.IStatueDressupSettings pSettings,
System.Action pOnFinishedCallback, System.Action onShowOutline = null, System.Action onHideOutline = null)
{
var context = DecorationDragContext.CreateForNewDrag(
data, pStatueOutline, pStatueParent, pController, pSettings,
pOnFinishedCallback, onShowOutline, onHideOutline
);
InitializeWithContext(context);
}
/// <summary>
/// Initialize as already placed decoration (legacy method - prefer InitializeWithContext)
/// </summary>
[System.Obsolete("Use InitializeWithContext instead")]
public void InitializeAsPlaced(DecorationData data, StatueDecorationController pController,
AppleHills.Core.Settings.IStatueDressupSettings pSettings, RectTransform pStatueOutline = null,
Transform pCanvasParent = null, System.Action onShowOutline = null, System.Action onHideOutline = null,
System.Action onFinished = null)
{
var context = DecorationDragContext.CreateForPlaced(
data, pController, pSettings, pStatueOutline, pCanvasParent,
onShowOutline, onHideOutline, onFinished
);
InitializeWithContext(context);
} }
/// <summary> /// <summary>
@@ -153,18 +153,18 @@ namespace Minigames.StatueDressup.DragDrop
/// </summary> /// </summary>
public void StartDragFromIcon(PointerEventData eventData) public void StartDragFromIcon(PointerEventData eventData)
{ {
_isDragging = true; isDragging = true;
// Calculate offset from cursor to object center // Calculate offset from cursor to object center
RectTransformUtility.ScreenPointToLocalPointInRectangle( RectTransformUtility.ScreenPointToLocalPointInRectangle(
_canvas.transform as RectTransform, canvas.transform as RectTransform,
eventData.position, eventData.position,
eventData.pressEventCamera, eventData.pressEventCamera,
out Vector2 localPoint); out Vector2 localPoint);
_dragOffset = _rectTransform.localPosition - (Vector3)localPoint; dragOffset = rectTransform.localPosition - (Vector3)localPoint;
Logging.Debug($"[DecorationDraggableInstance] Started drag from icon: {_decorationData?.DecorationName}"); Logging.Debug($"[DecorationDraggableInstance] Started drag from icon: {decorationData?.DecorationName}");
} }
/// <summary> /// <summary>
@@ -172,16 +172,16 @@ namespace Minigames.StatueDressup.DragDrop
/// </summary> /// </summary>
public void ContinueDrag(PointerEventData eventData) public void ContinueDrag(PointerEventData eventData)
{ {
if (!_isDragging) return; if (!isDragging) return;
// Update position to follow cursor // Update position to follow cursor
RectTransformUtility.ScreenPointToLocalPointInRectangle( RectTransformUtility.ScreenPointToLocalPointInRectangle(
_canvas.transform as RectTransform, canvas.transform as RectTransform,
eventData.position, eventData.position,
eventData.pressEventCamera, eventData.pressEventCamera,
out Vector2 localPoint); out Vector2 localPoint);
_rectTransform.localPosition = localPoint + (Vector2)_dragOffset; rectTransform.localPosition = localPoint + (Vector2)dragOffset;
} }
/// <summary> /// <summary>
@@ -189,9 +189,9 @@ namespace Minigames.StatueDressup.DragDrop
/// </summary> /// </summary>
public void EndDrag(PointerEventData eventData) public void EndDrag(PointerEventData eventData)
{ {
_isDragging = false; isDragging = false;
Logging.Debug($"[DecorationDraggableInstance] Drag ended: {_decorationData?.DecorationName}"); Logging.Debug($"[DecorationDraggableInstance] Drag ended: {decorationData?.DecorationName}");
// Check if overlapping with statue // Check if overlapping with statue
if (IsOverlappingStatue()) if (IsOverlappingStatue())
@@ -209,20 +209,20 @@ namespace Minigames.StatueDressup.DragDrop
/// </summary> /// </summary>
private bool IsOverlappingStatue() private bool IsOverlappingStatue()
{ {
if (_statueOutline == null || _rectTransform == null) if (statueOutline == null || rectTransform == null)
{ {
Logging.Warning($"[DecorationDraggableInstance] Cannot check overlap - statueOutline or RectTransform is null"); Logging.Warning($"[DecorationDraggableInstance] Cannot check overlap - statueOutline or RectTransform is null");
return false; return false;
} }
// Get bounds of this item in world space // Get bounds of this item in world space
Rect itemRect = GetWorldRect(_rectTransform); Rect itemRect = GetWorldRect(rectTransform);
Rect outlineRect = GetWorldRect(_statueOutline); Rect outlineRect = GetWorldRect(statueOutline);
// Check for any overlap // Check for any overlap
bool overlaps = itemRect.Overlaps(outlineRect); bool overlaps = itemRect.Overlaps(outlineRect);
Logging.Debug($"[DecorationDraggableInstance] Overlap check: {_decorationData?.DecorationName}, overlaps={overlaps}"); Logging.Debug($"[DecorationDraggableInstance] Overlap check: {decorationData?.DecorationName}, overlaps={overlaps}");
return overlaps; return overlaps;
} }
@@ -230,10 +230,10 @@ namespace Minigames.StatueDressup.DragDrop
/// <summary> /// <summary>
/// Get world space rect for a RectTransform /// Get world space rect for a RectTransform
/// </summary> /// </summary>
private Rect GetWorldRect(RectTransform rectTransform) private Rect GetWorldRect(RectTransform pRectTransform)
{ {
Vector3[] corners = new Vector3[4]; Vector3[] corners = new Vector3[4];
rectTransform.GetWorldCorners(corners); pRectTransform.GetWorldCorners(corners);
Vector3 bottomLeft = corners[0]; Vector3 bottomLeft = corners[0];
Vector3 topRight = corners[2]; Vector3 topRight = corners[2];
@@ -246,24 +246,24 @@ namespace Minigames.StatueDressup.DragDrop
/// </summary> /// </summary>
private void PlaceOnStatue() private void PlaceOnStatue()
{ {
Logging.Debug($"[DecorationDraggableInstance] Placing on statue: {_decorationData?.DecorationName}"); Logging.Debug($"[DecorationDraggableInstance] Placing on statue: {decorationData?.DecorationName}");
_isPlacedOnStatue = true; isPlacedOnStatue = true;
// Move to statue parent if specified // Move to statue parent if specified
if (_statueParent != null && transform.parent != _statueParent) if (statueParent != null && transform.parent != statueParent)
{ {
transform.SetParent(_statueParent, true); // Keep world position transform.SetParent(statueParent, true); // Keep world position
} }
// Register with controller // Register with controller
if (_controller != null) if (controller != null)
{ {
_controller.RegisterDecoration(this); controller.RegisterDecoration(this);
} }
// Notify menu controller to hide outline // Notify menu controller to hide outline
_onFinishedCallback?.Invoke(); onFinishedCallback?.Invoke();
} }
/// <summary> /// <summary>
@@ -271,12 +271,12 @@ namespace Minigames.StatueDressup.DragDrop
/// </summary> /// </summary>
private void PlayPopOutAndDestroy() private void PlayPopOutAndDestroy()
{ {
Logging.Debug($"[DecorationDraggableInstance] Pop-out and destroy: {_decorationData?.DecorationName}"); Logging.Debug($"[DecorationDraggableInstance] Pop-out and destroy: {decorationData?.DecorationName}");
// Notify menu controller to hide outline immediately // Notify menu controller to hide outline immediately
_onFinishedCallback?.Invoke(); onFinishedCallback?.Invoke();
float duration = _settings?.PlacementAnimationDuration ?? 0.3f; float duration = settings?.PlacementAnimationDuration ?? 0.3f;
// Play pop-out with fade animation // Play pop-out with fade animation
TweenAnimationUtility.PopOutWithFade(transform, canvasGroup, duration, () => TweenAnimationUtility.PopOutWithFade(transform, canvasGroup, duration, () =>
@@ -290,22 +290,22 @@ namespace Minigames.StatueDressup.DragDrop
/// </summary> /// </summary>
public void StartDragFromStatue(PointerEventData eventData) public void StartDragFromStatue(PointerEventData eventData)
{ {
Logging.Debug($"[DecorationDraggableInstance] StartDragFromStatue called for: {_decorationData?.DecorationName}"); Logging.Debug($"[DecorationDraggableInstance] StartDragFromStatue called for: {decorationData?.DecorationName}");
Logging.Debug($"[DecorationDraggableInstance] Show outline callback is null: {_onShowOutlineCallback == null}"); Logging.Debug($"[DecorationDraggableInstance] Show outline callback is null: {onShowOutlineCallback == null}");
if (_controller != null) if (controller != null)
{ {
_controller.UnregisterDecoration(this); controller.UnregisterDecoration(this);
} }
_isPlacedOnStatue = false; isPlacedOnStatue = false;
_isDragging = true; isDragging = true;
// Show statue outline when picking up from statue // Show statue outline when picking up from statue
if (_onShowOutlineCallback != null) if (onShowOutlineCallback != null)
{ {
Logging.Debug("[DecorationDraggableInstance] Invoking show outline callback"); Logging.Debug("[DecorationDraggableInstance] Invoking show outline callback");
_onShowOutlineCallback.Invoke(); onShowOutlineCallback.Invoke();
} }
else else
{ {
@@ -313,24 +313,24 @@ namespace Minigames.StatueDressup.DragDrop
} }
// Reparent to canvas for dragging (so coordinates work correctly) // Reparent to canvas for dragging (so coordinates work correctly)
if (_canvasParent != null && transform.parent != _canvasParent) if (canvasParent != null && transform.parent != canvasParent)
{ {
// Store world position before reparenting // Store world position before reparenting
Vector3 worldPos = transform.position; Vector3 worldPos = transform.position;
transform.SetParent(_canvasParent, false); transform.SetParent(canvasParent, false);
transform.position = worldPos; // Restore world position transform.position = worldPos; // Restore world position
} }
// Calculate offset using proper camera // Calculate offset using proper camera
RectTransformUtility.ScreenPointToLocalPointInRectangle( RectTransformUtility.ScreenPointToLocalPointInRectangle(
_canvas.transform as RectTransform, canvas.transform as RectTransform,
eventData.position, eventData.position,
eventData.pressEventCamera, eventData.pressEventCamera,
out Vector2 localPoint); out Vector2 localPoint);
_dragOffset = _rectTransform.localPosition - (Vector3)localPoint; dragOffset = rectTransform.localPosition - (Vector3)localPoint;
Logging.Debug($"[DecorationDraggableInstance] Started drag from statue: {_decorationData?.DecorationName}"); Logging.Debug($"[DecorationDraggableInstance] Started drag from statue: {decorationData?.DecorationName}");
} }
#region Pointer Event Handlers #region Pointer Event Handlers
@@ -341,9 +341,9 @@ namespace Minigames.StatueDressup.DragDrop
public void OnPointerClick(PointerEventData eventData) public void OnPointerClick(PointerEventData eventData)
{ {
// Only handle clicks when placed on statue and not currently dragging // Only handle clicks when placed on statue and not currently dragging
if (!_isPlacedOnStatue || _dragStarted) return; if (!isPlacedOnStatue || dragStarted) return;
Logging.Debug($"[DecorationDraggableInstance] Decoration tapped: {_decorationData?.DecorationName}"); Logging.Debug($"[DecorationDraggableInstance] Decoration tapped: {decorationData?.DecorationName}");
// Future: Open detail view, play sound effect, show info popup, etc. // Future: Open detail view, play sound effect, show info popup, etc.
} }
@@ -354,9 +354,9 @@ namespace Minigames.StatueDressup.DragDrop
public void OnBeginDrag(PointerEventData eventData) public void OnBeginDrag(PointerEventData eventData)
{ {
// Only handle drag from statue if already placed // Only handle drag from statue if already placed
if (!_isPlacedOnStatue) return; if (!isPlacedOnStatue) return;
_dragStarted = true; dragStarted = true;
StartDragFromStatue(eventData); StartDragFromStatue(eventData);
} }
@@ -365,7 +365,7 @@ namespace Minigames.StatueDressup.DragDrop
/// </summary> /// </summary>
public void OnDrag(PointerEventData eventData) public void OnDrag(PointerEventData eventData)
{ {
if (!_isDragging) return; if (!isDragging) return;
ContinueDrag(eventData); ContinueDrag(eventData);
} }
@@ -375,9 +375,9 @@ namespace Minigames.StatueDressup.DragDrop
/// </summary> /// </summary>
public void OnEndDrag(PointerEventData eventData) public void OnEndDrag(PointerEventData eventData)
{ {
if (!_isDragging) return; if (!isDragging) return;
_dragStarted = false; dragStarted = false;
EndDrag(eventData); EndDrag(eventData);
} }

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2ad8b8c5b4f24f52af870512f5d18592
timeCreated: 1764241594

View File

@@ -12,27 +12,27 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
public class PhotoEnlargeController public class PhotoEnlargeController
{ {
private readonly GameObject _backdrop; private readonly GameObject backdrop;
private readonly Transform _enlargedContainer; private readonly Transform enlargedContainer;
private readonly float _animationDuration; private readonly float animationDuration;
private GameObject _currentEnlargedPreview; private GameObject currentEnlargedPreview;
private PhotoGridItem _currentSourceItem; private PhotoGridItem currentSourceItem;
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public PhotoEnlargeController(GameObject backdrop, Transform enlargedContainer, float animationDuration = 0.3f) public PhotoEnlargeController(GameObject backdrop, Transform enlargedContainer, float animationDuration = 0.3f)
{ {
_backdrop = backdrop; this.backdrop = backdrop;
_enlargedContainer = enlargedContainer; this.enlargedContainer = enlargedContainer;
_animationDuration = animationDuration; this.animationDuration = animationDuration;
} }
/// <summary> /// <summary>
/// Check if a photo is currently enlarged /// Check if a photo is currently enlarged
/// </summary> /// </summary>
public bool IsPhotoEnlarged => _currentEnlargedPreview != null; public bool IsPhotoEnlarged => currentEnlargedPreview != null;
/// <summary> /// <summary>
/// Enlarge a photo from a grid item /// Enlarge a photo from a grid item
@@ -46,30 +46,30 @@ namespace Minigames.StatueDressup.Controllers
} }
// Don't allow multiple enlargements // Don't allow multiple enlargements
if (_currentEnlargedPreview != null) if (currentEnlargedPreview != null)
{ {
Logging.Warning("[PhotoEnlargeController] Photo already enlarged"); Logging.Warning("[PhotoEnlargeController] Photo already enlarged");
return; return;
} }
_currentSourceItem = sourceItem; currentSourceItem = sourceItem;
// Show backdrop // Show backdrop
if (_backdrop != null) if (backdrop != null)
{ {
_backdrop.SetActive(true); backdrop.SetActive(true);
} }
// Spawn preview clone // Spawn preview clone
_currentEnlargedPreview = Object.Instantiate(previewPrefab, _enlargedContainer); currentEnlargedPreview = Object.Instantiate(previewPrefab, enlargedContainer);
_currentEnlargedPreview.transform.SetAsLastSibling(); currentEnlargedPreview.transform.SetAsLastSibling();
// Position at source item's world position // Position at source item's world position
_currentEnlargedPreview.transform.position = sourceItem.transform.position; currentEnlargedPreview.transform.position = sourceItem.transform.position;
_currentEnlargedPreview.transform.localScale = sourceItem.transform.localScale; currentEnlargedPreview.transform.localScale = sourceItem.transform.localScale;
// Set photo texture on preview // Set photo texture on preview
var previewImage = _currentEnlargedPreview.GetComponent<UnityEngine.UI.Image>(); var previewImage = currentEnlargedPreview.GetComponent<UnityEngine.UI.Image>();
if (previewImage != null) if (previewImage != null)
{ {
// Create sprite from texture // Create sprite from texture
@@ -82,10 +82,10 @@ namespace Minigames.StatueDressup.Controllers
} }
// Add click handler to preview // Add click handler to preview
var clickHandler = _currentEnlargedPreview.GetComponent<EventTrigger>(); var clickHandler = currentEnlargedPreview.GetComponent<EventTrigger>();
if (clickHandler == null) if (clickHandler == null)
{ {
clickHandler = _currentEnlargedPreview.AddComponent<EventTrigger>(); clickHandler = currentEnlargedPreview.AddComponent<EventTrigger>();
} }
var pointerClickEntry = new EventTrigger.Entry { eventID = EventTriggerType.PointerClick }; var pointerClickEntry = new EventTrigger.Entry { eventID = EventTriggerType.PointerClick };
@@ -93,8 +93,8 @@ namespace Minigames.StatueDressup.Controllers
clickHandler.triggers.Add(pointerClickEntry); clickHandler.triggers.Add(pointerClickEntry);
// Animate to center and scale up // Animate to center and scale up
TweenAnimationUtility.AnimateLocalPosition(_currentEnlargedPreview.transform, Vector3.zero, _animationDuration); TweenAnimationUtility.AnimateLocalPosition(currentEnlargedPreview.transform, Vector3.zero, animationDuration);
TweenAnimationUtility.AnimateScale(_currentEnlargedPreview.transform, Vector3.one * enlargedScale, _animationDuration); TweenAnimationUtility.AnimateScale(currentEnlargedPreview.transform, Vector3.one * enlargedScale, animationDuration);
// Play audio feedback // Play audio feedback
AudioManager.Instance.LoadAndPlayUIAudio("card_albumdrop_deep", false); AudioManager.Instance.LoadAndPlayUIAudio("card_albumdrop_deep", false);
@@ -107,35 +107,35 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
public void ShrinkPhoto() public void ShrinkPhoto()
{ {
if (_currentEnlargedPreview == null || _currentSourceItem == null) if (currentEnlargedPreview == null || currentSourceItem == null)
{ {
Logging.Warning("[PhotoEnlargeController] No photo to shrink"); Logging.Warning("[PhotoEnlargeController] No photo to shrink");
return; return;
} }
// Hide backdrop // Hide backdrop
if (_backdrop != null) if (backdrop != null)
{ {
_backdrop.SetActive(false); backdrop.SetActive(false);
} }
// Get target position from source item // Get target position from source item
Vector3 targetWorldPos = _currentSourceItem.transform.position; Vector3 targetWorldPos = currentSourceItem.transform.position;
Vector3 targetScale = _currentSourceItem.transform.localScale; Vector3 targetScale = currentSourceItem.transform.localScale;
GameObject previewToDestroy = _currentEnlargedPreview; GameObject previewToDestroy = currentEnlargedPreview;
// Animate back to source position // Animate back to source position
Pixelplacement.Tween.Position(previewToDestroy.transform, targetWorldPos, _animationDuration, 0f, Pixelplacement.Tween.EaseInOut); Pixelplacement.Tween.Position(previewToDestroy.transform, targetWorldPos, animationDuration, 0f, Pixelplacement.Tween.EaseInOut);
TweenAnimationUtility.AnimateScale(previewToDestroy.transform, targetScale, _animationDuration, () => TweenAnimationUtility.AnimateScale(previewToDestroy.transform, targetScale, animationDuration, () =>
{ {
// Destroy preview after animation // Destroy preview after animation
Object.Destroy(previewToDestroy); Object.Destroy(previewToDestroy);
}); });
// Clear references // Clear references
_currentEnlargedPreview = null; currentEnlargedPreview = null;
_currentSourceItem = null; currentSourceItem = null;
Logging.Debug("[PhotoEnlargeController] Photo shrunk"); Logging.Debug("[PhotoEnlargeController] Photo shrunk");
} }
@@ -145,18 +145,18 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
public void Cleanup() public void Cleanup()
{ {
if (_currentEnlargedPreview != null) if (currentEnlargedPreview != null)
{ {
Object.Destroy(_currentEnlargedPreview); Object.Destroy(currentEnlargedPreview);
_currentEnlargedPreview = null; currentEnlargedPreview = null;
} }
if (_backdrop != null) if (backdrop != null)
{ {
_backdrop.SetActive(false); backdrop.SetActive(false);
} }
_currentSourceItem = null; currentSourceItem = null;
} }
} }
} }

View File

@@ -15,16 +15,16 @@ namespace Minigames.StatueDressup.Controllers
[SerializeField] private Image thumbnailImage; [SerializeField] private Image thumbnailImage;
[SerializeField] private GameObject loadingIndicator; [SerializeField] private GameObject loadingIndicator;
private string _photoId; private string photoId;
private StatuePhotoGalleryController _galleryController; private StatuePhotoGalleryController galleryController;
/// <summary> /// <summary>
/// Initialize grid item with photo ID /// Initialize grid item with photo ID
/// </summary> /// </summary>
public void Initialize(string photoId, StatuePhotoGalleryController controller) public void Initialize(string newPhotoId, StatuePhotoGalleryController controller)
{ {
_photoId = photoId; this.photoId = newPhotoId;
_galleryController = controller; galleryController = controller;
// Show loading state // Show loading state
if (loadingIndicator != null) if (loadingIndicator != null)
@@ -41,7 +41,7 @@ namespace Minigames.StatueDressup.Controllers
{ {
if (thumbnail == null) if (thumbnail == null)
{ {
Logging.Warning($"[PhotoGridItem] Null thumbnail for photo: {_photoId}"); Logging.Warning($"[PhotoGridItem] Null thumbnail for photo: {photoId}");
return; return;
} }
@@ -68,10 +68,10 @@ namespace Minigames.StatueDressup.Controllers
/// </summary> /// </summary>
public void OnPointerClick(PointerEventData eventData) public void OnPointerClick(PointerEventData eventData)
{ {
if (_galleryController != null && !string.IsNullOrEmpty(_photoId)) if (galleryController != null && !string.IsNullOrEmpty(photoId))
{ {
Logging.Debug($"[PhotoGridItem] Clicked: {_photoId}"); Logging.Debug($"[PhotoGridItem] Clicked: {photoId}");
_galleryController.OnGridItemClicked(this, _photoId); galleryController.OnGridItemClicked(this, photoId);
} }
} }
} }

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dc39e89d2088421187d48d89e0eed813
timeCreated: 1764241512

View File

@@ -2,7 +2,7 @@
using UnityEngine.UI; using UnityEngine.UI;
using Utils; using Utils;
namespace Minigames.StatueDressup.Controllers namespace Minigames.StatueDressup.Test
{ {
/// <summary> /// <summary>
/// Minimal test for photo capture - just capture and save to disk /// Minimal test for photo capture - just capture and save to disk