You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
5.5 KiB

  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using UnityEngine;
  4. using UnityEngine.Experimental.UIElements;
  5. namespace UnityEditor.PackageManager.UI
  6. {
  7. #if !UNITY_2018_3_OR_NEWER
  8. internal class PackageStatusBarFactory : UxmlFactory<PackageStatusBar>
  9. {
  10. protected override PackageStatusBar DoCreate(IUxmlAttributes bag, CreationContext cc)
  11. {
  12. return new PackageStatusBar();
  13. }
  14. }
  15. #endif
  16. internal class PackageStatusBar : VisualElement
  17. {
  18. #if UNITY_2018_3_OR_NEWER
  19. internal new class UxmlFactory : UxmlFactory<PackageStatusBar> { }
  20. #endif
  21. private readonly VisualElement root;
  22. private string LastErrorMessage;
  23. private List<IBaseOperation> operationsInProgress;
  24. private enum StatusType {Normal, Loading, Error};
  25. public PackageStatusBar()
  26. {
  27. root = Resources.GetTemplate("PackageStatusBar.uxml");
  28. Add(root);
  29. MoreAddOptionsButton.clickable.clicked += OnMoreAddOptionsButtonClick;
  30. LastErrorMessage = string.Empty;
  31. operationsInProgress = new List<IBaseOperation>();
  32. SetDefaultMessage();
  33. PackageCollection.Instance.ListSignal.WhenOperation(OnListOrSearchOperation);
  34. PackageCollection.Instance.SearchSignal.WhenOperation(OnListOrSearchOperation);
  35. }
  36. private void SetDefaultMessage()
  37. {
  38. if(!string.IsNullOrEmpty(PackageCollection.Instance.lastUpdateTime))
  39. SetStatusMessage(StatusType.Normal, "Last update " + PackageCollection.Instance.lastUpdateTime);
  40. else
  41. SetStatusMessage(StatusType.Normal, string.Empty);
  42. }
  43. private void OnListOrSearchOperation(IBaseOperation operation)
  44. {
  45. if (operation == null || operation.IsCompleted)
  46. return;
  47. operationsInProgress.Add(operation);
  48. operation.OnOperationFinalized += () => { OnOperationFinalized(operation); };
  49. operation.OnOperationError += OnOperationError;
  50. SetStatusMessage(StatusType.Loading, "Loading packages...");
  51. }
  52. private void OnOperationFinalized(IBaseOperation operation)
  53. {
  54. operationsInProgress.Remove(operation);
  55. if (operationsInProgress.Any()) return;
  56. var errorMessage = LastErrorMessage;
  57. if (Application.internetReachability == NetworkReachability.NotReachable)
  58. {
  59. EditorApplication.update -= CheckInternetReachability;
  60. EditorApplication.update += CheckInternetReachability;
  61. errorMessage = "You seem to be offline.";
  62. }
  63. if (!string.IsNullOrEmpty(errorMessage))
  64. SetStatusMessage(StatusType.Error, errorMessage);
  65. else
  66. SetDefaultMessage();
  67. }
  68. private void OnOperationError(Error error)
  69. {
  70. LastErrorMessage = "Cannot load packages, see console.";
  71. }
  72. private void CheckInternetReachability()
  73. {
  74. if (Application.internetReachability == NetworkReachability.NotReachable) return;
  75. PackageCollection.Instance.FetchListCache(true);
  76. PackageCollection.Instance.FetchSearchCache(true);
  77. EditorApplication.update -= CheckInternetReachability;
  78. }
  79. private void SetStatusMessage(StatusType status, string message)
  80. {
  81. if (status == StatusType.Loading)
  82. LoadingSpinner.Start();
  83. else
  84. LoadingSpinner.Stop();
  85. UIUtils.SetElementDisplay(LoadingIcon, status == StatusType.Error);
  86. if (status == StatusType.Error)
  87. LoadingText.AddToClassList("icon");
  88. else
  89. LoadingText.RemoveFromClassList("icon");
  90. LoadingText.text = message;
  91. }
  92. private void OnMoreAddOptionsButtonClick()
  93. {
  94. var menu = new GenericMenu();
  95. var addPackageFromDiskItem = new GUIContent("Add package from disk...");
  96. /* // Disable adding from url field before the feature is ready
  97. var addPackageFromUrlItem = new GUIContent("Add package from URL...");
  98. menu.AddItem(addPackageFromUrlItem, false, delegate
  99. {
  100. AddFromUrlField.Show(true);
  101. });
  102. */
  103. menu.AddItem(addPackageFromDiskItem, false, delegate
  104. {
  105. var path = EditorUtility.OpenFilePanelWithFilters("Select package on disk", "", new[] { "package.json file", "json" });
  106. if (!string.IsNullOrEmpty(path) && !Package.AddRemoveOperationInProgress)
  107. Package.AddFromLocalDisk(path);
  108. });
  109. var menuPosition = MoreAddOptionsButton.LocalToWorld(new Vector2(MoreAddOptionsButton.layout.width, 0));
  110. var menuRect = new Rect(menuPosition, Vector2.zero);
  111. menu.DropDown(menuRect);
  112. }
  113. private PackageAddFromUrlField AddFromUrlField { get { return root.Q<PackageAddFromUrlField>("packageAddFromUrlField"); }}
  114. private VisualElement LoadingSpinnerContainer { get { return root.Q<VisualElement>("loadingSpinnerContainer"); }}
  115. private LoadingSpinner LoadingSpinner { get { return root.Q<LoadingSpinner>("packageSpinner"); }}
  116. private Label LoadingIcon { get { return root.Q<Label>("loadingIcon"); }}
  117. private Label LoadingText { get { return root.Q<Label>("loadingText"); }}
  118. private Button MoreAddOptionsButton{ get { return root.Q<Button>("moreAddOptionsButton"); }}
  119. }
  120. }