Commit 1c847220 authored by jang dong hyeok's avatar jang dong hyeok
Browse files

.

parent 076f0c68
using System;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEngine.Assertions;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components.ChangeListEntries
{
internal class ToggleableChangeListElement : BaseChangeListElement
{
public new const string UssClassName = "toggleable-change-list-element";
public const string ToggleUssClassName = UssClassName + "__toggle";
public const string StatusIconUssClassName = UssClassName + "__icon";
public const string DiffButtonUssClassName = UssClassName + "__diff-button";
public const string DiscardButtonUssClassName = UssClassName + "__revert-button";
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(ToggleableChangeListElement)}.uss";
public readonly Toggle toggle;
public readonly IconButton diffButton;
public readonly IconButton discardButton;
public readonly VisualElement statusIcon;
[CanBeNull]
EventCallback<ChangeEvent<bool>> m_ToggleCallback;
public ToggleableChangeListElement()
{
AddToClassList(UssClassName);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
// Setup icons
var toggleContainer = new VisualElement();
toggle = new Toggle();
toggle.AddToClassList(ToggleUssClassName);
toggleContainer.Add(toggle);
statusIcon = new VisualElement();
statusIcon.AddToClassList(IconUssClassName);
statusIcon.AddToClassList(StatusIconUssClassName);
icons.Add(toggleContainer);
icons.Add(statusIcon);
// Setup buttons
diffButton = new IconButton();
diffButton.AddToClassList(IconButton.DiffUssCLassName);
diffButton.AddToClassList(ButtonUssClassName);
diffButton.AddToClassList(DiffButtonUssClassName);
discardButton = new IconButton();
discardButton.AddToClassList(IconButton.UndoUssClassName);
discardButton.AddToClassList(ButtonUssClassName);
discardButton.AddToClassList(DiscardButtonUssClassName);
buttons.Add(diffButton);
buttons.Add(discardButton);
}
public void SetToggleCallback(Action<bool> callback)
{
Assert.IsNull(m_ToggleCallback);
m_ToggleCallback = c => callback(c.newValue);
toggle.RegisterValueChangedCallback(m_ToggleCallback);
}
public override void ClearData()
{
base.ClearData();
diffButton.UnregisterClickEvents();
discardButton.UnregisterClickEvents();
statusIcon.ClearClassList();
statusIcon.AddToClassList(IconUssClassName);
statusIcon.AddToClassList(StatusIconUssClassName);
if (m_ToggleCallback != null)
{
toggle.UnregisterValueChangedCallback(m_ToggleCallback);
m_ToggleCallback = null;
}
}
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<ToggleableChangeListElement> { }
}
}
using System;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.Assets;
using Unity.Cloud.Collaborate.UserInterface;
using Unity.Cloud.Collaborate.Utilities;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components
{
internal class ChangesGroupHeader : VisualElement
{
public const string UssClassName = "changes-group-header";
public const string NameUssClassName = UssClassName + "__name";
public const string OverflowButtonUssClassName = UssClassName + "__overflow-button";
static readonly string k_LayoutPath = $"{CollaborateWindow.LayoutPath}/{nameof(ChangesGroupHeader)}.uxml";
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(ChangesGroupHeader)}.uss";
readonly Label m_GroupName;
readonly IconButton m_OverflowButton;
public event Action<float, float> OnOverflowButtonClicked;
public ChangesGroupHeader()
{
// Get the layout and style sheet
AddToClassList(UssClassName);
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(k_LayoutPath).CloneTree(this);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
// Initialise fields
m_GroupName = this.Q<Label>(className: NameUssClassName);
m_OverflowButton = this.Q<IconButton>(className: OverflowButtonUssClassName);
// Wire up overflow button
m_OverflowButton.Clicked += TriggerOverflowMenu;
}
public void SetEnableOverflowMenu(bool enable)
{
if (enable)
{
m_OverflowButton.RemoveFromClassList(UiConstants.ussHidden);
}
else
{
m_OverflowButton.AddToClassList(UiConstants.ussHidden);
}
}
void TriggerOverflowMenu()
{
var (x, y) = MenuUtilities.GetMenuPosition(m_OverflowButton, MenuUtilities.AnchorPoint.BottomRight);
OnOverflowButtonClicked?.Invoke(x, y);
}
public void UpdateGroupName(string text)
{
m_GroupName.text = text;
}
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<ChangesGroupHeader> { }
}
}
using System;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components
{
internal class ErrorPageView : PageComponent
{
public const string UssClassName = "error-page-view";
static readonly string k_LayoutPath = $"{CollaborateWindow.LayoutPath}/{nameof(ErrorPageView)}.uxml";
bool m_Visible;
public ErrorPageView()
{
AddToClassList(UssClassName);
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(k_LayoutPath).CloneTree(this);
}
protected override void SetActive()
{
throw new NotImplementedException();
}
protected override void SetInactive()
{
throw new NotImplementedException();
}
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<ErrorPageView> { }
}
}
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.Assets;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEngine.UIElements;
using UnityEngine;
namespace Unity.Cloud.Collaborate.Components
{
internal class HistoryEntryComponent : VisualElement
{
public const string UssClassName = "history-entry-component";
public const string ProfileInitialUssClassName = UssClassName + "__profile-initial";
public const string AuthorNameUssClassName = UssClassName + "__author-name";
public const string TimestampUssClassName = UssClassName + "__timestamp";
public const string RevisionIdUssClassName = UssClassName + "__revision-id";
public const string CommitMessageUssClassName = UssClassName + "__commit-message";
public const string ChangedFilesCountUssClassName = UssClassName + "__changed-files-count";
public const string ChangedFilesUssClassName = UssClassName + "__changed-files";
public const string RollbackButtonUssClassName = UssClassName + "__goto-button";
public const string ShowFilesButtonUssClassName = UssClassName + "__files-button";
public const string BuildStatusUssClassName = UssClassName + "__cloud-build-status";
static readonly string k_LayoutPath = $"{CollaborateWindow.LayoutPath}/{nameof(HistoryEntryComponent)}.uxml";
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(HistoryEntryComponent)}.uss";
public readonly Label profileInitial;
public readonly Label authorName;
public readonly Label timestamp;
public readonly Label revisionId;
public readonly Label commitMessage;
public readonly Button gotoButton;
public readonly Button showFilesButton;
public readonly Label cloudStatusText;
public readonly Label changedFilesCount;
public readonly AdapterListView changedFiles;
public HistoryEntryComponent()
{
// Get the layout
AddToClassList(UssClassName);
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(k_LayoutPath).CloneTree(this);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
// Initialise fields
profileInitial = this.Q<Label>(className: ProfileInitialUssClassName);
authorName = this.Q<Label>(className: AuthorNameUssClassName);
timestamp = this.Q<Label>(className: TimestampUssClassName);
revisionId = this.Q<Label>(className: RevisionIdUssClassName);
commitMessage = this.Q<Label>(className: CommitMessageUssClassName);
changedFilesCount = this.Q<Label>(className: ChangedFilesCountUssClassName);
changedFiles = this.Q<AdapterListView>(className: ChangedFilesUssClassName);
gotoButton = this.Q<Button>(className: RollbackButtonUssClassName);
showFilesButton = this.Q<Button>(className: ShowFilesButtonUssClassName);
cloudStatusText = this.Q<Label>(className: BuildStatusUssClassName);
changedFiles.SelectionType = SelectionType.None;
gotoButton.text = StringAssets.rollback;
}
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<HistoryEntryComponent> { }
}
}
using System;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components
{
internal class IconButton : Image
{
public const string UssClassName = "unity-icon-button";
public const string UndoUssClassName = "btn-undo";
public const string ShowUssClassName = "btn-show";
public const string MergeUssClassName = "btn-merge";
public const string ChooseMineUssClassName = "btn-choose-mine";
public const string ChooseRemoteUssClassName = "btn-choose-remote";
public const string DiffUssCLassName = "btn-diff";
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(IconButton)}.uss";
public event Action Clicked;
public IconButton() : this(null)
{
}
public IconButton([CanBeNull] Action clickEvent = null)
{
AddToClassList(UssClassName);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
// Setup Clickable
Clicked += clickEvent;
this.AddManipulator(new Clickable(OnClick));
}
void OnClick()
{
Clicked?.Invoke();
Blur();
}
/// <summary>
/// Remove all event handlers for the Clicked event.
/// </summary>
public void UnregisterClickEvents()
{
Clicked = null;
}
public Texture2D Image
{
get => style.backgroundImage.value.texture;
set => style.backgroundImage = value;
}
public override bool canGrabFocus { get; } = true;
/// <summary>
/// Catch the enter key event to allow for tab & enter UI navigation.
/// </summary>
/// <param name="evt">Event to check.</param>
protected override void ExecuteDefaultActionAtTarget(EventBase evt)
{
base.ExecuteDefaultActionAtTarget(evt);
// Catch enter key being pressed.
if (!(evt is KeyDownEvent downEvent)) return;
if ((downEvent.keyCode != KeyCode.KeypadEnter) && (downEvent.keyCode != KeyCode.Return)) return;
Clicked?.Invoke();
downEvent.StopPropagation();
}
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<IconButton> {}
}
}
using System;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components
{
internal class IconTextButton : VisualElement
{
public const string ussClassName = "unity-icon-text-button";
public const string imageUssClassName = ussClassName + "__image";
public const string textUssClassName = ussClassName + "__text";
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(IconTextButton)}.uss";
readonly TextElement m_TextElement;
readonly VisualElement m_Image;
public event Action Clicked;
public IconTextButton() : this(null)
{
}
public IconTextButton([CanBeNull] Action clickEvent = null)
{
AddToClassList(ussClassName);
AddToClassList(Button.ussClassName);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
Add(m_Image = new Image());
Add(m_TextElement = new TextElement());
m_Image.AddToClassList(imageUssClassName);
m_TextElement.AddToClassList(textUssClassName);
// Setup Clickable
Clicked += clickEvent;
this.AddManipulator(new Clickable(OnClick));
}
void OnClick()
{
Clicked?.Invoke();
Blur();
}
public string Text
{
get => m_TextElement.text;
set => m_TextElement.text = value;
}
public Texture2D Image
{
get => m_Image.style.backgroundImage.value.texture;
set => m_Image.style.backgroundImage = value;
}
public override bool canGrabFocus { get; } = true;
/// <summary>
/// Catch the enter key event to allow for tab & enter UI navigation.
/// </summary>
/// <param name="evt">Event to check.</param>
protected override void ExecuteDefaultActionAtTarget(EventBase evt)
{
base.ExecuteDefaultActionAtTarget(evt);
// Catch enter key being pressed.
if (!(evt is KeyDownEvent downEvent)) return;
if ((downEvent.keyCode != KeyCode.KeypadEnter) && (downEvent.keyCode != KeyCode.Return)) return;
Clicked?.Invoke();
downEvent.StopPropagation();
}
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<IconTextButton, UxmlTraits> {}
public new class UxmlTraits : VisualElement.UxmlTraits
{
readonly UxmlStringAttributeDescription m_Text = new UxmlStringAttributeDescription { name = "text" };
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
{
base.Init(ve, bag, cc);
var field = (IconTextButton)ve;
field.Text = m_Text.GetValueFromBag(bag, cc);
}
}
}
}
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components
{
internal class ListNotice : VisualElement
{
public const string UssClassName = "list-notice";
public const string ListNoticeTextUssClassName = UssClassName + "__text";
static readonly string k_LayoutPath = $"{CollaborateWindow.LayoutPath}/{nameof(ListNotice)}.uxml";
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(ListNotice)}.uss";
readonly Label m_Text;
public ListNotice()
{
AddToClassList(UssClassName);
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(k_LayoutPath).CloneTree(this);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
m_Text = this.Q<Label>(className: ListNoticeTextUssClassName);
}
public string Text
{
set => m_Text.text = value;
}
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<ListNotice> { }
}
}
using System;
using Unity.Cloud.Collaborate.Assets;
using Unity.Cloud.Collaborate.UserInterface;
using Unity.Cloud.Collaborate.Utilities;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components.Menus
{
/// <summary>
/// Global element that is used to display dialogues throughout the window.
/// </summary>
internal class FloatingDialogue : VisualElement
{
/// <summary>
/// USS class name of elements of this type.
/// </summary>
public const string UssClassName = "unity-floating-dialogue";
/// <summary>
/// Location the uss file for this element is stored.
/// </summary>
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(FloatingDialogue)}.uss";
/// <summary>
/// Backing field for the singleton.
/// </summary>
static FloatingDialogue s_Instance;
/// <summary>
/// Singleton for accessing the global FloatingDialogue
/// </summary>
public static FloatingDialogue Instance => s_Instance ?? (s_Instance = new FloatingDialogue());
/// <summary>
/// Constructor used by the singleton.
/// </summary>
FloatingDialogue()
{
AddToClassList(UssClassName);
AddToClassList(UiConstants.ussHidden);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
}
/// <summary>
/// Allows focus to be set when the window opens. Allows for the options to be next up for tab.
/// </summary>
public override bool canGrabFocus => true;
/// <summary>
/// Set the position of the dialogue.
/// </summary>
/// <param name="x">World x coordinate.</param>
/// <param name="y">World y coordinate.</param>
/// <param name="content">Content of the window.</param>
/// <param name="openDirection">Direction to open the dialogue towards.</param>
void SetPosition(float x, float y, VisualElement content, MenuUtilities.OpenDirection openDirection)
{
// Correct for the top left corner of the element based on the direction it opens.
switch (openDirection)
{
case MenuUtilities.OpenDirection.UpLeft:
x -= content.worldBound.width;
y -= content.worldBound.height;
break;
case MenuUtilities.OpenDirection.UpRight:
y -= content.worldBound.height;
break;
case MenuUtilities.OpenDirection.DownLeft:
x -= content.worldBound.width;
break;
case MenuUtilities.OpenDirection.DownRight:
break;
default:
throw new ArgumentOutOfRangeException(nameof(openDirection), openDirection, null);
}
// Set the position.
style.top = y - parent.worldBound.yMin;
style.left = x - parent.worldBound.xMin;
style.right = new StyleLength(StyleKeyword.Auto);
style.bottom = new StyleLength(StyleKeyword.Auto);
}
/// <summary>
/// Open the dialogue.
/// </summary>
/// <param name="x">World x coordinate.</param>
/// <param name="y">World y coordinate.</param>
/// <param name="content">Content to display.</param>
/// <param name="openDirection">Direction to open the dialogue towards.</param>
internal void Open(float x, float y, VisualElement content, MenuUtilities.OpenDirection openDirection = MenuUtilities.OpenDirection.DownLeft)
{
// Set new content
Clear();
Add(content);
// Set visible and give focus
RemoveFromClassList(UiConstants.ussHidden);
Focus();
BringToFront();
// Catch scrolling to avoid menu becoming detached.
parent.RegisterCallback<WheelEvent>(OnScroll, TrickleDown.TrickleDown);
// Catch clicks outside of the dialogue and close it.
parent.RegisterCallback<MouseDownEvent>(OnMouseDown, TrickleDown.TrickleDown);
// Catch window size changes so that the menu position can be fixed.
parent.RegisterCallback<GeometryChangedEvent>(OnGeometryChange, TrickleDown.TrickleDown);
content.RegisterCallback<GeometryChangedEvent>(SizeKnownCallback);
void SizeKnownCallback(GeometryChangedEvent _)
{
// Unregister now that we know it has a size.
content.UnregisterCallback<GeometryChangedEvent>(SizeKnownCallback);
// Set the position in the window
SetPosition(x, y, content, openDirection);
}
}
/// <summary>
/// Close the dialogue.
/// </summary>
internal void Close()
{
AddToClassList(UiConstants.ussHidden);
Clear();
// Avoid wasting extra cycles when closed.
parent.UnregisterCallback<WheelEvent>(OnScroll, TrickleDown.TrickleDown);
parent.UnregisterCallback<MouseDownEvent>(OnMouseDown, TrickleDown.TrickleDown);
}
/// <summary>
/// On scroll event.
/// </summary>
/// <param name="evt">Event data.</param>
void OnScroll(WheelEvent evt)
{
// Close the window if the user scrolls outside the dialogue.
if (!worldBound.Contains(evt.mousePosition))
{
Close();
}
}
/// <summary>
/// Mouse down event.
/// </summary>
/// <param name="evt">Event data.</param>
void OnMouseDown(MouseDownEvent evt)
{
// Close the window if the user clicks outside the dialogue.
if (!worldBound.Contains(evt.mousePosition))
{
Close();
}
}
/// <summary>
/// Geometry changed event.
/// </summary>
/// <param name="evt">Event data.</param>
void OnGeometryChange(GeometryChangedEvent evt)
{
// Close to avoid the dialogue getting detached.
Close();
}
}
}
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.UserInterface;
using Unity.Cloud.Collaborate.Utilities;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components.Menus
{
[UsedImplicitly]
internal class FloatingMenu
{
public const string ussClassName = "unity-floating-menu";
// Fields used to display the option list.
const float k_ItemHeight = 28f;
readonly List<(string Text, Action Action, bool Enabled)> m_Items;
/// <summary>
/// Location the uss file for this element is stored.
/// </summary>
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(FloatingMenu)}.uss";
/// <summary>
/// Container for the menu items.
/// </summary>
readonly VisualElement m_Content;
/// <summary>
/// Direction to open the menu.
/// </summary>
MenuUtilities.OpenDirection m_OpenDirection = MenuUtilities.OpenDirection.DownLeft;
/// <summary>
/// Create a new floating menu. Follows the builder pattern.
/// </summary>
public FloatingMenu()
{
m_Items = new List<(string Text, Action Action, bool Enabled)>();
m_Content = new VisualElement();
m_Content.AddToClassList(ussClassName);
m_Content.styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
}
/// <summary>
/// Add a single option to the menu.
/// </summary>
/// <param name="text">Text in the option.</param>
/// <param name="action">Action to invoke on click.</param>
/// <param name="enabled">State of the entry.</param>
/// <returns>This.</returns>
public FloatingMenu AddEntry(string text, Action action, bool enabled)
{
m_Items.Add((text, action, enabled));
return this;
}
/// <summary>
/// Add a list of entries.
/// </summary>
/// <param name="items">Entries to add.</param>
/// <returns>This.</returns>
public FloatingMenu AddEntries(IEnumerable<(string Text, Action Action, bool Enabled)> items)
{
m_Items.AddRange(items);
return this;
}
/// <summary>
/// Sets the open direction of the menu.
/// </summary>
/// <param name="openDirection">Direction the menu opens towards.</param>
/// <returns>This.</returns>
public FloatingMenu SetOpenDirection(MenuUtilities.OpenDirection openDirection)
{
m_OpenDirection = openDirection;
return this;
}
/// <summary>
/// Opens the constructed menu.
/// </summary>
/// <param name="x">World x coordinate.</param>
/// <param name="y">World y coordinate.</param>
public void Open(float x, float y)
{
FloatingDialogue.Instance.Open(x, y, GenerateContent(), m_OpenDirection);
}
/// <summary>
/// Generate the visual element that displays the content of this menu.
/// </summary>
/// <returns>The constructed visual element.</returns>
VisualElement GenerateContent()
{
m_Content.Clear();
foreach (var item in m_Items)
{
// Ensure the dialogue closes once the option is selected
void Action()
{
FloatingDialogue.Instance.Close();
item.Action();
}
var elem = new FloatingMenuItem(item.Text, Action, item.Enabled, k_ItemHeight);
m_Content.Add(elem);
}
return m_Content;
}
}
}
using System;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components.Menus
{
internal class FloatingMenuItem : VisualElement
{
const string k_UssClassName = "unity-floating-menu-item";
/// <summary>
/// Location the uss file for this element is stored.
/// </summary>
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(FloatingMenuItem)}.uss";
public override bool canGrabFocus { get; } = true;
readonly Action m_Action;
public FloatingMenuItem(string text, Action action, bool enabled, float height)
{
AddToClassList(k_UssClassName);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
m_Action = action;
focusable = true;
this.AddManipulator(new Clickable(OnExec));
SetEnabled(enabled);
Add(new Label(text));
style.height = height;
}
void OnExec()
{
m_Action();
}
/// <summary>
/// Catch the enter key event to allow for tab & enter UI navigation.
/// </summary>
/// <param name="evt">Event to check.</param>
protected override void ExecuteDefaultActionAtTarget(EventBase evt)
{
base.ExecuteDefaultActionAtTarget(evt);
// Catch enter key being pressed.
if (!(evt is KeyDownEvent downEvent)) return;
if (downEvent.keyCode != KeyCode.KeypadEnter && downEvent.keyCode != KeyCode.Return) return;
OnExec();
downEvent.StopPropagation();
}
}
}
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components
{
internal abstract class PageComponent : VisualElement
{
/// <summary>
/// Current active status for this page.
/// </summary>
protected bool Active { get; private set; }
/// <summary>
/// Set active status of this page.
/// </summary>
/// <param name="active">True if the page is to be active.</param>
public void SetActive(bool active)
{
Active = active;
if (Active)
{
SetActive();
}
else
{
SetInactive();
}
}
/// <summary>
/// Set this page active.
/// </summary>
protected abstract void SetActive();
/// <summary>
/// Set this page inactive.
/// </summary>
protected abstract void SetInactive();
}
}
using System;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components
{
internal class Paginator : VisualElement
{
public const string UssClassName = "paginator";
public const string PageTextUssClassName = UssClassName + "__page-text";
public const string BackButtonUssClassName = UssClassName + "__back-button";
public const string ForwardsButtonUssClassName = UssClassName + "__forwards-button";
static readonly string k_LayoutPath = $"{CollaborateWindow.LayoutPath}/{nameof(Paginator)}.uxml";
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(Paginator)}.uss";
public const int MoveBackwards = -1;
public const int MoveForwards = 1;
public event Action<int> ClickedMovePage;
readonly Label m_PageText;
readonly Button m_BackButton;
readonly Button m_ForwardsButton;
public Paginator()
{
// Get the layout
AddToClassList(UssClassName);
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(k_LayoutPath).CloneTree(this);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
m_PageText = this.Q<Label>(className: PageTextUssClassName);
m_BackButton = this.Q<Button>(className: BackButtonUssClassName);
m_ForwardsButton = this.Q<Button>(className: ForwardsButtonUssClassName);
m_BackButton.text = "<";
m_ForwardsButton.text = ">";
m_BackButton.clickable.clicked += () => ClickedMovePage?.Invoke(MoveBackwards);
m_ForwardsButton.clickable.clicked += () => ClickedMovePage?.Invoke(MoveForwards);
}
public void SetPage(int page, int maxPage)
{
m_PageText.text = $"Page {page + 1} of {maxPage + 1}";
m_BackButton.SetEnabled(page != 0);
m_ForwardsButton.SetEnabled(page != maxPage);
}
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<Paginator> { }
}
}
using System;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.Assets;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components
{
[UsedImplicitly]
internal class ProgressView : VisualElement
{
public const string UssClassName = "progress-view";
public const string LabelUssClassName = UssClassName + "__label";
public const string ProgressBarUssClassName = UssClassName + "__progress-bar";
public const string ButtonUssClassName = UssClassName + "__button";
static readonly string k_LayoutPath = $"{CollaborateWindow.LayoutPath}/{nameof(ProgressView)}.uxml";
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(ProgressView)}.uss";
readonly Label m_Label;
readonly ProgressBar m_ProgressBar;
readonly Button m_Button;
public ProgressView()
{
AddToClassList(UssClassName);
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(k_LayoutPath).CloneTree(this);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
m_Label = this.Q<Label>(className: LabelUssClassName);
m_Label.text = string.Empty;
m_ProgressBar = this.Q<ProgressBar>(className: ProgressBarUssClassName);
m_Button = this.Q<Button>(className: ButtonUssClassName);
m_Button.text = StringAssets.cancel;
}
public void SetText(string text, string progressText)
{
m_Label.text = text;
m_ProgressBar.title = progressText;
}
public void SetPercentComplete(int percent)
{
m_ProgressBar.value = percent;
}
public void SetCancelCallback(Action callback)
{
m_Button.clickable.clicked += callback;
}
public void SetCancelButtonActive(bool active)
{
m_Button.SetEnabled(active);
}
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<ProgressView> { }
}
}
# Resources
This directory contains the UIElements-based user interface components.
## Overview
Each component is defined as its own class and file in this directory.
## Adding a New Component
Each component is a C# class that extends the UiElements' VisualElement class and provides a UXML factory. If no UXML
parameters are required/desired, a simple factory like this (taken from AlertBar) works:
```csharp
public new class UxmlFactory : UxmlFactory<AlertBar> { }
```
Just adding this line to the bottom of the component class with the `<AlertBar>` replaced with the name of the class.
Adding UXML parameters used to be covered in the official docs. Until it is returned: look at the source code for
any UiElements class such as TextElement.
To use the component in UXML (with editor inspections) the xml schema needs to be updated within the Unity Editor.
Instructions on how to do that is contained in `../Assets/`.
using System;
using System.Threading;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.Assets;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components
{
class SearchBar : VisualElement
{
public const string UssClassName = "unity-search-bar";
public const string SearchFieldUssClassName = UssClassName + "__search-field";
public const string PlaceholderUssClassName = UssClassName + "__placeholder";
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(SearchBar)}.uss";
public const int timeoutMilliseconds = 1000;
readonly ToolbarSearchField m_SearchField;
readonly Label m_Placeholder;
string m_LatestSearchValue;
bool m_SearchEventFlag;
readonly Timer m_SearchEventTimer;
bool m_Focused;
public event Action<string> Search = delegate { };
public SearchBar() : this(null)
{
}
public SearchBar([CanBeNull] Action<string> searchEvent = null)
{
// Setup delayed search event to throttle requests.
m_SearchEventTimer = new Timer(_ => EditorApplication.delayCall += () =>
{
m_SearchEventFlag = false;
Search(m_LatestSearchValue);
});
AddToClassList(UssClassName);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
m_SearchField = new ToolbarSearchField();
m_Placeholder = new Label { text = StringAssets.search, pickingMode = PickingMode.Ignore };
m_SearchField.AddToClassList(SearchFieldUssClassName);
m_Placeholder.AddToClassList(PlaceholderUssClassName);
Add(m_SearchField);
Add(m_Placeholder);
// Setup search event
if (searchEvent != null)
{
Search += searchEvent;
}
// Setup events to hide/show placeholder.
var textField = m_SearchField.Q<TextField>(className: ToolbarSearchField.textUssClassName);
textField.RegisterCallback<FocusInEvent>(e =>
{
m_Focused = true;
UpdatePlaceholderVisibility();
});
textField.RegisterCallback<FocusOutEvent>(e =>
{
m_Focused = false;
UpdatePlaceholderVisibility();
});
m_SearchField.RegisterValueChangedCallback(SearchEventThrottle);
// Set initial placeholder hide/show status.
ShowPlaceholder();
}
void SearchEventThrottle(ChangeEvent<string> evt)
{
UpdatePlaceholderVisibility();
m_LatestSearchValue = evt.newValue;
if (m_SearchEventFlag) return;
m_SearchEventFlag = true;
m_SearchEventTimer.Change(timeoutMilliseconds, Timeout.Infinite);
}
public string Value
{
get => m_SearchField.value;
set
{
m_SearchField.value = value;
UpdatePlaceholderVisibility();
}
}
public void SetValueWithoutNotify(string value)
{
m_SearchField.SetValueWithoutNotify(value);
UpdatePlaceholderVisibility();
}
void UpdatePlaceholderVisibility()
{
if (string.IsNullOrEmpty(m_SearchField.value) && !m_Focused)
{
ShowPlaceholder();
}
else
{
HidePlaceholder();
}
}
void HidePlaceholder()
{
m_Placeholder.AddToClassList(UiConstants.ussHidden);
}
void ShowPlaceholder()
{
m_Placeholder.RemoveFromClassList(UiConstants.ussHidden);
}
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<SearchBar> { }
}
}
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components
{
abstract class TabPageComponent : VisualElement
{
/// <summary>
/// Current active status for this page.
/// </summary>
protected bool Active { get; private set; }
/// <summary>
/// Set active status of this page.
/// </summary>
/// <param name="active">True if the page is to be active.</param>
public void SetActive(bool active)
{
Active = active;
if (Active)
{
SetActive();
}
else
{
SetInactive();
}
}
/// <summary>
/// Set this tab page active.
/// </summary>
protected abstract void SetActive();
/// <summary>
/// Set this tab page inactive.
/// </summary>
protected abstract void SetInactive();
}
}
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.Assets;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components
{
[UsedImplicitly]
internal class TabView : VisualElement
{
public const string UssClassName = "unity-tab-view";
public const string ContentContainerUssClassName = UssClassName + "__content-container";
public const string TabHeaderUssClassName = UssClassName + "__tab-header";
public const string ToolbarUssClassName = UssClassName + "__toolbar";
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(TabView)}.uss";
const int k_NoTabs = -1;
int m_ActiveTabIndex = k_NoTabs;
bool m_Active;
readonly VisualElement m_Content;
readonly VisualElement m_Toolbar;
readonly List<(TextButton button, TabPageComponent tab)> m_TabList;
public event Action<int> TabSwitched;
public TabView()
{
AddToClassList(UssClassName);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
m_Toolbar = new VisualElement { name = "unity-tab-view-toolbar" };
m_Toolbar.AddToClassList(ToolbarUssClassName);
m_Toolbar.AddToClassList(UiConstants.ussDefaultInset);
hierarchy.Add(m_Toolbar);
m_Content = new VisualElement { name = "unity-content-container" };
m_Content.AddToClassList(ContentContainerUssClassName);
hierarchy.Add(m_Content);
m_TabList = new List<(TextButton button, TabPageComponent tab)>();
}
public void SetActive()
{
Assert.IsFalse(m_Active, "TabView is already active.");
m_Active = true;
if (m_ActiveTabIndex != k_NoTabs)
{
m_TabList[m_ActiveTabIndex].tab.SetActive(true);
}
}
public void SetInactive()
{
Assert.IsTrue(m_Active, "TabView is already inactive.");
m_Active = false;
if (m_ActiveTabIndex != k_NoTabs)
{
m_TabList[m_ActiveTabIndex].tab.SetActive(false);
}
}
/// <summary>
/// Add a tab to the view.
/// </summary>
/// <param name="tabName">Title of the tab.</param>
/// <param name="tab">Tab content to display.</param>
public void AddTab(string tabName, TabPageComponent tab)
{
// Get the tab index
var index = m_TabList.Count;
tab.style.flexGrow = 1;
tab.style.flexShrink = 1;
tab.style.flexBasis = new StyleLength(StyleKeyword.Auto);
// Copy value to avoid modification of the closure scope.
var indexCopy = index;
var btn = new TextButton(() => SwitchTabInternal(indexCopy)) { text = tabName };
btn.AddToClassList(TabHeaderUssClassName);
m_Toolbar.Add(btn);
// Add tab to list
m_TabList.Add((btn, tab));
// If no currently active tab, switch to this newly added one.
if (m_ActiveTabIndex == k_NoTabs)
{
SwitchToNextTab();
}
}
/// <summary>
/// Switch to the tab with the given index. Does nothing with an invalid index.
/// </summary>
/// <param name="index">Index of the tab to switch to.</param>
public void SwitchTab(int index)
{
// Sanitise index to be passed into the internal switch method.
if (index == k_NoTabs) return;
if (index < m_TabList.Count)
{
SwitchTabInternal(index);
}
}
/// <summary>
/// Switch to tab with the given index. Does *NOT* check the validity of the index.
/// </summary>
/// <param name="index">Index of the tab to switch to.</param>
void SwitchTabInternal(int index)
{
// Reset tab state of previously active content/button - if there was one.
if (m_ActiveTabIndex != k_NoTabs)
{
m_TabList[m_ActiveTabIndex].tab.RemoveFromHierarchy();
if (m_Active)
{
m_TabList[m_ActiveTabIndex].tab.SetActive(false);
}
m_TabList[m_ActiveTabIndex].button.RemoveFromClassList(UiConstants.ussActive);
}
// Set new active tab.
m_ActiveTabIndex = index;
// Set tab state for newly active content/button.
if (m_Active)
{
m_TabList[m_ActiveTabIndex].tab.SetActive(true);
}
m_TabList[m_ActiveTabIndex].button.AddToClassList(UiConstants.ussActive);
m_Content.Add(m_TabList[m_ActiveTabIndex].tab);
TabSwitched?.Invoke(index);
}
/// <summary>
/// Switch to the next valid tab. Wraps if there's no direct successor.
/// </summary>
void SwitchToNextTab()
{
var index = (m_ActiveTabIndex + 1) % m_TabList.Count;
SwitchTabInternal(index);
}
public override VisualElement contentContainer => m_Content;
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<TabView> { }
}
}
using System;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components {
internal class TextButton : TextElement
{
public const string UssClassName = "unity-text-button";
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(TextButton)}.uss";
public event Action Clicked;
[UsedImplicitly]
public TextButton() : this(null)
{
}
public TextButton([CanBeNull] Action clickEvent = null)
{
AddToClassList(UssClassName);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
Clicked += clickEvent;
this.AddManipulator(new Clickable(OnClick));
}
void OnClick()
{
Clicked?.Invoke();
Blur();
}
public override bool canGrabFocus { get; } = true;
/// <summary>
/// Catch the enter key event to allow for tab & enter UI navigation.
/// </summary>
/// <param name="evt">Event to check.</param>
protected override void ExecuteDefaultActionAtTarget(EventBase evt)
{
base.ExecuteDefaultActionAtTarget(evt);
// Catch enter key being pressed.
if (!(evt is KeyDownEvent downEvent)) return;
if ((downEvent.keyCode != KeyCode.KeypadEnter) && (downEvent.keyCode != KeyCode.Return)) return;
Clicked?.Invoke();
downEvent.StopPropagation();
}
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<TextButton, UxmlTraits> {}
}
}
using System;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.Assets;
using Unity.Cloud.Collaborate.Components.Menus;
using Unity.Cloud.Collaborate.UserInterface;
using Unity.Cloud.Collaborate.Utilities;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components
{
[UsedImplicitly]
internal class TopBar : VisualElement
{
public const string UssClassName = "top-bar";
public const string IconUssClassName = UssClassName + "__icon";
public const string BranchInfoUssClassName = UssClassName + "__branch-info";
public const string OverflowMenuUssClassName = UssClassName + "__overflow-button";
public const string BackUssClassName = UssClassName + "__back";
public const string BackButtonUssClassName = UssClassName + "__back-button";
public const string BackTextUssClassName = UssClassName + "__back-text";
static readonly string k_LayoutPath = $"{CollaborateWindow.LayoutPath}/{nameof(TopBar)}.uxml";
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(TopBar)}.uss";
public event Action BackButtonClicked;
readonly VisualElement m_Icon;
readonly TextElement m_BranchInfo;
readonly IconButton m_OverflowMenu;
readonly VisualElement m_BackContainer;
readonly IconButton m_BackButton;
readonly TextElement m_BackText;
[CanBeNull]
string m_BranchName;
public TopBar()
{
// Get the layout
AddToClassList(UssClassName);
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(k_LayoutPath).CloneTree(this);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
// Initialise fields
m_Icon = this.Q<VisualElement>(className: IconUssClassName);
m_BranchInfo = this.Q<TextElement>(className: BranchInfoUssClassName);
m_OverflowMenu = this.Q<IconButton>(className: OverflowMenuUssClassName);
m_BackContainer = this.Q<VisualElement>(className: BackUssClassName);
m_BackButton = this.Q<IconButton>(className: BackButtonUssClassName);
m_BackText = this.Q<TextElement>(className: BackTextUssClassName);
m_OverflowMenu.Clicked += ClickableOnClicked;
m_BackButton.Clicked += () => BackButtonClicked?.Invoke();
HideBackNavigation();
}
/// <summary>
/// Hide the current back navigation.
/// </summary>
public void HideBackNavigation()
{
m_BackContainer.AddToClassList(UiConstants.ussHidden);
m_BackButton.SetEnabled(false);
m_BackText.text = string.Empty;
}
/// <summary>
/// Register back navigation to be made available to the user to navigate backwards in the UI.
/// </summary>
/// <param name="text">Destination of the back navigation</param>
public void DisplayBackNavigation([NotNull] string text)
{
m_BackText.text = text;
m_BackButton.SetEnabled(true);
m_BackContainer.RemoveFromClassList(UiConstants.ussHidden);
}
void ClickableOnClicked()
{
var (x, y) = MenuUtilities.GetMenuPosition(m_OverflowMenu, MenuUtilities.AnchorPoint.BottomRight);
new FloatingMenu()
.AddEntry("Invite Teammate", OpenLinksUtility.OpenMembersLink, true)
.SetOpenDirection(MenuUtilities.OpenDirection.DownLeft)
.Open(x, y);
}
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<TopBar> { }
}
}
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.Models.Enums;
using Unity.Cloud.Collaborate.Models.Structures;
namespace Unity.Cloud.Collaborate.Models.Api
{
internal interface ISourceControlProvider
{
/// <summary>
/// Event called whenever the change list is updated.
/// </summary>
event Action UpdatedChangeList;
/// <summary>
/// Event called whenever the selected change list is updated.
/// </summary>
event Action<IReadOnlyList<string>> UpdatedSelectedChangeList;
/// <summary>
/// Event called whenever the list of historical revisions is updated.
/// </summary>
event Action UpdatedHistoryEntries;
/// <summary>
/// Event called whenever a long operation (with progress) has completed / started.
/// </summary>
event Action<bool> UpdatedOperationStatus;
/// <summary>
/// Event called whenever a long operation progress has changed.
/// </summary>
event Action<IProgressInfo> UpdatedOperationProgress;
/// <summary>
/// Event called whenever an error has occurred.
/// </summary>
event Action<IErrorInfo> ErrorOccurred;
/// <summary>
/// Event called whenever an error has cleared.
/// </summary>
event Action ErrorCleared;
/// <summary>
/// Event called whenever the conflict state changes.
/// </summary>
event Action<bool> UpdatedConflictState;
/// <summary>
/// Event called whenever the availability of remote revisions changes.
/// </summary>
event Action<bool> UpdatedRemoteRevisionsAvailability;
/// <summary>
/// Event that is triggered when the project status changes.
/// </summary>
event Action<ProjectStatus> UpdatedProjectStatus;
/// <summary>
/// Get whether there are available revisions to fetch.
/// </summary>
/// <returns>True if there are revisions available</returns>
bool GetRemoteRevisionAvailability();
/// <summary>
/// Get whether there is a conflict or not.
/// </summary>
/// <returns>True if there is a conflict.</returns>
bool GetConflictedState();
/// <summary>
/// Get the current progress state.
/// </summary>
/// <returns>The current progress state. Null if no operation ongoing.</returns>
[CanBeNull]
IProgressInfo GetProgressState();
/// <summary>
/// Get the current error state.
/// </summary>
/// <returns>The current error state. Null if no errors presently.</returns>
[CanBeNull]
IErrorInfo GetErrorState();
/// <summary>
/// Returns the current project status.
/// </summary>
/// <returns>Current project status.</returns>
ProjectStatus GetProjectStatus();
/// <summary>
/// Request the current change list.
/// </summary>
/// <param name="callback">Callback for the result.</param>
void RequestChangeList([NotNull] Action<IReadOnlyList<IChangeEntry>> callback);
/// <summary>
/// Publish files to Collaborate.
/// </summary>
/// <param name="message">Message to commit with.</param>
/// <param name="changes">Changes to publish. Pass null to publish all.</param>
void RequestPublish([NotNull] string message, [CanBeNull] IReadOnlyList<IChangeEntry> changes = null);
/// <summary>
/// Request a single historical revision.
/// </summary>
/// <param name="revisionId">Id of the revision to request.</param>
/// <param name="callback">Callback for the result.</param>
void RequestHistoryEntry([NotNull] string revisionId, [NotNull] Action<IHistoryEntry> callback);
/// <summary>
/// Request a page of historical revisions.
/// </summary>
/// <param name="offset">Where to start the page from.</param>
/// <param name="pageSize">Number of entries in the page.</param>
/// <param name="callback">Callback for the result.</param>
void RequestHistoryPage(int offset, int pageSize, [NotNull] Action<IReadOnlyList<IHistoryEntry>> callback);
/// <summary>
/// Request the total number of historical revisions.
/// </summary>
/// <param name="callback">Callback for the result.</param>
void RequestHistoryCount([NotNull] Action<int?> callback);
/// <summary>
/// Revert the specified file to the state of the current revision.
/// of the source control system, or delete it if it's a new file.
/// </summary>
/// <param name="entry">Entry to discard.</param>
void RequestDiscard([NotNull] IChangeEntry entry);
/// <summary>
/// Revert the specified files to the state of the current revision.
/// of the source control system.
/// </summary>
/// <param name="paths">List of entries to discard.</param>
void RequestBulkDiscard([NotNull] IReadOnlyList<IChangeEntry> entries);
/// <summary>
/// Diff the changes for the file at the given path.
/// </summary>
/// <param name="path">Path of the file to diff.</param>
void RequestDiffChanges([NotNull] string path);
/// <summary>
/// Returns true if the provider supports revert.
/// </summary>
bool SupportsRevert { get; }
/// <summary>
/// Request revert the specified files to the given revision.
/// </summary>
/// <param name="revisionId">Revision to revert the files back to.</param>
/// <param name="files">Files to revert back.</param>
void RequestRevert([NotNull] string revisionId, [NotNull] IReadOnlyList<string> files);
/// <summary>
/// Request to update the state of the project to a new provided revision.
/// </summary>
/// <param name="revisionId">New revision id of the project to go to.</param>
void RequestUpdateTo([NotNull] string revisionId);
/// <summary>
/// Request to take the state of the project back to the given (and current) revision.
/// </summary>
/// <param name="revisionId">Current revision id of the project to go back to.</param>
void RequestRestoreTo([NotNull] string revisionId);
/// <summary>
/// Request to take the state of the project back to the given revision, but do not change the current revision or history.
/// </summary>
/// <param name="revisionId">Revision id to go back to.</param>
void RequestGoBackTo([NotNull] string revisionId);
/// <summary>
/// Clears the error state.
/// </summary>
void ClearError();
/// <summary>
/// Show the difference between both version of a conlicted file.
/// </summary>
/// <param name="path">Path of the file to show.</param>
void RequestShowConflictedDifferences([NotNull] string path);
/// <summary>
/// Request to choose merge for the provided conflict.
/// </summary>
/// <param name="path">Path of the file to choose merge for.</param>
void RequestChooseMerge([NotNull] string path);
/// <summary>
/// Request to choose mine for the provided conflict.
/// </summary>
/// <param name="paths">Paths of the files to choose mine for.</param>
void RequestChooseMine([NotNull] string[] paths);
/// <summary>
/// Request to choose remote for the provided conflict.
/// </summary>
/// <param name="paths">Paths of the files to choose remote for.</param>
void RequestChooseRemote([NotNull] string[] paths);
/// <summary>
/// Request sync to latest revision.
/// </summary>
void RequestSync();
/// <summary>
/// Request cancel current job.
/// </summary>
void RequestCancelJob();
/// <summary>
/// Request to turn on the service.
/// </summary>
/// <returns></returns>
void RequestTurnOnService();
/// <summary>
/// Show the service page.
/// </summary>
void ShowServicePage();
/// <summary>
/// Show login page.
/// </summary>
void ShowLoginPage();
/// <summary>
/// Show no seat page.
/// </summary>
void ShowNoSeatPage();
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment