Add various quantity input ui for every needed feature

This commit is contained in:
HungDK
2026-05-21 17:39:47 +07:00
parent b903258b22
commit f2ab96750b
5 changed files with 1920 additions and 2 deletions
+19 -1
View File
@@ -326,6 +326,9 @@ namespace BrewMonster.UI
return null;
}
var prefab = m_dialogResouce.GetPrefabDialog(pszName);
if (prefab == null)
prefab = TryLoadDialogPrefabFallback(pszName);
if (prefab != null)
{
var instance = GameObject.Instantiate(prefab, m_canvas.transform);
@@ -336,10 +339,11 @@ namespace BrewMonster.UI
m_DlgName[pszName] = dialog;
return dialog;
}
BMLogger.LogError($"[AUIManager] Prefab '{pszName}' has no AUIDialog component on root.");
}
else
{
BMLogger.LogError($" Không tìm thấy prefab chứa dialog {pszName} ");
BMLogger.LogError($"[AUIManager] Không tìm thấy prefab dialog '{pszName}'. Add id+prefab to DialogScriptTableObject (Resources/UI/DialogScriptTableObject.asset).");
}
}
@@ -389,5 +393,19 @@ namespace BrewMonster.UI
return true;
}
/// <summary>
/// Runtime fallback when a dialog exists as prefab but is missing from DialogScriptTableObject.
/// </summary>
static GameObject TryLoadDialogPrefabFallback(string pszName)
{
if (string.IsNullOrEmpty(pszName))
return null;
#if UNITY_EDITOR
return UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>($"Assets/Prefabs/UI/{pszName}.prefab");
#else
return null;
#endif
}
}
}
@@ -0,0 +1,251 @@
using BrewMonster.Network;
using BrewMonster.Scripts;
using BrewMonster.Scripts.Managers;
using System;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace BrewMonster.UI
{
/// <summary>
/// Numeric input dialog (C++ CDlgInputNO / DlgInputNO). Dialog id: <c>DlgQuantity</c>.
/// </summary>
public class DlgQuantity : AUIDialog
{
public enum QuantityMode
{
None = 0,
/// <summary>Gửi tiền vào kho — C++ INPUTNO_STORAGE_IVTR_MONEY (Win_Inventory choosemoney + storage open).</summary>
StorageDepositMoney,
/// <summary>Rút tiền ra — C++ INPUTNO_STORAGE_TRASH_MONEY (Win_Storage choosemoney).</summary>
StorageWithdrawMoney,
}
[Header("Amount")]
[SerializeField] private TMP_InputField amountInput;
[SerializeField] private Text amountTextLegacy;
[Header("Buttons (C++: confirm / IDCANCEL / add / minus / max)")]
[SerializeField] private Button confirmButton;
[SerializeField] private Button cancelButton;
[SerializeField] private Button addButton;
[SerializeField] private Button minusButton;
[SerializeField] private Button maxButton;
private QuantityMode _mode = QuantityMode.None;
private int _min = 1;
private int _max = 1;
private int _current = 1;
private Action<int, QuantityMode> _onConfirmed;
public static DlgQuantity GetDialog()
{
return EC_Game.GetGameRun()?.GetUIManager()?.GetInGameUIMan()?.GetDialog("DlgQuantity") as DlgQuantity;
}
/// <summary>Open quantity panel; on confirm invokes callback then sends C2S when mode is storage money.</summary>
public static void Show(QuantityMode mode, int maxAmount, int defaultAmount = 1, Action<int, QuantityMode> onConfirmed = null)
{
var dlg = GetDialog();
if (dlg == null)
{
Debug.LogError("[DlgQuantity] Dialog 'DlgQuantity' not found. Add prefab to DialogScriptTableObject (id DlgQuantity).");
return;
}
CECUIManager.Instance?.ShowDialogOverlay("DlgQuantity");
dlg.Open(mode, maxAmount, defaultAmount, onConfirmed);
}
public override void Awake()
{
base.Awake();
ResolveControls();
WireButtons();
}
void ResolveControls()
{
if (amountInput == null)
{
amountInput = GetComponentInChildren<TMP_InputField>(true);
if (amountInput != null && amountInput.name.Contains("DEFAULT", StringComparison.OrdinalIgnoreCase) == false)
{
var all = GetComponentsInChildren<TMP_InputField>(true);
for (int i = 0; i < all.Length; i++)
{
if (all[i] != null && all[i].name.IndexOf("Txt_No", StringComparison.OrdinalIgnoreCase) >= 0)
{
amountInput = all[i];
break;
}
}
}
}
ResolveButton(ref confirmButton, "confirm", "btn_confirm", "ok");
ResolveButton(ref cancelButton, "cancel", "idcanel", "btn_cancel", "close");
ResolveButton(ref addButton, "add", "btn_add", "incre", "plus");
ResolveButton(ref minusButton, "minus", "btn_minus", "reduce", "decre");
ResolveButton(ref maxButton, "max", "btn_max");
}
void ResolveButton(ref Button field, params string[] nameHints)
{
if (field != null)
return;
var buttons = GetComponentsInChildren<Button>(true);
for (int i = 0; i < buttons.Length; i++)
{
var btn = buttons[i];
if (btn == null)
continue;
string n = btn.name.ToLowerInvariant();
for (int h = 0; h < nameHints.Length; h++)
{
if (n.Contains(nameHints[h]))
{
field = btn;
return;
}
}
}
}
void WireButtons()
{
if (confirmButton != null)
{
confirmButton.onClick.RemoveAllListeners();
confirmButton.onClick.AddListener(OnConfirm);
}
if (cancelButton != null)
{
cancelButton.onClick.RemoveAllListeners();
cancelButton.onClick.AddListener(OnCancel);
}
if (addButton != null)
{
addButton.onClick.RemoveAllListeners();
addButton.onClick.AddListener(OnAdd);
}
if (minusButton != null)
{
minusButton.onClick.RemoveAllListeners();
minusButton.onClick.AddListener(OnMinus);
}
if (maxButton != null)
{
maxButton.onClick.RemoveAllListeners();
maxButton.onClick.AddListener(OnMax);
}
if (amountInput != null)
{
amountInput.onValueChanged.RemoveAllListeners();
amountInput.onValueChanged.AddListener(OnAmountInputChanged);
amountInput.contentType = TMP_InputField.ContentType.IntegerNumber;
}
}
public void Open(QuantityMode mode, int maxAmount, int defaultAmount, Action<int, QuantityMode> onConfirmed)
{
_mode = mode;
_onConfirmed = onConfirmed;
_max = Mathf.Max(0, maxAmount);
_min = _max > 0 ? 1 : 0;
_current = Mathf.Clamp(defaultAmount, _min, Mathf.Max(_min, _max));
if (_max <= 0)
_current = 0;
ApplyAmountToUi();
Show(true);
}
void ApplyAmountToUi()
{
string text = _current.ToString();
if (amountInput != null)
amountInput.SetTextWithoutNotify(text);
if (amountTextLegacy != null)
amountTextLegacy.text = text;
}
int ReadAmountFromUi()
{
if (amountInput != null && int.TryParse(amountInput.text, out int v))
return v;
if (amountTextLegacy != null && int.TryParse(amountTextLegacy.text, out v))
return v;
return _current;
}
void SetAmount(int value)
{
if (_max <= 0)
{
_current = 0;
}
else
{
_current = Mathf.Clamp(value, _min, _max);
}
ApplyAmountToUi();
}
void OnAmountInputChanged(string _)
{
SetAmount(ReadAmountFromUi());
}
void OnAdd() => SetAmount(_current + 1);
void OnMinus() => SetAmount(_current - 1);
void OnMax() => SetAmount(_max);
void OnConfirm()
{
if (_max <= 0)
{
OnCancel();
return;
}
int n = ReadAmountFromUi();
if (n < _min)
n = _min;
if (n > _max)
n = _max;
if (n <= 0)
return;
ExecuteMode(n);
_onConfirmed?.Invoke(n, _mode);
Close();
}
void ExecuteMode(int amount)
{
switch (_mode)
{
case QuantityMode.StorageDepositMoney:
// C++ INPUTNO_STORAGE_IVTR_MONEY: ExgTrashBoxMoney(iTrash=0, iIvtr=amount)
UnityGameSession.c2s_CmdExgTrashBoxMoney(amount, 0);
break;
case QuantityMode.StorageWithdrawMoney:
// C++ INPUTNO_STORAGE_TRASH_MONEY: ExgTrashBoxMoney(iTrash=amount, iIvtr=0)
UnityGameSession.c2s_CmdExgTrashBoxMoney(0, amount);
break;
}
}
void OnCancel() => Close();
void Close()
{
_mode = QuantityMode.None;
_onConfirmed = null;
CECUIManager.Instance?.HideDialogOverlay("DlgQuantity");
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: dbd9eed9b75d31f44b114eb840444ae0
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 11d09ee52b0c5f24fb3ef21e177ebe2d
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: