UnityGame/Library/PackageCache/com.unity.multiplayer.center/Editor/MultiplayerCenterWindow/RecommendationTabView.cs

198 lines
7.9 KiB
C#
Raw Normal View History

2024-10-27 10:53:47 +03:00
using System;
using Unity.Multiplayer.Center.Analytics;
using Unity.Multiplayer.Center.Common;
using Unity.Multiplayer.Center.Questionnaire;
using Unity.Multiplayer.Center.Recommendations;
using Unity.Multiplayer.Center.Window.UI;
using Unity.Multiplayer.Center.Window.UI.RecommendationView;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.Multiplayer.Center.Window
{
internal class RecommendationTabView : ITabView
{
QuestionnaireView m_QuestionnaireView;
RecommendationView m_RecommendationView;
RecommendationViewBottomBar m_BottomBarView;
bool m_IsVisible;
bool m_ShouldRefresh = true;
[SerializeField]
PreReleaseHandling m_PreReleaseHandling = new();
[field: SerializeField] // Marked as redundant by Rider, but it is not.
public string Name { get; private set; }
public VisualElement RootVisualElement { get; set; }
public IMultiplayerCenterAnalytics MultiplayerCenterAnalytics { get; set; }
// Access to QuestionnaireView for testing purposes
internal QuestionnaireView QuestionnaireView => m_QuestionnaireView;
public RecommendationTabView(string name = "Recommendation")
{
Name = name;
m_PreReleaseHandling.OnAllChecksFinished += PatchData;
m_PreReleaseHandling.CheckForUpdates();
Undo.undoRedoPerformed += OnUndoRedoPerformed;
}
void OnUndoRedoPerformed()
{
UserChoicesObject.instance.Save();
m_QuestionnaireView?.Refresh();
UpdateRecommendation(keepSelection:true);
}
public void Clear()
{
Undo.undoRedoPerformed -= OnUndoRedoPerformed;
m_RecommendationView?.Clear();
m_QuestionnaireView?.Clear();
RootVisualElement?.Clear();
m_QuestionnaireView = null;
m_RecommendationView = null;
}
public void SetVisible(bool visible)
{
RootVisualElement.style.display = visible ? DisplayStyle.Flex : DisplayStyle.None;
m_IsVisible = visible;
}
public void Refresh()
{
Debug.Assert(MultiplayerCenterAnalytics != null, "MultiplayerCenterAnalytics != null");
RefreshPreReleaseHandling();
if (!m_ShouldRefresh && RootVisualElement.childCount > 0) return;
CreateStandardView();
m_ShouldRefresh = false;
}
void RefreshPreReleaseHandling()
{
if (!m_PreReleaseHandling.IsReady)
{
m_PreReleaseHandling.OnAllChecksFinished += PatchData;
m_PreReleaseHandling.CheckForUpdates();
}
else
{
m_PreReleaseHandling.PatchRecommenderSystemData();
}
}
void CreateStandardView()
{
Clear();
Undo.undoRedoPerformed -= OnUndoRedoPerformed;
Undo.undoRedoPerformed += OnUndoRedoPerformed;
MigrateUserChoices();
// We need this because Bottom bar is a part of the Recommendations Tab and it should always stay
// at the bottom of the view. So we need to make sure that the root tab element is always 100% height.
RootVisualElement.style.height = Length.Percent(100);
var horizontalContainer = new TwoPaneSplitView(0, 250, TwoPaneSplitViewOrientation.Horizontal);
horizontalContainer.AddToClassList(StyleClasses.MainSplitView);
horizontalContainer.name = "recommendation-tab-split-view";
// This is used to make sure the left side does not grow to 100% as this is what would happen by default.
// It feels not 100% correct. But it seems to be the only way to match the height of the 2 sides with how
// our views are build currently.
horizontalContainer.contentContainer.style.position = Position.Relative;
m_QuestionnaireView = new QuestionnaireView(QuestionnaireObject.instance.Questionnaire);
m_QuestionnaireView.OnQuestionnaireDataChanged += HandleQuestionnaireDataChanged;
m_QuestionnaireView.OnPresetSelected += OnPresetSelected;
m_QuestionnaireView.Root.AddToClassList(StyleClasses.MainSplitViewLeft);
horizontalContainer.Add(m_QuestionnaireView.Root);
m_RecommendationView = new RecommendationView();
m_RecommendationView.Root.AddToClassList(StyleClasses.MainSplitViewRight);
horizontalContainer.Add(m_RecommendationView.Root);
RootVisualElement.Add(horizontalContainer);
m_BottomBarView = new RecommendationViewBottomBar(MultiplayerCenterAnalytics);
m_RecommendationView.OnPackageSelectionChanged +=
() => m_BottomBarView.UpdatePackagesToInstall(m_RecommendationView.CurrentRecommendation, m_RecommendationView.AllPackages);
RootVisualElement.Add(m_BottomBarView);
UpdateRecommendation(keepSelection: true);
m_BottomBarView.SetInfoTextForCheckingPackages(!m_PreReleaseHandling.IsReady);
}
void HandleQuestionnaireDataChanged()
{
UpdateRecommendation(keepSelection: false);
}
static void MigrateUserChoices()
{
var questionnaire = QuestionnaireObject.instance.Questionnaire;
var userChoices = UserChoicesObject.instance;
// make sure the version of the questionnaire is the same as the one in the user choices.
if (questionnaire.Version != userChoices.QuestionnaireVersion && userChoices.UserAnswers.Answers.Count > 0)
{
Logic.MigrateUserChoices(questionnaire, userChoices);
}
}
void UpdateRecommendation(bool keepSelection)
{
var questionnaire = QuestionnaireObject.instance.Questionnaire;
var userChoices = UserChoicesObject.instance;
var errors = Logic.ValidateAnswers(questionnaire, userChoices.UserAnswers);
foreach (var error in errors)
{
Debug.LogError(error);
}
var recommendation = userChoices.Preset == Preset.None? null
: RecommenderSystem.GetRecommendation(questionnaire, userChoices.UserAnswers);
m_PreReleaseHandling.PatchPackages(recommendation);
if (keepSelection)
{
RecommendationUtils.ApplyPreviousSelection(recommendation, userChoices.SelectedSolutions);
}
else if (recommendation != null) // we only send the event if there is a recommendation and it is a new one
{
MultiplayerCenterAnalytics.SendRecommendationEvent(userChoices.UserAnswers, userChoices.Preset);
}
m_RecommendationView.UpdateRecommendation(recommendation, m_PreReleaseHandling);
m_BottomBarView.UpdatePackagesToInstall(recommendation, m_RecommendationView.AllPackages);
}
void PatchData()
{
m_PreReleaseHandling.PatchRecommenderSystemData();
m_PreReleaseHandling.OnAllChecksFinished -= PatchData;
m_ShouldRefresh = true;
if(m_IsVisible)
Refresh();
}
void OnPresetSelected(Preset preset)
{
var (resultAnswerData, recommendation) = Logic.ApplyPresetToAnswerData(
UserChoicesObject.instance.UserAnswers, preset, QuestionnaireObject.instance.Questionnaire);
UserChoicesObject.instance.UserAnswers = resultAnswerData;
UserChoicesObject.instance.Save();
if (recommendation != null)
MultiplayerCenterAnalytics.SendRecommendationEvent(resultAnswerData, preset);
m_QuestionnaireView.Refresh();
m_RecommendationView.UpdateRecommendation(recommendation, m_PreReleaseHandling);
}
}
}