using System; using System.Collections; using JetBrains.Annotations; using Sirenix.OdinInspector; using UnityEngine; using UnityEngine.UI; #if ODIN_INSPECTOR #endif namespace JohnsonUtils.Canvases { public class SliderUIComponent : UISelectableComponentBase { [UsedImplicitly] public event Action OnValueChanged; #if ODIN_INSPECTOR [Required] #endif [Header("Association"), SerializeField] 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; [UsedImplicitly] public float Value { get => _currentValue; set { if (isChangeValueAnimated) { _targetValue = value; StartAnimation(); } else { _currentValue = value; slider.value = value; } } } [UsedImplicitly] public float MaxValue { get => slider.maxValue; set => slider.maxValue = value; } [UsedImplicitly] public Color BackgroundColor { set { if (backgroundImage != null) { backgroundImage.color = value; } } } [UsedImplicitly] public Color FillColor { set { if (fillImage != null) { _initialColor = value; fillImage.color = _initialColor; } } } [UsedImplicitly] 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(); } } }