From 723f4446f5c566ae84994cf2a1f6cd1f715d61dfcf9c85b0a443830be7a0bd85 Mon Sep 17 00:00:00 2001 From: copecone Date: Sat, 10 Oct 2026 16:28:00 +0900 Subject: [PATCH] Add Two-Step Confirmation for Preset Deletion in `RenderConfigWindow` --- Localization/Locale/en.json | 1 + Localization/Locale/ko.json | 1 + UI/Window/RenderConfigWindow.cs | 92 ++++++++++++++++++++++++++------- 3 files changed, 76 insertions(+), 18 deletions(-) diff --git a/Localization/Locale/en.json b/Localization/Locale/en.json index dd18ac8..033d9d8 100644 --- a/Localization/Locale/en.json +++ b/Localization/Locale/en.json @@ -5,6 +5,7 @@ "ui.render_config.preset_name_placeholder": "New preset name...", "ui.render_config.preset_save": "Save", "ui.render_config.preset_delete": "Delete", + "ui.render_config.preset_delete_confirm": "Confirm?", "ui.render_config.preset_overwrite_title": "Overwrite Preset", "ui.render_config.preset_overwrite_desc": "A preset named '{0}' already exists. Do you want to overwrite it?", "ui.render_config.preset_delete_title": "Delete Preset", diff --git a/Localization/Locale/ko.json b/Localization/Locale/ko.json index 1296232..8c02196 100644 --- a/Localization/Locale/ko.json +++ b/Localization/Locale/ko.json @@ -5,6 +5,7 @@ "ui.render_config.preset_name_placeholder": "새 프리셋 이름...", "ui.render_config.preset_save": "저장", "ui.render_config.preset_delete": "삭제", + "ui.render_config.preset_delete_confirm": "삭제 확인", "ui.render_config.preset_overwrite_title": "프리셋 덮어쓰기", "ui.render_config.preset_overwrite_desc": "'{0}' 프리셋이 이미 존재합니다. 덮어쓰시겠습니까?", "ui.render_config.preset_delete_title": "프리셋 삭제", diff --git a/UI/Window/RenderConfigWindow.cs b/UI/Window/RenderConfigWindow.cs index edede6e..b1597f8 100644 --- a/UI/Window/RenderConfigWindow.cs +++ b/UI/Window/RenderConfigWindow.cs @@ -26,6 +26,10 @@ internal static class RenderConfigWindow private static O5InputField? _presetNameInput; private static O5Button? _savePresetButton; private static O5Button? _deletePresetButton; + // ReSharper disable once InconsistentNaming + private static LayoutElement? _deletePresetButtonLE; + private static bool _isDeletePending; + private static Coroutine? _deleteResetCoroutine; private static string? _lastLoadedPresetName; // Controls cache for validation & sync @@ -95,6 +99,7 @@ internal static class RenderConfigWindow _configWindow.CloseRequested += win => { CloseAllPickers(); + ResetDeletePendingState(); win.Rect.gameObject.SetActive(false); }; @@ -255,10 +260,17 @@ internal static class RenderConfigWindow onClick: () => OnDeletePresetClicked(config), height: 40f ); - var deleteLE = _deletePresetButton.Rect.GetComponent() ?? _deletePresetButton.Rect.gameObject.AddComponent(); - deleteLE.preferredWidth = 90f; - deleteLE.flexibleWidth = 0f; - deleteLE.preferredHeight = 40f; + if (_deletePresetButton.Label != null) + { + LocalizedText.Bind(_deletePresetButton.Label, () => + _isDeletePending + ? LocalizationManager.Get("ui.render_config.preset_delete_confirm") + : LocalizationManager.Get("ui.render_config.preset_delete")); + } + _deletePresetButtonLE = _deletePresetButton.Rect.GetComponent() ?? _deletePresetButton.Rect.gameObject.AddComponent(); + _deletePresetButtonLE.preferredWidth = 90f; + _deletePresetButtonLE.flexibleWidth = 0f; + _deletePresetButtonLE.preferredHeight = 40f; UpdateDeleteButtonState(); @@ -907,6 +919,7 @@ internal static class RenderConfigWindow private static void OnPresetSelected(string? selectedName, RenderConfig config) { + ResetDeletePendingState(); if (string.IsNullOrEmpty(selectedName) || selectedName == CustomPresetLabel) return; var preset = PresetManager.GetPresets().FirstOrDefault(p => string.Equals(p.Name, selectedName, StringComparison.OrdinalIgnoreCase)); if (preset == null) return; @@ -991,20 +1004,62 @@ internal static class RenderConfigWindow } } - var ctx = RendererUIManager.Context; - CommonWarningDialogUI.ShowDialog( - LocalizationManager.Get("ui.render_config.preset_delete_title"), - LocalizationManager.Get("ui.render_config.preset_delete_desc", targetPresetName), - new DialogButton( - LocalizationManager.Get("ui.render_config.confirm"), - () => DoDeletePreset(targetPresetName, config), - ctx.Theme.SoftRed - ), - new DialogButton( - LocalizationManager.Get("ui.render_config.cancel"), - () => { } - ) - ); + if (!_isDeletePending) + { + _isDeletePending = true; + if (_deletePresetButtonLE != null) _deletePresetButtonLE.preferredWidth = 110f; + if (_deletePresetButton != null) + { + if (_deletePresetButton.Label != null) + { + _deletePresetButton.Label.text = LocalizationManager.Get("ui.render_config.preset_delete_confirm"); + } + _deletePresetButton.NormalColor = new Color(0.95f, 0.25f, 0.25f, 1f); + _deletePresetButton.UpdateVisual(); + } + + if (_deleteResetCoroutine != null) + { + RendererUIManager.Instance.StopCoroutine(_deleteResetCoroutine); + } + _deleteResetCoroutine = RendererUIManager.Instance.StartCoroutine(ResetDeletePendingAfterDelay()); + return; + } + + ResetDeletePendingState(); + DoDeletePreset(targetPresetName, config); + } + + private static System.Collections.IEnumerator ResetDeletePendingAfterDelay() + { + yield return new WaitForSeconds(3f); + ResetDeletePendingState(); + } + + private static void ResetDeletePendingState() + { + if (_deleteResetCoroutine != null) + { + RendererUIManager.Instance.StopCoroutine(_deleteResetCoroutine); + _deleteResetCoroutine = null; + } + + if (!_isDeletePending && (_deletePresetButton == null || _deletePresetButton.Label?.text == LocalizationManager.Get("ui.render_config.preset_delete"))) + { + return; + } + + _isDeletePending = false; + if (_deletePresetButtonLE) _deletePresetButtonLE.preferredWidth = 90f; + if (_deletePresetButton != null) + { + if (_deletePresetButton.Label != null) + { + _deletePresetButton.Label.text = LocalizationManager.Get("ui.render_config.preset_delete"); + } + _deletePresetButton.NormalColor = RendererUIManager.Context.Theme.SoftRed; + _deletePresetButton.UpdateVisual(); + } } private static void DoDeletePreset(string name, RenderConfig config) @@ -1029,6 +1084,7 @@ internal static class RenderConfigWindow private static void ReloadPresetDropdown(string? selectName = null) { + ResetDeletePendingState(); var presets = PresetManager.GetPresets(); var names = presets.Select(p => p.Name).ToList(); if (names.Count == 0)