inventoryView 로직 분리

This commit is contained in:
NTG 2025-08-21 19:11:47 +09:00
parent f75ec7684f
commit 5642a5fe77
12 changed files with 176 additions and 650 deletions

View File

@ -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)

View File

@ -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)

View File

@ -1,167 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace DDD
{
/// <summary>
/// 인벤토리 관련 비즈니스 로직을 담당하는 서비스
/// 기존 InventoryView의 로직을 서비스 계층으로 분리
/// </summary>
public class InventoryService : IUiService
{
private RestaurantManagementData _restaurantManagementData;
private RestaurantManagementState _restaurantManagementState;
/// <summary>
/// 서비스 초기화
/// </summary>
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");
}
/// <summary>
/// 서비스 정리
/// </summary>
public void Cleanup()
{
// 필요한 경우 리소스 정리
}
/// <summary>
/// UI 상태 업데이트
/// </summary>
public void UpdateUiState()
{
// UI 상태 업데이트 로직
}
/// <summary>
/// 인벤토리 아이템 목록 가져오기
/// </summary>
/// <returns>인벤토리 아이템 ViewModel 목록</returns>
public List<ItemViewModel> GetInventoryItems()
{
return ItemViewModelFactory.CreateRestaurantManagementInventoryItem();
}
/// <summary>
/// 카테고리와 정렬 타입에 따라 필터링된 아이템 목록 가져오기
/// </summary>
/// <param name="category">카테고리 필터</param>
/// <param name="sortType">정렬 타입</param>
/// <returns>필터링 및 정렬된 아이템 목록</returns>
public IEnumerable<ItemViewModel> FilterItems(InventoryCategoryType category, InventorySortType sortType)
{
var items = GetInventoryItems();
// 카테고리 필터링
var filtered = items.Where(item => MatchesCategory(item, category));
// 정렬
return ApplySort(filtered, sortType);
}
/// <summary>
/// 오늘의 메뉴에 등록되지 않은 아이템들만 필터링
/// </summary>
/// <param name="items">원본 아이템 목록</param>
/// <returns>오늘의 메뉴에 등록되지 않은 아이템들</returns>
public IEnumerable<ItemViewModel> FilterOutTodayMenuItems(IEnumerable<ItemViewModel> items)
{
return items.Where(item =>
!(item.ItemType == ItemType.Recipe && _restaurantManagementState.IsContainTodayMenu(item.Id)));
}
/// <summary>
/// 아이템이 특정 카테고리와 일치하는지 확인
/// </summary>
/// <param name="item">확인할 아이템</param>
/// <param name="category">카테고리</param>
/// <returns>일치 여부</returns>
public bool MatchesCategory(ItemViewModel item, InventoryCategoryType category)
{
switch (category)
{
case InventoryCategoryType.Food:
if (item.ItemType != ItemType.Recipe) return false;
return DataManager.Instance.GetDataSo<RecipeDataSo>()
.TryGetDataById(item.Id, out var foodRecipe) && foodRecipe.RecipeType == RecipeType.FoodRecipe;
case InventoryCategoryType.Drink:
if (item.ItemType != ItemType.Recipe) return false;
return DataManager.Instance.GetDataSo<RecipeDataSo>()
.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<CookwareDataSo>()
.TryGetDataById(item.Id, out var cookwareData);
case InventoryCategoryType.Special:
return false; // 특수 아이템 로직 추가 필요
default:
return false;
}
}
/// <summary>
/// 정렬 타입에 따라 아이템 목록 정렬
/// </summary>
/// <param name="items">정렬할 아이템 목록</param>
/// <param name="sortType">정렬 타입</param>
/// <returns>정렬된 아이템 목록</returns>
public IEnumerable<ItemViewModel> ApplySort(IEnumerable<ItemViewModel> 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
};
}
/// <summary>
/// 아이템이 아이템을 보유하고 있는지 확인
/// </summary>
/// <param name="items">확인할 아이템 목록</param>
/// <returns>아이템을 보유한 목록</returns>
public IEnumerable<ItemViewModel> GetItemsWithStock(IEnumerable<ItemViewModel> items)
{
return items.Where(item => item.HasItem);
}
/// <summary>
/// 카테고리별 아이템 개수 가져오기
/// </summary>
/// <param name="category">카테고리</param>
/// <returns>해당 카테고리의 보유 아이템 수</returns>
public int GetItemCountByCategory(InventoryCategoryType category)
{
var filteredItems = FilterItems(category, InventorySortType.None);
var itemsWithStock = GetItemsWithStock(filteredItems);
return itemsWithStock.Count();
}
/// <summary>
/// 전체 인벤토리에서 보유한 아이템 총 개수
/// </summary>
/// <returns>보유 아이템 총 개수</returns>
public int GetTotalItemCount()
{
var allItems = GetInventoryItems();
return GetItemsWithStock(allItems).Count();
}
}
}

