From ff66c5d94ff8c16ecafc72683d7916e9f745a2a9 Mon Sep 17 00:00:00 2001 From: NTG Date: Sun, 17 Aug 2025 21:51:51 +0900 Subject: [PATCH] =?UTF-8?q?ui=20=EC=B2=B4=ED=81=AC=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RestaurantManagementUi/ChecklistData.cs | 29 ++++ .../RestaurantManagementUi/ChecklistView.cs | 69 +++++++++ .../RestaurantManagementUi.cs | 134 +++++++++++------- .../FlowStates/RestaurantManagementStateSo.cs | 93 +++++++++--- 4 files changed, 254 insertions(+), 71 deletions(-) create mode 100644 Assets/_DDD/_Scripts/GameUi/RestaurantManagementUi/ChecklistData.cs create mode 100644 Assets/_DDD/_Scripts/GameUi/RestaurantManagementUi/ChecklistView.cs diff --git a/Assets/_DDD/_Scripts/GameUi/RestaurantManagementUi/ChecklistData.cs b/Assets/_DDD/_Scripts/GameUi/RestaurantManagementUi/ChecklistData.cs new file mode 100644 index 000000000..0b450d4e7 --- /dev/null +++ b/Assets/_DDD/_Scripts/GameUi/RestaurantManagementUi/ChecklistData.cs @@ -0,0 +1,29 @@ +using TMPro; +using UnityEngine; +using UnityEngine.Localization.Components; +using UnityEngine.UI; + +namespace DDD +{ + public class ChecklistData : MonoBehaviour + { + [SerializeField] private TextMeshProUGUI _textLabel; + [SerializeField] private Image _checkLineImage; + + public void Initialize() + { + _textLabel.text = string.Empty; + _checkLineImage.gameObject.SetActive(false); + } + + public void UpdateData(string localizationKey, bool isChecked) + { + SetText(localizationKey); + SetActiveCheckLine(isChecked); + } + + public void SetText(string localizationKey) => _textLabel.text = LocalizationManager.Instance.GetString(localizationKey); + public void SetActiveCheckLine(bool isActive) => _checkLineImage.gameObject.SetActive(isActive); + public bool IsChecked() => _checkLineImage.gameObject.activeSelf; + } +} diff --git a/Assets/_DDD/_Scripts/GameUi/RestaurantManagementUi/ChecklistView.cs b/Assets/_DDD/_Scripts/GameUi/RestaurantManagementUi/ChecklistView.cs new file mode 100644 index 000000000..61e3289e9 --- /dev/null +++ b/Assets/_DDD/_Scripts/GameUi/RestaurantManagementUi/ChecklistView.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using System.Linq; +using TMPro; +using UnityEngine; +using UnityEngine.Localization.Components; +using UnityEngine.UI; + +namespace DDD +{ + public enum ChecklistLocalizationKey + { + Checklist1 = 0, + Checklist2, + Checklist3, + } + + public class ChecklistView : MonoBehaviour, IEventHandler, IEventHandler + { + private List _checklistDatas; + + private Dictionary _checklistLocalizationKeys = new() + { + {ChecklistLocalizationKey.Checklist1, "checklist_1"}, + {ChecklistLocalizationKey.Checklist2, "checklist_2"}, + {ChecklistLocalizationKey.Checklist3, "checklist_3"}, + }; + + private RestaurantManagementStateSo restaurantManagementStateSo; + + public void Initalize() + { + restaurantManagementStateSo = RestaurantState.instance.ManagementState; + + _checklistDatas = new List(3); + _checklistDatas = GetComponentsInChildren().ToList(); + + foreach (var checklistData in _checklistDatas) + { + checklistData.Initialize(); + } + + UpdateView(); + + EventBus.Register(this); + EventBus.Register(this); + } + + public void UpdateView() + { + if (restaurantManagementStateSo == null) return; + + bool[] states = restaurantManagementStateSo.GetChecklistStates(); + int loopCount = Mathf.Min(_checklistDatas.Count, states.Length); + for (int i = 0; i < loopCount; i++) + { + _checklistDatas[i].UpdateData(_checklistLocalizationKeys[(ChecklistLocalizationKey)i], states[i]); + } + } + + public void Invoke(TodayMenuRemovedEvent evt) => UpdateView(); + public void Invoke(TodayMenuAddedEvent evt) => UpdateView(); + + private void OnDestroy() + { + EventBus.Unregister(this); + EventBus.Unregister(this); + } + } +} \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/RestaurantManagementUi/RestaurantManagementUi.cs b/Assets/_DDD/_Scripts/GameUi/RestaurantManagementUi/RestaurantManagementUi.cs index 63e04787f..2c65ddfe7 100644 --- a/Assets/_DDD/_Scripts/GameUi/RestaurantManagementUi/RestaurantManagementUi.cs +++ b/Assets/_DDD/_Scripts/GameUi/RestaurantManagementUi/RestaurantManagementUi.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.InputSystem; @@ -9,6 +10,7 @@ namespace DDD { public class RestaurantManagementUi : PopupUi, IEventHandler { + [SerializeField] private ChecklistView _checklistView; [SerializeField] private InventoryView _inventoryView; [SerializeField] private ItemDetailView _itemDetailView; [SerializeField] private TabGroupUi _sectionTabs; @@ -16,51 +18,66 @@ public class RestaurantManagementUi : PopupUi, IEventHandle [SerializeField] private TabGroupUi _cookwareCategoryTabs; [SerializeField] private Image _completeBatchFilledImage; - - [SerializeField] private float _holdCompleteTime = 1f; private float _elapsedTime; private bool _isHolding; + private const string ChecklistFailedMessageKey = "checklist_failed_message"; + protected override void Update() { base.Update(); if (_isHolding) { - if (_holdCompleteTime <= 0f) - { - _elapsedTime = 0f; - HandleInteract2Canceled(); - var evt = GameEvents.OpenPopupUiEvent; - evt.UiType = typeof(ConfirmUi); - evt.IsCancelButtonVisible = true; - evt.NewMessageKey = "Global_Message_001"; - evt.OnConfirm = ClosePanel; - EventBus.Broadcast(evt); - return; - } - - _completeBatchFilledImage.fillAmount = _elapsedTime; - - var multiply = 1f / _holdCompleteTime; - if (_elapsedTime >= 1f) - { - // TODO : 추후에 체크리스트와 비교해서 팝업 띄울지 말지 결정 - HandleInteract2Canceled(); - var evt = GameEvents.OpenPopupUiEvent; - evt.UiType = typeof(ConfirmUi); - evt.IsCancelButtonVisible = true; - evt.NewMessageKey = "Global_Message_001"; - evt.OnConfirm = ClosePanel; - EventBus.Broadcast(evt); - return; - } - - _elapsedTime += Time.deltaTime * multiply; + UpdateHoldProgress(); } } + private void UpdateHoldProgress() + { + if (_holdCompleteTime <= 0f) + { + HandleInteract2Canceled(); + ProcessCompleteBatchAction(); + return; + } + + _completeBatchFilledImage.fillAmount = _elapsedTime; + + var multiply = 1f / _holdCompleteTime; + if (_elapsedTime >= 1f) + { + HandleInteract2Canceled(); + ProcessCompleteBatchAction(); + return; + } + + _elapsedTime += Time.deltaTime * multiply; + } + + private void ProcessCompleteBatchAction() + { + if (RestaurantState.instance.ManagementState.GetChecklistStates().Any(state => state == false)) + { + ShowChecklistFailedPopup(); + } + else + { + Close(); + } + } + + private void ShowChecklistFailedPopup() + { + var evt = GameEvents.OpenPopupUiEvent; + evt.UiType = typeof(ConfirmUi); + evt.IsCancelButtonVisible = true; + evt.NewMessageKey = ChecklistFailedMessageKey; + evt.OnConfirm = ClosePanel; + EventBus.Broadcast(evt); + } + protected override GameObject GetInitialSelected() { var inventoryViewInitialSelectedObject = _inventoryView.GetInitialSelected(); @@ -84,19 +101,18 @@ protected override GameObject GetInitialSelected() public override void Open(OpenPopupUiEvent evt) { base.Open(evt); - - _inventoryView.Initialize(); - - // 각 그룹별로 허용된 카테고리 설정 + + InitializeViews(); SetupCategoryTabs(); - - _sectionTabs.Initialize(OnSectionTabSelected); - _menuCategoryTabs.Initialize(OnCategoryTabSelected); - _cookwareCategoryTabs.Initialize(OnCategoryTabSelected); - - _sectionTabs.SelectFirstTab(); - _menuCategoryTabs.SelectFirstTab(); - EventBus.Register(this); + InitializeTabGroups(); + SelectInitialTabs(); + RegisterEventHandlers(); + } + + private void InitializeViews() + { + _checklistView.Initalize(); + _inventoryView.Initialize(); } /// @@ -109,17 +125,35 @@ private void SetupCategoryTabs() _cookwareCategoryTabs.UseDefaultAllowedValues(); } + private void InitializeTabGroups() + { + _sectionTabs.Initialize(OnSectionTabSelected); + _menuCategoryTabs.Initialize(OnCategoryTabSelected); + _cookwareCategoryTabs.Initialize(OnCategoryTabSelected); + } + + private void SelectInitialTabs() + { + _sectionTabs.SelectFirstTab(); + _menuCategoryTabs.SelectFirstTab(); + } + + private void RegisterEventHandlers() + { + EventBus.Register(this); + } + public override void Close() { base.Close(); - + EventBus.Unregister(this); } protected override bool OnInputPerformed(RestaurantUiActions actionEnum, InputAction.CallbackContext context) { if (base.OnInputPerformed(actionEnum, context) == false) return false; - + switch (actionEnum) { case RestaurantUiActions.Cancel: @@ -141,11 +175,11 @@ protected override bool OnInputPerformed(RestaurantUiActions actionEnum, InputAc return true; } - + protected override bool OnInputCanceled(RestaurantUiActions actionEnum, InputAction.CallbackContext context) { if (base.OnInputPerformed(actionEnum, context) == false) return false; - + switch (actionEnum) { case RestaurantUiActions.Interact2: @@ -172,7 +206,7 @@ private void HandleInteract1Performed() var interactable = selected?.GetComponent(); interactable?.OnInteract(); } - + private void HandleInteract2Performed() { _isHolding = true; @@ -207,7 +241,7 @@ private void OnCategoryTabSelected(int categoryValue) _inventoryView.UpdateCategoryView(category); _itemDetailView.UpdateCategory(category); } - + public void Invoke(TodayMenuRemovedEvent evt) { _menuCategoryTabs.SelectTab((int)evt.InventoryCategoryType); diff --git a/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantManagementStateSo.cs b/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantManagementStateSo.cs index 1a30db65d..8c19ff11c 100644 --- a/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantManagementStateSo.cs +++ b/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantManagementStateSo.cs @@ -8,26 +8,36 @@ namespace DDD { public class RestaurantManagementStateSo : ScriptableObject { - // TODO : 체크리스트 기능 - // TODO : 데이터에서 초기화하고, 동적으로 변경 [Title("오늘의 레스토랑 상태")] public int MaxFoodCount = 8; public int MaxDrinkCount = 6; public int MaxCookwareCount = 6; - + + [Title("체크리스트 조건")] + public int ChecklistFoodCount = 1; + public int ChecklistCookwareCount = 1; + public int ChecklistMatchedMenuWithCookwareCount = 1; + [Title("실시간 데이터")] [ReadOnly, SerializeField] private bool _isOpenable; [ReadOnly, ShowInInspector] private Dictionary _todayFoodRecipeIds = new(); [ReadOnly, ShowInInspector] private Dictionary _todayDrinkRecipeIds = new(); [ReadOnly, ShowInInspector] private List _todayWorkerIds = new(); [ReadOnly, ShowInInspector] private Dictionary> _cookwareToRecipeIds = new(); - + public IReadOnlyDictionary TodayFoodRecipeIds => _todayFoodRecipeIds; public IReadOnlyDictionary TodayDrinkRecipeIds => _todayDrinkRecipeIds; public IReadOnlyList TodayWorkerIds => _todayWorkerIds; public IReadOnlyDictionary> CookwareToRecipeIds => _cookwareToRecipeIds; - + + public int AddedTodayMenuCount => AddedTodayFoodCount + AddedTodayDrinkCount; + public int AddedTodayFoodCount => _todayFoodRecipeIds.Count; + public int AddedTodayDrinkCount => _todayDrinkRecipeIds.Count; + public int AddedTodayWorkerCount => _todayWorkerIds.Count; + public int AddedTodayCookwareCount => _cookwareToRecipeIds.Count; + public int MatchedTodayMenuWithCookwareCount => _cookwareToRecipeIds.Values.Count(recipeSet => recipeSet.Count > 0); + public void InitializeReadyForRestaurant() { // TODO : Load from disk if possible (save data) @@ -37,6 +47,34 @@ public void InitializeReadyForRestaurant() _cookwareToRecipeIds.Clear(); } + /// + /// 체크리스트 항목들의 상태를 확인하는 메서드 + /// + /// 체크리스트 완료 여부 배열 (순서: 음식레시피, 조리도구, 매칭여부) + public bool[] GetChecklistStates() + { + bool hasFood = HasFoodRecipes(); + bool hasCookware = HasCookwares(); + bool hasMatching = HasMatchedMenuWithCookware(); + + return new bool[] { hasFood, hasCookware, hasMatching }; + } + + public bool HasFoodRecipes() + { + return _todayFoodRecipeIds.Count > 0; + } + + public bool HasCookwares() + { + return _cookwareToRecipeIds.Count > 0; + } + + public bool HasMatchedMenuWithCookware() + { + return _cookwareToRecipeIds.Values.Any(recipeSet => recipeSet.Count > 0); + } + public bool IsOpenable() { // TODO : 영업 가능한 상태인지 조건 추가 (최소 요리, 요리도구 배치 등) @@ -55,13 +93,13 @@ public RestaurantManagementDataSo GetManagementData() public bool TryAddTodayMenu(ItemViewModel model) { string recipeId = model.Id; - + if (model.ItemType != ItemType.Recipe) return false; if (DataManager.Instance.GetDataSo().TryGetDataById(recipeId, out RecipeData recipeData) == false) return false; - + bool added = false; - + if (recipeData.RecipeType == RecipeType.FoodRecipe) { if (_todayFoodRecipeIds.Count >= MaxFoodCount || _todayFoodRecipeIds.ContainsKey(recipeId)) return false; @@ -92,7 +130,10 @@ public bool TryAddTodayMenu(ItemViewModel model) { recipeSet.Add(recipeId); } - + + var dirtyEvt = GameEvents.SmartVariablesDirtyEvent; + dirtyEvt.DomainFlags = SmartVariablesDomain.RestaurantToday; + EventBus.Broadcast(dirtyEvt); EventBus.Broadcast(RestaurantEvents.TodayMenuAddedEvent); } @@ -102,7 +143,7 @@ public bool TryAddTodayMenu(ItemViewModel model) public bool TryRemoveTodayMenu(ItemViewModel model) { string recipeId = model.Id; - var evt = RestaurantEvents.TodayMenuRemovedEvent; + var removedEvt = RestaurantEvents.TodayMenuRemovedEvent; if (DataManager.Instance.GetDataSo().TryGetDataById(recipeId, out RecipeData recipeData) == false) return false; @@ -114,7 +155,7 @@ public bool TryRemoveTodayMenu(ItemViewModel model) if (_todayFoodRecipeIds.TryGetValue(recipeId, out refundCount)) { removed = _todayFoodRecipeIds.Remove(recipeId); - evt.InventoryCategoryType = InventoryCategoryType.Food; + removedEvt.InventoryCategoryType = InventoryCategoryType.Food; if (removed) { @@ -128,7 +169,7 @@ public bool TryRemoveTodayMenu(ItemViewModel model) if (_todayDrinkRecipeIds.TryGetValue(recipeId, out refundCount)) { removed = _todayDrinkRecipeIds.Remove(recipeId); - evt.InventoryCategoryType = InventoryCategoryType.Drink; + removedEvt.InventoryCategoryType = InventoryCategoryType.Drink; if (removed) { @@ -146,7 +187,11 @@ public bool TryRemoveTodayMenu(ItemViewModel model) recipeSet.Remove(recipeId); } - EventBus.Broadcast(evt); + var dirtyEvt = GameEvents.SmartVariablesDirtyEvent; + dirtyEvt.DomainFlags = SmartVariablesDomain.RestaurantToday; + EventBus.Broadcast(dirtyEvt); + EventBus.Broadcast(removedEvt); + } return removed; @@ -155,13 +200,13 @@ public bool TryRemoveTodayMenu(ItemViewModel model) public bool TryAddTodayCookware(ItemViewModel model) { var cookwareId = model.Id; - + if (model.HasItem == false || DataManager.Instance.GetDataSo().ContainsData(cookwareId) == false) return false; if (_cookwareToRecipeIds.Count >= MaxCookwareCount || _cookwareToRecipeIds.ContainsKey(cookwareId)) return false; - + _cookwareToRecipeIds[cookwareId] = new HashSet(); - + foreach (var recipeId in _todayFoodRecipeIds.Keys.Concat(_todayDrinkRecipeIds.Keys)) { var required = GetRequiredCookwareKey(recipeId); @@ -170,13 +215,16 @@ public bool TryAddTodayCookware(ItemViewModel model) _cookwareToRecipeIds[cookwareId].Add(recipeId); } } - + EventBus.Broadcast(RestaurantEvents.TodayMenuAddedEvent); + var dirtyEvt2 = GameEvents.SmartVariablesDirtyEvent; + dirtyEvt2.DomainFlags = SmartVariablesDomain.RestaurantToday; + EventBus.Broadcast(dirtyEvt2); return true; } - - public bool IsContainTodayMenu(string recipeId)=> _todayFoodRecipeIds.ContainsKey(recipeId) || _todayDrinkRecipeIds.ContainsKey(recipeId); + + public bool IsContainTodayMenu(string recipeId) => _todayFoodRecipeIds.ContainsKey(recipeId) || _todayDrinkRecipeIds.ContainsKey(recipeId); public bool TryRemoveTodayCookware(ItemViewModel model) { @@ -189,10 +237,13 @@ public bool TryRemoveTodayCookware(ItemViewModel model) var evt = RestaurantEvents.TodayMenuRemovedEvent; evt.InventoryCategoryType = InventoryCategoryType.Cookware; EventBus.Broadcast(evt); - + var dirtyEvt3 = GameEvents.SmartVariablesDirtyEvent; + dirtyEvt3.DomainFlags = SmartVariablesDomain.RestaurantToday; + EventBus.Broadcast(dirtyEvt3); + return true; } - + private string GetRequiredCookwareKey(string recipeId) { if (DataManager.Instance.GetDataSo().TryGetDataById(recipeId, out var recipeData) == false) return null;