From ac49d77573ccb7488abc969562db6d3119d36d5a Mon Sep 17 00:00:00 2001 From: NTG Date: Thu, 21 Aug 2025 16:25:27 +0900 Subject: [PATCH] =?UTF-8?q?ui=20=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Prefabs/Uis/GameUi/Common/FadeUi.prefab | 1 + .../Uis/GameUi/Common/GlobalMessageUi.prefab | 1 + .../GameUi/Common/InteractionMessageUi.prefab | 1 + .../Huds/{Hud.prefab => RestaurantHud.prefab} | 26 +- ....prefab.meta => RestaurantHud.prefab.meta} | 0 .../Uis/GameUi/PopupUis/ConfirmUi.prefab | 2 + .../PopupUis/RestaurantManagementUi.prefab | 2 + .../_Addressables/So/GameData/GameData.asset | 4 +- .../_Addressables/So/GameData/UiData.asset | 3 + .../UiData.asset.meta} | 2 +- .../_DDD/_Addressables/So/PopupUiState.asset | 3 - .../_ScriptAssets/Prefabs/UiManager.prefab | 161 +++- .../So/ManagerDefinitionSo.asset | 2 +- Assets/_DDD/_Scripts/GameData/GameData.cs | 8 + Assets/_DDD/_Scripts/GameData/PopupUiData.cs | 12 + .../_Scripts/GameData/PopupUiData.cs.meta | 3 + .../_DDD/_Scripts/GameFlow/GameFlowManager.cs | 2 +- Assets/_DDD/_Scripts/GameState/GameState.cs | 7 +- Assets/_DDD/_Scripts/GameUi/BaseUi.cs | 123 +-- Assets/_DDD/_Scripts/GameUi/FadeUi.cs | 3 +- .../_DDD/_Scripts/GameUi/GlobalMessageUi.cs | 2 +- .../_Scripts/GameUi/InteractionMessageUi.cs | 2 +- .../GameUi/New/Converters/CommonConverters.cs | 2 +- .../GameUi/New/Converters/IValueConverter.cs | 2 +- .../New/RestaurantManagementViewModel.cs | 72 +- .../_Scripts/GameUi/New/Services/IService.cs | 2 +- .../GameUi/New/Services/InventoryService.cs | 2 +- .../GameUi/New/Utils/BindToAttribute.cs | 114 --- .../GameUi/New/Utils/BindToAttribute.cs.meta | 2 - .../GameUi/New/Utils/BindingContext.cs | 105 +-- .../GameUi/New/Utils/BindingHelper.cs | 39 + .../GameUi/New/Utils/BindingHelper.cs.meta | 3 + .../GameUi/New/Utils/IBindingTarget.cs | 118 +++ .../GameUi/New/Utils/IBindingTarget.cs.meta | 3 + .../_Scripts/GameUi/New/Utils/InputPhase.cs | 24 - .../GameUi/New/Utils/InputPhase.cs.meta | 2 - .../New/ViewModels/Base/SimpleViewModel.cs | 21 +- .../New/ViewModels/InventoryViewModel.cs | 23 +- Assets/_DDD/_Scripts/GameUi/New/Views.meta | 8 - .../_DDD/_Scripts/GameUi/New/Views/Base.meta | 8 - .../GameUi/New/Views/Base/AutoBindView.cs | 210 ----- .../New/Views/Base/AutoBindView.cs.meta | 2 - .../_Scripts/GameUi/New/Views/Examples.meta | 8 - .../_Scripts/GameUi/PopupUi/BasePopupUi.cs | 10 +- .../_Scripts/GameUi/PopupUi/PopupUiState.cs | 93 +- .../RestaurantManagementUi.cs | 31 +- Assets/_DDD/_Scripts/GameUi/RestaurantHud.cs | 7 + .../_Scripts/GameUi/RestaurantHud.cs.meta | 2 + Assets/_DDD/_Scripts/GameUi/UiButton.cs | 792 +++++++++--------- Assets/_DDD/_Scripts/GameUi/UiButtonTest.cs | 133 --- .../_DDD/_Scripts/GameUi/UiButtonTest.cs.meta | 3 - Assets/_DDD/_Scripts/GameUi/UiManager.cs | 89 +- 52 files changed, 967 insertions(+), 1333 deletions(-) rename Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Huds/{Hud.prefab => RestaurantHud.prefab} (95%) rename Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Huds/{Hud.prefab.meta => RestaurantHud.prefab.meta} (100%) create mode 100644 Assets/_DDD/_Addressables/So/GameData/UiData.asset rename Assets/_DDD/_Addressables/So/{PopupUiState.asset.meta => GameData/UiData.asset.meta} (79%) delete mode 100644 Assets/_DDD/_Addressables/So/PopupUiState.asset create mode 100644 Assets/_DDD/_Scripts/GameData/PopupUiData.cs create mode 100644 Assets/_DDD/_Scripts/GameData/PopupUiData.cs.meta delete mode 100644 Assets/_DDD/_Scripts/GameUi/New/Utils/BindToAttribute.cs delete mode 100644 Assets/_DDD/_Scripts/GameUi/New/Utils/BindToAttribute.cs.meta create mode 100644 Assets/_DDD/_Scripts/GameUi/New/Utils/BindingHelper.cs create mode 100644 Assets/_DDD/_Scripts/GameUi/New/Utils/BindingHelper.cs.meta create mode 100644 Assets/_DDD/_Scripts/GameUi/New/Utils/IBindingTarget.cs create mode 100644 Assets/_DDD/_Scripts/GameUi/New/Utils/IBindingTarget.cs.meta delete mode 100644 Assets/_DDD/_Scripts/GameUi/New/Utils/InputPhase.cs delete mode 100644 Assets/_DDD/_Scripts/GameUi/New/Utils/InputPhase.cs.meta delete mode 100644 Assets/_DDD/_Scripts/GameUi/New/Views.meta delete mode 100644 Assets/_DDD/_Scripts/GameUi/New/Views/Base.meta delete mode 100644 Assets/_DDD/_Scripts/GameUi/New/Views/Base/AutoBindView.cs delete mode 100644 Assets/_DDD/_Scripts/GameUi/New/Views/Base/AutoBindView.cs.meta delete mode 100644 Assets/_DDD/_Scripts/GameUi/New/Views/Examples.meta create mode 100644 Assets/_DDD/_Scripts/GameUi/RestaurantHud.cs create mode 100644 Assets/_DDD/_Scripts/GameUi/RestaurantHud.cs.meta delete mode 100644 Assets/_DDD/_Scripts/GameUi/UiButtonTest.cs delete mode 100644 Assets/_DDD/_Scripts/GameUi/UiButtonTest.cs.meta diff --git a/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Common/FadeUi.prefab b/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Common/FadeUi.prefab index 1ecc13c85..b859d4fe1 100644 --- a/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Common/FadeUi.prefab +++ b/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Common/FadeUi.prefab @@ -134,4 +134,5 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 41f0ee0aabb2f954d918caa8d484f646, type: 3} m_Name: m_EditorClassIdentifier: + k__BackingField: 4 _enableBlockImage: 1 diff --git a/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Common/GlobalMessageUi.prefab b/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Common/GlobalMessageUi.prefab index cdd0e1f3c..a1c0b705b 100644 --- a/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Common/GlobalMessageUi.prefab +++ b/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Common/GlobalMessageUi.prefab @@ -319,5 +319,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 828648aab79941544bf8ceb7b25b586c, type: 3} m_Name: m_EditorClassIdentifier: + k__BackingField: 4 _enableBlockImage: 0 _messageText: {fileID: 1263817835881307751} diff --git a/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Common/InteractionMessageUi.prefab b/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Common/InteractionMessageUi.prefab index a505b8a0b..0563c79b6 100644 --- a/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Common/InteractionMessageUi.prefab +++ b/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Common/InteractionMessageUi.prefab @@ -422,6 +422,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: eccb2d58803b65f4e82f22153315d3c6, type: 3} m_Name: m_EditorClassIdentifier: + k__BackingField: 2 _enableBlockImage: 0 _filledImage: {fileID: 1182510989530764005} _textLabel: {fileID: 5874059589008679693} diff --git a/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Huds/Hud.prefab b/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Huds/RestaurantHud.prefab similarity index 95% rename from Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Huds/Hud.prefab rename to Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Huds/RestaurantHud.prefab index 134e265d0..db2495a0a 100644 --- a/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Huds/Hud.prefab +++ b/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Huds/RestaurantHud.prefab @@ -651,7 +651,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 6952779389930089995, guid: 4f2bf029cb06b084ba41defc8fc76731, type: 3} propertyPath: m_Name - value: Hud + value: RestaurantHud objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: @@ -663,8 +663,30 @@ PrefabInstance: - targetCorrespondingSourceObject: {fileID: 8967231042952671610, guid: 4f2bf029cb06b084ba41defc8fc76731, type: 3} insertIndex: -1 addedObject: {fileID: 8229589654595845064} - m_AddedComponents: [] + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 6952779389930089995, guid: 4f2bf029cb06b084ba41defc8fc76731, type: 3} + insertIndex: -1 + addedObject: {fileID: 3263769952751147662} m_SourcePrefab: {fileID: 100100000, guid: 4f2bf029cb06b084ba41defc8fc76731, type: 3} +--- !u!1 &3080325846008693413 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 6952779389930089995, guid: 4f2bf029cb06b084ba41defc8fc76731, type: 3} + m_PrefabInstance: {fileID: 5387070474184109230} + m_PrefabAsset: {fileID: 0} +--- !u!114 &3263769952751147662 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3080325846008693413} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7521841876f5b054aa4a0b0081ff8425, type: 3} + m_Name: + m_EditorClassIdentifier: + k__BackingField: 1 + _enableBlockImage: 0 --- !u!224 &3940853162783645140 stripped RectTransform: m_CorrespondingSourceObject: {fileID: 8967231042952671610, guid: 4f2bf029cb06b084ba41defc8fc76731, type: 3} diff --git a/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Huds/Hud.prefab.meta b/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Huds/RestaurantHud.prefab.meta similarity index 100% rename from Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Huds/Hud.prefab.meta rename to Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/Huds/RestaurantHud.prefab.meta diff --git a/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/PopupUis/ConfirmUi.prefab b/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/PopupUis/ConfirmUi.prefab index 2343b3045..f2eb270bb 100644 --- a/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/PopupUis/ConfirmUi.prefab +++ b/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/PopupUis/ConfirmUi.prefab @@ -811,7 +811,9 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 7b3eb65dc42aeb84eba2397a9603e94d, type: 3} m_Name: m_EditorClassIdentifier: + k__BackingField: 3 _enableBlockImage: 1 + InputActionMaps: 3 _uiActionsInputBinding: {fileID: 11400000, guid: 99d3d87bd43df65488e757c43a308f36, type: 2} _messageLabel: {fileID: 3495127426411772216} _messageLabelLocalizeStringEvent: {fileID: 7334955628972040157} diff --git a/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/PopupUis/RestaurantManagementUi.prefab b/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/PopupUis/RestaurantManagementUi.prefab index f33167b14..5015c637f 100644 --- a/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/PopupUis/RestaurantManagementUi.prefab +++ b/Assets/_DDD/_Addressables/Prefabs/Uis/GameUi/PopupUis/RestaurantManagementUi.prefab @@ -6338,6 +6338,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 46c8396c996c804449b383960b44e812, type: 3} m_Name: m_EditorClassIdentifier: + k__BackingField: 3 _enableBlockImage: 0 InputActionMaps: 3 _uiActionsInputBinding: {fileID: 11400000, guid: 8073fcaf56fc7c34e996d0d47044f146, type: 2} @@ -6362,6 +6363,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 80dee5e1862248aab26236036049e5fc, type: 3} m_Name: m_EditorClassIdentifier: + _holdCompleteTime: 0 --- !u!1001 &4530765275021007961 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/_DDD/_Addressables/So/GameData/GameData.asset b/Assets/_DDD/_Addressables/So/GameData/GameData.asset index 07df3339f..c96e2c625 100644 --- a/Assets/_DDD/_Addressables/So/GameData/GameData.asset +++ b/Assets/_DDD/_Addressables/So/GameData/GameData.asset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ee22eb98f65214d577983951e58f21cdcffed74244711225db4f48309efdd2e -size 566 +oid sha256:ca4aaf7a1ff591322a217b21910976f88c06ed85c70465f142bf7fa9776ba655 +size 722 diff --git a/Assets/_DDD/_Addressables/So/GameData/UiData.asset b/Assets/_DDD/_Addressables/So/GameData/UiData.asset new file mode 100644 index 000000000..199fd4de1 --- /dev/null +++ b/Assets/_DDD/_Addressables/So/GameData/UiData.asset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:88c00489fd80d6412f0919a9b13efd587f19d8a6cf04aa3ed641c315e1f6e0e4 +size 2801 diff --git a/Assets/_DDD/_Addressables/So/PopupUiState.asset.meta b/Assets/_DDD/_Addressables/So/GameData/UiData.asset.meta similarity index 79% rename from Assets/_DDD/_Addressables/So/PopupUiState.asset.meta rename to Assets/_DDD/_Addressables/So/GameData/UiData.asset.meta index e332490c3..85a3ca051 100644 --- a/Assets/_DDD/_Addressables/So/PopupUiState.asset.meta +++ b/Assets/_DDD/_Addressables/So/GameData/UiData.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: dd182535820ec034b9d5a0315f93fa26 +guid: d6d7638e05d740944a77a01f60b331c4 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/Assets/_DDD/_Addressables/So/PopupUiState.asset b/Assets/_DDD/_Addressables/So/PopupUiState.asset deleted file mode 100644 index f792667ef..000000000 --- a/Assets/_DDD/_Addressables/So/PopupUiState.asset +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a2ffcd5421ab4902f8d7df18de785daba51fd284682cec5bc8b83e3f87a1debb -size 1962 diff --git a/Assets/_DDD/_ScriptAssets/Prefabs/UiManager.prefab b/Assets/_DDD/_ScriptAssets/Prefabs/UiManager.prefab index 7d11c81e7..0eae5cdb7 100644 --- a/Assets/_DDD/_ScriptAssets/Prefabs/UiManager.prefab +++ b/Assets/_DDD/_ScriptAssets/Prefabs/UiManager.prefab @@ -10,7 +10,7 @@ GameObject: m_Component: - component: {fileID: 4347279445921954555} m_Layer: 5 - m_Name: PopupUis + m_Name: PopupUiRoot m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -38,6 +38,115 @@ RectTransform: m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1111901944139047714 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6076800063500988294} + m_Layer: 5 + m_Name: HudRoot + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6076800063500988294 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1111901944139047714} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 7916164406893547064} + m_Father: {fileID: 5760169274063006291} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &4130064528218324885 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6174235207617529232} + m_Layer: 5 + m_Name: CommonUiRoot + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6174235207617529232 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4130064528218324885} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 4191602006120035298} + - {fileID: 4862733150375458244} + m_Father: {fileID: 5760169274063006291} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &4851448928365776117 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3090446084811068791} + m_Layer: 5 + m_Name: InteractionUiRoot + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3090446084811068791 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4851448928365776117} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 496411955364970508} + m_Father: {fileID: 5760169274063006291} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} --- !u!1 &6838253471355869082 GameObject: m_ObjectHideFlags: 0 @@ -73,11 +182,10 @@ RectTransform: m_LocalScale: {x: 0, y: 0, z: 0} m_ConstrainProportionsScale: 1 m_Children: - - {fileID: 7916164406893547064} - - {fileID: 496411955364970508} + - {fileID: 6076800063500988294} + - {fileID: 3090446084811068791} - {fileID: 4347279445921954555} - - {fileID: 4191602006120035298} - - {fileID: 4862733150375458244} + - {fileID: 6174235207617529232} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -219,13 +327,10 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _persistent: 1 - _popupUiState: - m_AssetGUID: dd182535820ec034b9d5a0315f93fa26 - m_SubObjectName: - m_SubObjectType: - m_SubObjectGUID: - m_EditorAssetChanged: 1 + _hudRoot: {fileID: 6076800063500988294} + _interactionUiRoot: {fileID: 3090446084811068791} _popupUiRoot: {fileID: 4347279445921954555} + _commonUiRoot: {fileID: 6174235207617529232} --- !u!1001 &291049386471777514 PrefabInstance: m_ObjectHideFlags: 0 @@ -274,7 +379,7 @@ PrefabInstance: serializedVersion: 2 m_Modification: serializedVersion: 3 - m_TransformParent: {fileID: 5760169274063006291} + m_TransformParent: {fileID: 6076800063500988294} m_Modifications: - target: {fileID: 1353387648420519096, guid: 86a58b93c36851e4787861c23023b094, type: 3} propertyPath: m_AnchorMax.y @@ -302,7 +407,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 3080325846008693413, guid: 86a58b93c36851e4787861c23023b094, type: 3} propertyPath: m_Name - value: Hud + value: RestaurantHud objectReference: {fileID: 0} - target: {fileID: 4664972416674662382, guid: 86a58b93c36851e4787861c23023b094, type: 3} propertyPath: m_Pivot.x @@ -354,15 +459,15 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 4664972416674662382, guid: 86a58b93c36851e4787861c23023b094, type: 3} propertyPath: m_LocalRotation.x - value: 0 + value: -0 objectReference: {fileID: 0} - target: {fileID: 4664972416674662382, guid: 86a58b93c36851e4787861c23023b094, type: 3} propertyPath: m_LocalRotation.y - value: 0 + value: -0 objectReference: {fileID: 0} - target: {fileID: 4664972416674662382, guid: 86a58b93c36851e4787861c23023b094, type: 3} propertyPath: m_LocalRotation.z - value: 0 + value: -0 objectReference: {fileID: 0} - target: {fileID: 4664972416674662382, guid: 86a58b93c36851e4787861c23023b094, type: 3} propertyPath: m_AnchoredPosition.x @@ -1811,7 +1916,7 @@ PrefabInstance: serializedVersion: 2 m_Modification: serializedVersion: 3 - m_TransformParent: {fileID: 5760169274063006291} + m_TransformParent: {fileID: 6174235207617529232} m_Modifications: - target: {fileID: 1926278333613504521, guid: f84d9014b084dbf46b1c4d44fe5b63c3, type: 3} propertyPath: m_Name @@ -1867,15 +1972,15 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8122602890985372994, guid: f84d9014b084dbf46b1c4d44fe5b63c3, type: 3} propertyPath: m_LocalRotation.x - value: 0 + value: -0 objectReference: {fileID: 0} - target: {fileID: 8122602890985372994, guid: f84d9014b084dbf46b1c4d44fe5b63c3, type: 3} propertyPath: m_LocalRotation.y - value: 0 + value: -0 objectReference: {fileID: 0} - target: {fileID: 8122602890985372994, guid: f84d9014b084dbf46b1c4d44fe5b63c3, type: 3} propertyPath: m_LocalRotation.z - value: 0 + value: -0 objectReference: {fileID: 0} - target: {fileID: 8122602890985372994, guid: f84d9014b084dbf46b1c4d44fe5b63c3, type: 3} propertyPath: m_AnchoredPosition.x @@ -2079,7 +2184,7 @@ PrefabInstance: serializedVersion: 2 m_Modification: serializedVersion: 3 - m_TransformParent: {fileID: 5760169274063006291} + m_TransformParent: {fileID: 6174235207617529232} m_Modifications: - target: {fileID: 2726783183655360567, guid: 085fe4e2983c9ed4780abfb56bf5c322, type: 3} propertyPath: m_Pivot.x @@ -2131,15 +2236,15 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 2726783183655360567, guid: 085fe4e2983c9ed4780abfb56bf5c322, type: 3} propertyPath: m_LocalRotation.x - value: 0 + value: -0 objectReference: {fileID: 0} - target: {fileID: 2726783183655360567, guid: 085fe4e2983c9ed4780abfb56bf5c322, type: 3} propertyPath: m_LocalRotation.y - value: 0 + value: -0 objectReference: {fileID: 0} - target: {fileID: 2726783183655360567, guid: 085fe4e2983c9ed4780abfb56bf5c322, type: 3} propertyPath: m_LocalRotation.z - value: 0 + value: -0 objectReference: {fileID: 0} - target: {fileID: 2726783183655360567, guid: 085fe4e2983c9ed4780abfb56bf5c322, type: 3} propertyPath: m_AnchoredPosition.x @@ -2181,7 +2286,7 @@ PrefabInstance: serializedVersion: 2 m_Modification: serializedVersion: 3 - m_TransformParent: {fileID: 5760169274063006291} + m_TransformParent: {fileID: 3090446084811068791} m_Modifications: - target: {fileID: 507999590019405259, guid: 67b28d928cd16794eba49dade35d395d, type: 3} propertyPath: m_Name @@ -2313,15 +2418,15 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 7858233056384553088, guid: 67b28d928cd16794eba49dade35d395d, type: 3} propertyPath: m_LocalRotation.x - value: 0 + value: -0 objectReference: {fileID: 0} - target: {fileID: 7858233056384553088, guid: 67b28d928cd16794eba49dade35d395d, type: 3} propertyPath: m_LocalRotation.y - value: 0 + value: -0 objectReference: {fileID: 0} - target: {fileID: 7858233056384553088, guid: 67b28d928cd16794eba49dade35d395d, type: 3} propertyPath: m_LocalRotation.z - value: 0 + value: -0 objectReference: {fileID: 0} - target: {fileID: 7858233056384553088, guid: 67b28d928cd16794eba49dade35d395d, type: 3} propertyPath: m_AnchoredPosition.x diff --git a/Assets/_DDD/_ScriptAssets/So/ManagerDefinitionSo.asset b/Assets/_DDD/_ScriptAssets/So/ManagerDefinitionSo.asset index cfa713405..a76bc5919 100644 --- a/Assets/_DDD/_ScriptAssets/So/ManagerDefinitionSo.asset +++ b/Assets/_DDD/_ScriptAssets/So/ManagerDefinitionSo.asset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2cc6e792afdc31275ecdb437ed91664bf5775f4941fd12acec40b2e92647c871 +oid sha256:e22d6af69a361da6b510144cfed3df81e14ae58cc18093c2fed9f06553f42259 size 1504 diff --git a/Assets/_DDD/_Scripts/GameData/GameData.cs b/Assets/_DDD/_Scripts/GameData/GameData.cs index e25d84940..9ffe8df5b 100644 --- a/Assets/_DDD/_Scripts/GameData/GameData.cs +++ b/Assets/_DDD/_Scripts/GameData/GameData.cs @@ -8,8 +8,10 @@ namespace DDD public class GameData : ScriptSingleton { [SerializeField] private AssetReference _gameLocalizationData; + [SerializeField] private AssetReference _uiData; public GameLocalizationData LocalizationData { get; private set; } + public UiData UiData { get; private set; } private bool _isLoaded; @@ -21,10 +23,16 @@ public async Task LoadData() } var gameLocalizationDataHandle = _gameLocalizationData.LoadAssetAsync(); + var popupUiDataHandle = _uiData.LoadAssetAsync(); + await gameLocalizationDataHandle.Task; + await popupUiDataHandle.Task; LocalizationData = gameLocalizationDataHandle.Result; + UiData = popupUiDataHandle.Result; + Debug.Assert(LocalizationData != null, "GameLocalizationData is null"); + Debug.Assert(UiData != null, "UiData is null"); _isLoaded = true; } diff --git a/Assets/_DDD/_Scripts/GameData/PopupUiData.cs b/Assets/_DDD/_Scripts/GameData/PopupUiData.cs new file mode 100644 index 000000000..b8a81dc36 --- /dev/null +++ b/Assets/_DDD/_Scripts/GameData/PopupUiData.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using Sirenix.OdinInspector; +using UnityEngine; + +namespace DDD +{ + [CreateAssetMenu(fileName = "UiData", menuName = "GameData/UiData")] + public class UiData : SerializedScriptableObject + { + public Dictionary> FlowToUiMapping = new(); + } +} \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameData/PopupUiData.cs.meta b/Assets/_DDD/_Scripts/GameData/PopupUiData.cs.meta new file mode 100644 index 000000000..a52e29f3c --- /dev/null +++ b/Assets/_DDD/_Scripts/GameData/PopupUiData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a0663996283946b0a51684c1047c24a1 +timeCreated: 1755751458 \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameFlow/GameFlowManager.cs b/Assets/_DDD/_Scripts/GameFlow/GameFlowManager.cs index e3f3887dd..3184814d7 100644 --- a/Assets/_DDD/_Scripts/GameFlow/GameFlowManager.cs +++ b/Assets/_DDD/_Scripts/GameFlow/GameFlowManager.cs @@ -28,7 +28,7 @@ public void PreInit() public Task Init() { - return Task.CompletedTask; ; + return Task.CompletedTask; } public async void PostInit() diff --git a/Assets/_DDD/_Scripts/GameState/GameState.cs b/Assets/_DDD/_Scripts/GameState/GameState.cs index 70dfbc792..69e1ad901 100644 --- a/Assets/_DDD/_Scripts/GameState/GameState.cs +++ b/Assets/_DDD/_Scripts/GameState/GameState.cs @@ -1,17 +1,14 @@ -using UnityEngine; -using UnityEngine.AddressableAssets; - namespace DDD { public class GameState : ScriptSingleton { - [SerializeField] private AssetReference _gameLevelState; - public GameLevelState LevelState { get; private set; } + public UiState UiState { get; private set; } private void OnEnable() { LevelState = CreateInstance(); + UiState = CreateInstance(); } } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/BaseUi.cs b/Assets/_DDD/_Scripts/GameUi/BaseUi.cs index 05871ee2a..c3586c48a 100644 --- a/Assets/_DDD/_Scripts/GameUi/BaseUi.cs +++ b/Assets/_DDD/_Scripts/GameUi/BaseUi.cs @@ -2,14 +2,24 @@ using System.ComponentModel; using System.Linq; using System.Reflection; +using TMPro; using UnityEngine; using UnityEngine.UI; -using DDD.MVVM; namespace DDD { + public enum UiType + { + None = 0, + Hud, + Interaction, + Popup, + Common + } + public abstract class BaseUi : MonoBehaviour { + [field: SerializeField] public UiType UiType { get; set; } [SerializeField] protected bool _enableBlockImage; protected CanvasGroup _canvasGroup; @@ -27,7 +37,6 @@ protected virtual void Awake() _blockImage = transform.Find(CommonConstants.BlockImage)?.gameObject; _bindingContext = new BindingContext(); - SetupAutoBindings(); SetupBindings(); } @@ -38,7 +47,6 @@ protected virtual void OnEnable() protected virtual void Start() { - TryRegister(); ClosePanel(); } @@ -58,8 +66,20 @@ protected virtual void OnDestroy() _bindingContext?.Dispose(); } - protected virtual void TryRegister() { } - protected virtual void TryUnregister() { } + public virtual void CreateInitialize() + { + TryRegister(); + } + + protected virtual void TryRegister() + { + UiManager.Instance.UiState.RegisterUI(this); + } + + protected virtual void TryUnregister() + { + UiManager.Instance.UiState.UnregisterUI(this); + } // BaseUi 메서드들을 직접 구현 public virtual void OpenPanel() @@ -93,74 +113,6 @@ public virtual void SetUiInteractable(bool active) public bool IsOpenPanel() => _panel && _panel.activeInHierarchy; - /// - /// Attribute 기반 자동 바인딩 설정 - /// - private void SetupAutoBindings() - { - var fields = GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public) - .Where(f => f.GetCustomAttribute() != null); - - foreach (var field in fields) - { - var bindAttribute = field.GetCustomAttribute(); - SetupBinding(field, bindAttribute); - } - - // 컬렉션 바인딩 설정 - var collectionFields = GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public) - .Where(f => f.GetCustomAttribute() != null); - - foreach (var field in collectionFields) - { - var bindAttribute = field.GetCustomAttribute(); - SetupCollectionBinding(field, bindAttribute); - } - } - - /// - /// 개별 필드의 바인딩 설정 - /// - private void SetupBinding(FieldInfo field, BindToAttribute bindAttribute) - { - var target = field.GetValue(this); - - IValueConverter converter = null; - if (bindAttribute.ConverterType != null) - { - converter = Activator.CreateInstance(bindAttribute.ConverterType) as IValueConverter; - } - - // UI 컴포넌트 타입별 바인딩 타겟 생성 - IBindingTarget bindingTarget = target switch - { - Text text => new TextBindingTarget(text, bindAttribute.PropertyPath), - Image image => new ImageBindingTarget(image, bindAttribute.PropertyPath), - GameObject go => new ActiveBindingTarget(go, bindAttribute.PropertyPath), - Slider slider => new SliderBindingTarget(slider, bindAttribute.PropertyPath), - _ => null - }; - - if (bindingTarget != null) - { - _bindingContext.Bind(bindAttribute.PropertyPath, bindingTarget, converter); - } - } - - /// - /// 컬렉션 바인딩 설정 - /// - private void SetupCollectionBinding(FieldInfo field, BindCollectionAttribute bindAttribute) - { - var target = field.GetValue(this); - - if (target is Transform parent) - { - // 컬렉션 바인딩 로직 (필요시 확장) - Debug.Log($"Collection binding for {bindAttribute.PropertyPath} is set up on {parent.name}"); - } - } - /// /// 추가 바인딩 설정 - 하위 클래스에서 구현 /// @@ -181,30 +133,5 @@ protected virtual void HandleCustomPropertyChanged(string propertyName) { // 하위 클래스에서 구현 } - - // 수동 바인딩 헬퍼 메서드들 - protected void BindText(Text text, string propertyPath, IValueConverter converter = null) - { - var target = new TextBindingTarget(text, propertyPath); - _bindingContext?.Bind(propertyPath, target, converter); - } - - protected void BindImage(Image image, string propertyPath, IValueConverter converter = null) - { - var target = new ImageBindingTarget(image, propertyPath); - _bindingContext?.Bind(propertyPath, target, converter); - } - - protected void BindActive(GameObject gameObject, string propertyPath, IValueConverter converter = null) - { - var target = new ActiveBindingTarget(gameObject, propertyPath); - _bindingContext?.Bind(propertyPath, target, converter); - } - - protected void BindSlider(Slider slider, string propertyPath, IValueConverter converter = null) - { - var target = new SliderBindingTarget(slider, propertyPath); - _bindingContext?.Bind(propertyPath, target, converter); - } } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/FadeUi.cs b/Assets/_DDD/_Scripts/GameUi/FadeUi.cs index 16bd91103..41c49a618 100644 --- a/Assets/_DDD/_Scripts/GameUi/FadeUi.cs +++ b/Assets/_DDD/_Scripts/GameUi/FadeUi.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using DG.Tweening; -using UnityEngine; namespace DDD { @@ -15,6 +14,8 @@ protected override void Awake() protected override void TryRegister() { + base.TryRegister(); + EventBus.Register(this); EventBus.Register(this); } diff --git a/Assets/_DDD/_Scripts/GameUi/GlobalMessageUi.cs b/Assets/_DDD/_Scripts/GameUi/GlobalMessageUi.cs index d1be8944f..099fc779d 100644 --- a/Assets/_DDD/_Scripts/GameUi/GlobalMessageUi.cs +++ b/Assets/_DDD/_Scripts/GameUi/GlobalMessageUi.cs @@ -20,7 +20,7 @@ protected override void Awake() _canvasGroup.alpha = 0; _messageText.text = null; } - + protected override void TryRegister() { base.TryRegister(); diff --git a/Assets/_DDD/_Scripts/GameUi/InteractionMessageUi.cs b/Assets/_DDD/_Scripts/GameUi/InteractionMessageUi.cs index 55f9fba11..0aff28d0f 100644 --- a/Assets/_DDD/_Scripts/GameUi/InteractionMessageUi.cs +++ b/Assets/_DDD/_Scripts/GameUi/InteractionMessageUi.cs @@ -24,7 +24,7 @@ protected override void Awake() _filledImage.fillAmount = 0f; } - + protected override void TryRegister() { base.TryRegister(); diff --git a/Assets/_DDD/_Scripts/GameUi/New/Converters/CommonConverters.cs b/Assets/_DDD/_Scripts/GameUi/New/Converters/CommonConverters.cs index d15ab1849..74befbeca 100644 --- a/Assets/_DDD/_Scripts/GameUi/New/Converters/CommonConverters.cs +++ b/Assets/_DDD/_Scripts/GameUi/New/Converters/CommonConverters.cs @@ -1,7 +1,7 @@ using System.Linq; using UnityEngine; -namespace DDD.MVVM +namespace DDD { /// /// 불린 값을 반전시키는 컨버터 diff --git a/Assets/_DDD/_Scripts/GameUi/New/Converters/IValueConverter.cs b/Assets/_DDD/_Scripts/GameUi/New/Converters/IValueConverter.cs index 16bb141ff..4f291400f 100644 --- a/Assets/_DDD/_Scripts/GameUi/New/Converters/IValueConverter.cs +++ b/Assets/_DDD/_Scripts/GameUi/New/Converters/IValueConverter.cs @@ -1,4 +1,4 @@ -namespace DDD.MVVM +namespace DDD { /// /// 값 변환기 인터페이스 diff --git a/Assets/_DDD/_Scripts/GameUi/New/RestaurantManagementViewModel.cs b/Assets/_DDD/_Scripts/GameUi/New/RestaurantManagementViewModel.cs index e88b79e83..fb8825c30 100644 --- a/Assets/_DDD/_Scripts/GameUi/New/RestaurantManagementViewModel.cs +++ b/Assets/_DDD/_Scripts/GameUi/New/RestaurantManagementViewModel.cs @@ -1,5 +1,4 @@ using System.Linq; -using DDD.MVVM; using UnityEngine; namespace DDD @@ -11,41 +10,31 @@ namespace DDD public class RestaurantManagementViewModel : SimpleViewModel, IEventHandler { // 홀드 진행 상태 관리 + [SerializeField] private float _holdCompleteTime = 1f; private bool _isHolding; - private float _elapsedTime; - private float _holdCompleteTime = 1f; + + private float _holdProgress; + public float HoldProgress + { + get => _holdProgress; + private set + { + if (SetField(ref _holdProgress, value)) + { + OnPropertyChanged(nameof(NormalizedHoldProgress)); + } + } + } + + /// + /// 홀드 진행률을 0~1 범위로 변환한 값 + /// + public float NormalizedHoldProgress => _holdCompleteTime <= 0f ? 0f : Mathf.Clamp01(_holdProgress / _holdCompleteTime); // 탭 상태 관리 private SectionButtonType _currentSection = SectionButtonType.Menu; private InventoryCategoryType _currentCategory = InventoryCategoryType.Food; - /// - /// 현재 홀드 상태 - /// - public bool IsHolding - { - get => _isHolding; - private set => SetField(ref _isHolding, value); - } - - /// - /// 홀드 진행 시간 (0.0 ~ 1.0) - /// - public float HoldProgress - { - get => _elapsedTime; - private set => SetField(ref _elapsedTime, value); - } - - /// - /// 홀드 완료에 필요한 시간 - /// - public float HoldCompleteTime - { - get => _holdCompleteTime; - set => SetField(ref _holdCompleteTime, value); - } - /// /// 현재 선택된 섹션 /// @@ -67,13 +56,7 @@ public InventoryCategoryType CurrentCategory /// /// 배치 완료 가능 여부 (체크리스트 완료 상태) /// - public bool CanCompleteBatch => - RestaurantState.Instance.ManagementState.GetChecklistStates().All(state => state); - - /// - /// 홀드 진행률을 0~1 범위로 변환한 값 - /// - public float NormalizedHoldProgress => HoldCompleteTime <= 0f ? 1f : Mathf.Clamp01(HoldProgress / HoldCompleteTime); + public bool CanCompleteBatch => RestaurantState.Instance.ManagementState.GetChecklistStates().All(state => state); public override void Initialize() { @@ -103,9 +86,9 @@ private void UnregisterEvents() /// public void UpdateHoldProgress() { - if (!IsHolding) return; + if (_isHolding == false) return; - if (HoldCompleteTime <= 0f) + if (_holdCompleteTime <= 0f) { ProcessCompleteBatch(); return; @@ -114,13 +97,10 @@ public void UpdateHoldProgress() var deltaTime = Time.deltaTime; HoldProgress += deltaTime; - if (HoldProgress >= HoldCompleteTime) + if (HoldProgress >= _holdCompleteTime) { ProcessCompleteBatch(); } - - // UI 업데이트를 위한 정규화된 진행률 알림 - OnPropertyChanged(nameof(NormalizedHoldProgress)); } /// @@ -128,9 +108,8 @@ public void UpdateHoldProgress() /// public void StartHold() { - IsHolding = true; + _isHolding = true; HoldProgress = 0f; - OnPropertyChanged(nameof(NormalizedHoldProgress)); } /// @@ -143,9 +122,8 @@ public void CancelHold() private void ResetHoldState() { - IsHolding = false; + _isHolding = false; HoldProgress = 0f; - OnPropertyChanged(nameof(NormalizedHoldProgress)); } /// diff --git a/Assets/_DDD/_Scripts/GameUi/New/Services/IService.cs b/Assets/_DDD/_Scripts/GameUi/New/Services/IService.cs index 4162b4604..569c7c22c 100644 --- a/Assets/_DDD/_Scripts/GameUi/New/Services/IService.cs +++ b/Assets/_DDD/_Scripts/GameUi/New/Services/IService.cs @@ -1,4 +1,4 @@ -namespace DDD.MVVM +namespace DDD { /// /// 서비스 계층의 기본 인터페이스 diff --git a/Assets/_DDD/_Scripts/GameUi/New/Services/InventoryService.cs b/Assets/_DDD/_Scripts/GameUi/New/Services/InventoryService.cs index ca8212a86..60d4d55c4 100644 --- a/Assets/_DDD/_Scripts/GameUi/New/Services/InventoryService.cs +++ b/Assets/_DDD/_Scripts/GameUi/New/Services/InventoryService.cs @@ -2,7 +2,7 @@ using System.Linq; using UnityEngine; -namespace DDD.MVVM +namespace DDD { /// /// 인벤토리 관련 비즈니스 로직을 담당하는 서비스 diff --git a/Assets/_DDD/_Scripts/GameUi/New/Utils/BindToAttribute.cs b/Assets/_DDD/_Scripts/GameUi/New/Utils/BindToAttribute.cs deleted file mode 100644 index cdf9580c2..000000000 --- a/Assets/_DDD/_Scripts/GameUi/New/Utils/BindToAttribute.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; - -namespace DDD.MVVM -{ - /// - /// UI 요소를 ViewModel 속성에 바인딩하기 위한 Attribute - /// Inspector에서 바인딩 정보를 시각적으로 확인할 수 있도록 지원 - /// - [System.AttributeUsage(System.AttributeTargets.Field)] - public class BindToAttribute : System.Attribute - { - /// - /// 바인딩할 ViewModel 속성의 경로 (nameof 사용 권장) - /// - public string PropertyPath { get; } - - /// - /// 값 변환기 타입 (선택사항) - /// - public System.Type ConverterType { get; } - - /// - /// 바인딩 Attribute 생성자 - /// - /// 바인딩할 속성 경로 (nameof 사용 권장) - /// 값 변환기 타입 (선택사항) - public BindToAttribute(string propertyPath, System.Type converterType = null) - { - PropertyPath = propertyPath; - ConverterType = converterType; - } - } - - // /// - // /// 타입 안전한 바인딩 Attribute (제네릭 버전) - // /// 특정 ViewModel 타입에 대한 바인딩을 명시적으로 지정 - // /// - // /// 바인딩할 ViewModel 타입 - // [System.AttributeUsage(System.AttributeTargets.Field)] - // public class BindToAttribute : System.Attribute where TViewModel : class - // { - // /// - // /// 바인딩할 ViewModel 속성의 경로 - // /// - // public string PropertyPath { get; } - // - // /// - // /// 값 변환기 타입 (선택사항) - // /// - // public System.Type ConverterType { get; } - // - // /// - // /// 타입 안전한 바인딩 Attribute 생성자 - // /// - // /// 바인딩할 속성 경로 - // /// 값 변환기 타입 (선택사항) - // public BindToAttribute(string propertyPath, System.Type converterType = null) - // { - // PropertyPath = propertyPath; - // ConverterType = converterType; - // } - // } - - /// - /// 컬렉션 바인딩을 위한 Attribute - /// 동적으로 생성되는 UI 요소들을 컬렉션에 바인딩 - /// - [System.AttributeUsage(System.AttributeTargets.Field)] - public class BindCollectionAttribute : System.Attribute - { - /// - /// 바인딩할 컬렉션 속성의 경로 - /// - public string PropertyPath { get; } - - /// - /// 아이템 프리팹의 필드명 또는 속성명 - /// - public string ItemPrefabReference { get; } - - /// - /// 컬렉션 바인딩 Attribute 생성자 - /// - /// 바인딩할 컬렉션 속성 경로 - /// 아이템 프리팹 참조 - public BindCollectionAttribute(string propertyPath, string itemPrefabReference = null) - { - PropertyPath = propertyPath; - ItemPrefabReference = itemPrefabReference; - } - } - - /// - /// 커맨드 바인딩을 위한 Attribute - /// 버튼 클릭 등의 이벤트를 ViewModel 메서드에 바인딩 - /// - [System.AttributeUsage(System.AttributeTargets.Field)] - public class BindCommandAttribute : System.Attribute - { - /// - /// 바인딩할 ViewModel 메서드 이름 - /// - public string MethodName { get; } - - /// - /// 커맨드 바인딩 Attribute 생성자 - /// - /// 바인딩할 메서드 이름 - public BindCommandAttribute(string methodName) - { - MethodName = methodName; - } - } -} \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/New/Utils/BindToAttribute.cs.meta b/Assets/_DDD/_Scripts/GameUi/New/Utils/BindToAttribute.cs.meta deleted file mode 100644 index a23282769..000000000 --- a/Assets/_DDD/_Scripts/GameUi/New/Utils/BindToAttribute.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 279b3238907a3564f842594af646eab7 \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/New/Utils/BindingContext.cs b/Assets/_DDD/_Scripts/GameUi/New/Utils/BindingContext.cs index 85904a96e..b9e5ea4dc 100644 --- a/Assets/_DDD/_Scripts/GameUi/New/Utils/BindingContext.cs +++ b/Assets/_DDD/_Scripts/GameUi/New/Utils/BindingContext.cs @@ -2,113 +2,12 @@ using System.Collections.Generic; using System.ComponentModel; using System.Reflection; +using TMPro; using UnityEngine; using UnityEngine.UI; -namespace DDD.MVVM +namespace DDD { - /// - /// 바인딩 타겟 인터페이스 - /// UI 요소와 ViewModel 속성을 연결하는 역할 - /// - public interface IBindingTarget - { - /// - /// 바인딩된 속성의 경로 - /// - string PropertyPath { get; } - - /// - /// UI 요소의 값을 업데이트 - /// - /// 새로운 값 - void UpdateValue(object value); - } - - /// - /// Text 컴포넌트에 대한 바인딩 타겟 - /// - public class TextBindingTarget : IBindingTarget - { - private readonly Text _text; - public string PropertyPath { get; } - - public TextBindingTarget(Text text, string propertyPath) - { - _text = text; - PropertyPath = propertyPath; - } - - public void UpdateValue(object value) - { - if (_text != null) - _text.text = value?.ToString() ?? string.Empty; - } - } - - /// - /// Image 컴포넌트에 대한 바인딩 타겟 - /// - public class ImageBindingTarget : IBindingTarget - { - private readonly Image _image; - public string PropertyPath { get; } - - public ImageBindingTarget(Image image, string propertyPath) - { - _image = image; - PropertyPath = propertyPath; - } - - public void UpdateValue(object value) - { - if (_image != null && value is Sprite sprite) - _image.sprite = sprite; - } - } - - /// - /// GameObject의 활성화 상태에 대한 바인딩 타겟 - /// - public class ActiveBindingTarget : IBindingTarget - { - private readonly GameObject _gameObject; - public string PropertyPath { get; } - - public ActiveBindingTarget(GameObject gameObject, string propertyPath) - { - _gameObject = gameObject; - PropertyPath = propertyPath; - } - - public void UpdateValue(object value) - { - if (_gameObject != null) - _gameObject.SetActive(value is bool active && active); - } - } - - /// - /// Slider 컴포넌트에 대한 바인딩 타겟 - /// - public class SliderBindingTarget : IBindingTarget - { - private readonly Slider _slider; - public string PropertyPath { get; } - - public SliderBindingTarget(Slider slider, string propertyPath) - { - _slider = slider; - PropertyPath = propertyPath; - } - - public void UpdateValue(object value) - { - if (_slider != null && value is float floatValue) - _slider.value = floatValue; - } - } - /// /// 바인딩 컨텍스트 - ViewModel과 View 간의 데이터 바인딩을 관리 /// diff --git a/Assets/_DDD/_Scripts/GameUi/New/Utils/BindingHelper.cs b/Assets/_DDD/_Scripts/GameUi/New/Utils/BindingHelper.cs new file mode 100644 index 000000000..1b55af711 --- /dev/null +++ b/Assets/_DDD/_Scripts/GameUi/New/Utils/BindingHelper.cs @@ -0,0 +1,39 @@ +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +namespace DDD +{ + public static class BindingHelper + { + public static void BindText(BindingContext context, TextMeshProUGUI text, string propertyPath, IValueConverter converter = null) + { + var target = new TextBindingTarget(text, propertyPath); + context?.Bind(propertyPath, target, converter); + } + + public static void BindImage(BindingContext context, Image image, string propertyPath, IValueConverter converter = null) + { + var target = new ImageBindingTarget(image, propertyPath); + context?.Bind(propertyPath, target, converter); + } + + public static void BindImageFilled(BindingContext context, Image image, string propertyPath, IValueConverter converter = null) + { + var target = new ImageFilledBindingTarget(image, propertyPath); + context?.Bind(propertyPath, target, converter); + } + + public static void BindActive(BindingContext context, GameObject gameObject, string propertyPath, IValueConverter converter = null) + { + var target = new ActiveBindingTarget(gameObject, propertyPath); + context?.Bind(propertyPath, target, converter); + } + + public static void BindSlider(BindingContext context, Slider slider, string propertyPath, IValueConverter converter = null) + { + var target = new SliderBindingTarget(slider, propertyPath); + context?.Bind(propertyPath, target, converter); + } + } +} \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/New/Utils/BindingHelper.cs.meta b/Assets/_DDD/_Scripts/GameUi/New/Utils/BindingHelper.cs.meta new file mode 100644 index 000000000..82ab2b2fa --- /dev/null +++ b/Assets/_DDD/_Scripts/GameUi/New/Utils/BindingHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a76b583779de40c0b4b3a922c4efb82d +timeCreated: 1755747839 \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/New/Utils/IBindingTarget.cs b/Assets/_DDD/_Scripts/GameUi/New/Utils/IBindingTarget.cs new file mode 100644 index 000000000..37702732e --- /dev/null +++ b/Assets/_DDD/_Scripts/GameUi/New/Utils/IBindingTarget.cs @@ -0,0 +1,118 @@ +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +namespace DDD +{ + public interface IBindingTarget + { + /// + /// 바인딩된 속성의 경로 + /// + string PropertyPath { get; } + + /// + /// UI 요소의 값을 업데이트 + /// + /// 새로운 값 + void UpdateValue(object value); + } + + public class TextBindingTarget : IBindingTarget + { + private readonly TextMeshProUGUI _text; + public string PropertyPath { get; } + + public TextBindingTarget(TextMeshProUGUI text, string propertyPath) + { + _text = text; + PropertyPath = propertyPath; + } + + public void UpdateValue(object value) + { + if (_text != null) + { + _text.text = value?.ToString() ?? string.Empty; + } + } + } + + public class ImageBindingTarget : IBindingTarget + { + private readonly Image _image; + public string PropertyPath { get; } + + public ImageBindingTarget(Image image, string propertyPath) + { + _image = image; + PropertyPath = propertyPath; + } + + public void UpdateValue(object value) + { + if (_image != null && value is Sprite sprite) + { + _image.sprite = sprite; + } + } + } + + public class ImageFilledBindingTarget : IBindingTarget + { + private readonly Image _image; + public string PropertyPath { get; } + + public ImageFilledBindingTarget(Image image, string propertyPath) + { + _image = image; + PropertyPath = propertyPath; + } + + public void UpdateValue(object value) + { + if (_image != null && value is float floatValue) + { + _image.fillAmount = Mathf.Clamp01(floatValue); // 0-1 범위로 제한 + } + } + } + + public class ActiveBindingTarget : IBindingTarget + { + private readonly GameObject _gameObject; + public string PropertyPath { get; } + + public ActiveBindingTarget(GameObject go, string propertyPath) + { + _gameObject = go; + PropertyPath = propertyPath; + } + + public void UpdateValue(object value) + { + if (_gameObject != null) + { + _gameObject.SetActive(value is true); + } + } + } + + public class SliderBindingTarget : IBindingTarget + { + private readonly Slider _slider; + public string PropertyPath { get; } + + public SliderBindingTarget(Slider slider, string propertyPath) + { + _slider = slider; + PropertyPath = propertyPath; + } + + public void UpdateValue(object value) + { + if (_slider != null && value is float floatValue) + _slider.value = floatValue; + } + } +} \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/New/Utils/IBindingTarget.cs.meta b/Assets/_DDD/_Scripts/GameUi/New/Utils/IBindingTarget.cs.meta new file mode 100644 index 000000000..e9f884bec --- /dev/null +++ b/Assets/_DDD/_Scripts/GameUi/New/Utils/IBindingTarget.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cd44087c256644b9815bfdc23ac4b29f +timeCreated: 1755749119 \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/New/Utils/InputPhase.cs b/Assets/_DDD/_Scripts/GameUi/New/Utils/InputPhase.cs deleted file mode 100644 index 0fbbc29b5..000000000 --- a/Assets/_DDD/_Scripts/GameUi/New/Utils/InputPhase.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace DDD.MVVM -{ - /// - /// 입력 처리 단계를 나타내는 열거형 - /// 매직 스트링을 제거하고 타입 안전성을 제공 - /// - public enum InputPhaseType - { - /// - /// 입력이 시작됨 - /// - Started, - - /// - /// 입력이 수행됨 - /// - Performed, - - /// - /// 입력이 취소됨 - /// - Canceled - } -} \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/New/Utils/InputPhase.cs.meta b/Assets/_DDD/_Scripts/GameUi/New/Utils/InputPhase.cs.meta deleted file mode 100644 index 1152c6f08..000000000 --- a/Assets/_DDD/_Scripts/GameUi/New/Utils/InputPhase.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 5c9b66b101f99e1458e01b9e0653935f \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/New/ViewModels/Base/SimpleViewModel.cs b/Assets/_DDD/_Scripts/GameUi/New/ViewModels/Base/SimpleViewModel.cs index 4ab0a5655..50267af30 100644 --- a/Assets/_DDD/_Scripts/GameUi/New/ViewModels/Base/SimpleViewModel.cs +++ b/Assets/_DDD/_Scripts/GameUi/New/ViewModels/Base/SimpleViewModel.cs @@ -10,8 +10,11 @@ public abstract class SimpleViewModel : MonoBehaviour, INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; protected virtual void Awake() { } + protected virtual void OnEnable() { } protected virtual void Start() { } + protected virtual void OnDisable() { } protected virtual void OnDestroy() { } + public virtual void Initialize() { } public virtual void Cleanup() { } @@ -35,6 +38,7 @@ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName protected bool SetField(ref T field, T value, [CallerMemberName] string propertyName = null) { if (EqualityComparer.Default.Equals(field, value)) return false; + field = value; OnPropertyChanged(propertyName); return true; @@ -64,24 +68,11 @@ protected void EndUpdate() if (_pendingNotifications.Count > 0) { foreach (var prop in _pendingNotifications) + { OnPropertyChanged(prop); + } _pendingNotifications.Clear(); } } - - /// - /// PropertyChanged 이벤트 발생 (배치 업데이트 고려) - /// - protected virtual void OnPropertyChangedInternal([CallerMemberName] string propertyName = null) - { - if (_isUpdating) - { - _pendingNotifications.Add(propertyName); - } - else - { - OnPropertyChanged(propertyName); - } - } } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/New/ViewModels/InventoryViewModel.cs b/Assets/_DDD/_Scripts/GameUi/New/ViewModels/InventoryViewModel.cs index dea265beb..4f54fdfad 100644 --- a/Assets/_DDD/_Scripts/GameUi/New/ViewModels/InventoryViewModel.cs +++ b/Assets/_DDD/_Scripts/GameUi/New/ViewModels/InventoryViewModel.cs @@ -1,9 +1,8 @@ using System.Collections.Generic; -using System.ComponentModel; using System.Linq; using UnityEngine; -namespace DDD.MVVM +namespace DDD { /// /// 인벤토리 UI의 ViewModel @@ -12,8 +11,7 @@ namespace DDD.MVVM public class InventoryViewModel : SimpleViewModel, IEventHandler, IEventHandler, IEventHandler { - [Header("Services")] - [SerializeField] private InventoryService _inventoryService; + private InventoryService _inventoryService; // Private fields for properties private InventoryCategoryType _currentCategory = InventoryCategoryType.Food; @@ -33,8 +31,6 @@ public InventoryCategoryType CurrentCategory if (SetField(ref _currentCategory, value)) { UpdateVisibleItems(); - // 연관된 계산된 속성들도 알림 - OnPropertyChanged(nameof(CategoryDisplayText)); } } } @@ -81,21 +77,6 @@ public ItemViewModel SelectedItem set => SetField(ref _selectedItem, value); } - // Computed Properties (계산된 속성들) - - /// - /// 카테고리 표시 텍스트 (한국어) - /// - public string CategoryDisplayText => CurrentCategory switch - { - InventoryCategoryType.Food => "음식", - InventoryCategoryType.Drink => "음료", - InventoryCategoryType.Ingredient => "재료", - InventoryCategoryType.Cookware => "조리도구", - InventoryCategoryType.Special => "특수", - _ => "전체" - }; - /// /// 보이는 아이템들 중 실제 보유한 아이템이 있는지 확인 /// diff --git a/Assets/_DDD/_Scripts/GameUi/New/Views.meta b/Assets/_DDD/_Scripts/GameUi/New/Views.meta deleted file mode 100644 index dac16c089..000000000 --- a/Assets/_DDD/_Scripts/GameUi/New/Views.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 36adabeb3767cf64684116798ff0ef30 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_DDD/_Scripts/GameUi/New/Views/Base.meta b/Assets/_DDD/_Scripts/GameUi/New/Views/Base.meta deleted file mode 100644 index 368529dc5..000000000 --- a/Assets/_DDD/_Scripts/GameUi/New/Views/Base.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 76b62bf64be94ab4bb1e4b610da29fa4 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_DDD/_Scripts/GameUi/New/Views/Base/AutoBindView.cs b/Assets/_DDD/_Scripts/GameUi/New/Views/Base/AutoBindView.cs deleted file mode 100644 index 2298041d0..000000000 --- a/Assets/_DDD/_Scripts/GameUi/New/Views/Base/AutoBindView.cs +++ /dev/null @@ -1,210 +0,0 @@ -using System; -using System.ComponentModel; -using System.Linq; -using System.Reflection; -using UnityEngine; -using UnityEngine.UI; - -namespace DDD.MVVM -{ - /// - /// 자동 바인딩을 지원하는 View 기본 클래스 - /// Attribute를 통해 설정된 바인딩을 자동으로 처리 - /// - /// 바인딩할 ViewModel 타입 - public abstract class AutoBindView : MonoBehaviour where TViewModel : SimpleViewModel - { - [SerializeField] protected TViewModel _viewModel; - protected BindingContext _bindingContext; - - /// - /// ViewModel 인스턴스 - /// - public TViewModel ViewModel => _viewModel; - - protected virtual void Awake() - { - if (_viewModel == null) - _viewModel = GetComponent(); - - _bindingContext = new BindingContext(); - - SetupAutoBindings(); - } - - protected virtual void OnEnable() - { - if (_viewModel != null && _bindingContext != null) - { - _bindingContext.SetDataContext(_viewModel); - _viewModel.PropertyChanged += OnViewModelPropertyChanged; - } - } - - protected virtual void OnDisable() - { - if (_viewModel != null) - { - _viewModel.PropertyChanged -= OnViewModelPropertyChanged; - } - } - - protected virtual void OnDestroy() - { - _bindingContext?.Dispose(); - } - - /// - /// Attribute 기반 자동 바인딩 설정 - /// - private void SetupAutoBindings() - { - var fields = GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public) - .Where(f => f.GetCustomAttribute() != null); - - foreach (var field in fields) - { - var bindAttribute = field.GetCustomAttribute(); - SetupBinding(field, bindAttribute); - } - - // 컬렉션 바인딩 설정 - var collectionFields = GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public) - .Where(f => f.GetCustomAttribute() != null); - - foreach (var field in collectionFields) - { - var bindAttribute = field.GetCustomAttribute(); - SetupCollectionBinding(field, bindAttribute); - } - } - - /// - /// 개별 필드의 바인딩 설정 - /// - /// 바인딩할 필드 - /// 바인딩 Attribute - private void SetupBinding(FieldInfo field, BindToAttribute bindAttribute) - { - var target = field.GetValue(this); - - IValueConverter converter = null; - if (bindAttribute.ConverterType != null) - { - converter = Activator.CreateInstance(bindAttribute.ConverterType) as IValueConverter; - } - - // UI 컴포넌트 타입별 바인딩 타겟 생성 - IBindingTarget bindingTarget = target switch - { - Text text => new TextBindingTarget(text, bindAttribute.PropertyPath), - Image image => new ImageBindingTarget(image, bindAttribute.PropertyPath), - GameObject gameObject => new ActiveBindingTarget(gameObject, bindAttribute.PropertyPath), - Slider slider => new SliderBindingTarget(slider, bindAttribute.PropertyPath), - _ => null - }; - - if (bindingTarget != null) - { - _bindingContext.Bind(bindAttribute.PropertyPath, bindingTarget, converter); - } - } - - /// - /// 컬렉션 바인딩 설정 - /// - /// 바인딩할 필드 - /// 바인딩 Attribute - private void SetupCollectionBinding(FieldInfo field, BindCollectionAttribute bindAttribute) - { - var target = field.GetValue(this); - - if (target is Transform parent) - { - // 컬렉션 바인딩은 별도 구현이 필요한 복잡한 기능으로 - // 현재는 기본 구조만 제공 - Debug.Log($"Collection binding for {bindAttribute.PropertyPath} is set up on {parent.name}"); - } - } - - /// - /// ViewModel 속성 변경 이벤트 핸들러 - /// 추가적인 커스텀 로직이 필요한 경우 오버라이드 - /// - /// 이벤트 발신자 - /// 속성 변경 정보 - protected virtual void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs e) - { - // 자동 바인딩으로 처리되지 않는 특별한 속성들의 커스텀 처리 - HandleCustomPropertyChanged(e.PropertyName); - } - - /// - /// 커스텀 속성 변경 처리 (하위 클래스에서 오버라이드) - /// - /// 변경된 속성 이름 - protected virtual void HandleCustomPropertyChanged(string propertyName) - { - // 하위 클래스에서 구현 - } - - /// - /// 수동 바인딩 헬퍼 메서드들 - /// Attribute 사용이 어려운 경우 코드로 바인딩 설정 - /// - - protected void BindText(Text text, string propertyPath, IValueConverter converter = null) - { - var target = new TextBindingTarget(text, propertyPath); - _bindingContext?.Bind(propertyPath, target, converter); - } - - protected void BindImage(Image image, string propertyPath, IValueConverter converter = null) - { - var target = new ImageBindingTarget(image, propertyPath); - _bindingContext?.Bind(propertyPath, target, converter); - } - - protected void BindActive(GameObject gameObject, string propertyPath, IValueConverter converter = null) - { - var target = new ActiveBindingTarget(gameObject, propertyPath); - _bindingContext?.Bind(propertyPath, target, converter); - } - - protected void BindSlider(Slider slider, string propertyPath, IValueConverter converter = null) - { - var target = new SliderBindingTarget(slider, propertyPath); - _bindingContext?.Bind(propertyPath, target, converter); - } - - /// - /// ViewModel 메서드 호출 헬퍼 - /// UI 이벤트에서 ViewModel 메서드를 쉽게 호출 - /// - /// 호출할 메서드 이름 - /// 메서드 매개변수 - protected void InvokeViewModelMethod(string methodName, params object[] parameters) - { - if (_viewModel == null) return; - - var method = _viewModel.GetType().GetMethod(methodName); - method?.Invoke(_viewModel, parameters); - } - - /// - /// ViewModel 속성 직접 설정 헬퍼 - /// - /// 속성 이름 - /// 설정할 값 - protected void SetViewModelProperty(string propertyName, object value) - { - if (_viewModel == null) return; - - var property = _viewModel.GetType().GetProperty(propertyName); - if (property != null && property.CanWrite) - { - property.SetValue(_viewModel, value); - } - } - } -} \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/New/Views/Base/AutoBindView.cs.meta b/Assets/_DDD/_Scripts/GameUi/New/Views/Base/AutoBindView.cs.meta deleted file mode 100644 index 36e96d1a7..000000000 --- a/Assets/_DDD/_Scripts/GameUi/New/Views/Base/AutoBindView.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 738101122cf3fb74e99b244165797ab8 \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/New/Views/Examples.meta b/Assets/_DDD/_Scripts/GameUi/New/Views/Examples.meta deleted file mode 100644 index 53babe302..000000000 --- a/Assets/_DDD/_Scripts/GameUi/New/Views/Examples.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: abb1dd67b48daeb4f968a2641cf7b4a3 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_DDD/_Scripts/GameUi/PopupUi/BasePopupUi.cs b/Assets/_DDD/_Scripts/GameUi/PopupUi/BasePopupUi.cs index c13bc96bf..43b1303af 100644 --- a/Assets/_DDD/_Scripts/GameUi/PopupUi/BasePopupUi.cs +++ b/Assets/_DDD/_Scripts/GameUi/PopupUi/BasePopupUi.cs @@ -5,7 +5,7 @@ namespace DDD { public abstract class BasePopupUi : BaseUi { - public bool IsTopPopup => UiManager.Instance.PopupUiState.IsTopPopup(this); + public bool IsTopPopup => UiManager.Instance.UiState.IsTopPopup(this); public InputActionMaps InputActionMaps; protected override void Awake() @@ -29,10 +29,10 @@ protected override void Update() if (IsOpenPanel() == false) return; var currentSelectedGameObject = EventSystem.current.currentSelectedGameObject; - if (currentSelectedGameObject == null || currentSelectedGameObject.activeInHierarchy == false) + if (!currentSelectedGameObject || currentSelectedGameObject.activeInHierarchy == false) { var initialSelected = GetInitialSelected(); - if (initialSelected != null) + if (initialSelected) { EventSystem.current.SetSelectedGameObject(initialSelected); } @@ -43,14 +43,14 @@ protected override void TryRegister() { base.TryRegister(); - UiManager.Instance.PopupUiState?.RegisterPopupUI(this); + UiManager.Instance.UiState.RegisterPopupUI(this); } protected override void TryUnregister() { base.TryUnregister(); - UiManager.Instance?.PopupUiState?.UnregisterPopupUI(this); + UiManager.Instance?.UiState?.UnregisterPopupUI(this); } public virtual void Open(OpenPopupUiEvent evt) diff --git a/Assets/_DDD/_Scripts/GameUi/PopupUi/PopupUiState.cs b/Assets/_DDD/_Scripts/GameUi/PopupUi/PopupUiState.cs index 69d34f7e8..f23f7e963 100644 --- a/Assets/_DDD/_Scripts/GameUi/PopupUi/PopupUiState.cs +++ b/Assets/_DDD/_Scripts/GameUi/PopupUi/PopupUiState.cs @@ -6,31 +6,47 @@ namespace DDD { - [CreateAssetMenu(fileName = "PopupUiState", menuName = "GameUi/PopupUiState")] - public class PopupUiState : SerializedScriptableObject, IEventHandler, IEventHandler + public class UiState : SerializedScriptableObject, IEventHandler, IEventHandler { - public Dictionary> FlowToPopupUiMapping = new(); + private readonly Dictionary _uis = new(); + + private readonly Dictionary _popupUis = new(); + private readonly Stack _popupUiStack = new(); + private InputActionMaps _previousActionMap = InputActionMaps.None; + + private UiData _uiData => GameData.Instance.UiData; + + public void OnEnable() + { + EventBus.Register(this); + EventBus.Register(this); - [Title("디버그")] - [ReadOnly, ShowInInspector] private readonly Dictionary _popupUis = new(); - [ReadOnly, ShowInInspector] private readonly Stack _popupUiStack = new(); - [ReadOnly, SerializeField] private InputActionMaps _previousActionMap = InputActionMaps.None; + _uis.Clear(); + _popupUis.Clear(); + _popupUiStack.Clear(); + } private void OnDisable() { EventBus.Unregister(this); EventBus.Unregister(this); } - - public void Initialize() + + public void RegisterUI(BaseUi ui) { - EventBus.Register(this); - EventBus.Register(this); - - _popupUis.Clear(); - _popupUiStack.Clear(); + var type = ui.GetType(); + _uis.TryAdd(type, ui); } + public void UnregisterUI(BaseUi ui) + { + var type = ui.GetType(); + if (_uis.TryGetValue(type, out var registered) && registered == ui) + { + _uis.Remove(type); + } + } + public void RegisterPopupUI(BasePopupUi ui) { var type = ui.GetType(); @@ -85,51 +101,26 @@ public void Invoke(ClosePopupUiEvent evt) } } } - - public void CreatePopup(BasePopupUi popup, Transform parent) - { - if (_popupUis.TryGetValue(popup.GetType(), out var registered) && registered == popup) return; - - var instance = Instantiate(popup, parent); - instance.name = popup.name; - } - - public void DestroyPopup(BasePopupUi popup) - { - if (_popupUis.TryGetValue(popup.GetType(), out var registered) == false || registered != popup) return; - - Destroy(popup.gameObject); - } - - public List GetMatchingPopupUis(GameFlowState flowState) - { - return FlowToPopupUiMapping - .Where(keyValuePair => (keyValuePair.Key & flowState) != 0) - .SelectMany(keyValuePair => keyValuePair.Value) - .ToList(); - } - + public bool HasMatchingPopupUis(GameFlowState flowState) { - return FlowToPopupUiMapping.Any(keyValuePair => (keyValuePair.Key & flowState) != 0); + return _uiData.FlowToUiMapping.Any(keyValuePair => (keyValuePair.Key & flowState) != 0); } - public void CreateMatchingPopupUis(GameFlowState flowState, Transform parent) + public void CreateUi(BaseUi ui, Transform parent) { - var matchingPopupUis = GetMatchingPopupUis(flowState); - foreach (var popupUi in matchingPopupUis) - { - CreatePopup(popupUi, parent); - } + if (_uis.TryGetValue(ui.GetType(), out var registered) && registered == ui) return; + + var instance = Instantiate(ui, parent); + instance.name = ui.name; + instance.CreateInitialize(); } - public void DestroyMatchingPopupUis(GameFlowState flowState) + public void DestroyUi(BaseUi ui) { - var matchingPopupUis = GetMatchingPopupUis(flowState); - foreach (var popupUi in matchingPopupUis) - { - DestroyPopup(popupUi); - } + if (_uis.TryGetValue(ui.GetType(), out var registered) && registered == ui) return; + + Destroy(ui.gameObject); } public bool IsTopPopup(BasePopupUi popup) diff --git a/Assets/_DDD/_Scripts/GameUi/PopupUi/RestaurantManagementUi/RestaurantManagementUi.cs b/Assets/_DDD/_Scripts/GameUi/PopupUi/RestaurantManagementUi/RestaurantManagementUi.cs index c65d6b376..cca7ea97b 100644 --- a/Assets/_DDD/_Scripts/GameUi/PopupUi/RestaurantManagementUi/RestaurantManagementUi.cs +++ b/Assets/_DDD/_Scripts/GameUi/PopupUi/RestaurantManagementUi/RestaurantManagementUi.cs @@ -2,14 +2,9 @@ using UnityEngine.UI; using UnityEngine.EventSystems; using UnityEngine.InputSystem; -using DDD.MVVM; namespace DDD { - /// - /// MVVM 패턴을 적용한 새로운 레스토랑 관리 UI - /// 기존 RestaurantManagementUi의 기능을 ViewModel과 분리하여 구현 - /// [RequireComponent(typeof(RestaurantManagementViewModel))] public class RestaurantManagementUi : PopupUi { @@ -26,26 +21,25 @@ public class RestaurantManagementUi : PopupUi(); - } - - // Get Selectable component (Button inherits from Selectable) - if (_selectable == null) - { - _selectable = _button; - } - - // Get target graphic from button if not assigned - if (_targetGraphic == null && _button != null) - { - _targetGraphic = _button.targetGraphic as Image; - } - - // Get Animator if not assigned - if (_animator == null) - { - _animator = GetComponent(); - } - } - - private void HandleInputUpdate() - { - if (!_handleKeyboardInput && !_handleGamepadInput) return; - if (_selectable == null || !_selectable.interactable) return; - - // Handle keyboard/gamepad input when this button is selected - if (EventSystem.current != null && EventSystem.current.currentSelectedGameObject == gameObject) - { - //HandleSelectedInput(); - } - } - - private void HandleSelectedInput() - { - var keyboard = Keyboard.current; - var gamepad = Gamepad.current; - - // Handle keyboard input - if (_handleKeyboardInput && keyboard != null) - { - if (keyboard.enterKey.wasPressedThisFrame || keyboard.spaceKey.wasPressedThisFrame) - { - HandleButtonClick(); - } - } - - // Handle gamepad input - if (_handleGamepadInput && gamepad != null) - { - if (gamepad.buttonSouth.wasPressedThisFrame) // A button on Xbox controller - { - HandleButtonClick(); - } - } - } - - private void HandleButtonClick() - { - if (_selectable != null && !_selectable.interactable) return; - - if (_useToggle) - { - _isToggled = !_isToggled; - - if (_isToggled) - { - // When toggled on, maintain pressed state and make non-interactable - _isPressed = true; - _selectable.interactable = false; - } - else - { - // When toggled off, restore normal behavior - _isPressed = false; - _selectable.interactable = true; - } - - UpdateVisualState(); - } - - OnClicked?.Invoke(); - } - - private void UpdateVisualState() - { - if (!_synchronizeStates) return; - - var currentState = GetCurrentState(); - print(currentState); - ApplyVisualState(currentState); - OnStateChanged?.Invoke(); - } - - private ButtonState GetCurrentState() - { - if (_selectable == null || (!_selectable.interactable && !_isToggled)) - return ButtonState.Disabled; - - // Toggle mode: when toggled on, maintain pressed state even if not interactable - if (_useToggle && _isToggled) - return ButtonState.Pressed; - - if (_isPressed) - return ButtonState.Pressed; - - if (_isSelected) - return ButtonState.Selected; - - if (_isHighlighted) - return ButtonState.Highlighted; - - return ButtonState.Normal; - } - - private void ApplyVisualState(ButtonState state) - { - // Apply animator state if available - if (_animator != null && _animator.runtimeAnimatorController != null) - { - ApplyAnimatorState(state); - } - - // Apply color tint if using Button's color block - if (_button != null && _targetGraphic != null) - { - ApplyColorState(state); - } - } - - private void ApplyAnimatorState(ButtonState state) - { - switch (state) - { - case ButtonState.Normal: - _animator.SetTrigger(_normalHash); - break; - case ButtonState.Highlighted: - _animator.SetTrigger(_highlightedHash); - break; - case ButtonState.Pressed: - _animator.SetTrigger(_pressedHash); - break; - case ButtonState.Selected: - _animator.SetTrigger(_selectedHash); - break; - case ButtonState.Disabled: - _animator.SetTrigger(_disabledHash); - break; - } - } - - private void ApplyColorState(ButtonState state) - { - var colors = _button.colors; - Color targetColor; - - switch (state) - { - case ButtonState.Normal: - targetColor = colors.normalColor; - break; - case ButtonState.Highlighted: - targetColor = colors.highlightedColor; - break; - case ButtonState.Pressed: - targetColor = colors.pressedColor; - break; - case ButtonState.Selected: - targetColor = colors.selectedColor; - break; - case ButtonState.Disabled: - targetColor = colors.disabledColor; - break; - default: - targetColor = colors.normalColor; - break; - } - - _targetGraphic.color = targetColor; - } - - // IInteractableUi implementation - public void OnInteract() - { - if (_selectable != null && _selectable.interactable) - { - // This method is called for programmatic interaction - HandleButtonClick(); - } - } - - // Pointer event handlers - public void OnPointerEnter(PointerEventData eventData) - { - _isHighlighted = true; - UpdateVisualState(); - } - - public void OnPointerExit(PointerEventData eventData) - { - _isHighlighted = false; - UpdateVisualState(); - } - - public void OnPointerDown(PointerEventData eventData) - { - if (eventData.button == PointerEventData.InputButton.Left) - { - if (_isSelected) - { - _isPressed = true; - UpdateVisualState(); - return; - } - _isSelected = true; - UpdateVisualState(); - } - } - - public void OnPointerUp(PointerEventData eventData) - { - if (eventData.button == PointerEventData.InputButton.Left) - { - // Don't reset pressed state in toggle mode when toggled on - if (_isPressed && !(_useToggle && _isToggled)) - { - _isPressed = false; - } - _isSelected = false; - UpdateVisualState(); - } - } - - // Selection event handlers (for keyboard/gamepad navigation) - public void OnSelect(BaseEventData eventData) - { - _isSelected = true; - UpdateVisualState(); - } - - public void OnDeselect(BaseEventData eventData) - { - _isSelected = false; - UpdateVisualState(); - } - - // Submit handler (for keyboard/gamepad activation) - public void OnSubmit(BaseEventData eventData) - { - HandleButtonClick(); - } - - // Public API - public bool IsInteractable => _selectable != null && _selectable.interactable; - - public void SetInteractable(bool interactable) - { - if (_selectable != null) - { - _selectable.interactable = interactable; - UpdateVisualState(); - } - } - - public void ForceUpdateState() - { - UpdateVisualState(); - } - - // Toggle functionality API - public bool UseToggle - { - get => _useToggle; - set => _useToggle = value; - } - - public bool IsToggled => _isToggled; - - public void SetToggleState(bool toggled) - { - if (!_useToggle) return; - - _isToggled = toggled; - - if (_isToggled) - { - _isPressed = true; - if (_selectable != null) - _selectable.interactable = false; - } - else - { - _isPressed = false; - if (_selectable != null) - _selectable.interactable = true; - } - - UpdateVisualState(); - } - } -} \ No newline at end of file +// using System; +// using UnityEngine; +// using UnityEngine.UI; +// using UnityEngine.EventSystems; +// using UnityEngine.InputSystem; +// +// namespace DDD +// { +// public enum ButtonState +// { +// Normal, +// Highlighted, +// Pressed, +// Selected, +// Disabled +// } +// +// public enum ButtonType +// { +// None = 0, +// Toggle +// } +// +// // TODO : ButtonType == None +// // normal, selected(마우스 pointerEnter, eventsystem selected), pressed (마우스 pointerDown, 키보드 외부 입력처리), disabled +// // Highlighted가 사실상 selected로 통합, 실제로 마우스가 가리키는 오브젝트가 eventsystem의 selected가 됨 +// // ButtonType == Toggle +// // normal, highlighted, selected(계속 눌려있는 상태, 추후에 ToggleGroup 클래스에서 관리 - 다른 토글이 눌리기 전까지 풀리지 않음), pressed(눌리면 selected 고정), disabled +// +// public class UiButton : MonoBehaviour, IInteractableUi, IPointerEnterHandler, IPointerExitHandler, +// IPointerDownHandler, IPointerUpHandler, ISelectHandler, IDeselectHandler, ISubmitHandler +// { +// [Header("Button Components")] +// [SerializeField] private Button _button; +// [SerializeField] private Selectable _selectable; +// +// [Header("State Synchronization")] +// [SerializeField] private bool _synchronizeStates = true; +// [SerializeField] private bool _handleKeyboardInput = true; +// [SerializeField] private bool _handleGamepadInput = true; +// +// [Header("Visual Feedback")] +// [SerializeField] private Animator _animator; +// [SerializeField] private Image _targetGraphic; +// +// [Header("Toggle Functionality")] +// [SerializeField] private ButtonType _buttonType; +// +// // State tracking +// private bool _isPressed; +// private bool _isHighlighted; +// private bool _isSelected; +// private bool _wasSelectedByKeyboard; +// private bool _isToggled = false; +// +// // Events +// public event Action OnClicked; +// public event Action OnStateChanged; +// +// // Animation parameter hashes (if using Animator) +// private readonly int _normalHash = Animator.StringToHash("Normal"); +// private readonly int _highlightedHash = Animator.StringToHash("Highlighted"); +// private readonly int _pressedHash = Animator.StringToHash("Pressed"); +// private readonly int _selectedHash = Animator.StringToHash("Selected"); +// private readonly int _disabledHash = Animator.StringToHash("Disabled"); +// +// private void Awake() +// { +// InitializeComponents(); +// } +// +// private void OnEnable() +// { +// if (_button != null) +// { +// _button.onClick.AddListener(HandleButtonClick); +// } +// +// UpdateVisualState(); +// } +// +// private void OnDisable() +// { +// if (_button != null) +// { +// _button.onClick.RemoveListener(HandleButtonClick); +// } +// } +// +// private void Update() +// { +// HandleInputUpdate(); +// } +// +// private void InitializeComponents() +// { +// // Get Button component if not assigned +// if (_button == null) +// { +// _button = GetComponent