View File

@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 682535d5577b54c499b1f52b4177d202

View File

@ -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<InventoryChangedEvent>,
IEventHandler<TodayMenuAddedEvent>, IEventHandler<TodayMenuRemovedEvent>
{
private RestaurantManagementViewModel _viewModel;
[SerializeField] private Transform _slotParent;
private RestaurantManagementData restaurantManagementDataSo;
private RestaurantManagementState restaurantManagementStateSo;
private InventoryCategoryType _currenInventoryCategoryType = InventoryCategoryType.Food;
public GameObject GetInitialSelected() => _viewModel.GetInitialSelectedByInventory();
private readonly Dictionary<string, ItemSlotUi> _slotLookup = new();
private GameObject _firstSlot;
private InventorySortType _currentSortType = InventorySortType.None;
private const string ItemSlotUiName = "ItemSlotUi_";
public GameObject GetInitialSelected() => _firstSlot;
private void OnEnable()
{
EventBus.Register<InventoryChangedEvent>(this);
EventBus.Register<TodayMenuAddedEvent>(this);
EventBus.Register<TodayMenuRemovedEvent>(this);
}
private void OnDisable()
private void OnDestroy()
{
EventBus.Unregister<InventoryChangedEvent>(this);
EventBus.Unregister<TodayMenuAddedEvent>(this);
EventBus.Unregister<TodayMenuRemovedEvent>(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();
ClearObject(_slotParent);
_viewModel.CreateInventoryItemSlot(_slotParent);
var models = ItemViewModelFactory.CreateRestaurantManagementInventoryItem();
_slotLookup.Clear();
foreach (var model in models)
{
var itemSlotUi = Instantiate(restaurantManagementDataSo.ItemSlotUiPrefab, _slotParent);
var slot = itemSlotUi.GetComponent<ItemSlotUi>();
slot.Initialize(model, new InventorySlotUiStrategy());
itemSlotUi.name = ItemSlotUiName + model.Id;
var interactor = itemSlotUi.GetComponent<ItemSlotInteractor>();
if (model.ItemType == ItemType.Recipe)
{
interactor.Initialize(TodayMenuEventType.Add, new TodayMenuInteractorStrategy());
}
else
{
if (DataManager.Instance.GetDataSo<CookwareDataSo>().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<ItemSlotUi> SortSlots(IEnumerable<ItemSlotUi> 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;
}
}
}
_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<RecipeDataSo>()
.TryGetDataById(model.Id, out var foodRecipe) && foodRecipe.RecipeType == RecipeType.FoodRecipe;
case InventoryCategoryType.Drink:
if (model.ItemType != ItemType.Recipe) return false;
return DataManager.Instance.GetDataSo<RecipeDataSo>()
.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<CookwareDataSo>()
.TryGetDataById(model.Id, out var cookwareData);
case InventoryCategoryType.Special:
return false;
default:
return false;
}
EventBus.Register<InventoryChangedEvent>(this);
EventBus.Register<TodayMenuAddedEvent>(this);
EventBus.Register<TodayMenuRemovedEvent>(this);
}
public void UpdateView()
{
UpdateCategoryView(_currenInventoryCategoryType);
_viewModel.UpdateCategoryView();
}
private void Clear()
public void UpdateCategoryView(InventoryCategoryType category) => _viewModel.UpdateCategoryViewByCategory(category);
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();
}
}
}

