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.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
@ -9,6 +10,7 @@ namespace DDD
{
public class RestaurantManagementUi : PopupUi<RestaurantUiActions>, IEventHandler<TodayMenuRemovedEvent>
{
[SerializeField] private ChecklistView _checklistView;
[SerializeField] private InventoryView _inventoryView;
[SerializeField] private ItemDetailView _itemDetailView;
[SerializeField] private TabGroupUi _sectionTabs;
@ -16,51 +18,66 @@ public class RestaurantManagementUi : PopupUi<RestaurantUiActions>, 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();
@ -85,18 +102,17 @@ public override void Open(OpenPopupUiEvent evt)
{
base.Open(evt);
_inventoryView.Initialize();
// 각 그룹별로 허용된 카테고리 설정
InitializeViews();
SetupCategoryTabs();
InitializeTabGroups();
SelectInitialTabs();
RegisterEventHandlers();
}
_sectionTabs.Initialize(OnSectionTabSelected);
_menuCategoryTabs.Initialize(OnCategoryTabSelected);
_cookwareCategoryTabs.Initialize(OnCategoryTabSelected);
_sectionTabs.SelectFirstTab();
_menuCategoryTabs.SelectFirstTab();
EventBus.Register<TodayMenuRemovedEvent>(this);
private void InitializeViews()
{
_checklistView.Initalize();
_inventoryView.Initialize();
}
/// <summary>
@ -109,6 +125,24 @@ 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<TodayMenuRemovedEvent>(this);
}
public override void Close()
{
base.Close();

View File

@ -8,14 +8,17 @@ 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<string, int> _todayFoodRecipeIds = new();
@ -28,6 +31,13 @@ public class RestaurantManagementStateSo : ScriptableObject
public IReadOnlyList<string> TodayWorkerIds => _todayWorkerIds;
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()
{
// TODO : Load from disk if possible (save data)
@ -37,6 +47,34 @@ public void InitializeReadyForRestaurant()
_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()
{
// TODO : 영업 가능한 상태인지 조건 추가 (최소 요리, 요리도구 배치 등)
@ -93,6 +131,9 @@ 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<RecipeDataSo>().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;
@ -172,11 +217,14 @@ public bool TryAddTodayCookware(ItemViewModel model)
}
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,6 +237,9 @@ 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;
}