Danro/Assets/Scripts/Settings/UI/TextInputSettingsBinder.cs
Danil Iarosh 2417f58f61
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
feat: Add text input system and balance management with settings improvements
- Добавлена система ввода текста через модальное окно с ячейками для аркадного автомата
- Реализован TextInputModal с поддержкой кастомных алфавитов и навигации
- Добавлен TextInputCell для ввода отдельных символов с циклической навигацией
- Создан TextInputSettingsBinder для интеграции ввода текста с системой настроек
- Реализована компактная сериализация настроек (только нужные поля в JSON)

- Внедрена система баланса игрока (BalanceManager)
- Баланс начисляется при оплате импульсом, списывается при начале/продолжении игры
- Добавлен InactivityManager для выхода в меню при отсутствии активности (5 минут)

- Улучшена система настроек
- Добавлены флаги shownInSettings и exposed для управления видимостью настроек
- Реализована автоматическая регистрация/отписка SettingsButtonBinder при активации/деактивации
- Исправлена загрузка настроек с проверкой типов через Sanitize()
- SettingsApplier упрощен - оставлена только поддержка AudioManager
- Добавлен ValueSelectorRow для выбора целочисленных значений с шагом

- Удалены примеры и документация из production кода (QUICK_SETUP.md, TextInputExample, AdvancedLoggingExample)
- Убран весь отладочный вывод Debug.Log из системы настроек и ввода текста
- Очищены неразрывные пробелы из файлов проекта
- Добавлены префабы UI (InputCell)
2026-02-11 16:27:33 +03:00

247 lines
9.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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