using System.Collections; using Core; using UnityEngine; using UnityEngine.UI; using AppleHills.Core.Settings; namespace UI.CardSystem { /// /// Controls a vertical progress bar made of individual Image elements. /// Fills from bottom to top and animates the newest element with a blink effect. /// /// Setup: Place on GameObject with VerticalLayoutGroup (Reverse Arrangement enabled). /// First child = first progress element (1/5), last child = last progress element (5/5). /// public class ProgressBarController : MonoBehaviour { [Header("Progress Elements")] [Tooltip("The individual Image components representing progress segments (auto-detected from children)")] private Image[] _progressElements; private ICardSystemSettings _settings; private Coroutine _currentBlinkCoroutine; private void Awake() { _settings = GameManager.GetSettingsObject(); // Auto-detect all child Image components _progressElements = GetComponentsInChildren(true); if (_progressElements.Length == 0) { Logging.Warning("[ProgressBarController] No child Image components found! Add Image children to this GridLayout."); } } /// /// Show progress and animate the newest element with a blink effect. /// /// Current progress (1 to maxCount) /// Maximum progress value (typically 5) /// Callback invoked after blink animation completes public void ShowProgress(int currentCount, int maxCount, System.Action onComplete) { // Validate input if (currentCount < 0 || currentCount > maxCount) { Logging.Warning($"[ProgressBarController] Invalid progress: {currentCount}/{maxCount}"); onComplete?.Invoke(); return; } // Validate element count if (_progressElements.Length < maxCount) { Logging.Warning($"[ProgressBarController] Not enough progress elements! Expected {maxCount}, found {_progressElements.Length}"); onComplete?.Invoke(); return; } // Stop any existing blink animation if (_currentBlinkCoroutine != null) { StopCoroutine(_currentBlinkCoroutine); _currentBlinkCoroutine = null; } // Disable all elements first foreach (var element in _progressElements) { element.enabled = false; } // Enable first N elements (since first child = 1/5, last child = 5/5) // If currentCount = 3, enable elements [0], [1], [2] (first 3 elements) for (int i = 0; i < currentCount && i < _progressElements.Length; i++) { _progressElements[i].enabled = true; } Logging.Debug($"[ProgressBarController] Showing progress {currentCount}/{maxCount}"); // Blink the NEWEST element (the last one we just enabled) // Newest element is at index (currentCount - 1) int newestIndex = currentCount - 1; if (newestIndex >= 0 && newestIndex < _progressElements.Length && currentCount > 0) { _currentBlinkCoroutine = StartCoroutine(BlinkElement(newestIndex, onComplete)); } else { // No element to blink (e.g., currentCount = 0) onComplete?.Invoke(); } } /// /// Show progress without blink animation (instant display). /// /// Current progress (1 to maxCount) /// Maximum progress value public void ShowProgressInstant(int currentCount, int maxCount) { // Validate if (currentCount < 0 || currentCount > maxCount || _progressElements.Length < maxCount) { return; } // Disable all foreach (var element in _progressElements) { element.enabled = false; } // Enable first N elements for (int i = 0; i < currentCount && i < _progressElements.Length; i++) { _progressElements[i].enabled = true; } } /// /// Hide all progress elements. /// public void HideProgress() { foreach (var element in _progressElements) { element.enabled = false; } } /// /// Blink a specific element by toggling enabled/disabled. /// private IEnumerator BlinkElement(int index, System.Action onComplete) { if (index < 0 || index >= _progressElements.Length) { onComplete?.Invoke(); yield break; } Image element = _progressElements[index]; // Get blink settings (or use defaults if not available) float blinkDuration = 0.15f; // Duration for each on/off toggle int blinkCount = 3; // Number of full blinks (on->off->on = 1 blink) // Try to get settings if available if (_settings != null) { // Settings could expose these if needed: // blinkDuration = _settings.ProgressBlinkDuration; // blinkCount = _settings.ProgressBlinkCount; } Logging.Debug($"[ProgressBarController] Blinking element {index} ({blinkCount} times)"); // Wait a brief moment before starting blink yield return new WaitForSeconds(0.3f); // Perform blinks (on->off->on = 1 full blink) for (int i = 0; i < blinkCount; i++) { // Off element.enabled = false; yield return new WaitForSeconds(blinkDuration); // On element.enabled = true; yield return new WaitForSeconds(blinkDuration); } // Ensure element is enabled at the end element.enabled = true; Logging.Debug($"[ProgressBarController] Blink complete for element {index}"); _currentBlinkCoroutine = null; onComplete?.Invoke(); } /// /// Get the total number of progress elements available. /// public int GetElementCount() { return _progressElements?.Length ?? 0; } private void OnDestroy() { // Clean up any running coroutines if (_currentBlinkCoroutine != null) { StopCoroutine(_currentBlinkCoroutine); _currentBlinkCoroutine = null; } } } }