181 lines
5.0 KiB
C#
181 lines
5.0 KiB
C#
using System;
|
|
using System.Threading;
|
|
using BriarQueen.Framework.Coordinators.Events;
|
|
using BriarQueen.Framework.Events.UI;
|
|
using BriarQueen.Framework.Managers.UI.Base;
|
|
using Cysharp.Threading.Tasks;
|
|
using PrimeTween;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using VContainer;
|
|
|
|
namespace BriarQueen.UI
|
|
{
|
|
public class ScreenFader : MonoBehaviour, IScreenFader
|
|
{
|
|
private const float ALPHA_EPSILON = 0.001f;
|
|
|
|
[Header("UI Elements")]
|
|
[SerializeField]
|
|
private CanvasGroup _canvasGroup;
|
|
|
|
[Tooltip("Used for black / solid-color fades.")]
|
|
[SerializeField]
|
|
private Image _solidImage;
|
|
|
|
private Sequence _currentFadeSequence;
|
|
private EventCoordinator _eventCoordinator;
|
|
private CancellationTokenSource _fadeCts;
|
|
|
|
public bool IsModal => true;
|
|
|
|
|
|
private void Awake()
|
|
{
|
|
if (_canvasGroup == null)
|
|
Debug.LogError($"{nameof(ScreenFader)} on {name} is missing a CanvasGroup reference.", this);
|
|
|
|
SetInteractionState(_canvasGroup != null && _canvasGroup.alpha > ALPHA_EPSILON);
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
CancelAndDisposeFadeToken();
|
|
StopCurrentSequence();
|
|
}
|
|
|
|
// Window Stubs - Fader is Non-Interactive
|
|
public async UniTask Show()
|
|
{
|
|
await FadeToAsync( 1f);
|
|
}
|
|
|
|
public async UniTask Hide()
|
|
{
|
|
await FadeFromAsync(1f);
|
|
}
|
|
|
|
[Inject]
|
|
public void Construct(EventCoordinator eventCoordinator)
|
|
{
|
|
Debug.Log("ScreenFader constructed");
|
|
_eventCoordinator = eventCoordinator;
|
|
}
|
|
|
|
public async UniTask FadeToAsync(float duration)
|
|
{
|
|
if (_canvasGroup == null)
|
|
return;
|
|
|
|
_solidImage.color = Color.black;
|
|
|
|
BeginNewFade();
|
|
|
|
gameObject.SetActive(true);
|
|
SetInteractionState(true);
|
|
|
|
await FadeScreen(1f, duration, _fadeCts.Token);
|
|
}
|
|
|
|
public async UniTask FadeFromAsync(float duration)
|
|
{
|
|
if (_canvasGroup == null) return;
|
|
|
|
BeginNewFade();
|
|
|
|
await FadeScreen(0f, duration, _fadeCts.Token);
|
|
|
|
if (!_fadeCts.IsCancellationRequested)
|
|
{
|
|
_canvasGroup.alpha = 0f;
|
|
SetInteractionState(false);
|
|
}
|
|
}
|
|
|
|
public UniTask FadeToAsync(FadeStyle style, System.Drawing.Color tint, float duration)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
private void ApplyTint(FadeStyle style, Color tint)
|
|
{
|
|
if (_solidImage != null)
|
|
{
|
|
_solidImage.enabled = true;
|
|
_solidImage.color = Color.black;
|
|
}
|
|
}
|
|
|
|
private async UniTask FadeScreen(float targetAlpha, float duration, CancellationToken token)
|
|
{
|
|
targetAlpha = Mathf.Clamp01(targetAlpha);
|
|
duration = Mathf.Max(0f, duration);
|
|
|
|
var currentAlpha = _canvasGroup.alpha;
|
|
|
|
if (Mathf.Abs(currentAlpha - targetAlpha) <= ALPHA_EPSILON)
|
|
{
|
|
_canvasGroup.alpha = targetAlpha;
|
|
SetInteractionState(targetAlpha > ALPHA_EPSILON);
|
|
return;
|
|
}
|
|
|
|
StopCurrentSequence();
|
|
|
|
if (duration <= 0f)
|
|
{
|
|
_canvasGroup.alpha = targetAlpha;
|
|
SetInteractionState(targetAlpha > ALPHA_EPSILON);
|
|
|
|
_eventCoordinator?.PublishImmediate(new FadeCompletedEvent());
|
|
return;
|
|
}
|
|
|
|
_currentFadeSequence = Sequence.Create()
|
|
.Group(Tween.Alpha(_canvasGroup, targetAlpha, duration, Ease.InOutSine));
|
|
|
|
try
|
|
{
|
|
await _currentFadeSequence.ToUniTask(cancellationToken: token);
|
|
|
|
_canvasGroup.alpha = targetAlpha;
|
|
SetInteractionState(targetAlpha > ALPHA_EPSILON);
|
|
|
|
_eventCoordinator?.PublishImmediate(new FadeCompletedEvent());
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
// Another fade interrupted this one. Intentionally ignore completion.
|
|
}
|
|
}
|
|
|
|
private void BeginNewFade()
|
|
{
|
|
CancelAndDisposeFadeToken();
|
|
StopCurrentSequence();
|
|
|
|
_fadeCts = new CancellationTokenSource();
|
|
}
|
|
|
|
private void CancelAndDisposeFadeToken()
|
|
{
|
|
if (_fadeCts == null) return;
|
|
|
|
if (!_fadeCts.IsCancellationRequested) _fadeCts.Cancel();
|
|
|
|
_fadeCts.Dispose();
|
|
_fadeCts = null;
|
|
}
|
|
|
|
private void StopCurrentSequence()
|
|
{
|
|
if (_currentFadeSequence.isAlive) _currentFadeSequence.Stop();
|
|
}
|
|
|
|
private void SetInteractionState(bool isBlocking)
|
|
{
|
|
_canvasGroup.interactable = isBlocking;
|
|
_canvasGroup.blocksRaycasts = isBlocking;
|
|
}
|
|
}
|
|
} |