319 lines
11 KiB
C#
319 lines
11 KiB
C#
|
using System;
|
||
|
using System.Linq;
|
||
|
using System.Threading.Tasks;
|
||
|
using JetBrains.Annotations;
|
||
|
using Unity.Cloud.Collaborate.Assets;
|
||
|
using Unity.Cloud.Collaborate.Components.Menus;
|
||
|
using Unity.Cloud.Collaborate.Models;
|
||
|
using Unity.Cloud.Collaborate.Models.Structures;
|
||
|
using Unity.Cloud.Collaborate.Utilities;
|
||
|
using Unity.Cloud.Collaborate.Views;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.Assertions;
|
||
|
|
||
|
namespace Unity.Cloud.Collaborate.Presenters
|
||
|
{
|
||
|
internal class ChangesPresenter : IChangesPresenter
|
||
|
{
|
||
|
[NotNull]
|
||
|
readonly IChangesView m_View;
|
||
|
[NotNull]
|
||
|
readonly IChangesModel m_Model;
|
||
|
[NotNull]
|
||
|
readonly IMainModel m_MainModel;
|
||
|
|
||
|
bool m_IsStarted;
|
||
|
|
||
|
public ChangesPresenter([NotNull] IChangesView view, [NotNull] IChangesModel model, [NotNull] IMainModel mainModel)
|
||
|
{
|
||
|
m_View = view;
|
||
|
m_Model = model;
|
||
|
m_MainModel = mainModel;
|
||
|
}
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public void Start()
|
||
|
{
|
||
|
Assert.IsFalse(m_IsStarted, "The presenter has already been started.");
|
||
|
m_IsStarted = true;
|
||
|
|
||
|
m_Model.UpdatedChangeList += OnUpdatedChangeList;
|
||
|
m_Model.OnUpdatedSelectedChanges += OnUpdatedPartiallySelectedChanges;
|
||
|
m_Model.BusyStatusUpdated += OnBusyStatusUpdated;
|
||
|
m_Model.StateChanged += OnStateChanged;
|
||
|
m_MainModel.RemoteRevisionsAvailabilityChange += OnRemoteRevisionsAvailabilityChange;
|
||
|
m_MainModel.ConflictStatusChange += OnConflictStatusChange;
|
||
|
|
||
|
PopulateInitialData();
|
||
|
}
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public void Stop()
|
||
|
{
|
||
|
Assert.IsTrue(m_IsStarted, "The presenter has already been stopped.");
|
||
|
m_IsStarted = false;
|
||
|
|
||
|
m_Model.UpdatedChangeList -= OnUpdatedChangeList;
|
||
|
m_Model.OnUpdatedSelectedChanges -= OnUpdatedPartiallySelectedChanges;
|
||
|
m_Model.BusyStatusUpdated -= OnBusyStatusUpdated;
|
||
|
m_Model.StateChanged -= OnStateChanged;
|
||
|
m_MainModel.RemoteRevisionsAvailabilityChange -= OnRemoteRevisionsAvailabilityChange;
|
||
|
m_MainModel.ConflictStatusChange -= OnConflictStatusChange;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Refresh state from the model.
|
||
|
/// </summary>
|
||
|
void OnStateChanged()
|
||
|
{
|
||
|
PopulateInitialData();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Populate the view with the initial data from the model.
|
||
|
/// </summary>
|
||
|
void PopulateInitialData()
|
||
|
{
|
||
|
m_View.SetRevisionSummary(m_Model.SavedRevisionSummary);
|
||
|
m_View.SetSearchQuery(m_Model.SavedSearchQuery);
|
||
|
m_View.SetBusyStatus(m_Model.Busy);
|
||
|
m_Model.RequestInitialData();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Event handler to receive updated remote changes available status.
|
||
|
/// </summary>
|
||
|
/// <param name="available">Whether or not remote changes are available.</param>
|
||
|
protected void OnRemoteRevisionsAvailabilityChange(bool available)
|
||
|
{
|
||
|
UpdatePublishButton();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Event handler to receive updated busy status.
|
||
|
/// </summary>
|
||
|
/// <param name="busy">New busy status.</param>
|
||
|
void OnBusyStatusUpdated(bool busy)
|
||
|
{
|
||
|
m_View.SetBusyStatus(busy);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Event handler for when the model reports an updated change list.
|
||
|
/// </summary>
|
||
|
protected void OnUpdatedChangeList()
|
||
|
{
|
||
|
UpdatePublishButton();
|
||
|
UpdateChangeList();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Request the change or conflict list depending on the state of the model. The result is then given to the
|
||
|
/// view to populate itself. Fire and forget method -- must be run on main thread.
|
||
|
/// </summary>
|
||
|
void UpdateChangeList()
|
||
|
{
|
||
|
Assert.IsTrue(Threading.IsMainThread, "Updating the change lists must be done from the main thread.");
|
||
|
|
||
|
// Fetch and send data to the UI depending on what's the current display mode.
|
||
|
if (m_Model.Conflicted)
|
||
|
{
|
||
|
Task.Run(() => m_Model.GetConflictedEntries(m_Model.SavedSearchQuery))
|
||
|
.ContinueWith(r => m_View.SetConflicts(r.Result), TaskScheduler.FromCurrentSynchronizationContext());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Task.Run(() => m_Model.GetAllEntries(m_Model.SavedSearchQuery))
|
||
|
.ContinueWith(r => m_View.SetChanges(r.Result), TaskScheduler.FromCurrentSynchronizationContext());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Inform view to refresh its selections.
|
||
|
/// </summary>
|
||
|
protected void OnUpdatedPartiallySelectedChanges()
|
||
|
{
|
||
|
UpdatePublishButton();
|
||
|
m_View.SetSelectedChanges();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Update changelist display in response to the conflict status changing.
|
||
|
/// </summary>
|
||
|
/// <param name="conflicted">New conflicted status.</param>
|
||
|
protected void OnConflictStatusChange(bool conflicted)
|
||
|
{
|
||
|
UpdatePublishButton();
|
||
|
UpdateChangeList();
|
||
|
}
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public bool UpdateEntryToggle(string path, bool toggled)
|
||
|
{
|
||
|
var result = m_Model.UpdateEntryToggle(path, toggled);
|
||
|
m_View.SetToggledCount(ToggledCount);
|
||
|
UpdatePublishButton();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public int ToggledCount => m_Model.ToggledCount;
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public int TotalCount => m_Model.TotalCount;
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public int ConflictedCount => m_Model.ConflictedCount;
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public bool Searching => !string.IsNullOrEmpty(m_Model.SavedSearchQuery);
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public void RequestPublish()
|
||
|
{
|
||
|
Assert.IsFalse(Searching, "Cannot publish while searching");
|
||
|
m_Model.RequestPublish(m_Model.SavedRevisionSummary, m_Model.GetToggledEntries().Select(i => i.Entry).ToList());
|
||
|
}
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public void RequestDiscard(IChangeEntry entry)
|
||
|
{
|
||
|
if (m_View.DisplayDialogue(StringAssets.confirmDiscardChangesTitle,
|
||
|
StringAssets.confirmDiscardChangeMessage, StringAssets.discardChanges,
|
||
|
StringAssets.cancel))
|
||
|
{
|
||
|
m_Model.RequestDiscard(entry);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Discard all toggled entries. Fire and forget method -- must be called on main thread.
|
||
|
/// </summary>
|
||
|
void RequestDiscardToggled()
|
||
|
{
|
||
|
var entries = m_Model.GetToggledEntries(m_Model.SavedSearchQuery).Select(e => e.Entry).ToList();
|
||
|
if (m_View.DisplayDialogue(StringAssets.confirmDiscardChangesTitle,
|
||
|
string.Format(StringAssets.confirmDiscardChangesMessage, entries.Count), StringAssets.discardChanges,
|
||
|
StringAssets.cancel))
|
||
|
{
|
||
|
m_Model.RequestBulkDiscard(entries);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Update the state of the publish button in the view based on the state of the model.
|
||
|
/// </summary>
|
||
|
void UpdatePublishButton()
|
||
|
{
|
||
|
if (m_Model.Conflicted)
|
||
|
{
|
||
|
m_View.SetPublishEnabled(false, StringAssets.cannotPublishWhileConflicted);
|
||
|
}
|
||
|
else if (m_MainModel.RemoteRevisionsAvailable)
|
||
|
{
|
||
|
m_View.SetPublishEnabled(false, StringAssets.cannotPublishWithIncomingChanges);
|
||
|
}
|
||
|
else if (m_Model.ToggledCount < 1)
|
||
|
{
|
||
|
m_View.SetPublishEnabled(false, StringAssets.cannotPublishWithoutFiles);
|
||
|
}
|
||
|
else if (Searching)
|
||
|
{
|
||
|
m_View.SetPublishEnabled(false, StringAssets.cannotPublishWhileSearching);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_View.SetPublishEnabled(true);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public void RequestDiffChanges(string path)
|
||
|
{
|
||
|
m_Model.RequestDiffChanges(path);
|
||
|
}
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public void SetSearchQuery(string query)
|
||
|
{
|
||
|
var value = StringUtility.TrimAndToLower(query);
|
||
|
m_Model.SavedSearchQuery = value;
|
||
|
m_View.SetSearchQuery(query);
|
||
|
UpdateChangeList();
|
||
|
UpdatePublishButton();
|
||
|
}
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public void SetRevisionSummary(string message)
|
||
|
{
|
||
|
m_View.SetRevisionSummary(message);
|
||
|
m_Model.SavedRevisionSummary = message;
|
||
|
}
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public int GroupOverflowEntryCount => 1;
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public void OnClickGroupOverflow(float x, float y)
|
||
|
{
|
||
|
new FloatingMenu()
|
||
|
.AddEntry(StringAssets.menuDiscardToggledChanges, RequestDiscardToggled, ToggledCount > 0)
|
||
|
.SetOpenDirection(MenuUtilities.OpenDirection.DownLeft)
|
||
|
.Open(x, y);
|
||
|
}
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public int ConflictGroupOverflowEntryCount => 2;
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public void OnClickConflictGroupOverflow(float x, float y)
|
||
|
{
|
||
|
new FloatingMenu()
|
||
|
.AddEntry(StringAssets.useMyChanges, OnBulkUseMine, true)
|
||
|
.AddEntry(StringAssets.useRemoteChanges, OnBulkUseRemote, true)
|
||
|
.SetOpenDirection(MenuUtilities.OpenDirection.DownLeft)
|
||
|
.Open(x, y);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Perform bulk choose mine on all conflicted entries.
|
||
|
/// </summary>
|
||
|
void OnBulkUseMine()
|
||
|
{
|
||
|
m_Model.RequestChooseMine(m_Model.GetConflictedEntries().Select(e => e.Entry.Path).ToArray());
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Perform bulk choose theirs on all conflicted entries.
|
||
|
/// </summary>
|
||
|
void OnBulkUseRemote()
|
||
|
{
|
||
|
m_Model.RequestChooseRemote(m_Model.GetConflictedEntries().Select(e => e.Entry.Path).ToArray());
|
||
|
}
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public void RequestShowConflictedDifferences(string path)
|
||
|
{
|
||
|
m_Model.RequestShowConflictedDifferences(path);
|
||
|
}
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public void RequestChooseMerge(string path)
|
||
|
{
|
||
|
m_Model.RequestChooseMerge(path);
|
||
|
}
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public void RequestChooseMine(string path)
|
||
|
{
|
||
|
m_Model.RequestChooseMine(new [] { path });
|
||
|
}
|
||
|
|
||
|
/// <inheritdoc />
|
||
|
public void RequestChooseRemote(string path)
|
||
|
{
|
||
|
m_Model.RequestChooseRemote(new [] { path });
|
||
|
}
|
||
|
}
|
||
|
}
|