using System; using System.Collections; using Sirenix.OdinInspector; using UnityEngine; using UnityEngine.UI; namespace Canvases.Components { // ReSharper disable once InconsistentNaming Reason: UI should be capitalized public class SliderUIComponent : UISelectableComponentBase { public event Action OnValueChanged; [Header("Association"), SerializeField, Required] private Slider slider; [SerializeField] private Image backgroundImage; [SerializeField] private Image fillImage; [SerializeField] private Image frame; [Header("Animation"), SerializeField] private bool isChangeValueAnimated; [SerializeField] [Range(0f, 1f)] private float animationSpeed = 0.05f; [SerializeField] private Color valueIncreaseColor = Color.green; [SerializeField] private Color valueDecreaseColor = Color.red; private float targetValue; private float currentValue; private Coroutine animationRoutine; private Color initialColor = Color.black; public float Value { get => currentValue; set { if (isChangeValueAnimated) { targetValue = value; StartAnimation(); } else { currentValue = value; slider.value = value; } } } public float MaxValue { get => slider.maxValue; set => slider.maxValue = value; } public Color BackgroundColor { set { if (backgroundImage != null) { backgroundImage.color = value; } } } public Color FillColor { set { if (fillImage != null) { initialColor = value; fillImage.color = initialColor; } } } public Color FrameColor { set { if (frame != null) { frame.color = value; } } } private void Start() { Debug.Assert(slider, $"A {nameof(slider)} must be assigned to a {nameof(SliderUIComponent)}"); slider.onValueChanged.AddListener(OnSliderChanged); } protected override void SetSelectableGameObject() => Selectable = slider; protected override void OnDestroy() { slider.onValueChanged.RemoveListener(OnSliderChanged); base.OnDestroy(); } private void StartAnimation() { if (animationRoutine != null) StopCoroutine(animationRoutine); animationRoutine = StartCoroutine(AnimateValueChange(targetValue > currentValue)); } private IEnumerator AnimateValueChange(bool isValueChangePositive) { if (isValueChangePositive) { fillImage.color = valueIncreaseColor; while (currentValue < targetValue) { currentValue += animationSpeed * Time.deltaTime; slider.value = currentValue; yield return null; } } else { fillImage.color = valueDecreaseColor; while (currentValue > targetValue) { currentValue -= animationSpeed * Time.deltaTime; slider.value = currentValue; yield return null; } } currentValue = targetValue; slider.value = currentValue; fillImage.color = initialColor; } private void OnSliderChanged(float value) => OnValueChanged?.Invoke(value); private void OnValidate() { if (!slider) slider = GetComponent(); } } }