Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
- Добавлена система ввода текста через модальное окно с ячейками для аркадного автомата - Реализован TextInputModal с поддержкой кастомных алфавитов и навигации - Добавлен TextInputCell для ввода отдельных символов с циклической навигацией - Создан TextInputSettingsBinder для интеграции ввода текста с системой настроек - Реализована компактная сериализация настроек (только нужные поля в JSON) - Внедрена система баланса игрока (BalanceManager) - Баланс начисляется при оплате импульсом, списывается при начале/продолжении игры - Добавлен InactivityManager для выхода в меню при отсутствии активности (5 минут) - Улучшена система настроек - Добавлены флаги shownInSettings и exposed для управления видимостью настроек - Реализована автоматическая регистрация/отписка SettingsButtonBinder при активации/деактивации - Исправлена загрузка настроек с проверкой типов через Sanitize() - SettingsApplier упрощен - оставлена только поддержка AudioManager - Добавлен ValueSelectorRow для выбора целочисленных значений с шагом - Удалены примеры и документация из production кода (QUICK_SETUP.md, TextInputExample, AdvancedLoggingExample) - Убран весь отладочный вывод Debug.Log из системы настроек и ввода текста - Очищены неразрывные пробелы из файлов проекта - Добавлены префабы UI (InputCell)
247 lines
9.9 KiB
C#
247 lines
9.9 KiB
C#
using RR.Common.Settings;
|
||
using UnityEngine;
|
||
|
||
namespace RR.Common.UI
|
||
{
|
||
/// <summary>
|
||
/// Биндер для связывания кнопки настроек с модальным окном ввода текста.
|
||
/// При нажатии кнопки открывает TextInputModal с текущим значением настройки,
|
||
/// при подтверждении ввода сохраняет новое значение в настройку.
|
||
///
|
||
/// ИСПОЛЬЗОВАНИЕ:
|
||
/// 1. Создайте в MainSettingsDatabase настройку типа String (например, "prize.description")
|
||
/// 2. На объект с SettingsButtonBinder добавьте компонент TextInputSettingsBinder
|
||
/// 3. Укажите ссылку на TextInputModal (должен быть в сцене)
|
||
/// 4. Настройте параметры:
|
||
/// - settingKey: ключ настройки (если пусто, используется ключ кнопки)
|
||
/// - modalTitle: заголовок окна ввода
|
||
/// - maxLength: максимальная длина текста
|
||
/// - customAlphabet: кастомный алфавит (опционально)
|
||
/// 5. При нажатии кнопки в настройках автоматически откроется окно ввода
|
||
/// 6. При подтверждении ввода значение сохранится в настройку
|
||
///
|
||
/// ПРИМЕР НАСТРОЙКИ В MainSettingsDatabase:
|
||
/// {
|
||
/// "key": "prize.phoneNumber",
|
||
/// "displayName": "Номер телефона",
|
||
/// "description": "Введите номер телефона для связи",
|
||
/// "group": "Prizes",
|
||
/// "valueType": "String",
|
||
/// "defaultString": "",
|
||
/// "shownInSettings": true,
|
||
/// "exposed": true
|
||
/// }
|
||
/// </summary>
|
||
[RequireComponent(typeof(SettingsButtonBinder))]
|
||
public class TextInputSettingsBinder : MonoBehaviour
|
||
{
|
||
[Header("Text Input Settings")]
|
||
[Tooltip("Ключ настройки для сохранения/загрузки значения")]
|
||
[SerializeField] private string settingKey;
|
||
|
||
[Tooltip("Ссылка на модальное окно ввода текста")]
|
||
[SerializeField] private TextInputModal textInputModal;
|
||
|
||
[Header("Modal Settings")]
|
||
[Tooltip("Заголовок модального окна")]
|
||
[SerializeField] private string modalTitle = "Введите текст";
|
||
|
||
[Tooltip("Максимальная длина текста (количество ячеек)")]
|
||
[SerializeField] private int maxLength = 10;
|
||
|
||
[Tooltip("Алфавит для ввода (если пусто - использует дефолтный)")]
|
||
[SerializeField] private string[] customAlphabet;
|
||
|
||
private SettingsButtonBinder buttonBinder;
|
||
private SettingEntry settingEntry;
|
||
|
||
private void Awake()
|
||
{
|
||
buttonBinder = GetComponent<SettingsButtonBinder>();
|
||
|
||
// Если ключ настройки не задан, используем ключ кнопки
|
||
if (string.IsNullOrWhiteSpace(settingKey))
|
||
{
|
||
settingKey = buttonBinder.Key;
|
||
}
|
||
|
||
Debug.Log($"[TextInputSettingsBinder] settingKey: '{settingKey}'");
|
||
|
||
// Если TextInputModal не назначен, ищем его на сцене
|
||
if (textInputModal == null)
|
||
{
|
||
textInputModal = FindFirstObjectByType<TextInputModal>();
|
||
|
||
if (textInputModal == null)
|
||
{
|
||
Debug.LogError("[TextInputSettingsBinder] TextInputModal not found in scene! Please add TextInputModal to the scene or assign it manually.", this);
|
||
}
|
||
else
|
||
{
|
||
Debug.Log($"[TextInputSettingsBinder] Found TextInputModal on scene: {textInputModal.name}");
|
||
}
|
||
}
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
if (string.IsNullOrWhiteSpace(settingKey))
|
||
{
|
||
Debug.LogError("[TextInputSettingsBinder] Setting key is not set!", this);
|
||
return;
|
||
}
|
||
|
||
// Получаем определение настройки
|
||
if (SettingsManager.Instance)
|
||
{
|
||
settingEntry = SettingsManager.Instance.Define(settingKey);
|
||
|
||
if (settingEntry == null)
|
||
{
|
||
Debug.LogWarning($"[TextInputSettingsBinder] Setting '{settingKey}' not found in SettingsManager!");
|
||
}
|
||
}
|
||
}
|
||
|
||
private void OnEnable()
|
||
{
|
||
if (textInputModal != null)
|
||
{
|
||
textInputModal.OnTextConfirmed += OnTextConfirmed;
|
||
textInputModal.OnTextCancelled += OnTextCancelled;
|
||
}
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
if (textInputModal != null)
|
||
{
|
||
textInputModal.OnTextConfirmed -= OnTextConfirmed;
|
||
textInputModal.OnTextCancelled -= OnTextCancelled;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Открывает модальное окно ввода текста с текущим значением настройки
|
||
/// </summary>
|
||
public void OpenTextInput()
|
||
{
|
||
if (textInputModal == null)
|
||
{
|
||
Debug.LogError("[TextInputSettingsBinder] TextInputModal is not assigned!", this);
|
||
return;
|
||
}
|
||
|
||
// Загружаем текущее значение из настройки
|
||
string currentValue = LoadCurrentValue();
|
||
|
||
// ВАЖНО: Порядок вызовов:
|
||
// 1. Сначала устанавливаем алфавит (если задан)
|
||
if (customAlphabet != null && customAlphabet.Length > 0)
|
||
{
|
||
textInputModal.SetAlphabet(customAlphabet);
|
||
}
|
||
|
||
// 2. Потом устанавливаем количество ячеек (это создаст ячейки с сохраненным текстом)
|
||
if (maxLength > 0)
|
||
{
|
||
textInputModal.SetCellCount(maxLength);
|
||
}
|
||
|
||
// 3. Открываем модалку с текущим значением (ячейки уже созданы, просто обновим значения)
|
||
textInputModal.OpenForInput(modalTitle, currentValue);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Загружает текущее значение настройки
|
||
/// </summary>
|
||
private string LoadCurrentValue()
|
||
{
|
||
if (SettingsManager.Instance == null)
|
||
{
|
||
Debug.LogWarning("[TextInputSettingsBinder] SettingsManager is not available!");
|
||
return "";
|
||
}
|
||
|
||
// Проверяем, существует ли настройка
|
||
var entry = SettingsManager.Instance.Define(settingKey);
|
||
if (entry == null)
|
||
{
|
||
Debug.LogWarning($"[TextInputSettingsBinder] Setting '{settingKey}' not found!");
|
||
return "";
|
||
}
|
||
|
||
// Пытаемся загрузить значение как строку
|
||
try
|
||
{
|
||
string value = SettingsManager.Instance.GetString(settingKey);
|
||
return value ?? "";
|
||
}
|
||
catch (System.Exception ex)
|
||
{
|
||
Debug.LogWarning($"[TextInputSettingsBinder] Failed to load value for '{settingKey}': {ex.Message}");
|
||
return "";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Вызывается при подтверждении ввода текста
|
||
/// </summary>
|
||
private void OnTextConfirmed(string text)
|
||
{
|
||
if (SettingsManager.Instance == null)
|
||
{
|
||
Debug.LogError("[TextInputSettingsBinder] SettingsManager is not available!");
|
||
return;
|
||
}
|
||
|
||
// Сохраняем значение в настройку
|
||
SettingsManager.Instance.SetString(settingKey, text);
|
||
|
||
// Автоматически сохраняем настройки на диск
|
||
SettingsManager.Instance.SaveSettings();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Вызывается при отмене ввода текста
|
||
/// </summary>
|
||
private void OnTextCancelled()
|
||
{
|
||
// Ничего не делаем при отмене
|
||
}
|
||
|
||
/// <summary>
|
||
/// Устанавливает заголовок модального окна
|
||
/// </summary>
|
||
public void SetModalTitle(string title)
|
||
{
|
||
modalTitle = title;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Устанавливает максимальную длину текста
|
||
/// </summary>
|
||
public void SetMaxLength(int length)
|
||
{
|
||
maxLength = length;
|
||
if (textInputModal != null)
|
||
{
|
||
textInputModal.SetCellCount(length);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Устанавливает пользовательский алфавит
|
||
/// </summary>
|
||
public void SetCustomAlphabet(string[] alphabet)
|
||
{
|
||
customAlphabet = alphabet;
|
||
if (textInputModal != null && alphabet != null && alphabet.Length > 0)
|
||
{
|
||
textInputModal.SetAlphabet(alphabet);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|