using System; using System.Collections.Concurrent; using System.Threading; using BITKit.Mod; using BITKit.UX; using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.UIElements; namespace BITKit { [Serializable] public sealed class UXWaitingSingleton : IUXWaiting { private IUXWaiting Implementation => UXWaiting.Singleton; public IUXWaitingHandle Get() { return Implementation.Get(); } public void Release(IUXWaitingHandle handle) { Implementation.Release(handle); } } public sealed class WaitingHandle : IUXWaitingHandle { public string Message { get => Label.text; set => SetMessage(value); } public object Container => VisualElement; internal VisualElement VisualElement; internal Label Label; internal Action OnDispose; internal Action OnSetMessage; public void SetMessage(string message) => OnSetMessage?.Invoke(message); public void Dispose() => OnDispose?.Invoke(); } [CustomType(typeof(IUXWaiting))] public sealed class UXWaiting : UIToolkitOverlay,IUXWaiting { private const string HandleTemplate = "ux_waiting_handle"; public static UXWaiting Singleton { get; private set; } private readonly ITicker _ticker; public UXWaiting(IUXService uxService, ITicker ticker, CancellationTokenSource cancellationToken) : base(uxService, cancellationToken) { _ticker = ticker; Singleton = this; _visibleHandle.AddListener(Dispose); } protected override string DocumentPath => "ux_global_waiting"; private VisualTreeAsset _handleTemplate; [UXBindPath("waiting-container")] private VisualElement _container; private readonly ConcurrentQueue<(WaitingHandle handle,string text)> _messageQueue = new(); private readonly ConcurrentQueue _initializedHandles = new(); private readonly ConcurrentQueue _disposeQueue = new(); private readonly ValidHandle _visibleHandle = new(); private InitializationState _initializationState; public IUXWaitingHandle Get() { var handle = new WaitingHandle(); _initializedHandles.Enqueue(handle); handle.OnSetMessage = (text) => { _messageQueue.Enqueue((handle,text)); }; handle.OnDispose = () => { _disposeQueue.Enqueue(handle); _ticker.Add(OnTick); }; _ticker.Add(OnTick); return handle; } public void Release(IUXWaitingHandle handle) { handle.Dispose(); } private void OnTick(float deltaTime) { if(_initializationState is not InitializationState.Initialized)return; while (_initializedHandles.TryDequeue(out var handle)) { var container = _container.Create(_handleTemplate); _visibleHandle.AddElement(handle); handle.VisualElement = container; handle.Label = container.Get