Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
- завершен спринт 24 марта - 2 апреля с опережением плана и закрытием задач раньше срока - расширена и стабилизирована система призов: добавлены и доработаны QR-tier конфиги, новые типы и модели данных, сохранение `qrCodes` в `prizes.json`, fallback-логика и синхронизация через `PrizeSystemManager`, `PrizeDatabase` и `LevelPrizeConfig` - переработан flow настройки QR-призов: добавлены `QRCodeSettingsModal` и связанный UI-код, разнесены короткий текст приза и полный текст сообщения, добавлены шаблоны форматирования, корректная подстановка текста в QR и в UI-модалках, а также сохранение конфигурации между запусками - доработан flow суперприза и текстовых настроек: добавлены fallback-правила показа, корректная обработка пустых строк и строк из одних пробелов, обновлены binders и показ текста в меню - реализована и обновлена отдельная настройка витрины: добавлена `PrizeStandSettingsModal`, обновлена навигация строк, логика выбора ячейки и порогов очков, циклический выбор ячеек, ускорение изменения значений и исправления для keyboard/gamepad UX - доработана игровая модалка витрины `PrizeStandModal`: добавлен вывод очков игрока, форматируемый текст счета, улучшено отображение ячеек и связанная логика выбора приза - исправлен подсчет очков и интеграция с prize flow: `ScoreSystem` переведен на событийное обновление текущего счета, добавлены `CurrentScore`, `CurrentScoreChanged` и корректный display score, витрина и связанные UI-элементы теперь получают актуальные очки, а не нулевые или несвоевременные preview-значения - переработаны модальные окна и навигация UI: улучшены `Modal`, `ModalManager`, `UIRowPointer`, `RulesModal`, `QRCodeModal`, `PrizeStandModal`, `LevelPrizeSettingsModal` и др., чтобы фокус, указатель и submit работали консистентно без мыши - обновлен win/prize UI: доработаны `WinBannerController`, `GameEndUIController`, `MainMenu`, `QRCodeUIController`, `TopPanelTextController` и настройки UI, улучшены тексты баннеров, отображение призов и итогового счета - обновлены сцены и ассеты под новый flow: `MainMenu`, `Level UI`, prefab'ы строк настроек и кнопок, глобальные префабы, шрифты TMP, иконки, recovery-данные и ресурсы UI - добавлены вспомогательные UI-компоненты и служебные скрипты: `ButtonTextFocusColor`, `SelectableDescriptionTarget`, `QRTier` и другие изменения, поддерживающие новый конфигурируемый prize UI
682 lines
21 KiB
C#
682 lines
21 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Reflection;
|
||
using TMPro;
|
||
using UnityEngine;
|
||
using UnityEngine.EventSystems;
|
||
using UnityEngine.InputSystem;
|
||
using UnityEngine.UI;
|
||
using RR.Common.Managers;
|
||
using RR.Common.Prizes;
|
||
using RR.Common.Utility;
|
||
|
||
namespace RR.Common.UI
|
||
{
|
||
/// <summary>
|
||
/// Отдельная модалка глобальной настройки QR-кодов по градациям.
|
||
/// Не привязана к уровням: уровень выбирает только qrTier в LevelPrizeSettingsModal.
|
||
/// </summary>
|
||
public class QRCodeSettingsModal : Modal
|
||
{
|
||
[Header("UI")]
|
||
[SerializeField] private TMP_Text titleText;
|
||
[SerializeField] private TMP_Text tierLabel;
|
||
[SerializeField] private TMP_Text prizeTextLabel;
|
||
[SerializeField] private Button editPrizeTextButton;
|
||
[SerializeField] private TextInputModal textInputModal;
|
||
|
||
[Header("Rows")]
|
||
[SerializeField] private RectTransform tierRow;
|
||
[SerializeField] private RectTransform prizeTextRow;
|
||
|
||
[Header("Pointer")]
|
||
[SerializeField] private UIRowPointer rowPointer;
|
||
|
||
[Header("Close")]
|
||
[SerializeField] private Button closeModalButton;
|
||
|
||
[Header("Navigation")]
|
||
[SerializeField] private InputActionReference navigateAction;
|
||
[SerializeField] private InputActionReference submitAction;
|
||
[SerializeField] private float deadZone = 0.5f;
|
||
|
||
[Header("Behaviour")]
|
||
[SerializeField] private bool createEntryIfMissing = true;
|
||
[SerializeField] private string prizeTextModalTitle = "Введите текст приза QR";
|
||
[SerializeField] private int prizeTextMaxLength = 12;
|
||
|
||
private static readonly QRTier[] EditableTiers = { QRTier.Bronze, QRTier.Silver, QRTier.Gold };
|
||
private const int MaxPrizeTextLength = 12;
|
||
private const int RowTier = 0;
|
||
private const int RowPrizeText = 1;
|
||
private const int RowClose = 2;
|
||
private const int RowCount = 3;
|
||
|
||
private PrizeSystemManager _manager;
|
||
private List<QRCodeInfo> _workingEntries;
|
||
private int _currentTierIndex;
|
||
private int _activeRow;
|
||
private string _currentPrizeText = string.Empty;
|
||
private bool _axisHeldX;
|
||
private bool _axisHeldY;
|
||
private bool _isPrizeTextInputOpen;
|
||
private Selectable _pendingFocusTarget;
|
||
private int _pendingFocusFrames;
|
||
private Selectable _tierRowSelectable;
|
||
private Selectable _prizeTextRowSelectable;
|
||
private RectTransform _prizeTextPointerTarget;
|
||
|
||
protected override void Awake()
|
||
{
|
||
base.Awake();
|
||
|
||
if (editPrizeTextButton != null)
|
||
{
|
||
Graphic buttonGraphic = editPrizeTextButton.GetComponent<Graphic>();
|
||
if (buttonGraphic != null)
|
||
{
|
||
editPrizeTextButton.targetGraphic = buttonGraphic;
|
||
}
|
||
|
||
editPrizeTextButton.onClick.AddListener(OpenPrizeTextInput);
|
||
}
|
||
|
||
if (textInputModal == null)
|
||
{
|
||
textInputModal = FindFirstObjectByType<TextInputModal>(FindObjectsInactive.Include);
|
||
}
|
||
}
|
||
|
||
protected override void OnEnable()
|
||
{
|
||
base.OnEnable();
|
||
|
||
if (navigateAction != null && navigateAction.action != null)
|
||
{
|
||
navigateAction.action.Enable();
|
||
}
|
||
}
|
||
|
||
protected override void OnDisable()
|
||
{
|
||
_isPrizeTextInputOpen = false;
|
||
_pendingFocusTarget = null;
|
||
_pendingFocusFrames = 0;
|
||
_axisHeldX = false;
|
||
_axisHeldY = false;
|
||
base.OnDisable();
|
||
}
|
||
|
||
protected override void OnReturnedToTop()
|
||
{
|
||
_isPrizeTextInputOpen = false;
|
||
_pendingFocusTarget = null;
|
||
_pendingFocusFrames = 0;
|
||
_axisHeldX = false;
|
||
_axisHeldY = false;
|
||
RefreshRowHighlights();
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
if (editPrizeTextButton != null)
|
||
{
|
||
editPrizeTextButton.onClick.RemoveListener(OpenPrizeTextInput);
|
||
}
|
||
|
||
if (textInputModal != null)
|
||
{
|
||
textInputModal.OnTextConfirmed -= OnPrizeTextConfirmed;
|
||
textInputModal.OnTextCancelled -= OnPrizeTextCancelled;
|
||
}
|
||
}
|
||
|
||
public override void Open()
|
||
{
|
||
PrepareForEditing();
|
||
base.Open();
|
||
RefreshRowHighlights();
|
||
}
|
||
|
||
public void OpenForEditing()
|
||
{
|
||
Open();
|
||
}
|
||
|
||
public override void Close()
|
||
{
|
||
Save();
|
||
base.Close();
|
||
}
|
||
|
||
private void Save()
|
||
{
|
||
ApplyCurrentFieldValues();
|
||
|
||
if (_manager == null)
|
||
{
|
||
Debug.LogWarning("[QRCodeSettingsModal] PrizeSystemManager не найден.");
|
||
return;
|
||
}
|
||
|
||
_manager.SetQRCodeConfigs(_workingEntries);
|
||
}
|
||
|
||
private void PrepareForEditing()
|
||
{
|
||
_manager = PrizeSystemManager.Instance;
|
||
_workingEntries = _manager != null ? _manager.GetQRCodeConfigs() : new List<QRCodeInfo>();
|
||
|
||
_currentTierIndex = Mathf.Clamp(_currentTierIndex, 0, EditableTiers.Length - 1);
|
||
_activeRow = RowTier;
|
||
AutoResolveRows();
|
||
EnsureRowSelectables();
|
||
LoadCurrentTierIntoFields();
|
||
RefreshRowHighlights();
|
||
}
|
||
|
||
private void ProcessNavigationInput()
|
||
{
|
||
if (navigateAction == null || navigateAction.action == null)
|
||
{
|
||
_axisHeldX = false;
|
||
_axisHeldY = false;
|
||
return;
|
||
}
|
||
|
||
Vector2 value = navigateAction.action.ReadValue<Vector2>();
|
||
|
||
if (Mathf.Abs(value.y) >= deadZone)
|
||
{
|
||
if (!_axisHeldY)
|
||
{
|
||
_axisHeldY = true;
|
||
MoveRow(value.y > 0f ? -1 : 1);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_axisHeldY = false;
|
||
}
|
||
|
||
if (Mathf.Abs(value.x) >= deadZone)
|
||
{
|
||
if (!_axisHeldX)
|
||
{
|
||
_axisHeldX = true;
|
||
HandleLeftRight(value.x > 0f ? 1 : -1);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_axisHeldX = false;
|
||
}
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
if (!_isOpen || _isPrizeTextInputOpen)
|
||
{
|
||
return;
|
||
}
|
||
|
||
ProcessNavigationInput();
|
||
HandleSubmit();
|
||
}
|
||
|
||
private void LateUpdate()
|
||
{
|
||
if (!_isOpen || _isPrizeTextInputOpen)
|
||
{
|
||
return;
|
||
}
|
||
|
||
ApplyPendingFocus();
|
||
}
|
||
|
||
private void MoveRow(int delta)
|
||
{
|
||
_activeRow = (_activeRow + delta + RowCount) % RowCount;
|
||
RefreshRowHighlights();
|
||
}
|
||
|
||
private void HandleLeftRight(int direction)
|
||
{
|
||
if (_activeRow != RowTier)
|
||
return;
|
||
|
||
ApplyCurrentFieldValues();
|
||
_currentTierIndex = (_currentTierIndex + direction + EditableTiers.Length) % EditableTiers.Length;
|
||
LoadCurrentTierIntoFields();
|
||
RefreshRowHighlights();
|
||
}
|
||
|
||
private void LoadCurrentTierIntoFields()
|
||
{
|
||
if (titleText != null)
|
||
{
|
||
titleText.text = $"Настройки QR: {GetTierName(CurrentTier)}";
|
||
}
|
||
|
||
if (tierLabel != null)
|
||
{
|
||
tierLabel.text = GetTierName(CurrentTier);
|
||
}
|
||
|
||
List<QRCodeInfo> entries = GetEntriesForTier(CurrentTier, includeFallbackTemplates: false);
|
||
_currentPrizeText = ResolveDisplayedPrizeText(entries);
|
||
UpdatePrizeTextLabel(_currentPrizeText);
|
||
}
|
||
|
||
private void ApplyCurrentFieldValues()
|
||
{
|
||
if (_workingEntries == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
_currentPrizeText = NormalizePrizeText(_currentPrizeText);
|
||
|
||
List<int> tierIndices = GetEntryIndicesForTier(CurrentTier);
|
||
if (tierIndices.Count > 0)
|
||
{
|
||
for (int i = 0; i < tierIndices.Count; i++)
|
||
{
|
||
int index = tierIndices[i];
|
||
QRCodeInfo info = _workingEntries[index];
|
||
info.tier = CurrentTier;
|
||
info.prizeText = _currentPrizeText;
|
||
_workingEntries[index] = info;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
if (!createEntryIfMissing)
|
||
{
|
||
return;
|
||
}
|
||
|
||
List<QRCodeInfo> templateEntries = GetEntriesForTier(QRTier.None, includeFallbackTemplates: false);
|
||
if (templateEntries.Count == 0)
|
||
{
|
||
templateEntries.Add(CreateDefaultEntry(CurrentTier));
|
||
}
|
||
|
||
for (int i = 0; i < templateEntries.Count; i++)
|
||
{
|
||
QRCodeInfo clone = templateEntries[i];
|
||
clone.tier = CurrentTier;
|
||
clone.prizeText = _currentPrizeText;
|
||
_workingEntries.Add(clone);
|
||
}
|
||
}
|
||
|
||
private static QRCodeInfo CreateDefaultEntry(QRTier tier)
|
||
{
|
||
return new QRCodeInfo
|
||
{
|
||
tier = tier,
|
||
generateQRCode = true,
|
||
linkPrefix = string.Empty,
|
||
messageFormat = "{0}",
|
||
prizeText = string.Empty,
|
||
darkColor = new Vector3(0f, 0f, 0f),
|
||
lightColor = new Vector3(1f, 1f, 1f)
|
||
};
|
||
}
|
||
|
||
private void OpenPrizeTextInput()
|
||
{
|
||
if (textInputModal == null)
|
||
{
|
||
Debug.LogWarning("[QRCodeSettingsModal] TextInputModal не назначен.");
|
||
return;
|
||
}
|
||
|
||
_isPrizeTextInputOpen = true;
|
||
FocusSelectable(_prizeTextRowSelectable != null ? _prizeTextRowSelectable : editPrizeTextButton);
|
||
|
||
textInputModal.OnTextConfirmed -= OnPrizeTextConfirmed;
|
||
textInputModal.OnTextCancelled -= OnPrizeTextCancelled;
|
||
textInputModal.OnTextConfirmed += OnPrizeTextConfirmed;
|
||
textInputModal.OnTextCancelled += OnPrizeTextCancelled;
|
||
|
||
_currentPrizeText = NormalizePrizeText(_currentPrizeText);
|
||
textInputModal.SetAlphabet(TextInputAlphabets.RussianPrizeText);
|
||
textInputModal.SetCellCount(GetPrizeTextCellCount());
|
||
textInputModal.OpenForInput(prizeTextModalTitle, _currentPrizeText);
|
||
}
|
||
|
||
public void OpenPrizeTextEditor()
|
||
{
|
||
OpenPrizeTextInput();
|
||
}
|
||
|
||
private void OnPrizeTextConfirmed(string text)
|
||
{
|
||
_isPrizeTextInputOpen = false;
|
||
|
||
if (textInputModal != null)
|
||
{
|
||
textInputModal.OnTextConfirmed -= OnPrizeTextConfirmed;
|
||
textInputModal.OnTextCancelled -= OnPrizeTextCancelled;
|
||
}
|
||
|
||
_currentPrizeText = NormalizePrizeText(text);
|
||
UpdatePrizeTextLabel(_currentPrizeText);
|
||
FocusSelectable(_prizeTextRowSelectable != null ? _prizeTextRowSelectable : editPrizeTextButton);
|
||
}
|
||
|
||
private void OnPrizeTextCancelled()
|
||
{
|
||
_isPrizeTextInputOpen = false;
|
||
|
||
if (textInputModal != null)
|
||
{
|
||
textInputModal.OnTextConfirmed -= OnPrizeTextConfirmed;
|
||
textInputModal.OnTextCancelled -= OnPrizeTextCancelled;
|
||
}
|
||
|
||
FocusSelectable(_prizeTextRowSelectable != null ? _prizeTextRowSelectable : editPrizeTextButton);
|
||
}
|
||
|
||
private void UpdatePrizeTextLabel(string text)
|
||
{
|
||
if (prizeTextLabel != null)
|
||
{
|
||
string normalized = NormalizePrizeText(text);
|
||
prizeTextLabel.text = string.IsNullOrWhiteSpace(normalized) ? "<пусто>" : normalized;
|
||
}
|
||
}
|
||
|
||
private void RefreshRowHighlights()
|
||
{
|
||
RectTransform target = GetActiveRowTransform();
|
||
Selectable selectableToFocus = null;
|
||
|
||
switch (_activeRow)
|
||
{
|
||
case RowTier:
|
||
selectableToFocus = _tierRowSelectable;
|
||
break;
|
||
case RowPrizeText:
|
||
selectableToFocus = _prizeTextRowSelectable;
|
||
break;
|
||
case RowClose:
|
||
selectableToFocus = closeModalButton;
|
||
break;
|
||
}
|
||
|
||
if (_activeRow == RowClose)
|
||
{
|
||
if (rowPointer != null)
|
||
{
|
||
rowPointer.Hide();
|
||
}
|
||
}
|
||
else if (rowPointer != null && target != null)
|
||
{
|
||
rowPointer.SetTarget(target);
|
||
}
|
||
|
||
FocusSelectable(selectableToFocus);
|
||
}
|
||
|
||
private void AutoResolveRows()
|
||
{
|
||
if (tierRow == null && tierLabel != null)
|
||
{
|
||
tierRow = tierLabel.transform.parent as RectTransform;
|
||
}
|
||
|
||
if (prizeTextRow == null)
|
||
{
|
||
if (prizeTextLabel != null)
|
||
prizeTextRow = prizeTextLabel.transform.parent as RectTransform;
|
||
else if (editPrizeTextButton != null)
|
||
prizeTextRow = editPrizeTextButton.transform.parent as RectTransform;
|
||
}
|
||
|
||
_prizeTextPointerTarget = ResolvePrizeTextPointerTarget();
|
||
}
|
||
|
||
private QRTier CurrentTier => EditableTiers[Mathf.Clamp(_currentTierIndex, 0, EditableTiers.Length - 1)];
|
||
|
||
private static string GetTierName(QRTier tier)
|
||
{
|
||
return tier switch
|
||
{
|
||
QRTier.Bronze => "Бронзовый",
|
||
QRTier.Silver => "Серебряный",
|
||
QRTier.Gold => "Золотой",
|
||
_ => "Не задан"
|
||
};
|
||
}
|
||
|
||
private List<QRCodeInfo> GetEntriesForTier(QRTier tier, bool includeFallbackTemplates)
|
||
{
|
||
List<QRCodeInfo> result = new();
|
||
if (_workingEntries == null)
|
||
return result;
|
||
|
||
for (int i = 0; i < _workingEntries.Count; i++)
|
||
{
|
||
if (_workingEntries[i].tier == tier)
|
||
result.Add(_workingEntries[i]);
|
||
}
|
||
|
||
if (result.Count == 0 && includeFallbackTemplates && tier != QRTier.None)
|
||
{
|
||
for (int i = 0; i < _workingEntries.Count; i++)
|
||
{
|
||
if (_workingEntries[i].tier == QRTier.None)
|
||
result.Add(_workingEntries[i]);
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
private List<int> GetEntryIndicesForTier(QRTier tier)
|
||
{
|
||
List<int> result = new();
|
||
if (_workingEntries == null)
|
||
return result;
|
||
|
||
for (int i = 0; i < _workingEntries.Count; i++)
|
||
{
|
||
if (_workingEntries[i].tier == tier)
|
||
result.Add(i);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
private string ResolveDisplayedPrizeText(List<QRCodeInfo> tierEntries)
|
||
{
|
||
if (tierEntries == null || tierEntries.Count == 0)
|
||
return string.Empty;
|
||
|
||
for (int i = 0; i < tierEntries.Count; i++)
|
||
{
|
||
string candidate = NormalizePrizeText(tierEntries[i].prizeText);
|
||
if (!string.IsNullOrWhiteSpace(candidate))
|
||
return candidate;
|
||
}
|
||
|
||
return string.Empty;
|
||
}
|
||
|
||
private int GetPrizeTextCellCount()
|
||
{
|
||
return Mathf.Clamp(prizeTextMaxLength, 1, MaxPrizeTextLength);
|
||
}
|
||
|
||
private RectTransform GetActiveRowTransform()
|
||
{
|
||
return _activeRow switch
|
||
{
|
||
RowTier => tierRow,
|
||
RowPrizeText => _prizeTextPointerTarget,
|
||
_ => null
|
||
};
|
||
}
|
||
|
||
private void EnsureRowSelectables()
|
||
{
|
||
_tierRowSelectable = EnsureRowSelectable(tierRow);
|
||
_prizeTextRowSelectable = editPrizeTextButton != null
|
||
? editPrizeTextButton
|
||
: EnsureRowSelectable(_prizeTextPointerTarget);
|
||
}
|
||
|
||
private RectTransform ResolvePrizeTextPointerTarget()
|
||
{
|
||
if (editPrizeTextButton != null)
|
||
{
|
||
RectTransform buttonRect = editPrizeTextButton.transform as RectTransform;
|
||
if (buttonRect != null)
|
||
{
|
||
return buttonRect;
|
||
}
|
||
}
|
||
|
||
if (prizeTextRow != null)
|
||
{
|
||
return prizeTextRow;
|
||
}
|
||
|
||
return prizeTextLabel != null ? prizeTextLabel.transform.parent as RectTransform : null;
|
||
}
|
||
|
||
private Selectable EnsureRowSelectable(RectTransform row)
|
||
{
|
||
if (row == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
Selectable selectable = row.GetComponent<Selectable>();
|
||
if (selectable == null)
|
||
{
|
||
selectable = row.gameObject.AddComponent<Selectable>();
|
||
selectable.transition = Selectable.Transition.None;
|
||
selectable.navigation = new Navigation { mode = Navigation.Mode.None };
|
||
}
|
||
|
||
selectable.interactable = true;
|
||
return selectable;
|
||
}
|
||
|
||
private void FocusSelectable(Selectable selectable)
|
||
{
|
||
if (selectable == null || !selectable.gameObject.activeInHierarchy)
|
||
{
|
||
return;
|
||
}
|
||
|
||
SetFirstSelected(selectable);
|
||
_pendingFocusTarget = selectable;
|
||
_pendingFocusFrames = 2;
|
||
ApplyPendingFocus();
|
||
}
|
||
|
||
private void ApplyPendingFocus()
|
||
{
|
||
if (_pendingFocusTarget == null || _pendingFocusFrames <= 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (EventSystem.current == null || !_pendingFocusTarget.gameObject.activeInHierarchy)
|
||
{
|
||
_pendingFocusTarget = null;
|
||
_pendingFocusFrames = 0;
|
||
return;
|
||
}
|
||
|
||
if (EventSystem.current.currentSelectedGameObject != _pendingFocusTarget.gameObject)
|
||
{
|
||
EventSystem.current.SetSelectedGameObject(null);
|
||
EventSystem.current.SetSelectedGameObject(_pendingFocusTarget.gameObject);
|
||
_pendingFocusTarget.Select();
|
||
}
|
||
|
||
_pendingFocusFrames--;
|
||
if (_pendingFocusFrames <= 0)
|
||
{
|
||
_pendingFocusTarget = null;
|
||
}
|
||
}
|
||
|
||
private void HandleSubmit()
|
||
{
|
||
InputAction currentSubmitAction = GetSubmitAction();
|
||
if (currentSubmitAction == null || !currentSubmitAction.WasPerformedThisFrame())
|
||
{
|
||
return;
|
||
}
|
||
|
||
GameObject selectedObject = EventSystem.current != null ? EventSystem.current.currentSelectedGameObject : null;
|
||
|
||
switch (_activeRow)
|
||
{
|
||
case RowPrizeText:
|
||
if (selectedObject == editPrizeTextButton?.gameObject)
|
||
{
|
||
return;
|
||
}
|
||
|
||
OpenPrizeTextInput();
|
||
break;
|
||
case RowClose:
|
||
if (selectedObject == closeModalButton?.gameObject)
|
||
{
|
||
return;
|
||
}
|
||
|
||
Close();
|
||
break;
|
||
}
|
||
}
|
||
|
||
private InputAction GetSubmitAction()
|
||
{
|
||
if (submitAction != null && submitAction.action != null)
|
||
{
|
||
return submitAction.action;
|
||
}
|
||
|
||
if (EventSystem.current?.currentInputModule == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
object inputModule = EventSystem.current.currentInputModule;
|
||
PropertyInfo submitProperty = inputModule.GetType().GetProperty("submit", BindingFlags.Instance | BindingFlags.Public);
|
||
object submitObject = submitProperty != null ? submitProperty.GetValue(inputModule) : null;
|
||
InputActionReference submitReference = submitObject as InputActionReference;
|
||
return submitReference != null ? submitReference.action : null;
|
||
}
|
||
|
||
private string NormalizePrizeText(string text)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(text))
|
||
{
|
||
return string.Empty;
|
||
}
|
||
|
||
string normalized = text.Trim();
|
||
int maxLength = GetPrizeTextCellCount();
|
||
if (normalized.Length > maxLength)
|
||
{
|
||
normalized = normalized.Substring(0, maxLength);
|
||
}
|
||
|
||
return normalized;
|
||
}
|
||
|
||
}
|
||
}
|