ToolbarButton.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. using System;
  2. using System.Collections.Generic;
  3. using JetBrains.Annotations;
  4. using UnityEditor;
  5. using UnityEditor.Collaboration;
  6. using UnityEditor.Connect;
  7. using UnityEngine;
  8. using Unity.PlasticSCM.Editor;
  9. namespace Unity.Cloud.Collaborate.UserInterface
  10. {
  11. internal class ToolbarButton : SubToolbar
  12. {
  13. protected enum ToolbarButtonState
  14. {
  15. NeedToEnableCollab,
  16. UpToDate,
  17. Conflict,
  18. OperationError,
  19. ServerHasChanges,
  20. FilesToPush,
  21. InProgress,
  22. Disabled,
  23. Offline,
  24. Plastic
  25. }
  26. ToolbarButtonState m_CurrentState;
  27. string m_ErrorMessage;
  28. readonly Dictionary<ToolbarButtonState, GUIContent> m_IconCache = new Dictionary<ToolbarButtonState, GUIContent>();
  29. ButtonWithAnimatedIconRotation m_CollabButton;
  30. public ToolbarButton()
  31. {
  32. Collab.instance.StateChanged += OnCollabStateChanged;
  33. UnityConnect.instance.StateChanged += OnUnityConnectStateChanged;
  34. UnityConnect.instance.UserStateChanged += OnUnityConnectUserStateChanged;
  35. PlasticPlugin.OnNotificationUpdated += OnPlasticNotificationUpdated;
  36. }
  37. ~ToolbarButton()
  38. {
  39. Collab.instance.StateChanged -= OnCollabStateChanged;
  40. UnityConnect.instance.StateChanged -= OnUnityConnectStateChanged;
  41. UnityConnect.instance.UserStateChanged -= OnUnityConnectUserStateChanged;
  42. PlasticPlugin.OnNotificationUpdated -= OnPlasticNotificationUpdated;
  43. }
  44. void OnUnityConnectUserStateChanged(UserInfo state)
  45. {
  46. Update();
  47. }
  48. void OnUnityConnectStateChanged(ConnectInfo state)
  49. {
  50. Update();
  51. }
  52. void OnCollabStateChanged(CollabInfo info)
  53. {
  54. Update();
  55. }
  56. void OnPlasticNotificationUpdated()
  57. {
  58. Toolbar.RepaintToolbar();
  59. }
  60. [CanBeNull]
  61. static Texture LoadIcon([NotNull] string iconName)
  62. {
  63. var hidpi = EditorGUIUtility.pixelsPerPoint > 1f ? "@2x" : string.Empty;
  64. return AssetDatabase.LoadAssetAtPath<Texture>($"{CollaborateWindow.IconPath}/{iconName}-{(EditorGUIUtility.isProSkin ? "dark" : "light")}{hidpi}.png");
  65. }
  66. [NotNull]
  67. GUIContent GetIconForState()
  68. {
  69. // Get cached icon, or construct it.
  70. if (!m_IconCache.TryGetValue(m_CurrentState, out var content))
  71. {
  72. string iconName;
  73. string tooltip;
  74. switch (m_CurrentState)
  75. {
  76. case ToolbarButtonState.NeedToEnableCollab:
  77. iconName = "collaborate";
  78. tooltip = "You need to enable collab.";
  79. break;
  80. case ToolbarButtonState.UpToDate:
  81. iconName = "collaborate";
  82. tooltip = "You are up to date.";
  83. break;
  84. case ToolbarButtonState.Conflict:
  85. iconName = "collaborate-error";
  86. tooltip = "Please fix your conflicts prior to publishing.";
  87. break;
  88. case ToolbarButtonState.OperationError:
  89. iconName = "collaborate-error";
  90. tooltip = "Last operation failed. Please retry later.";
  91. break;
  92. case ToolbarButtonState.ServerHasChanges:
  93. iconName = "collaborate-incoming";
  94. tooltip = "Please update, there are server changes.";
  95. break;
  96. case ToolbarButtonState.FilesToPush:
  97. iconName = "collaborate-available-changes";
  98. tooltip = "You have files to publish.";
  99. break;
  100. case ToolbarButtonState.InProgress:
  101. iconName = "collaborate-progress";
  102. tooltip = "Operation in progress.";
  103. break;
  104. case ToolbarButtonState.Disabled:
  105. iconName = "collaborate";
  106. tooltip = "Collab is disabled.";
  107. break;
  108. case ToolbarButtonState.Offline:
  109. iconName = "collaborate-offline";
  110. tooltip = "Please check your network connection.";
  111. break;
  112. default:
  113. throw new ArgumentOutOfRangeException();
  114. }
  115. // Create icon with tooltip and cache.
  116. content = new GUIContent(LoadIcon(iconName), $"Collaborate • {tooltip}");
  117. m_IconCache[m_CurrentState] = content;
  118. }
  119. // Add error message tooltip if there's a message.
  120. var icon = new GUIContent(content);
  121. if (!string.IsNullOrEmpty(m_ErrorMessage))
  122. {
  123. icon.tooltip = $"Collaborate • {m_ErrorMessage}";
  124. }
  125. return icon;
  126. }
  127. public override void OnGUI(Rect rect)
  128. {
  129. GUIStyle collabButtonStyle = "AppCommand";
  130. var disable = EditorApplication.isPlaying;
  131. using (new EditorGUI.DisabledScope(disable))
  132. {
  133. if (m_CurrentState == ToolbarButtonState.Plastic)
  134. {
  135. var icon = PlasticPlugin.GetPluginIcon();
  136. EditorGUIUtility.SetIconSize(new Vector2(16, 16));
  137. if (GUI.Button(rect, new GUIContent(icon, "Plastic SCM"), collabButtonStyle))
  138. {
  139. PlasticWindow.Open();
  140. }
  141. EditorGUIUtility.SetIconSize(Vector2.zero);
  142. }
  143. else
  144. {
  145. var icon = GetIconForState();
  146. EditorGUIUtility.SetIconSize(new Vector2(16, 16));
  147. if (GUI.Button(rect, icon, collabButtonStyle))
  148. {
  149. CollaborateWindow.Init();
  150. }
  151. EditorGUIUtility.SetIconSize(Vector2.zero);
  152. }
  153. }
  154. }
  155. public void Update()
  156. {
  157. var currentState = GetCurrentState();
  158. if (m_CurrentState == currentState) return;
  159. m_CurrentState = currentState;
  160. Toolbar.RepaintToolbar();
  161. }
  162. protected virtual ToolbarButtonState GetCurrentState()
  163. {
  164. var currentState = ToolbarButtonState.UpToDate;
  165. var networkAvailable = UnityConnect.instance.connectInfo.online && UnityConnect.instance.connectInfo.loggedIn;
  166. m_ErrorMessage = string.Empty;
  167. if (UnityConnect.instance.isDisableCollabWindow)
  168. {
  169. currentState = ToolbarButtonState.Plastic;
  170. }
  171. else if (networkAvailable)
  172. {
  173. var collab = Collab.instance;
  174. var currentInfo = collab.collabInfo;
  175. if (!currentInfo.ready)
  176. {
  177. currentState = ToolbarButtonState.InProgress;
  178. }
  179. else if (collab.GetError(UnityConnect.UnityErrorFilter.ByContext | UnityConnect.UnityErrorFilter.ByChild, out var errInfo) &&
  180. errInfo.priority <= (int)UnityConnect.UnityErrorPriority.Error)
  181. {
  182. currentState = ToolbarButtonState.OperationError;
  183. m_ErrorMessage = errInfo.shortMsg;
  184. }
  185. else if (currentInfo.inProgress)
  186. {
  187. currentState = ToolbarButtonState.InProgress;
  188. }
  189. else
  190. {
  191. var collabEnabled = Collab.instance.IsCollabEnabledForCurrentProject();
  192. if (UnityConnect.instance.projectInfo.projectBound == false || !collabEnabled)
  193. {
  194. currentState = ToolbarButtonState.Plastic;
  195. }
  196. else if (currentInfo.update)
  197. {
  198. currentState = ToolbarButtonState.ServerHasChanges;
  199. }
  200. else if (currentInfo.conflict)
  201. {
  202. currentState = ToolbarButtonState.Conflict;
  203. }
  204. else if (currentInfo.publish)
  205. {
  206. currentState = ToolbarButtonState.FilesToPush;
  207. }
  208. }
  209. }
  210. else
  211. {
  212. currentState = ToolbarButtonState.Offline;
  213. }
  214. return currentState;
  215. }
  216. }
  217. }