# Click Blocking Refactoring Template ## Problem The click blocking functionality was duplicated across multiple UI components (`ActiveQuestUI`, `TeamOverviewController`, etc.), leading to code duplication and maintenance overhead. ## Solution Instead of inheritance (which caused compilation issues with Unity's build order), we use **composition** with a helper class pattern. ## Refactoring Template ### Step 1: Create the Helper Class Create `Assets/Scripts/UI/Common/ClickBlockingHelper.cs`: ```csharp using UnityEngine; using System.Collections; public static class ClickBlockingHelper { public static void RegisterWithClickManager(IClickBlocker blocker) { ClickManager.Instance?.RegisterClickBlocker(blocker); } public static void UnregisterWithClickManager(IClickBlocker blocker) { ClickManager.Instance?.UnregisterClickBlocker(blocker); } public static void SetClickFlag(string componentName, MonoBehaviour coroutineStarter, System.Action flagSetter) { flagSetter(true); Debug.Log($"🚫 {componentName}: Click flag SET - blocking map clicks"); coroutineStarter.StopAllCoroutines(); coroutineStarter.StartCoroutine(ResetClickFlagCoroutine(componentName, flagSetter)); } private static IEnumerator ResetClickFlagCoroutine(string componentName, System.Action flagSetter) { yield return new WaitForEndOfFrame(); yield return new WaitForEndOfFrame(); yield return new WaitForSeconds(0.1f); flagSetter(false); Debug.Log($"🔓 {componentName}: Click flag reset - map clicks allowed again"); } } ``` ### Step 2: Update UI Components For each UI component that implements `IClickBlocker`, replace the duplicated methods: #### REPLACE THIS PATTERN: ```csharp // OLD - Duplicated code in each component private bool recentlyHandledClick = false; void OnEnable() => ClickManager.Instance?.RegisterClickBlocker(this); void OnDisable() => ClickManager.Instance?.UnregisterClickBlocker(this); private void SetClickFlag() { recentlyHandledClick = true; Debug.Log("🚫 ComponentName: Click flag SET - blocking map clicks"); StopAllCoroutines(); StartCoroutine(ResetClickFlag()); } private IEnumerator ResetClickFlag() { yield return new WaitForEndOfFrame(); yield return new WaitForEndOfFrame(); yield return new WaitForSeconds(0.1f); recentlyHandledClick = false; Debug.Log("🔓 ComponentName: Click flag reset - map clicks allowed again"); } public bool IsBlockingClick(Vector2 screenPosition) { if (recentlyHandledClick) { Debug.Log("🚫 ComponentName: Blocking click due to recent UI interaction"); return true; } // ... rest of method } ``` #### WITH THIS PATTERN: ```csharp // NEW - Using helper for common functionality private bool recentlyHandledClick = false; void OnEnable() => ClickBlockingHelper.RegisterWithClickManager(this); void OnDisable() => ClickBlockingHelper.UnregisterWithClickManager(this); private void SetClickFlag() { ClickBlockingHelper.SetClickFlag(GetType().Name, this, (flag) => recentlyHandledClick = flag); } public bool IsBlockingClick(Vector2 screenPosition) { if (recentlyHandledClick) { Debug.Log($"🚫 {GetType().Name}: Blocking click due to recent UI interaction"); return true; } // ... rest of method unchanged } ``` ### Step 3: Components to Refactor Apply this pattern to: - ✅ `ActiveQuestUI.cs` (already done) - ⏳ `TeamOverviewController.cs` (needs refactoring) - ⏳ `TravelUI.cs` (if it has the same pattern) - ⏳ `CombatEventPopupUXML.cs` (if it has the same pattern) ### Benefits 1. **Eliminates Code Duplication**: Common logic is centralized 2. **Easier Maintenance**: Changes only need to be made in one place 3. **Consistent Behavior**: All components behave identically 4. **Unity-Compatible**: Uses composition instead of problematic inheritance 5. **Type-Safe**: Maintains compile-time safety ### Usage in Event Handlers In your UI event handlers, simply call: ```csharp someElement.RegisterCallback(evt => { SetClickFlag(); // Now uses the helper internally evt.StopPropagation(); }); ``` The helper handles all the coroutine management and timing automatically.