using JetBrains.Annotations; using Unity.Cloud.Collaborate.Assets; using Unity.Cloud.Collaborate.Components; using Unity.Cloud.Collaborate.Models; using Unity.Cloud.Collaborate.Models.Structures; using Unity.Cloud.Collaborate.Views; using UnityEngine; using UnityEngine.Assertions; namespace Unity.Cloud.Collaborate.Presenters { internal class MainPresenter : IMainPresenter { [NotNull] readonly IMainView m_View; [NotNull] readonly IMainModel m_Model; bool m_IsStarted; const string k_ErrorOccuredId = "error_occured"; const string k_ConflictsDetectedId = "conflicts_detected"; const string k_RevisionsAvailableId = "revisions_available"; public MainPresenter([NotNull] IMainView view, [NotNull] IMainModel model) { m_View = view; m_Model = model; } /// public void Start() { Assert.IsFalse(m_IsStarted, "The presenter has already been started."); m_IsStarted = true; // Setup listeners. m_Model.ConflictStatusChange += OnConflictStatusChange; m_Model.OperationStatusChange += OnOperationStatusChange; m_Model.OperationProgressChange += OnOperationProgressChange; m_Model.ErrorOccurred += OnErrorOccurred; m_Model.ErrorCleared += OnErrorCleared; m_Model.RemoteRevisionsAvailabilityChange += OnRemoteRevisionsAvailabilityChange; m_Model.BackButtonStateUpdated += OnBackButtonStateUpdated; m_Model.StateChanged += OnStateChanged; // Update progress info. var progressInfo = m_Model.ProgressInfo; if (progressInfo != null) { OnOperationStatusChange(true); OnOperationProgressChange(m_Model.ProgressInfo); } // Update error info. var errorInfo = m_Model.ErrorInfo; if (errorInfo != null) { OnErrorOccurred(errorInfo); } else { OnErrorCleared(); } // Get initial values. OnConflictStatusChange(m_Model.Conflicted); OnRemoteRevisionsAvailabilityChange(m_Model.RemoteRevisionsAvailable); PopulateInitialData(); } /// public void Stop() { Assert.IsTrue(m_IsStarted, "The presenter has already been stopped."); m_IsStarted = false; m_Model.ConflictStatusChange -= OnConflictStatusChange; m_Model.OperationStatusChange -= OnOperationStatusChange; m_Model.OperationProgressChange -= OnOperationProgressChange; m_Model.ErrorOccurred -= OnErrorOccurred; m_Model.ErrorCleared -= OnErrorCleared; m_Model.RemoteRevisionsAvailabilityChange -= OnRemoteRevisionsAvailabilityChange; m_Model.BackButtonStateUpdated -= OnBackButtonStateUpdated; m_Model.StateChanged -= OnStateChanged; } /// /// Refresh state from the model. /// void OnStateChanged() { PopulateInitialData(); } /// /// Populate the view with the initial data from the model. /// void PopulateInitialData() { // Set tab. m_View.SetTab(m_Model.CurrentTabIndex); // Update back navigation OnBackButtonStateUpdated(m_Model.GetBackNavigation()?.text); } /// public IHistoryPresenter AssignHistoryPresenter(IHistoryView view) { var presenter = new HistoryPresenter(view, m_Model.ConstructHistoryModel(), m_Model); view.Presenter = presenter; return presenter; } /// public IChangesPresenter AssignChangesPresenter(IChangesView view) { var presenter = new ChangesPresenter(view, m_Model.ConstructChangesModel(), m_Model); view.Presenter = presenter; return presenter; } /// public void RequestCancelJob() { m_Model.RequestCancelJob(); } /// public void UpdateTabIndex(int index) { m_Model.CurrentTabIndex = index; } /// public void NavigateBack() { // Grab back action from the model, clear it, then invoke it. var nav = m_Model.GetBackNavigation(); if (nav == null) return; m_Model.UnregisterBackNavigation(nav.Value.id); nav.Value.backAction.Invoke(); } /// /// Display an alert if there is conflicts detected. /// /// True if conflicts exist. void OnConflictStatusChange(bool conflicts) { if (conflicts) { m_View.AddAlert(k_ConflictsDetectedId, AlertBox.AlertLevel.Alert, StringAssets.conflictsDetected); } else { m_View.RemoveAlert(k_ConflictsDetectedId); } } /// /// Display a progress bar if an operation has started. /// /// void OnOperationStatusChange(bool inProgress) { if (inProgress) { m_View.AddOperationProgress(); } else { m_View.RemoveOperationProgress(); } } /// /// Update progress bar with incremental details. /// /// void OnOperationProgressChange(IProgressInfo progressInfo) { m_View.SetOperationProgress(progressInfo.Title, progressInfo.Details, progressInfo.PercentageComplete, progressInfo.CurrentCount, progressInfo.TotalCount, progressInfo.PercentageProgressType, progressInfo.CanCancel); } /// /// Display an error. /// /// void OnErrorOccurred(IErrorInfo errorInfo) { if (errorInfo.Behaviour == ErrorInfoBehavior.Alert) { m_View.AddAlert(k_ErrorOccuredId, AlertBox.AlertLevel.Alert, errorInfo.Message, (StringAssets.clear, m_Model.ClearError)); } } /// /// Clear the error state. /// void OnErrorCleared() { m_View.RemoveAlert(k_ErrorOccuredId); } /// /// Show or clear the revisions to fetch alert based on whether or not they are available. /// /// True if there are remote revisions to pull down. void OnRemoteRevisionsAvailabilityChange(bool remoteRevisionsAvailable) { if (remoteRevisionsAvailable) { m_View.AddAlert(k_RevisionsAvailableId, AlertBox.AlertLevel.Info, StringAssets.syncRemoteRevisionsMessage, (StringAssets.sync, m_Model.RequestSync)); } else { m_View.RemoveAlert(k_RevisionsAvailableId); } } /// /// Clear or show back navigation button. /// /// Text to display next to the back navigation. Null means no back navigation. void OnBackButtonStateUpdated([CanBeNull] string title) { if (title == null) { m_View.ClearBackNavigation(); } else { m_View.DisplayBackNavigation(title); } } } }