View File

@ -1,255 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace DDD
{
/// <summary>
/// 인벤토리 UI의 ViewModel
/// 기존 InventoryView의 상태와 로직을 MVVM 패턴으로 분리
/// </summary>
public class InventoryViewModel : SimpleViewModel, IEventHandler<InventoryChangedEvent>,
IEventHandler<TodayMenuAddedEvent>, IEventHandler<TodayMenuRemovedEvent>
{
private InventoryService _inventoryService;
// Private fields for properties
private InventoryCategoryType _currentCategory = InventoryCategoryType.Food;
private InventorySortType _currentSortType = InventorySortType.None;
private List<ItemViewModel> _allItems = new();
private List<ItemViewModel> _visibleItems = new();
private ItemViewModel _selectedItem;
/// <summary>
/// 현재 선택된 카테고리
/// </summary>
public InventoryCategoryType CurrentCategory
{
get => _currentCategory;
set
{
if (SetField(ref _currentCategory, value))
{
UpdateVisibleItems();
}
}
}
/// <summary>
/// 현재 정렬 타입
/// </summary>
public InventorySortType CurrentSortType
{
get => _currentSortType;
set
{
if (SetField(ref _currentSortType, value))
{
UpdateVisibleItems();
}
}
}
/// <summary>
/// 모든 인벤토리 아이템 목록
/// </summary>
public List<ItemViewModel> AllItems
{
get => _allItems;
private set => SetField(ref _allItems, value);
}
/// <summary>
/// 현재 필터링된 보이는 아이템 목록
/// </summary>
public List<ItemViewModel> VisibleItems
{
get => _visibleItems;
private set => SetField(ref _visibleItems, value);
}
/// <summary>
/// 현재 선택된 아이템
/// </summary>
public ItemViewModel SelectedItem
{
get => _selectedItem;
set => SetField(ref _selectedItem, value);
}
/// <summary>
/// 보이는 아이템들 중 실제 보유한 아이템이 있는지 확인
/// </summary>
public bool HasVisibleItems => VisibleItems.Any(item => item.HasItem);
/// <summary>
/// 보이는 아이템들 중 실제 보유한 아이템 개수
/// </summary>
public int VisibleItemCount => VisibleItems.Count(item => item.HasItem);
/// <summary>
/// 아이템 개수 표시 텍스트
/// </summary>
public string ItemCountText => $"아이템 수: {VisibleItemCount}";
/// <summary>
/// 빈 목록 메시지 표시 여부
/// </summary>
public bool ShowEmptyMessage => !HasVisibleItems;
/// <summary>
/// 첫 번째 유효한 아이템 (UI 포커스용)
/// </summary>
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();
}
/// <summary>
/// 이벤트 등록
/// </summary>
private void RegisterEvents()
{
EventBus.Register<InventoryChangedEvent>(this);
EventBus.Register<TodayMenuAddedEvent>(this);
EventBus.Register<TodayMenuRemovedEvent>(this);
}
/// <summary>
/// 이벤트 등록 해제
/// </summary>
private void UnregisterEvents()
{
EventBus.Unregister<InventoryChangedEvent>(this);
EventBus.Unregister<TodayMenuAddedEvent>(this);
EventBus.Unregister<TodayMenuRemovedEvent>(this);
}
/// <summary>
/// 인벤토리 데이터 로드
/// </summary>
private void LoadInventoryData()
{
AllItems = _inventoryService.GetInventoryItems();
UpdateVisibleItems();
}
/// <summary>
/// 카테고리 설정 (UI에서 호출)
/// </summary>
/// <param name="category">새 카테고리</param>
public void SetCategory(InventoryCategoryType category)
{
CurrentCategory = category;
}
/// <summary>
/// 정렬 타입 설정 (UI에서 호출)
/// </summary>
/// <param name="sortType">새 정렬 타입</param>
public void SetSortType(InventorySortType sortType)
{
CurrentSortType = sortType;
}
/// <summary>
/// 보이는 아이템 목록 업데이트
/// </summary>
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(); // 배치 업데이트 종료
}
/// <summary>
/// 아이템 선택
/// </summary>
/// <param name="item">선택할 아이템</param>
public void SelectItem(ItemViewModel item)
{
SelectedItem = item;
}
/// <summary>
/// 특정 카테고리의 아이템 개수 가져오기
/// </summary>
/// <param name="category">카테고리</param>
/// <returns>아이템 개수</returns>
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
}
}

