CollaborateWindow.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. using System;
  2. using System.Collections.Generic;
  3. using Unity.Cloud.Collaborate.Assets;
  4. using Unity.Cloud.Collaborate.Components;
  5. using Unity.Cloud.Collaborate.Components.Menus;
  6. using Unity.Cloud.Collaborate.Models;
  7. using Unity.Cloud.Collaborate.Models.Api;
  8. using Unity.Cloud.Collaborate.Models.Enums;
  9. using Unity.Cloud.Collaborate.Models.Providers;
  10. using Unity.Cloud.Collaborate.Views;
  11. using Unity.Cloud.Collaborate.Presenters;
  12. using Unity.Cloud.Collaborate.Settings;
  13. using UnityEditor;
  14. using UnityEngine;
  15. using UnityEngine.UIElements;
  16. namespace Unity.Cloud.Collaborate.UserInterface
  17. {
  18. internal class CollaborateWindow : EditorWindow
  19. {
  20. public const string UssClassName = "main-window";
  21. public const string ContainerUssClassName = UssClassName + "__container";
  22. public const string PackagePath = "Packages/com.unity.collab-proxy";
  23. public const string UserInterfacePath = PackagePath + "/Editor/Collaborate/UserInterface";
  24. public const string ResourcePath = PackagePath + "/Editor/Collaborate/Assets";
  25. public const string LayoutPath = ResourcePath + "/Layouts";
  26. public const string StylePath = ResourcePath + "/Styles";
  27. public const string IconPath = ResourcePath + "/Icons";
  28. public const string TestWindowPath = UserInterfacePath + "/TestWindows";
  29. const string k_LayoutPath = LayoutPath + "/main-window.uxml";
  30. public const string MainStylePath = StylePath + "/styles.uss";
  31. MainPageView m_MainView;
  32. ErrorPageView m_ErrorPageView;
  33. StartPageView m_StartView;
  34. VisualElement m_ViewContainer;
  35. PageComponent m_ActivePage;
  36. ISourceControlProvider m_Provider;
  37. List<IModel> m_Models;
  38. [MenuItem("Window/Collaborate")]
  39. internal static void Init()
  40. {
  41. Init(FocusTarget.None);
  42. }
  43. internal static void Init(FocusTarget focusTarget)
  44. {
  45. var openLocation = CollabSettingsManager.Get(CollabSettings.settingDefaultOpenLocation, fallback: CollabSettings.OpenLocation.Docked);
  46. CollaborateWindow window;
  47. if (openLocation == CollabSettings.OpenLocation.Docked)
  48. {
  49. // Dock next to inspector, if available
  50. var inspectorType = Type.GetType("UnityEditor.InspectorWindow,UnityEditor.dll");
  51. window = GetWindow<CollaborateWindow>(inspectorType);
  52. }
  53. else
  54. {
  55. window = GetWindow<CollaborateWindow>();
  56. }
  57. // Set up window
  58. window.titleContent = new GUIContent("Collaborate");
  59. window.minSize = new Vector2(256, 400);
  60. // Display window
  61. window.Show();
  62. window.Focus();
  63. if (focusTarget != FocusTarget.None)
  64. {
  65. window.RequestFocus(focusTarget);
  66. }
  67. }
  68. void OnDisable()
  69. {
  70. EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
  71. AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeAssemblyReload;
  72. AssemblyReloadEvents.afterAssemblyReload -= OnAfterAssemblyReload;
  73. if (m_Provider != null)
  74. {
  75. m_Provider.UpdatedProjectStatus -= OnUpdatedProjectStatus;
  76. }
  77. if (m_Models != null)
  78. {
  79. m_Models.ForEach(m => m.OnStop());
  80. }
  81. }
  82. void CreateGUI()
  83. {
  84. EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
  85. AssemblyReloadEvents.beforeAssemblyReload += OnBeforeAssemblyReload;
  86. AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload;
  87. var root = rootVisualElement;
  88. root.styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(MainStylePath));
  89. root.AddToClassList(EditorGUIUtility.isProSkin
  90. ? UiConstants.ussDark
  91. : UiConstants.ussLight);
  92. AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(k_LayoutPath).CloneTree(root);
  93. m_Provider = new Collab();
  94. m_Provider.UpdatedProjectStatus += OnUpdatedProjectStatus;
  95. m_ViewContainer = root.Q<VisualElement>(className: ContainerUssClassName);
  96. // Create models and configure them.
  97. var mainModel = new MainModel(m_Provider);
  98. var startModel = new StartModel(m_Provider);
  99. m_Models = new List<IModel> { mainModel, startModel };
  100. m_Models.ForEach(m => m.OnStart());
  101. // Get the views and configure them.
  102. m_MainView = new MainPageView();
  103. m_MainView.Presenter = new MainPresenter(m_MainView, mainModel);
  104. m_StartView = new StartPageView();
  105. m_StartView.Presenter = new StartPresenter(m_StartView, startModel);
  106. m_ErrorPageView = new ErrorPageView();
  107. // Add floating dialogue so it can be displayed anywhere in the window.
  108. root.Add(FloatingDialogue.Instance);
  109. OnUpdatedProjectStatus(m_Provider.GetProjectStatus());
  110. }
  111. /// <summary>
  112. /// React to the play mode state changing. When in play mode, disable collab.
  113. /// </summary>
  114. /// <param name="state">Editor play mode state.</param>
  115. void OnPlayModeStateChanged(PlayModeStateChange state)
  116. {
  117. bool enabled;
  118. switch (state)
  119. {
  120. case PlayModeStateChange.EnteredEditMode:
  121. case PlayModeStateChange.ExitingEditMode:
  122. enabled = true;
  123. break;
  124. case PlayModeStateChange.EnteredPlayMode:
  125. case PlayModeStateChange.ExitingPlayMode:
  126. enabled = false;
  127. break;
  128. default:
  129. throw new ArgumentOutOfRangeException(nameof(state), state, null);
  130. }
  131. m_ViewContainer.SetEnabled(enabled);
  132. }
  133. /// <summary>
  134. /// Restore window state after assembly reload.
  135. /// </summary>
  136. void OnAfterAssemblyReload()
  137. {
  138. m_Models.ForEach(m => m.RestoreState(WindowCache.Instance));
  139. }
  140. /// <summary>
  141. /// Save state before domain reload.
  142. /// </summary>
  143. void OnBeforeAssemblyReload()
  144. {
  145. m_Models.ForEach(m => m.SaveState(WindowCache.Instance));
  146. WindowCache.Instance.Serialize();
  147. }
  148. /// <summary>
  149. /// Respond to changes in the project status.
  150. /// </summary>
  151. /// <param name="status">New project status.</param>
  152. void OnUpdatedProjectStatus(ProjectStatus status)
  153. {
  154. if (status == ProjectStatus.Ready)
  155. {
  156. UpdateDisplayMode(Display.Main);
  157. }
  158. else
  159. {
  160. WindowCache.Instance.Clear();
  161. m_Models.ForEach(m => m.RestoreState(WindowCache.Instance));
  162. UpdateDisplayMode(Display.Add);
  163. }
  164. }
  165. void RequestFocus(FocusTarget focusTarget)
  166. {
  167. if (m_ActivePage != m_MainView)
  168. {
  169. // Cannot focus changes or history pane if we're not already on mainview
  170. return;
  171. }
  172. if (focusTarget == FocusTarget.Changes)
  173. {
  174. m_MainView.SetTab(MainPageView.ChangesTabIndex);
  175. }
  176. else if (focusTarget == FocusTarget.History)
  177. {
  178. m_MainView.SetTab(MainPageView.HistoryTabIndex);
  179. }
  180. else
  181. {
  182. Debug.LogError("Collab Error: Attempting to focus unknown target.");
  183. }
  184. }
  185. /// <summary>
  186. /// Switch the view displayed in the window.
  187. /// </summary>
  188. /// <param name="newDisplay">Display to switch the window to.</param>
  189. void UpdateDisplayMode(Display newDisplay)
  190. {
  191. m_ActivePage?.RemoveFromHierarchy();
  192. m_ActivePage?.SetActive(false);
  193. m_ViewContainer.Clear();
  194. // Get new page to display
  195. switch (newDisplay)
  196. {
  197. case Display.Add:
  198. m_ActivePage = m_StartView;
  199. break;
  200. case Display.Error:
  201. m_ActivePage = m_ErrorPageView;
  202. break;
  203. case Display.Main:
  204. m_ActivePage = m_MainView;
  205. break;
  206. default:
  207. throw new ArgumentOutOfRangeException();
  208. }
  209. m_ActivePage.SetActive(true);
  210. m_ViewContainer.Add(m_ActivePage);
  211. }
  212. enum Display
  213. {
  214. Add,
  215. Error,
  216. Main
  217. }
  218. public enum FocusTarget
  219. {
  220. None,
  221. History,
  222. Changes
  223. }
  224. }
  225. }