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