From 5642a5fe77f1c54c982461fc610d10d84b8cc2b3 Mon Sep 17 00:00:00 2001 From: NTG Date: Thu, 21 Aug 2025 19:11:47 +0900 Subject: [PATCH] =?UTF-8?q?inventoryView=20=EB=A1=9C=EC=A7=81=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/_DDD/_Scripts/GameUi/BaseUi/BaseUi.cs | 6 +- .../GameUi/BaseUi/PopupUis/BasePopupUi.cs | 2 +- .../InventoryUi/InventoryService.cs | 167 ------------ .../InventoryUi/InventoryService.cs.meta | 2 - .../InventoryUi/InventoryView.cs | 162 ++--------- .../InventoryUi/InventoryViewModel.cs | 255 ------------------ .../InventoryUi/InventoryViewModel.cs.meta | 2 - .../RestaurantManagementUi.cs | 15 +- .../RestaurantManagementViewModel.cs | 143 +++++++++- .../_DDD/_Scripts/GameUi/Utils/Services.meta | 8 - .../GameUi/Utils/Services/IService.cs | 62 ----- .../GameUi/Utils/Services/IService.cs.meta | 2 - 12 files changed, 176 insertions(+), 650 deletions(-) delete mode 100644 Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryService.cs delete mode 100644 Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryService.cs.meta delete mode 100644 Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryViewModel.cs delete mode 100644 Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryViewModel.cs.meta delete mode 100644 Assets/_DDD/_Scripts/GameUi/Utils/Services.meta delete mode 100644 Assets/_DDD/_Scripts/GameUi/Utils/Services/IService.cs delete mode 100644 Assets/_DDD/_Scripts/GameUi/Utils/Services/IService.cs.meta diff --git a/Assets/_DDD/_Scripts/GameUi/BaseUi/BaseUi.cs b/Assets/_DDD/_Scripts/GameUi/BaseUi/BaseUi.cs index c3586c48a..90cd7f2c6 100644 --- a/Assets/_DDD/_Scripts/GameUi/BaseUi/BaseUi.cs +++ b/Assets/_DDD/_Scripts/GameUi/BaseUi/BaseUi.cs @@ -27,8 +27,9 @@ public abstract class BaseUi : MonoBehaviour protected GameObject _panel; protected BindingContext _bindingContext; - public virtual bool IsBlockingTime => false; - public virtual bool IsOpen => _panel != null && _panel.activeSelf; + public bool IsInitialized { get; protected set; } + public bool IsBlockingTime => false; + public bool IsOpen => _panel != null && _panel.activeSelf; protected virtual void Awake() { @@ -100,6 +101,7 @@ public virtual void ClosePanel() } _panel.SetActive(false); + IsInitialized = false; } public virtual void SetUiInteractable(bool active) diff --git a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/BasePopupUi.cs b/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/BasePopupUi.cs index 74a905e75..fd9a0be80 100644 --- a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/BasePopupUi.cs +++ b/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/BasePopupUi.cs @@ -26,7 +26,7 @@ protected override void Update() base.Update(); // BasePopupUi의 Update 로직 구현 - if (IsOpenPanel() == false) return; + if (IsOpenPanel() == false || IsInitialized == false) return; var currentSelectedGameObject = EventSystem.current.currentSelectedGameObject; if (!currentSelectedGameObject || currentSelectedGameObject.activeInHierarchy == false) diff --git a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryService.cs b/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryService.cs deleted file mode 100644 index 60d4d55c4..000000000 --- a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryService.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace DDD -{ - /// - /// 인벤토리 관련 비즈니스 로직을 담당하는 서비스 - /// 기존 InventoryView의 로직을 서비스 계층으로 분리 - /// - public class InventoryService : IUiService - { - private RestaurantManagementData _restaurantManagementData; - private RestaurantManagementState _restaurantManagementState; - - /// - /// 서비스 초기화 - /// - public void Initialize() - { - _restaurantManagementState = RestaurantState.Instance.ManagementState; - _restaurantManagementData = RestaurantData.Instance.ManagementData; - - Debug.Assert(_restaurantManagementData != null, "RestaurantManagementData is null"); - Debug.Assert(_restaurantManagementState != null, "RestaurantManagementState is null"); - } - - /// - /// 서비스 정리 - /// - public void Cleanup() - { - // 필요한 경우 리소스 정리 - } - - /// - /// UI 상태 업데이트 - /// - public void UpdateUiState() - { - // UI 상태 업데이트 로직 - } - - /// - /// 인벤토리 아이템 목록 가져오기 - /// - /// 인벤토리 아이템 ViewModel 목록 - public List GetInventoryItems() - { - return ItemViewModelFactory.CreateRestaurantManagementInventoryItem(); - } - - /// - /// 카테고리와 정렬 타입에 따라 필터링된 아이템 목록 가져오기 - /// - /// 카테고리 필터 - /// 정렬 타입 - /// 필터링 및 정렬된 아이템 목록 - public IEnumerable FilterItems(InventoryCategoryType category, InventorySortType sortType) - { - var items = GetInventoryItems(); - - // 카테고리 필터링 - var filtered = items.Where(item => MatchesCategory(item, category)); - - // 정렬 - return ApplySort(filtered, sortType); - } - - /// - /// 오늘의 메뉴에 등록되지 않은 아이템들만 필터링 - /// - /// 원본 아이템 목록 - /// 오늘의 메뉴에 등록되지 않은 아이템들 - public IEnumerable FilterOutTodayMenuItems(IEnumerable items) - { - return items.Where(item => - !(item.ItemType == ItemType.Recipe && _restaurantManagementState.IsContainTodayMenu(item.Id))); - } - - /// - /// 아이템이 특정 카테고리와 일치하는지 확인 - /// - /// 확인할 아이템 - /// 카테고리 - /// 일치 여부 - public bool MatchesCategory(ItemViewModel item, InventoryCategoryType category) - { - switch (category) - { - case InventoryCategoryType.Food: - if (item.ItemType != ItemType.Recipe) return false; - return DataManager.Instance.GetDataSo() - .TryGetDataById(item.Id, out var foodRecipe) && foodRecipe.RecipeType == RecipeType.FoodRecipe; - - case InventoryCategoryType.Drink: - if (item.ItemType != ItemType.Recipe) return false; - return DataManager.Instance.GetDataSo() - .TryGetDataById(item.Id, out var drinkRecipe) && drinkRecipe.RecipeType == RecipeType.DrinkRecipe; - - case InventoryCategoryType.Ingredient: - return item.ItemType == ItemType.Ingredient; - - case InventoryCategoryType.Cookware: - return DataManager.Instance.GetDataSo() - .TryGetDataById(item.Id, out var cookwareData); - - case InventoryCategoryType.Special: - return false; // 특수 아이템 로직 추가 필요 - - default: - return false; - } - } - - /// - /// 정렬 타입에 따라 아이템 목록 정렬 - /// - /// 정렬할 아이템 목록 - /// 정렬 타입 - /// 정렬된 아이템 목록 - public IEnumerable ApplySort(IEnumerable items, InventorySortType sortType) - { - return sortType switch - { - InventorySortType.NameAscending => items.OrderByDescending(item => item.HasItem).ThenBy(item => item.DisplayName), - InventorySortType.NameDescending => items.OrderByDescending(item => item.HasItem).ThenByDescending(item => item.DisplayName), - InventorySortType.QuantityAscending => items.OrderByDescending(item => item.HasItem).ThenBy(item => item.Count), - InventorySortType.QuantityDescending => items.OrderByDescending(item => item.HasItem).ThenByDescending(item => item.Count), - InventorySortType.None => items.OrderBy(item => item.Id), - _ => items - }; - } - - /// - /// 아이템이 아이템을 보유하고 있는지 확인 - /// - /// 확인할 아이템 목록 - /// 아이템을 보유한 목록 - public IEnumerable GetItemsWithStock(IEnumerable items) - { - return items.Where(item => item.HasItem); - } - - /// - /// 카테고리별 아이템 개수 가져오기 - /// - /// 카테고리 - /// 해당 카테고리의 보유 아이템 수 - public int GetItemCountByCategory(InventoryCategoryType category) - { - var filteredItems = FilterItems(category, InventorySortType.None); - var itemsWithStock = GetItemsWithStock(filteredItems); - return itemsWithStock.Count(); - } - - /// - /// 전체 인벤토리에서 보유한 아이템 총 개수 - /// - /// 보유 아이템 총 개수 - public int GetTotalItemCount() - { - var allItems = GetInventoryItems(); - return GetItemsWithStock(allItems).Count(); - } - } -} \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryService.cs.meta b/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryService.cs.meta deleted file mode 100644 index 130fe7d1b..000000000 --- a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryService.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 682535d5577b54c499b1f52b4177d202 \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryView.cs b/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryView.cs index 5217129a9..64668dc55 100644 --- a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryView.cs +++ b/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryView.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using UnityEngine; namespace DDD @@ -8,158 +5,41 @@ namespace DDD public class InventoryView : MonoBehaviour, IEventHandler, IEventHandler, IEventHandler { - [SerializeField] private Transform _slotParent; - - private RestaurantManagementData restaurantManagementDataSo; - private RestaurantManagementState restaurantManagementStateSo; - private InventoryCategoryType _currenInventoryCategoryType = InventoryCategoryType.Food; - - private readonly Dictionary _slotLookup = new(); - private GameObject _firstSlot; - private InventorySortType _currentSortType = InventorySortType.None; - - private const string ItemSlotUiName = "ItemSlotUi_"; + private RestaurantManagementViewModel _viewModel; - public GameObject GetInitialSelected() => _firstSlot; + [SerializeField] private Transform _slotParent; + + public GameObject GetInitialSelected() => _viewModel.GetInitialSelectedByInventory(); - private void OnEnable() - { - EventBus.Register(this); - EventBus.Register(this); - EventBus.Register(this); - } - - private void OnDisable() + private void OnDestroy() { EventBus.Unregister(this); EventBus.Unregister(this); EventBus.Unregister(this); } - public void Initialize() + public void Initialize(RestaurantManagementViewModel viewModel) { - restaurantManagementStateSo = RestaurantState.Instance.ManagementState; - restaurantManagementDataSo = RestaurantData.Instance.ManagementData; - Debug.Assert(restaurantManagementDataSo != null, "_todayMenuDataSo != null"); + _viewModel = viewModel; - Clear(); - - var models = ItemViewModelFactory.CreateRestaurantManagementInventoryItem(); - - _slotLookup.Clear(); - foreach (var model in models) - { - var itemSlotUi = Instantiate(restaurantManagementDataSo.ItemSlotUiPrefab, _slotParent); - var slot = itemSlotUi.GetComponent(); - slot.Initialize(model, new InventorySlotUiStrategy()); - itemSlotUi.name = ItemSlotUiName + model.Id; - - var interactor = itemSlotUi.GetComponent(); - if (model.ItemType == ItemType.Recipe) - { - interactor.Initialize(TodayMenuEventType.Add, new TodayMenuInteractorStrategy()); - } - else - { - if (DataManager.Instance.GetDataSo().TryGetDataById(model.Id, out var cookwareData)) - { - interactor.Initialize(TodayMenuEventType.Add, new TodayCookwareInteractorStrategy()); - } - } - - _slotLookup[model.Id] = slot; - } - } - - public void SetSortType(InventorySortType sortType) - { - _currentSortType = sortType; - UpdateView(); - } - - private IEnumerable SortSlots(IEnumerable slots) - { - return _currentSortType switch - { - InventorySortType.NameAscending => slots.OrderByDescending(slot => slot.Model.HasItem).ThenBy(slot => slot.Model.DisplayName), - InventorySortType.NameDescending => slots.OrderByDescending(slot => slot.Model.HasItem).ThenByDescending(slot => slot.Model.DisplayName), - InventorySortType.QuantityAscending => slots.OrderByDescending(slot => slot.Model.HasItem).ThenBy(slot => slot.Model.Count), - InventorySortType.QuantityDescending => slots.OrderByDescending(slot => slot.Model.HasItem).ThenByDescending(slot => slot.Model.Count), - InventorySortType.None => slots.OrderBy(slot => slot.Model.Id), - _ => slots - }; - } - - public void UpdateCategoryView(InventoryCategoryType category) - { - _currenInventoryCategoryType = category; - GameObject firstValidSlot = null; - - var filteredSlots = _slotLookup.Values; - var sortedSlots = SortSlots(filteredSlots); - - int siblingIndex = 0; - - foreach (var slot in sortedSlots) - { - var model = slot.Model; - string id = model.Id; - - bool isRegisteredTodayMenu = model.ItemType == ItemType.Recipe && restaurantManagementStateSo.IsContainTodayMenu(id); - bool matchCategory = MatchesCategory(model, _currenInventoryCategoryType); - bool shouldShow = !isRegisteredTodayMenu && matchCategory; - - slot.SetActive(shouldShow); - - if (shouldShow && model.HasItem) - { - slot.transform.SetSiblingIndex(siblingIndex++); - - if (firstValidSlot == null) - { - firstValidSlot = slot.gameObject; - } - } - } + ClearObject(_slotParent); + _viewModel.CreateInventoryItemSlot(_slotParent); - _firstSlot = firstValidSlot; - } - - private bool MatchesCategory(ItemViewModel model, InventoryCategoryType category) - { - switch (category) - { - case InventoryCategoryType.Food: - if (model.ItemType != ItemType.Recipe) return false; - - return DataManager.Instance.GetDataSo() - .TryGetDataById(model.Id, out var foodRecipe) && foodRecipe.RecipeType == RecipeType.FoodRecipe; - case InventoryCategoryType.Drink: - if (model.ItemType != ItemType.Recipe) return false; - - return DataManager.Instance.GetDataSo() - .TryGetDataById(model.Id, out var drinkRecipe) && - drinkRecipe.RecipeType == RecipeType.DrinkRecipe; - case InventoryCategoryType.Ingredient: - return model.ItemType == ItemType.Ingredient; - case InventoryCategoryType.Cookware: - return DataManager.Instance.GetDataSo() - .TryGetDataById(model.Id, out var cookwareData); - case InventoryCategoryType.Special: - return false; - default: - return false; - } + EventBus.Register(this); + EventBus.Register(this); + EventBus.Register(this); } public void UpdateView() { - UpdateCategoryView(_currenInventoryCategoryType); + _viewModel.UpdateCategoryView(); } + + public void UpdateCategoryView(InventoryCategoryType category) => _viewModel.UpdateCategoryViewByCategory(category); - private void Clear() + private void ClearObject(Transform root) { - foreach (Transform child in _slotParent) + foreach (Transform child in root) { Destroy(child.gameObject); } @@ -177,13 +57,7 @@ public void Invoke(TodayMenuRemovedEvent evt) public void Invoke(InventoryChangedEvent evt) { - foreach (var slot in _slotLookup.Values) - { - if (slot.Strategy is InventorySlotUiStrategy inventorySlotUiStrategy) - { - inventorySlotUiStrategy.OnInventoryChanged(slot); - } - } + _viewModel.OnInventoryChanged(); } } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryViewModel.cs b/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryViewModel.cs deleted file mode 100644 index 4f54fdfad..000000000 --- a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryViewModel.cs +++ /dev/null @@ -1,255 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace DDD -{ - /// - /// 인벤토리 UI의 ViewModel - /// 기존 InventoryView의 상태와 로직을 MVVM 패턴으로 분리 - /// - public class InventoryViewModel : SimpleViewModel, IEventHandler, - IEventHandler, IEventHandler - { - private InventoryService _inventoryService; - - // Private fields for properties - private InventoryCategoryType _currentCategory = InventoryCategoryType.Food; - private InventorySortType _currentSortType = InventorySortType.None; - private List _allItems = new(); - private List _visibleItems = new(); - private ItemViewModel _selectedItem; - - /// - /// 현재 선택된 카테고리 - /// - public InventoryCategoryType CurrentCategory - { - get => _currentCategory; - set - { - if (SetField(ref _currentCategory, value)) - { - UpdateVisibleItems(); - } - } - } - - /// - /// 현재 정렬 타입 - /// - public InventorySortType CurrentSortType - { - get => _currentSortType; - set - { - if (SetField(ref _currentSortType, value)) - { - UpdateVisibleItems(); - } - } - } - - /// - /// 모든 인벤토리 아이템 목록 - /// - public List AllItems - { - get => _allItems; - private set => SetField(ref _allItems, value); - } - - /// - /// 현재 필터링된 보이는 아이템 목록 - /// - public List VisibleItems - { - get => _visibleItems; - private set => SetField(ref _visibleItems, value); - } - - /// - /// 현재 선택된 아이템 - /// - public ItemViewModel SelectedItem - { - get => _selectedItem; - set => SetField(ref _selectedItem, value); - } - - /// - /// 보이는 아이템들 중 실제 보유한 아이템이 있는지 확인 - /// - public bool HasVisibleItems => VisibleItems.Any(item => item.HasItem); - - /// - /// 보이는 아이템들 중 실제 보유한 아이템 개수 - /// - public int VisibleItemCount => VisibleItems.Count(item => item.HasItem); - - /// - /// 아이템 개수 표시 텍스트 - /// - public string ItemCountText => $"아이템 수: {VisibleItemCount}"; - - /// - /// 빈 목록 메시지 표시 여부 - /// - public bool ShowEmptyMessage => !HasVisibleItems; - - /// - /// 첫 번째 유효한 아이템 (UI 포커스용) - /// - public ItemViewModel FirstValidItem => VisibleItems.FirstOrDefault(item => item.HasItem); - - protected override void Awake() - { - base.Awake(); - - if (_inventoryService == null) - _inventoryService = new InventoryService(); - } - - public override void Initialize() - { - base.Initialize(); - - _inventoryService.Initialize(); - LoadInventoryData(); - RegisterEvents(); - } - - public override void Cleanup() - { - base.Cleanup(); - - UnregisterEvents(); - _inventoryService?.Cleanup(); - } - - /// - /// 이벤트 등록 - /// - private void RegisterEvents() - { - EventBus.Register(this); - EventBus.Register(this); - EventBus.Register(this); - } - - /// - /// 이벤트 등록 해제 - /// - private void UnregisterEvents() - { - EventBus.Unregister(this); - EventBus.Unregister(this); - EventBus.Unregister(this); - } - - /// - /// 인벤토리 데이터 로드 - /// - private void LoadInventoryData() - { - AllItems = _inventoryService.GetInventoryItems(); - UpdateVisibleItems(); - } - - /// - /// 카테고리 설정 (UI에서 호출) - /// - /// 새 카테고리 - public void SetCategory(InventoryCategoryType category) - { - CurrentCategory = category; - } - - /// - /// 정렬 타입 설정 (UI에서 호출) - /// - /// 새 정렬 타입 - public void SetSortType(InventorySortType sortType) - { - CurrentSortType = sortType; - } - - /// - /// 보이는 아이템 목록 업데이트 - /// - private void UpdateVisibleItems() - { - BeginUpdate(); // 배치 업데이트 시작 - - // 서비스에서 필터링된 아이템 가져오기 - var filteredItems = _inventoryService.FilterItems(CurrentCategory, CurrentSortType); - - // 오늘의 메뉴에 등록된 아이템 제외 - var finalItems = _inventoryService.FilterOutTodayMenuItems(filteredItems); - - VisibleItems = finalItems.ToList(); - - // 관련된 계산된 속성들 알림 - OnPropertyChanged(nameof(HasVisibleItems)); - OnPropertyChanged(nameof(VisibleItemCount)); - OnPropertyChanged(nameof(ItemCountText)); - OnPropertyChanged(nameof(ShowEmptyMessage)); - OnPropertyChanged(nameof(FirstValidItem)); - - EndUpdate(); // 배치 업데이트 종료 - } - - /// - /// 아이템 선택 - /// - /// 선택할 아이템 - public void SelectItem(ItemViewModel item) - { - SelectedItem = item; - } - - /// - /// 특정 카테고리의 아이템 개수 가져오기 - /// - /// 카테고리 - /// 아이템 개수 - public int GetItemCountForCategory(InventoryCategoryType category) - { - return _inventoryService.GetItemCountByCategory(category); - } - - // Event Handlers - - public void Invoke(InventoryChangedEvent evt) - { - LoadInventoryData(); - } - - public void Invoke(TodayMenuAddedEvent evt) - { - UpdateVisibleItems(); - } - - public void Invoke(TodayMenuRemovedEvent evt) - { - UpdateVisibleItems(); - } - - // Unity Editor에서 테스트용 메서드들 -#if UNITY_EDITOR - [ContextMenu("Test Category Change")] - private void TestCategoryChange() - { - var nextCategory = (InventoryCategoryType)(((int)CurrentCategory + 1) % 5); - SetCategory(nextCategory); - } - - [ContextMenu("Test Sort Change")] - private void TestSortChange() - { - var nextSort = (InventorySortType)(((int)CurrentSortType + 1) % 5); - SetSortType(nextSort); - } -#endif - } -} \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryViewModel.cs.meta b/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryViewModel.cs.meta deleted file mode 100644 index 74c89acef..000000000 --- a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/InventoryUi/InventoryViewModel.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 321a552f0b0773b4db1ab3dc95217719 \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/RestaurantManagementUi.cs b/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/RestaurantManagementUi.cs index a4d092d3a..e6f032b8b 100644 --- a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/RestaurantManagementUi.cs +++ b/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/RestaurantManagementUi.cs @@ -46,21 +46,32 @@ public override void Open(OpenPopupUiEvent evt) InitializeViews(); SetupTabs(); + + IsInitialized = true; } protected override GameObject GetInitialSelected() { + if (IsInitialized == false) return null; + // ViewModel의 현재 상태에 따라 초기 선택 UI 결정 var inventoryInitialSelected = _inventoryView.GetInitialSelected(); - if (inventoryInitialSelected) return inventoryInitialSelected; + 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; } @@ -101,7 +112,7 @@ private void SetupViewModelEvents() private void InitializeViews() { _checklistView.Initalize(); - _inventoryView.Initialize(); + _inventoryView.Initialize(_viewModel); _itemDetailView.Initialize(); _todayMenuView.Initialize(_viewModel); _todayRestaurantStateView.Initialize(); diff --git a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/RestaurantManagementViewModel.cs b/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/RestaurantManagementViewModel.cs index d86f6a3e9..70ceab8da 100644 --- a/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/RestaurantManagementViewModel.cs +++ b/Assets/_DDD/_Scripts/GameUi/BaseUi/PopupUis/RestaurantManagementUi/RestaurantManagementViewModel.cs @@ -6,9 +6,6 @@ namespace DDD { public class RestaurantManagementViewModel : SimpleViewModel, IEventHandler { - private List _foodSlots; - private List _drinkSlots; - // View에서 구독할 이벤트들 public System.Action OnBatchCompleted; public System.Action OnChecklistFailed; @@ -183,8 +180,148 @@ public void MoveTab(int direction) #endregion + #region InventoryView + + private InventoryCategoryType _currenInventoryCategoryType = InventoryCategoryType.Food; + + private readonly Dictionary _slotLookup = new(); + private InventorySortType _currentSortType = InventorySortType.None; + private GameObject _firstSlot; + private const string ItemSlotUiName = "ItemSlotUi_"; + public GameObject GetInitialSelectedByInventory() => _firstSlot; + + public void CreateInventoryItemSlot(Transform parent) + { + var models = ItemViewModelFactory.CreateRestaurantManagementInventoryItem(); + + _slotLookup.Clear(); + foreach (var model in models) + { + var itemSlotUi = Instantiate(GetRestaurantManagementData().ItemSlotUiPrefab, parent); + var slot = itemSlotUi.GetComponent(); + slot.Initialize(model, new InventorySlotUiStrategy()); + itemSlotUi.name = ItemSlotUiName + model.Id; + + var interactor = itemSlotUi.GetComponent(); + if (model.ItemType == ItemType.Recipe) + { + interactor.Initialize(TodayMenuEventType.Add, new TodayMenuInteractorStrategy()); + } + else + { + if (DataManager.Instance.GetDataSo().TryGetDataById(model.Id, out var cookwareData)) + { + interactor.Initialize(TodayMenuEventType.Add, new TodayCookwareInteractorStrategy()); + } + } + + _slotLookup[model.Id] = slot; + } + + UpdateCategoryView(); + } + + public void SetSortType(InventorySortType sortType) + { + _currentSortType = sortType; + UpdateCategoryView(); + } + + private IEnumerable SortSlots(IEnumerable slots) + { + return _currentSortType switch + { + InventorySortType.NameAscending => slots.OrderByDescending(slot => slot.Model.HasItem).ThenBy(slot => slot.Model.DisplayName), + InventorySortType.NameDescending => slots.OrderByDescending(slot => slot.Model.HasItem).ThenByDescending(slot => slot.Model.DisplayName), + InventorySortType.QuantityAscending => slots.OrderByDescending(slot => slot.Model.HasItem).ThenBy(slot => slot.Model.Count), + InventorySortType.QuantityDescending => slots.OrderByDescending(slot => slot.Model.HasItem).ThenByDescending(slot => slot.Model.Count), + InventorySortType.None => slots.OrderBy(slot => slot.Model.Id), + _ => slots + }; + } + + public void UpdateCategoryView() => UpdateCategoryViewByCategory(_currenInventoryCategoryType); + + public void UpdateCategoryViewByCategory(InventoryCategoryType category) + { + _currenInventoryCategoryType = category; + GameObject firstValidSlot = null; + + var filteredSlots = _slotLookup.Values; + var sortedSlots = SortSlots(filteredSlots); + + int siblingIndex = 0; + + foreach (var slot in sortedSlots) + { + var model = slot.Model; + string id = model.Id; + + bool isRegisteredTodayMenu = model.ItemType == ItemType.Recipe && GetRestaurantManagementState().IsContainTodayMenu(id); + bool matchCategory = MatchesCategory(model, _currenInventoryCategoryType); + bool shouldShow = !isRegisteredTodayMenu && matchCategory; + + slot.SetActive(shouldShow); + + if (shouldShow && model.HasItem) + { + slot.transform.SetSiblingIndex(siblingIndex++); + + if (firstValidSlot == null) + { + firstValidSlot = slot.gameObject; + } + } + } + + _firstSlot = firstValidSlot; + } + + private bool MatchesCategory(ItemViewModel model, InventoryCategoryType category) + { + switch (category) + { + case InventoryCategoryType.Food: + if (model.ItemType != ItemType.Recipe) return false; + + return DataManager.Instance.GetDataSo() + .TryGetDataById(model.Id, out var foodRecipe) && foodRecipe.RecipeType == RecipeType.FoodRecipe; + case InventoryCategoryType.Drink: + if (model.ItemType != ItemType.Recipe) return false; + + return DataManager.Instance.GetDataSo() + .TryGetDataById(model.Id, out var drinkRecipe) && + drinkRecipe.RecipeType == RecipeType.DrinkRecipe; + case InventoryCategoryType.Ingredient: + return model.ItemType == ItemType.Ingredient; + case InventoryCategoryType.Cookware: + return DataManager.Instance.GetDataSo() + .TryGetDataById(model.Id, out var cookwareData); + case InventoryCategoryType.Special: + return false; + default: + return false; + } + } + + public void OnInventoryChanged() + { + foreach (var slot in _slotLookup.Values) + { + if (slot.Strategy is InventorySlotUiStrategy inventorySlotUiStrategy) + { + inventorySlotUiStrategy.OnInventoryChanged(slot); + } + } + } + + #endregion + #region TodayMenuView + private List _foodSlots; + private List _drinkSlots; + public void CreateFoodSlot(Transform parent) { var foodMaxCount = GetRestaurantManagementData().MaxFoodCount; diff --git a/Assets/_DDD/_Scripts/GameUi/Utils/Services.meta b/Assets/_DDD/_Scripts/GameUi/Utils/Services.meta deleted file mode 100644 index 4d31e16a4..000000000 --- a/Assets/_DDD/_Scripts/GameUi/Utils/Services.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 7196d7444953d844c9b0e893fb3e958a -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_DDD/_Scripts/GameUi/Utils/Services/IService.cs b/Assets/_DDD/_Scripts/GameUi/Utils/Services/IService.cs deleted file mode 100644 index 569c7c22c..000000000 --- a/Assets/_DDD/_Scripts/GameUi/Utils/Services/IService.cs +++ /dev/null @@ -1,62 +0,0 @@ -namespace DDD -{ - /// - /// 서비스 계층의 기본 인터페이스 - /// MVVM 패턴에서 비즈니스 로직을 담당하는 서비스들의 공통 인터페이스 - /// - public interface IService - { - /// - /// 서비스 초기화 - /// - void Initialize(); - - /// - /// 서비스 종료 시 리소스 정리 - /// - void Cleanup(); - } - - /// - /// 데이터 서비스 인터페이스 - /// 데이터 CRUD 작업을 담당하는 서비스들의 기본 인터페이스 - /// - /// 관리할 데이터 타입 - public interface IDataService : IService - { - /// - /// 데이터 로드 - /// - void LoadData(); - - /// - /// 데이터 저장 - /// - void SaveData(); - - /// - /// 특정 ID의 데이터 가져오기 - /// - /// 데이터 ID - /// 데이터 객체 또는 null - TData GetData(string id); - - /// - /// 모든 데이터 가져오기 - /// - /// 모든 데이터 컬렉션 - System.Collections.Generic.IEnumerable GetAllData(); - } - - /// - /// UI 서비스 인터페이스 - /// UI 관련 비즈니스 로직을 담당하는 서비스들의 기본 인터페이스 - /// - public interface IUiService : IService - { - /// - /// UI 상태 업데이트 - /// - void UpdateUiState(); - } -} \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/Utils/Services/IService.cs.meta b/Assets/_DDD/_Scripts/GameUi/Utils/Services/IService.cs.meta deleted file mode 100644 index ff2af3d05..000000000 --- a/Assets/_DDD/_Scripts/GameUi/Utils/Services/IService.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 7f55f2be524632444aeebeb8b8965efc \ No newline at end of file