ui 체크리스트 기능 추가

This commit is contained in:
NTG 2025-08-17 21:51:51 +09:00
parent 4b1aa5229a
commit ff66c5d94f
4 changed files with 254 additions and 71 deletions

View File

@ -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;
}
}

View File

@ -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<TodayMenuAddedEvent>, IEventHandler<TodayMenuRemovedEvent>
{
private List<ChecklistData> _checklistDatas;
private Dictionary<ChecklistLocalizationKey, string> _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<ChecklistData>(3);
_checklistDatas = GetComponentsInChildren<ChecklistData>().ToList();
foreach (var checklistData in _checklistDatas)
{
checklistData.Initialize();
}
UpdateView();
EventBus.Register<TodayMenuAddedEvent>(this);
EventBus.Register<TodayMenuRemovedEvent>(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<TodayMenuAddedEvent>(this);
EventBus.Unregister<TodayMenuRemovedEvent>(this);
}
}
}

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
using UnityEngine.InputSystem; using UnityEngine.InputSystem;
@ -9,6 +10,7 @@ namespace DDD
{ {
public class RestaurantManagementUi : PopupUi<RestaurantUiActions>, IEventHandler<TodayMenuRemovedEvent> public class RestaurantManagementUi : PopupUi<RestaurantUiActions>, IEventHandler<TodayMenuRemovedEvent>
{ {
[SerializeField] private ChecklistView _checklistView;
[SerializeField] private InventoryView _inventoryView; [SerializeField] private InventoryView _inventoryView;
[SerializeField] private ItemDetailView _itemDetailView; [SerializeField] private ItemDetailView _itemDetailView;
[SerializeField] private TabGroupUi _sectionTabs; [SerializeField] private TabGroupUi _sectionTabs;
@ -16,28 +18,28 @@ public class RestaurantManagementUi : PopupUi<RestaurantUiActions>, IEventHandle
[SerializeField] private TabGroupUi _cookwareCategoryTabs; [SerializeField] private TabGroupUi _cookwareCategoryTabs;
[SerializeField] private Image _completeBatchFilledImage; [SerializeField] private Image _completeBatchFilledImage;
[SerializeField] private float _holdCompleteTime = 1f; [SerializeField] private float _holdCompleteTime = 1f;
private float _elapsedTime; private float _elapsedTime;
private bool _isHolding; private bool _isHolding;
private const string ChecklistFailedMessageKey = "checklist_failed_message";
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
if (_isHolding) if (_isHolding)
{
UpdateHoldProgress();
}
}
private void UpdateHoldProgress()
{ {
if (_holdCompleteTime <= 0f) if (_holdCompleteTime <= 0f)
{ {
_elapsedTime = 0f;
HandleInteract2Canceled(); HandleInteract2Canceled();
var evt = GameEvents.OpenPopupUiEvent; ProcessCompleteBatchAction();
evt.UiType = typeof(ConfirmUi);
evt.IsCancelButtonVisible = true;
evt.NewMessageKey = "Global_Message_001";
evt.OnConfirm = ClosePanel;
EventBus.Broadcast(evt);
return; return;
} }
@ -46,19 +48,34 @@ protected override void Update()
var multiply = 1f / _holdCompleteTime; var multiply = 1f / _holdCompleteTime;
if (_elapsedTime >= 1f) if (_elapsedTime >= 1f)
{ {
// TODO : 추후에 체크리스트와 비교해서 팝업 띄울지 말지 결정
HandleInteract2Canceled(); HandleInteract2Canceled();
var evt = GameEvents.OpenPopupUiEvent; ProcessCompleteBatchAction();
evt.UiType = typeof(ConfirmUi);
evt.IsCancelButtonVisible = true;
evt.NewMessageKey = "Global_Message_001";
evt.OnConfirm = ClosePanel;
EventBus.Broadcast(evt);
return; return;
} }
_elapsedTime += Time.deltaTime * multiply; _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() protected override GameObject GetInitialSelected()
@ -85,18 +102,17 @@ public override void Open(OpenPopupUiEvent evt)
{ {
base.Open(evt); base.Open(evt);
_inventoryView.Initialize(); InitializeViews();
// 각 그룹별로 허용된 카테고리 설정
SetupCategoryTabs(); SetupCategoryTabs();
InitializeTabGroups();
SelectInitialTabs();
RegisterEventHandlers();
}
_sectionTabs.Initialize(OnSectionTabSelected); private void InitializeViews()
_menuCategoryTabs.Initialize(OnCategoryTabSelected); {
_cookwareCategoryTabs.Initialize(OnCategoryTabSelected); _checklistView.Initalize();
_inventoryView.Initialize();
_sectionTabs.SelectFirstTab();
_menuCategoryTabs.SelectFirstTab();
EventBus.Register<TodayMenuRemovedEvent>(this);
} }
/// <summary> /// <summary>
@ -109,6 +125,24 @@ private void SetupCategoryTabs()
_cookwareCategoryTabs.UseDefaultAllowedValues(); _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<TodayMenuRemovedEvent>(this);
}
public override void Close() public override void Close()
{ {
base.Close(); base.Close();

View File

@ -8,14 +8,17 @@ namespace DDD
{ {
public class RestaurantManagementStateSo : ScriptableObject public class RestaurantManagementStateSo : ScriptableObject
{ {
// TODO : 체크리스트 기능
// TODO : 데이터에서 초기화하고, 동적으로 변경 // TODO : 데이터에서 초기화하고, 동적으로 변경
[Title("오늘의 레스토랑 상태")] [Title("오늘의 레스토랑 상태")]
public int MaxFoodCount = 8; public int MaxFoodCount = 8;
public int MaxDrinkCount = 6; public int MaxDrinkCount = 6;
public int MaxCookwareCount = 6; public int MaxCookwareCount = 6;
[Title("체크리스트 조건")]
public int ChecklistFoodCount = 1;
public int ChecklistCookwareCount = 1;
public int ChecklistMatchedMenuWithCookwareCount = 1;
[Title("실시간 데이터")] [Title("실시간 데이터")]
[ReadOnly, SerializeField] private bool _isOpenable; [ReadOnly, SerializeField] private bool _isOpenable;
[ReadOnly, ShowInInspector] private Dictionary<string, int> _todayFoodRecipeIds = new(); [ReadOnly, ShowInInspector] private Dictionary<string, int> _todayFoodRecipeIds = new();
@ -28,6 +31,13 @@ public class RestaurantManagementStateSo : ScriptableObject
public IReadOnlyList<string> TodayWorkerIds => _todayWorkerIds; public IReadOnlyList<string> TodayWorkerIds => _todayWorkerIds;
public IReadOnlyDictionary<string, HashSet<string>> CookwareToRecipeIds => _cookwareToRecipeIds; public IReadOnlyDictionary<string, HashSet<string>> 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() public void InitializeReadyForRestaurant()
{ {
// TODO : Load from disk if possible (save data) // TODO : Load from disk if possible (save data)
@ -37,6 +47,34 @@ public void InitializeReadyForRestaurant()
_cookwareToRecipeIds.Clear(); _cookwareToRecipeIds.Clear();
} }
/// <summary>
/// 체크리스트 항목들의 상태를 확인하는 메서드
/// </summary>
/// <returns>체크리스트 완료 여부 배열 (순서: 음식레시피, 조리도구, 매칭여부)</returns>
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() public bool IsOpenable()
{ {
// TODO : 영업 가능한 상태인지 조건 추가 (최소 요리, 요리도구 배치 등) // TODO : 영업 가능한 상태인지 조건 추가 (최소 요리, 요리도구 배치 등)
@ -93,6 +131,9 @@ public bool TryAddTodayMenu(ItemViewModel model)
recipeSet.Add(recipeId); recipeSet.Add(recipeId);
} }
var dirtyEvt = GameEvents.SmartVariablesDirtyEvent;
dirtyEvt.DomainFlags = SmartVariablesDomain.RestaurantToday;
EventBus.Broadcast(dirtyEvt);
EventBus.Broadcast(RestaurantEvents.TodayMenuAddedEvent); EventBus.Broadcast(RestaurantEvents.TodayMenuAddedEvent);
} }
@ -102,7 +143,7 @@ public bool TryAddTodayMenu(ItemViewModel model)
public bool TryRemoveTodayMenu(ItemViewModel model) public bool TryRemoveTodayMenu(ItemViewModel model)
{ {
string recipeId = model.Id; string recipeId = model.Id;
var evt = RestaurantEvents.TodayMenuRemovedEvent; var removedEvt = RestaurantEvents.TodayMenuRemovedEvent;
if (DataManager.Instance.GetDataSo<RecipeDataSo>().TryGetDataById(recipeId, out RecipeData recipeData) == false) return false; if (DataManager.Instance.GetDataSo<RecipeDataSo>().TryGetDataById(recipeId, out RecipeData recipeData) == false) return false;
@ -114,7 +155,7 @@ public bool TryRemoveTodayMenu(ItemViewModel model)
if (_todayFoodRecipeIds.TryGetValue(recipeId, out refundCount)) if (_todayFoodRecipeIds.TryGetValue(recipeId, out refundCount))
{ {
removed = _todayFoodRecipeIds.Remove(recipeId); removed = _todayFoodRecipeIds.Remove(recipeId);
evt.InventoryCategoryType = InventoryCategoryType.Food; removedEvt.InventoryCategoryType = InventoryCategoryType.Food;
if (removed) if (removed)
{ {
@ -128,7 +169,7 @@ public bool TryRemoveTodayMenu(ItemViewModel model)
if (_todayDrinkRecipeIds.TryGetValue(recipeId, out refundCount)) if (_todayDrinkRecipeIds.TryGetValue(recipeId, out refundCount))
{ {
removed = _todayDrinkRecipeIds.Remove(recipeId); removed = _todayDrinkRecipeIds.Remove(recipeId);
evt.InventoryCategoryType = InventoryCategoryType.Drink; removedEvt.InventoryCategoryType = InventoryCategoryType.Drink;
if (removed) if (removed)
{ {
@ -146,7 +187,11 @@ public bool TryRemoveTodayMenu(ItemViewModel model)
recipeSet.Remove(recipeId); recipeSet.Remove(recipeId);
} }
EventBus.Broadcast(evt); var dirtyEvt = GameEvents.SmartVariablesDirtyEvent;
dirtyEvt.DomainFlags = SmartVariablesDomain.RestaurantToday;
EventBus.Broadcast(dirtyEvt);
EventBus.Broadcast(removedEvt);
} }
return removed; return removed;
@ -172,6 +217,9 @@ public bool TryAddTodayCookware(ItemViewModel model)
} }
EventBus.Broadcast(RestaurantEvents.TodayMenuAddedEvent); EventBus.Broadcast(RestaurantEvents.TodayMenuAddedEvent);
var dirtyEvt2 = GameEvents.SmartVariablesDirtyEvent;
dirtyEvt2.DomainFlags = SmartVariablesDomain.RestaurantToday;
EventBus.Broadcast(dirtyEvt2);
return true; return true;
} }
@ -189,6 +237,9 @@ public bool TryRemoveTodayCookware(ItemViewModel model)
var evt = RestaurantEvents.TodayMenuRemovedEvent; var evt = RestaurantEvents.TodayMenuRemovedEvent;
evt.InventoryCategoryType = InventoryCategoryType.Cookware; evt.InventoryCategoryType = InventoryCategoryType.Cookware;
EventBus.Broadcast(evt); EventBus.Broadcast(evt);
var dirtyEvt3 = GameEvents.SmartVariablesDirtyEvent;
dirtyEvt3.DomainFlags = SmartVariablesDomain.RestaurantToday;
EventBus.Broadcast(dirtyEvt3);
return true; return true;
} }