Playvoi/Assets/ShiroginSDK/Runtime/Services/Implementations/UI/PopupService.cs
2025-10-30 22:48:16 +03:00

203 lines
No EOL
7.1 KiB
C#

using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using ShiroginSDK.Runtime.Core.SDK;
using ShiroginSDK.Runtime.Core.Utils;
using ShiroginSDK.Runtime.Modules.Events;
using ShiroginSDK.Runtime.Modules.UI.Popup.Enums;
using ShiroginSDK.Runtime.Modules.UI.Popup.Scripts.SO;
using ShiroginSDK.Runtime.Modules.UI.Popup.Scripts.UI.Base;
using ShiroginSDK.Runtime.Services.Base;
using ShiroginSDK.Runtime.Services.Interfaces;
using ShiroginSDK.Runtime.Shared.Constants;
using UnityEngine;
using UnityEngine.UI;
namespace ShiroginSDK.Runtime.Services.Implementations.UI
{
/// <summary>
/// Manages all queued popups with background dimming and smooth animations.
/// Integrated with EventService to automatically respond to common SDK events.
/// </summary>
public class PopupService : ServiceBase, IPopupService
{
private readonly Queue<(PopupType, object)> _popupQueue = new();
private CanvasGroup _dimBackground;
private bool _isShowing;
private PopupRepository _repository;
private Canvas _rootCanvas;
// ----------------------------------------------------
// Initialization
// ----------------------------------------------------
public void Initialize(Canvas canvas, PopupRepository repository)
{
_rootCanvas = canvas;
_repository = repository;
InitializeDim();
}
// ----------------------------------------------------
// Public API
// ----------------------------------------------------
public void Show(PopupType type, object data = null)
{
Enqueue(type, data);
}
public void SetRepository(PopupRepository repo)
{
_repository = repo;
}
public void SetCanvas(Canvas canvas)
{
_rootCanvas = canvas;
}
// ----------------------------------------------------
// Lifecycle
// ----------------------------------------------------
protected override void OnInitialize()
{
// Load repository from SDKConfig
var config = ShiroginConfig.Load();
if (config == null)
{
Debug.LogError("[PopupService] ❌ SDKConfig not found! Cannot load PopupRepository.");
return;
}
_repository = config.popupRepository;
if (_repository == null) Debug.LogWarning("[PopupService] ⚠️ PopupRepository is null in SDKConfig.");
// Try to find root canvas automatically if none assigned
if (_rootCanvas == null)
_rootCanvas = Object.FindFirstObjectByType<Canvas>();
InitializeDim();
SubscribeToEvents();
Debug.Log("[PopupService] ✅ Initialized and bound to SDKConfig.");
}
protected override void OnDispose()
{
_popupQueue.Clear();
_isShowing = false;
}
// ----------------------------------------------------
// Event Wiring
// ----------------------------------------------------
private void SubscribeToEvents()
{
var eventService = ServiceLocator.Get<IEventService>();
if (eventService == null)
{
Debug.LogError("[PopupService] ❌ EventService not found.");
return;
}
eventService.Subscribe<ShiroginEvents.Rewards.RewardClaimedEvent>(e => Enqueue(PopupType.RewardClaimed, e));
eventService.Subscribe<ShiroginEvents.IAP.PurchaseCompletedEvent>(e => Enqueue(PopupType.PurchaseSuccess, e));
eventService.Subscribe<ShiroginEvents.Connection.NoConnectionEvent>(e => Enqueue(PopupType.NoConnection, e));
eventService.Subscribe<ShiroginEvents.IAP.PurchaseFailedEvent>(e => Enqueue(PopupType.PurchaseFailed, e));
eventService.Subscribe<ShiroginEvents.Ads.AdWatchedEvent>(e =>
{
if (!e.Success)
Enqueue(PopupType.NoAdsAvailable, e);
});
eventService.Subscribe<ShiroginEvents.Ads.RewardedAdUnavailableEvent>(e =>
{
Enqueue(PopupType.RewardedAdUnavailable, e);
});
eventService.Subscribe<ShiroginEvents.Shop.Shop_UIStoreItem_Rewarded>(e =>
Enqueue(PopupType.Shop_UIStoreItem_Rewarded, e));
}
private void InitializeDim()
{
if (_dimBackground != null) return;
var dimObj = new GameObject("PopupDimmer", typeof(RectTransform), typeof(CanvasGroup), typeof(Image));
dimObj.transform.SetParent(_rootCanvas ? _rootCanvas.transform : null, false);
var img = dimObj.GetComponent<Image>();
img.color = new Color(0, 0, 0, 0.6f);
_dimBackground = dimObj.GetComponent<CanvasGroup>();
_dimBackground.alpha = 0;
_dimBackground.blocksRaycasts = false;
dimObj.transform.SetAsFirstSibling();
}
private void Enqueue(PopupType type, object data)
{
_popupQueue.Enqueue((type, data));
if (!_isShowing)
CoroutineRunner.Start(ProcessQueue());
}
private IEnumerator ProcessQueue()
{
_isShowing = true;
while (_popupQueue.Count > 0)
{
var (type, data) = _popupQueue.Dequeue();
yield return ShowPopup(type, data);
}
_isShowing = false;
yield return FadeDim(false);
}
private IEnumerator ShowPopup(PopupType type, object data)
{
if (_repository == null)
{
Debug.LogError("[PopupService] ❌ PopupRepository not assigned or missing in SDKConfig!");
yield break;
}
var prefab = _repository.GetPrefab(type);
if (prefab == null)
{
Debug.LogWarning($"[PopupService] ⚠️ No popup prefab for type: {type}");
yield break;
}
yield return FadeDim(true);
var instance = Object.Instantiate(prefab.gameObject, _rootCanvas ? _rootCanvas.transform : null);
var popup = instance.GetComponent<PopupBase>();
popup.Initialize(data);
yield return popup.AnimateIn();
yield return new WaitUntil(() => popup.IsClosed);
yield return popup.AnimateOut();
Object.Destroy(instance);
}
// ----------------------------------------------------
// Dimmer Control
// ----------------------------------------------------
private IEnumerator FadeDim(bool fadeIn)
{
if (_dimBackground == null) yield break;
_dimBackground.blocksRaycasts = fadeIn;
DOTween.To(() => _dimBackground.alpha,
x => _dimBackground.alpha = x,
fadeIn ? 1f : 0f,
0.3f);
yield return new WaitForSeconds(UIConstants.FadeDuration);
}
}
}