using System; using System.Text; using System.Threading; using System.Threading.Tasks; using Crowdin.Plugin.Helpers.PluginLocalization; using Crowdin.Plugin.Models; using Crowdin.Plugin.Operations; using Crowdin.Plugin.Server_API; using Crowdin.Plugin.Server_API.Helpers; using Crowdin.Plugin.Server_API.Services; using UnityEditor; using UnityEditor.PackageManager; using UnityEditor.PackageManager.Requests; using UnityEngine; namespace Crowdin.Editor { public abstract class BasePopupEditor : EditorWindow { private static ListRequest _request; protected StringBuilder status = new StringBuilder(); private Vector2 scrollPosition; protected bool isBusy; protected CancellationTokenSource lifetime; protected static T InitPopup(string popupTitle) where T : EditorWindow { _request = Client.List(); // List packages installed for the project EditorApplication.update += Progress; var window = (T)GetWindow(typeof(T), true, popupTitle); window.Show(); return window; } protected virtual void OnEnable() { lifetime = new CancellationTokenSource(); } protected virtual void OnDisable() { lifetime.Cancel(); lifetime.Dispose(); } /// The only permitted `async void` in the codebase - this is the UI event boundary reached /// from a button click, and every exception path below is handled before it can propagate. protected async void RunOperation( Func, CancellationToken, Task> operation, Action onCompleted) { isBusy = true; status.Clear(); var progress = new SynchronousProgress(p => { status.AppendLine(p.Message); Repaint(); }); try { T result = await operation(progress, lifetime.Token); onCompleted(result); } catch (OperationCanceledException) { // Popup was closed mid-run; nothing left to report to. } catch (CrowdinApiException e) { status.AppendLine(LocalizationHelper.GetLocalStringByException(e)); Debug.LogException(e); } catch (Exception e) { status.AppendLine(LocalizationHelper.GetLocalStringByKey(LocalKeys.error_processing)); Debug.LogException(e); } finally { isBusy = false; Repaint(); } } protected void OnGUIStatusLabel() { scrollPosition = GUILayout.BeginScrollView(scrollPosition); GUILayout.Label(status.ToString()); GUILayout.EndScrollView(); } protected bool IsProjectSelected() { if (SettingsHelper.IsProjectSelected()) { return true; } var message = LocalizationHelper.GetLocalStringByKey(LocalKeys.error_project_not_selected); Debug.LogError(message); status.Clear(); status.AppendLine(message); return false; } private static void Progress() { if (!_request.IsCompleted) { return; } if (_request.Status is StatusCode.Success) { foreach (var package in _request.Result) { if (package.name is "com.unity.localization") { BaseApiService.unityLocalization = package.version; } if (package.name is "com.crowdin.unity-plugin") { BaseApiService.crowdinUnityPlugin = package.version; } } } else if (_request.Status >= StatusCode.Failure) { Debug.Log(_request.Error.message); } EditorApplication.update -= Progress; } } }