using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HotUpdate.UI
{
///
/// 竖屏 UI 页面栈:加载 Prefab、打开/关闭、按名查找。
///
public sealed class UiManager : MonoBehaviour
{
public static UiManager Instance { get; private set; }
readonly Dictionary _opened = new Dictionary(StringComparer.Ordinal);
Transform _root;
UiPrefabLoader _loader;
readonly HashSet _loading = new HashSet(StringComparer.Ordinal);
public string Theme { get; private set; } = UiThemeCatalog.Candy;
public void Init(Transform root, UiPrefabLoader loader, string theme = UiThemeCatalog.Candy)
{
Instance = this;
_root = root;
_loader = loader ?? new UiPrefabLoader();
Theme = UiThemeCatalog.Normalize(theme);
}
public IEnumerator OpenAsync(string prefabName, Action onOpened, int siblingIndex = -1)
{
if (string.IsNullOrEmpty(prefabName)) { onOpened?.Invoke(null); yield break; }
while (_loading.Contains(prefabName)) yield return null;
if (_opened.TryGetValue(prefabName, out var existing) && existing != null)
{
existing.SetActive(true);
onOpened?.Invoke(existing);
yield break;
}
_loading.Add(prefabName);
GameObject prefab = null;
try
{
var assetName = UiThemeCatalog.Resolve(prefabName, Theme);
yield return _loader.LoadAsync(assetName, loaded => prefab = loaded);
if (prefab == null && assetName != prefabName)
{
Debug.LogWarning($"[UI] Missing {assetName}; falling back to {prefabName}. Include both themes in the resource package.");
yield return _loader.LoadAsync(prefabName, loaded => prefab = loaded);
}
}
finally { _loading.Remove(prefabName); }
if (prefab == null)
{
Debug.LogError($"[UiManager] prefab not found: {prefabName}");
onOpened?.Invoke(null);
yield break;
}
var go = Instantiate(prefab, _root, false);
go.name = prefabName;
if (siblingIndex >= 0)
go.transform.SetSiblingIndex(siblingIndex);
_opened[prefabName] = go;
onOpened?.Invoke(go);
}
public void Close(string prefabName, bool destroy = false)
{
if (!_opened.TryGetValue(prefabName, out var go) || go == null)
return;
if (destroy)
{
Destroy(go);
_opened.Remove(prefabName);
}
else go.SetActive(false);
}
public GameObject Get(string prefabName)
{
_opened.TryGetValue(prefabName, out var go);
return go;
}
void OnDestroy()
{
StopAllCoroutines();
_loader?.Dispose();
if (Instance == this) Instance = null;
}
}
}