테스트 내용 저장
This commit is contained in:
parent
832c369073
commit
0cce2efe62
@ -6311,7 +6311,7 @@ PrefabInstance:
|
||||
m_AddedComponents:
|
||||
- targetCorrespondingSourceObject: {fileID: 6952779389930089995, guid: 4f2bf029cb06b084ba41defc8fc76731, type: 3}
|
||||
insertIndex: -1
|
||||
addedObject: {fileID: 2438716745211137680}
|
||||
addedObject: {fileID: 7197937761328488698}
|
||||
m_SourcePrefab: {fileID: 100100000, guid: 4f2bf029cb06b084ba41defc8fc76731, type: 3}
|
||||
--- !u!224 &4720669467062659157 stripped
|
||||
RectTransform:
|
||||
@ -6323,7 +6323,7 @@ GameObject:
|
||||
m_CorrespondingSourceObject: {fileID: 6952779389930089995, guid: 4f2bf029cb06b084ba41defc8fc76731, type: 3}
|
||||
m_PrefabInstance: {fileID: 4463400116329503023}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!114 &2438716745211137680
|
||||
--- !u!114 &7197937761328488698
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
@ -6332,10 +6332,10 @@ MonoBehaviour:
|
||||
m_GameObject: {fileID: 6740783381500491556}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 46c8396c996c804449b383960b44e812, type: 3}
|
||||
m_Script: {fileID: 11500000, guid: 8a2e0954aa144633aad86e53dc80a46a, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_enableBlockImage: 1
|
||||
_enableBlockImage: 0
|
||||
_uiActionsInputBinding: {fileID: 11400000, guid: 8073fcaf56fc7c34e996d0d47044f146, type: 2}
|
||||
_checklistView: {fileID: 7075966153492927588}
|
||||
_inventoryView: {fileID: 3570087040626823091}
|
||||
@ -6346,7 +6346,6 @@ MonoBehaviour:
|
||||
_menuCategoryTabs: {fileID: 6805049896193344908}
|
||||
_cookwareCategoryTabs: {fileID: 6628923975427483430}
|
||||
_completeBatchFilledImage: {fileID: 2965326806322860544}
|
||||
_holdCompleteTime: 0.5
|
||||
--- !u!1001 &4530765275021007961
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
|
275
Assets/_DDD/_Scripts/GameUi/New/NewRestaurantManagementUi.cs
Normal file
275
Assets/_DDD/_Scripts/GameUi/New/NewRestaurantManagementUi.cs
Normal file
@ -0,0 +1,275 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.InputSystem;
|
||||
using DDD.MVVM;
|
||||
|
||||
namespace DDD
|
||||
{
|
||||
/// <summary>
|
||||
/// MVVM 패턴을 적용한 새로운 레스토랑 관리 UI
|
||||
/// 기존 RestaurantManagementUi의 기능을 ViewModel과 분리하여 구현
|
||||
/// </summary>
|
||||
public class NewRestaurantManagementUi : IntegratedBasePopupUi<RestaurantUiActions, RestaurantManagementViewModel>
|
||||
{
|
||||
[Header("Sub Views")]
|
||||
[SerializeField] private ChecklistView _checklistView;
|
||||
[SerializeField] private InventoryView _inventoryView;
|
||||
[SerializeField] private ItemDetailView _itemDetailView;
|
||||
[SerializeField] private TodayMenuView _todayMenuView;
|
||||
[SerializeField] private TodayRestaurantStateView _todayRestaurantStateView;
|
||||
|
||||
[Header("Tab Groups")]
|
||||
[SerializeField] private TabGroupUi _sectionTabs;
|
||||
[SerializeField] private TabGroupUi _menuCategoryTabs;
|
||||
[SerializeField] private TabGroupUi _cookwareCategoryTabs;
|
||||
|
||||
[Header("Hold Progress UI")]
|
||||
[SerializeField, BindTo(nameof(RestaurantManagementViewModel.NormalizedHoldProgress))]
|
||||
private Image _completeBatchFilledImage;
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
SetupViewModelEvents();
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (_viewModel != null && _viewModel.IsHolding)
|
||||
{
|
||||
_viewModel.UpdateHoldProgress();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Open(OpenPopupUiEvent evt)
|
||||
{
|
||||
base.Open(evt);
|
||||
|
||||
InitializeViews();
|
||||
SetupTabs();
|
||||
}
|
||||
|
||||
protected override GameObject GetInitialSelected()
|
||||
{
|
||||
// ViewModel의 현재 상태에 따라 초기 선택 UI 결정
|
||||
var inventoryInitialSelected = _inventoryView.GetInitialSelected();
|
||||
if (inventoryInitialSelected) return inventoryInitialSelected;
|
||||
|
||||
var menuCategoryButton = _menuCategoryTabs.GetFirstInteractableButton();
|
||||
if (menuCategoryButton != null && menuCategoryButton.activeInHierarchy)
|
||||
return menuCategoryButton;
|
||||
|
||||
var cookwareCategoryButton = _cookwareCategoryTabs.GetFirstInteractableButton();
|
||||
if (cookwareCategoryButton != null && cookwareCategoryButton.activeInHierarchy)
|
||||
return cookwareCategoryButton;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override void SetupBindings()
|
||||
{
|
||||
// Attribute 기반 자동 바인딩이 처리됨
|
||||
// 추가적인 수동 바인딩이 필요한 경우 여기에 구현
|
||||
}
|
||||
|
||||
protected override void HandleCustomPropertyChanged(string propertyName)
|
||||
{
|
||||
switch (propertyName)
|
||||
{
|
||||
case nameof(RestaurantManagementViewModel.CurrentSection):
|
||||
UpdateSectionTabs();
|
||||
break;
|
||||
case nameof(RestaurantManagementViewModel.CurrentCategory):
|
||||
UpdateCategoryTabs();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupViewModelEvents()
|
||||
{
|
||||
if (!_viewModel) return;
|
||||
|
||||
_viewModel.OnBatchCompleted = HandleBatchCompleted;
|
||||
_viewModel.OnChecklistFailed = HandleChecklistFailed;
|
||||
_viewModel.OnMenuSectionSelected = HandleMenuSectionSelected;
|
||||
_viewModel.OnCookwareSectionSelected = HandleCookwareSectionSelected;
|
||||
_viewModel.OnCategoryChanged = HandleCategoryChanged;
|
||||
_viewModel.OnTabMoved = HandleTabMoved;
|
||||
_viewModel.OnInteractRequested = HandleInteractRequested;
|
||||
_viewModel.OnCloseRequested = HandleCloseRequested;
|
||||
_viewModel.OnMenuCategorySelected = HandleMenuCategorySelected;
|
||||
}
|
||||
|
||||
private void InitializeViews()
|
||||
{
|
||||
_checklistView.Initalize();
|
||||
_inventoryView.Initialize();
|
||||
_itemDetailView.Initialize();
|
||||
_todayMenuView.Initialize();
|
||||
_todayRestaurantStateView.Initialize();
|
||||
}
|
||||
|
||||
private void SetupTabs()
|
||||
{
|
||||
SetupCategoryTabs();
|
||||
InitializeTabGroups();
|
||||
SelectInitialTabs();
|
||||
}
|
||||
|
||||
private void SetupCategoryTabs()
|
||||
{
|
||||
_menuCategoryTabs.UseDefaultAllowedValues();
|
||||
_cookwareCategoryTabs.UseDefaultAllowedValues();
|
||||
}
|
||||
|
||||
private void InitializeTabGroups()
|
||||
{
|
||||
_sectionTabs.Initialize(OnSectionTabSelected);
|
||||
_menuCategoryTabs.Initialize(OnCategoryTabSelected);
|
||||
_cookwareCategoryTabs.Initialize(OnCategoryTabSelected);
|
||||
}
|
||||
|
||||
private void SelectInitialTabs()
|
||||
{
|
||||
_sectionTabs.SelectFirstTab();
|
||||
_menuCategoryTabs.SelectFirstTab();
|
||||
}
|
||||
|
||||
private void UpdateSectionTabs()
|
||||
{
|
||||
if (_viewModel == null) return;
|
||||
_sectionTabs.SelectTab((int)_viewModel.CurrentSection);
|
||||
}
|
||||
|
||||
private void UpdateCategoryTabs()
|
||||
{
|
||||
if (_viewModel == null) return;
|
||||
|
||||
switch (_viewModel.CurrentSection)
|
||||
{
|
||||
case SectionButtonType.Menu:
|
||||
_menuCategoryTabs.SelectTab((int)_viewModel.CurrentCategory);
|
||||
break;
|
||||
case SectionButtonType.Cookware:
|
||||
_cookwareCategoryTabs.SelectTab((int)_viewModel.CurrentCategory);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ViewModel 이벤트 핸들러들
|
||||
private void HandleBatchCompleted()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void HandleChecklistFailed()
|
||||
{
|
||||
var evt = GameEvents.OpenPopupUiEvent;
|
||||
evt.UiType = typeof(ConfirmUi);
|
||||
evt.IsCancelButtonVisible = true;
|
||||
evt.NewMessageKey = "checklist_failed_message";
|
||||
evt.OnConfirm = ClosePanel;
|
||||
EventBus.Broadcast(evt);
|
||||
}
|
||||
|
||||
private void HandleMenuSectionSelected()
|
||||
{
|
||||
_menuCategoryTabs.SelectFirstTab();
|
||||
}
|
||||
|
||||
private void HandleCookwareSectionSelected()
|
||||
{
|
||||
_cookwareCategoryTabs.SelectFirstTab();
|
||||
}
|
||||
|
||||
private void HandleCategoryChanged(InventoryCategoryType category)
|
||||
{
|
||||
_inventoryView.UpdateCategoryView(category);
|
||||
_itemDetailView.UpdateCategory(category);
|
||||
}
|
||||
|
||||
private void HandleTabMoved(int direction)
|
||||
{
|
||||
_sectionTabs.Move(direction);
|
||||
}
|
||||
|
||||
private void HandleInteractRequested()
|
||||
{
|
||||
var selected = EventSystem.current.currentSelectedGameObject;
|
||||
var interactable = selected?.GetComponent<IInteractableUi>();
|
||||
interactable?.OnInteract();
|
||||
}
|
||||
|
||||
private void HandleCloseRequested()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void HandleMenuCategorySelected(InventoryCategoryType category)
|
||||
{
|
||||
_menuCategoryTabs.SelectTab((int)category);
|
||||
}
|
||||
|
||||
// UI 이벤트 핸들러들 (TabGroupUi 콜백)
|
||||
private void OnSectionTabSelected(int sectionValue)
|
||||
{
|
||||
_viewModel?.SetSection((SectionButtonType)sectionValue);
|
||||
}
|
||||
|
||||
private void OnCategoryTabSelected(int categoryValue)
|
||||
{
|
||||
_viewModel?.SetCategory((InventoryCategoryType)categoryValue);
|
||||
}
|
||||
|
||||
// 입력 처리 - ViewModel로 위임
|
||||
protected override bool OnInputPerformed(RestaurantUiActions actionEnum, InputAction.CallbackContext context)
|
||||
{
|
||||
var isHandled = base.OnInputPerformed(actionEnum, context);
|
||||
|
||||
if (isHandled && _viewModel != null)
|
||||
{
|
||||
switch (actionEnum)
|
||||
{
|
||||
case RestaurantUiActions.Cancel:
|
||||
_viewModel.CloseUi();
|
||||
break;
|
||||
case RestaurantUiActions.PreviousTab:
|
||||
_viewModel.MoveTab(-1);
|
||||
break;
|
||||
case RestaurantUiActions.NextTab:
|
||||
_viewModel.MoveTab(1);
|
||||
break;
|
||||
case RestaurantUiActions.Interact1:
|
||||
_viewModel.InteractWithSelected();
|
||||
break;
|
||||
case RestaurantUiActions.Interact2:
|
||||
_viewModel.StartHold();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return isHandled;
|
||||
}
|
||||
|
||||
protected override bool OnInputCanceled(RestaurantUiActions actionEnum, InputAction.CallbackContext context)
|
||||
{
|
||||
var isHandled = base.OnInputCanceled(actionEnum, context);
|
||||
|
||||
if (isHandled && _viewModel != null)
|
||||
{
|
||||
switch (actionEnum)
|
||||
{
|
||||
case RestaurantUiActions.Interact2:
|
||||
_viewModel.CancelHold();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return isHandled;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a2e0954aa144633aad86e53dc80a46a
|
||||
timeCreated: 1755673386
|
241
Assets/_DDD/_Scripts/GameUi/New/RestaurantManagementViewModel.cs
Normal file
241
Assets/_DDD/_Scripts/GameUi/New/RestaurantManagementViewModel.cs
Normal file
@ -0,0 +1,241 @@
|
||||
using System.Linq;
|
||||
using DDD.MVVM;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DDD
|
||||
{
|
||||
/// <summary>
|
||||
/// 레스토랑 관리 UI의 ViewModel
|
||||
/// 기존 RestaurantManagementUi의 상태 관리와 비즈니스 로직을 담당
|
||||
/// </summary>
|
||||
public class RestaurantManagementViewModel : SimpleViewModel, IEventHandler<TodayMenuRemovedEvent>
|
||||
{
|
||||
// 홀드 진행 상태 관리
|
||||
private bool _isHolding;
|
||||
private float _elapsedTime;
|
||||
private float _holdCompleteTime = 1f;
|
||||
|
||||
// 탭 상태 관리
|
||||
private SectionButtonType _currentSection = SectionButtonType.Menu;
|
||||
private InventoryCategoryType _currentCategory = InventoryCategoryType.Food;
|
||||
|
||||
/// <summary>
|
||||
/// 현재 홀드 상태
|
||||
/// </summary>
|
||||
public bool IsHolding
|
||||
{
|
||||
get => _isHolding;
|
||||
private set => SetField(ref _isHolding, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 홀드 진행 시간 (0.0 ~ 1.0)
|
||||
/// </summary>
|
||||
public float HoldProgress
|
||||
{
|
||||
get => _elapsedTime;
|
||||
private set => SetField(ref _elapsedTime, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 홀드 완료에 필요한 시간
|
||||
/// </summary>
|
||||
public float HoldCompleteTime
|
||||
{
|
||||
get => _holdCompleteTime;
|
||||
set => SetField(ref _holdCompleteTime, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 현재 선택된 섹션
|
||||
/// </summary>
|
||||
public SectionButtonType CurrentSection
|
||||
{
|
||||
get => _currentSection;
|
||||
set => SetField(ref _currentSection, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 현재 선택된 카테고리
|
||||
/// </summary>
|
||||
public InventoryCategoryType CurrentCategory
|
||||
{
|
||||
get => _currentCategory;
|
||||
set => SetField(ref _currentCategory, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 배치 완료 가능 여부 (체크리스트 완료 상태)
|
||||
/// </summary>
|
||||
public bool CanCompleteBatch =>
|
||||
RestaurantState.Instance.ManagementState.GetChecklistStates().All(state => state);
|
||||
|
||||
/// <summary>
|
||||
/// 홀드 진행률을 0~1 범위로 변환한 값
|
||||
/// </summary>
|
||||
public float NormalizedHoldProgress => HoldCompleteTime <= 0f ? 1f : Mathf.Clamp01(HoldProgress / HoldCompleteTime);
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
RegisterEvents();
|
||||
ResetHoldState();
|
||||
}
|
||||
|
||||
public override void Cleanup()
|
||||
{
|
||||
base.Cleanup();
|
||||
UnregisterEvents();
|
||||
}
|
||||
|
||||
private void RegisterEvents()
|
||||
{
|
||||
EventBus.Register<TodayMenuRemovedEvent>(this);
|
||||
}
|
||||
|
||||
private void UnregisterEvents()
|
||||
{
|
||||
EventBus.Unregister<TodayMenuRemovedEvent>(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 홀드 진행 업데이트 (View에서 Update마다 호출)
|
||||
/// </summary>
|
||||
public void UpdateHoldProgress()
|
||||
{
|
||||
if (!IsHolding) return;
|
||||
|
||||
if (HoldCompleteTime <= 0f)
|
||||
{
|
||||
ProcessCompleteBatch();
|
||||
return;
|
||||
}
|
||||
|
||||
var deltaTime = Time.deltaTime;
|
||||
HoldProgress += deltaTime;
|
||||
|
||||
if (HoldProgress >= HoldCompleteTime)
|
||||
{
|
||||
ProcessCompleteBatch();
|
||||
}
|
||||
|
||||
// UI 업데이트를 위한 정규화된 진행률 알림
|
||||
OnPropertyChanged(nameof(NormalizedHoldProgress));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 홀드 시작
|
||||
/// </summary>
|
||||
public void StartHold()
|
||||
{
|
||||
IsHolding = true;
|
||||
HoldProgress = 0f;
|
||||
OnPropertyChanged(nameof(NormalizedHoldProgress));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 홀드 취소
|
||||
/// </summary>
|
||||
public void CancelHold()
|
||||
{
|
||||
ResetHoldState();
|
||||
}
|
||||
|
||||
private void ResetHoldState()
|
||||
{
|
||||
IsHolding = false;
|
||||
HoldProgress = 0f;
|
||||
OnPropertyChanged(nameof(NormalizedHoldProgress));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 배치 완료 처리
|
||||
/// </summary>
|
||||
private void ProcessCompleteBatch()
|
||||
{
|
||||
ResetHoldState();
|
||||
|
||||
if (CanCompleteBatch)
|
||||
{
|
||||
// 배치 완료 - UI 닫기 이벤트 발생
|
||||
OnBatchCompleted?.Invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 체크리스트 미완료 - 실패 팝업 표시 이벤트 발생
|
||||
OnChecklistFailed?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 섹션 탭 선택 처리
|
||||
/// </summary>
|
||||
public void SetSection(SectionButtonType section)
|
||||
{
|
||||
CurrentSection = section;
|
||||
|
||||
// 섹션 변경 시 해당 섹션의 첫 번째 카테고리로 설정
|
||||
switch (section)
|
||||
{
|
||||
case SectionButtonType.Menu:
|
||||
OnMenuSectionSelected?.Invoke();
|
||||
break;
|
||||
case SectionButtonType.Cookware:
|
||||
OnCookwareSectionSelected?.Invoke();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 카테고리 탭 선택 처리
|
||||
/// </summary>
|
||||
public void SetCategory(InventoryCategoryType category)
|
||||
{
|
||||
CurrentCategory = category;
|
||||
OnCategoryChanged?.Invoke(category);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 탭 이동 (이전/다음)
|
||||
/// </summary>
|
||||
public void MoveTab(int direction)
|
||||
{
|
||||
OnTabMoved?.Invoke(direction);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 현재 선택된 UI 요소와 상호작용
|
||||
/// </summary>
|
||||
public void InteractWithSelected()
|
||||
{
|
||||
OnInteractRequested?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI 닫기
|
||||
/// </summary>
|
||||
public void CloseUi()
|
||||
{
|
||||
OnCloseRequested?.Invoke();
|
||||
}
|
||||
|
||||
// View에서 구독할 이벤트들
|
||||
public System.Action OnBatchCompleted;
|
||||
public System.Action OnChecklistFailed;
|
||||
public System.Action OnMenuSectionSelected;
|
||||
public System.Action OnCookwareSectionSelected;
|
||||
public System.Action<InventoryCategoryType> OnCategoryChanged;
|
||||
public System.Action<int> OnTabMoved;
|
||||
public System.Action OnInteractRequested;
|
||||
public System.Action OnCloseRequested;
|
||||
|
||||
// 이벤트 핸들러
|
||||
public void Invoke(TodayMenuRemovedEvent evt)
|
||||
{
|
||||
SetCategory(evt.InventoryCategoryType);
|
||||
OnMenuCategorySelected?.Invoke(evt.InventoryCategoryType);
|
||||
}
|
||||
|
||||
public System.Action<InventoryCategoryType> OnMenuCategorySelected;
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80dee5e1862248aab26236036049e5fc
|
||||
timeCreated: 1755673405
|
@ -3,7 +3,7 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DDD.MVVM
|
||||
namespace DDD
|
||||
{
|
||||
public abstract class SimpleViewModel : MonoBehaviour, INotifyPropertyChanged
|
||||
{
|
||||
|
@ -1,31 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using DDD.MVVM;
|
||||
using UnityEngine.UI;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine.InputSystem;
|
||||
using DDD.MVVM;
|
||||
|
||||
namespace DDD
|
||||
{
|
||||
public abstract class IntegratedBasePopupUi<TInputEnum, TViewModel> : IntegratedBaseUi<TViewModel>
|
||||
public abstract class IntegratedBasePopupUi<TInputEnum, TViewModel> : BasePopupUi
|
||||
where TInputEnum : Enum
|
||||
where TViewModel : SimpleViewModel
|
||||
{
|
||||
[SerializeField, Required] protected BaseUiActionsInputBinding<TInputEnum> _uiActionsInputBinding;
|
||||
|
||||
|
||||
protected readonly List<(InputAction action, Action<InputAction.CallbackContext> handler)> _registeredHandlers =
|
||||
new();
|
||||
|
||||
// MVVM 기능들
|
||||
protected BindingContext _bindingContext;
|
||||
protected TViewModel _viewModel;
|
||||
|
||||
public InputActionMaps InputActionMaps => _uiActionsInputBinding.InputActionMaps;
|
||||
public bool IsTopPopup => UiManager.Instance.PopupUiState.IsTopPopup(this as BasePopupUi);
|
||||
public override InputActionMaps InputActionMaps => _uiActionsInputBinding.InputActionMaps;
|
||||
public bool IsTopPopup => UiManager.Instance.PopupUiState.IsTopPopup(this);
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
// BasePopupUi의 기본값 적용
|
||||
|
||||
_enableBlockImage = true;
|
||||
_viewModel = GetComponent<TViewModel>();
|
||||
|
||||
_bindingContext = new BindingContext();
|
||||
SetupAutoBindings();
|
||||
SetupBindings();
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
@ -36,8 +48,7 @@ protected override void OnEnable()
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
// BasePopupUi의 Update 로직 구현
|
||||
|
||||
if (IsOpenPanel() == false) return;
|
||||
|
||||
var currentSelectedGameObject = EventSystem.current.currentSelectedGameObject;
|
||||
@ -50,8 +61,26 @@ protected override void Update()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Open(OpenPopupUiEvent evt)
|
||||
{
|
||||
base.Open(evt);
|
||||
|
||||
protected abstract GameObject GetInitialSelected();
|
||||
var initialSelected = GetInitialSelected();
|
||||
if (initialSelected != null)
|
||||
{
|
||||
EventSystem.current.SetSelectedGameObject(initialSelected);
|
||||
}
|
||||
|
||||
transform.SetAsLastSibling();
|
||||
|
||||
if (IsTopPopup)
|
||||
{
|
||||
InputManager.Instance.SwitchCurrentActionMap(_uiActionsInputBinding.InputActionMaps);
|
||||
}
|
||||
}
|
||||
|
||||
protected override abstract GameObject GetInitialSelected();
|
||||
|
||||
protected override void TryRegister()
|
||||
{
|
||||
@ -110,37 +139,114 @@ protected override void TryUnregister()
|
||||
|
||||
// 입력 처리 메서드들
|
||||
protected virtual bool OnInputStarted(TInputEnum actionEnum, InputAction.CallbackContext context) => IsTopPopup;
|
||||
protected virtual bool OnInputPerformed(TInputEnum actionEnum, InputAction.CallbackContext context) => IsTopPopup;
|
||||
protected virtual bool OnInputCanceled(TInputEnum actionEnum, InputAction.CallbackContext context) => IsTopPopup;
|
||||
|
||||
protected virtual bool OnInputPerformed(TInputEnum actionEnum, InputAction.CallbackContext context) =>
|
||||
IsTopPopup;
|
||||
|
||||
protected virtual bool OnInputCanceled(TInputEnum actionEnum, InputAction.CallbackContext context) =>
|
||||
IsTopPopup;
|
||||
|
||||
|
||||
public virtual void Open(OpenPopupUiEvent evt)
|
||||
/// <summary>
|
||||
/// Attribute 기반 자동 바인딩 설정
|
||||
/// </summary>
|
||||
private void SetupAutoBindings()
|
||||
{
|
||||
OpenPanel();
|
||||
var fields = GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)
|
||||
.Where(f => f.GetCustomAttribute<BindToAttribute>() != null);
|
||||
|
||||
var initialSelected = GetInitialSelected();
|
||||
if (initialSelected != null)
|
||||
foreach (var field in fields)
|
||||
{
|
||||
EventSystem.current.SetSelectedGameObject(initialSelected);
|
||||
var bindAttribute = field.GetCustomAttribute<BindToAttribute>();
|
||||
SetupBinding(field, bindAttribute);
|
||||
}
|
||||
|
||||
transform.SetAsLastSibling();
|
||||
// 컬렉션 바인딩 설정
|
||||
var collectionFields = GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)
|
||||
.Where(f => f.GetCustomAttribute<BindCollectionAttribute>() != null);
|
||||
|
||||
if (IsTopPopup)
|
||||
foreach (var field in collectionFields)
|
||||
{
|
||||
InputManager.Instance.SwitchCurrentActionMap(_uiActionsInputBinding.InputActionMaps);
|
||||
var bindAttribute = field.GetCustomAttribute<BindCollectionAttribute>();
|
||||
SetupCollectionBinding(field, bindAttribute);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Close()
|
||||
/// <summary>
|
||||
/// 개별 필드의 바인딩 설정
|
||||
/// </summary>
|
||||
private void SetupBinding(FieldInfo field, BindToAttribute bindAttribute)
|
||||
{
|
||||
var evt = GameEvents.ClosePopupUiEvent;
|
||||
evt.UiType = GetType();
|
||||
EventBus.Broadcast(evt);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 컬렉션 바인딩 설정
|
||||
/// </summary>
|
||||
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}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 추가 바인딩 설정 - 하위 클래스에서 구현
|
||||
/// </summary>
|
||||
protected virtual void SetupBindings() { }
|
||||
|
||||
/// <summary>
|
||||
/// ViewModel 속성 변경 이벤트 핸들러
|
||||
/// </summary>
|
||||
protected virtual void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
HandleCustomPropertyChanged(e.PropertyName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 커스텀 속성 변경 처리 (하위 클래스에서 오버라이드)
|
||||
/// </summary>
|
||||
protected virtual void HandleCustomPropertyChanged(string propertyName)
|
||||
{
|
||||
// 하위 클래스에서 구현
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI 패널 열기 오버라이드 (ViewModel 초기화 추가)
|
||||
/// </summary>
|
||||
public override void OpenPanel()
|
||||
{
|
||||
base.OpenPanel();
|
||||
_viewModel?.Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI 패널 닫기 오버라이드 (ViewModel 정리 추가)
|
||||
/// </summary>
|
||||
public override void ClosePanel()
|
||||
{
|
||||
_viewModel?.Cleanup();
|
||||
base.ClosePanel();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user