View File

@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 321a552f0b0773b4db1ab3dc95217719

View File

@ -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();

View File

@ -6,9 +6,6 @@ namespace DDD
{
public class RestaurantManagementViewModel : SimpleViewModel, IEventHandler<TodayMenuRemovedEvent>
{
private List<ItemSlotUi> _foodSlots;
private List<ItemSlotUi> _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<string, ItemSlotUi> _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<ItemSlotUi>();
slot.Initialize(model, new InventorySlotUiStrategy());
itemSlotUi.name = ItemSlotUiName + model.Id;
var interactor = itemSlotUi.GetComponent<ItemSlotInteractor>();
if (model.ItemType == ItemType.Recipe)
{
interactor.Initialize(TodayMenuEventType.Add, new TodayMenuInteractorStrategy());
}
else
{
if (DataManager.Instance.GetDataSo<CookwareDataSo>().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<ItemSlotUi> SortSlots(IEnumerable<ItemSlotUi> 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<RecipeDataSo>()
.TryGetDataById(model.Id, out var foodRecipe) && foodRecipe.RecipeType == RecipeType.FoodRecipe;
case InventoryCategoryType.Drink:
if (model.ItemType != ItemType.Recipe) return false;
return DataManager.Instance.GetDataSo<RecipeDataSo>()
.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<CookwareDataSo>()
.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<ItemSlotUi> _foodSlots;
private List<ItemSlotUi> _drinkSlots;
public void CreateFoodSlot(Transform parent)
{
var foodMaxCount = GetRestaurantManagementData().MaxFoodCount;

View File

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 7196d7444953d844c9b0e893fb3e958a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,62 +0,0 @@
namespace DDD
{
/// <summary>
/// 서비스 계층의 기본 인터페이스
/// MVVM 패턴에서 비즈니스 로직을 담당하는 서비스들의 공통 인터페이스
/// </summary>
public interface IService
{
/// <summary>
/// 서비스 초기화
/// </summary>
void Initialize();
/// <summary>
/// 서비스 종료 시 리소스 정리
/// </summary>
void Cleanup();
}
/// <summary>
/// 데이터 서비스 인터페이스
/// 데이터 CRUD 작업을 담당하는 서비스들의 기본 인터페이스
/// </summary>
/// <typeparam name="TData">관리할 데이터 타입</typeparam>
public interface IDataService<TData> : IService
{
/// <summary>
/// 데이터 로드
/// </summary>
void LoadData();
/// <summary>
/// 데이터 저장
/// </summary>
void SaveData();
/// <summary>
/// 특정 ID의 데이터 가져오기
/// </summary>
/// <param name="id">데이터 ID</param>
/// <returns>데이터 객체 또는 null</returns>
TData GetData(string id);
/// <summary>
/// 모든 데이터 가져오기
/// </summary>
/// <returns>모든 데이터 컬렉션</returns>
System.Collections.Generic.IEnumerable<TData> GetAllData();
}
/// <summary>
/// UI 서비스 인터페이스
/// UI 관련 비즈니스 로직을 담당하는 서비스들의 기본 인터페이스
/// </summary>
public interface IUiService : IService
{
/// <summary>
/// UI 상태 업데이트
/// </summary>
void UpdateUiState();
}
}

View File

@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 7f55f2be524632444aeebeb8b8965efc