< Summary

Class:DCL.Builder.PublishProjectDetailView
Assembly:BuilderPublisher
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/BuilderInWorld/Publisher/ProjectPublishHUD/Scripts/Projects/PublishProjectDetailView.cs
Covered lines:0
Uncovered lines:212
Coverable lines:212
Total lines:498
Line coverage:0% (0 of 212)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
PublishProjectDetailView()0%2100%
RefreshControl()0%6200%
Awake()0%2100%
Dispose()0%2100%
DeactivateSearch()0%2100%
Back()0%6200%
Next()0%2100%
SearchLand(...)0%42600%
ShowTopToast(...)0%2100%
ShowSearchBar()0%2100%
HideSearchBar()0%2100%
HideTopToast()0%6200%
ParcelClicked(...)0%6200%
LandSelected(...)0%30500%
ParcelHovered(...)0%2100%
ShowCurrentStep()0%30500%
RotateLeft()0%6200%
RotateRight()0%6200%
SetRotation(...)0%42600%
SetProjectToPublish(...)0%20400%
UpdateProjectSize(...)0%2100%
CheckAvailableLandsToPublish(...)0%2100%
LandSelected(...)0%2100%
GoToCoords(...)0%2100%
Show()0%6200%
ResetView()0%2100%
Hide()0%6200%
EnableNextButton()0%12300%
DisableNextButton()0%2100%
PublishButtonPressed()0%6200%
CancelPublish()0%6200%
CancelButtonPressed()0%2100%
WaitFrameToPositionMap()0%12300%
WaitAndHideTopToast()0%12300%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/BuilderInWorld/Publisher/ProjectPublishHUD/Scripts/Projects/PublishProjectDetailView.cs

#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Collections.Generic;
 4using System.Linq;
 5using TMPro;
 6using UnityEngine;
 7using UnityEngine.Events;
 8using UnityEngine.UI;
 9using UnityEngine.UIElements;
 10using Button = UnityEngine.UI.Button;
 11
 12namespace DCL.Builder
 13{
 14    public interface IPublishProjectDetailView
 15    {
 16        /// <summary>
 17        /// If the publish is canceled this action will be called
 18        /// </summary>
 19        event Action OnCancel;
 20
 21        /// <summary>
 22        /// If the publish button is pressed this action will be called
 23        /// </summary>
 24        event Action<PublishInfo> OnPublishButtonPressed;
 25
 26        /// <summary>
 27        /// If the rotation of the project is changed, this event will be fired
 28        /// </summary>
 29        event Action<PublishInfo.ProjectRotation>  OnProjectRotateChange;
 30
 31        /// <summary>
 32        /// Update the size of the project
 33        /// </summary>
 34        /// <param name="parcels"></param>
 35        void UpdateProjectSize(Vector2Int[] parcels);
 36
 37        /// <summary>
 38        /// Set the project to publish
 39        /// </summary>
 40        /// <param name="scene"></param>
 41        void SetProjectToPublish(IBuilderScene scene);
 42
 43        /// <summary>
 44        /// This will reset the view to the first state
 45        /// </summary>
 46        void ResetView();
 47
 48        /// <summary>
 49        /// This will show the detail modal
 50        /// </summary>
 51        void Show();
 52
 53        /// <summary>
 54        /// This will hide the detail modal
 55        /// </summary>
 56        void Hide();
 57
 58        /// <summary>
 59        /// Dispose the view
 60        /// </summary>
 61        void Dispose();
 62    }
 63
 64    public class PublishProjectDetailView : BaseComponentView, IPublishProjectDetailView
 65    {
 66        private const float SECONDS_TO_HIDE_TOP_TOAST = 4.5f;
 67        public event Action<PublishInfo.ProjectRotation> OnProjectRotateChange;
 68        public event Action OnCancel;
 69        public event Action<PublishInfo> OnPublishButtonPressed;
 70
 71        [SerializeField] internal ModalComponentView modal;
 72
 73        [Header("First step")]
 74        [SerializeField] internal GameObject firstStep;
 75
 76        [SerializeField] internal Button backButton;
 77        [SerializeField] internal Button nextButton;
 78        [SerializeField] internal Button rotateLeftButton;
 79        [SerializeField] internal Button rotateRightButton;
 80
 81        [SerializeField] internal GameObject aerialScreenshotGameObject;
 82        [SerializeField] internal RawImage sceneAerialScreenshotImage;
 83
 84        [SerializeField] internal LimitInputField nameInputField;
 85        [SerializeField] internal LimitInputField descriptionInputField;
 86
 87        [Header("Second step")]
 88        [SerializeField] internal GameObject secondStep;
 89        [SerializeField] internal Button backSecondButton;
 90        [SerializeField] internal Button publishButton;
 91        [SerializeField] internal PublishLandListView landListView;
 92        [SerializeField] internal ProjectPublishToast toastView;
 93        [SerializeField] internal PublishMapView mapView;
 94        [SerializeField] internal SearchLandView searchView;
 95        [SerializeField] internal Button miniSearchView;
 96        [SerializeField] internal TextMeshProUGUI topToastText;
 97        [SerializeField] internal GameObject topToastGameObject;
 98
 99        [SerializeField] internal RawImage sceneScreenshotImage;
 100
 101        internal IBuilderScene scene;
 102        private PublishInfo.ProjectRotation projectRotation = PublishInfo.ProjectRotation.NORTH;
 103        internal int currentStep = 0;
 0104        internal List<Vector2Int> availableLandsToPublish = new List<Vector2Int>();
 105
 106        internal Vector2Int selectedCoords;
 107        internal bool areCoordsSelected = false;
 108        private Coroutine toastTopHideCoroutine;
 109
 110
 111        public override void RefreshControl()
 112        {
 0113            if (scene == null)
 0114                return;
 115
 0116            SetProjectToPublish(scene);
 0117        }
 118
 119        public override void Awake()
 120        {
 0121            base.Awake();
 0122            modal.OnCloseAction += CancelPublish;
 123
 0124            landListView.OnLandSelected += LandSelected;
 0125            mapView.OnParcelHover += ParcelHovered;
 0126            mapView.OnParcelClicked += ParcelClicked;
 0127            searchView.OnValueSearch += SearchLand;
 0128            searchView.OnSearchCanceled += DeactivateSearch;
 129
 0130            backButton.onClick.AddListener(Back);
 0131            nextButton.onClick.AddListener(Next);
 132
 0133            backSecondButton.onClick.AddListener(Back);
 0134            publishButton.onClick.AddListener(PublishButtonPressed);
 135
 0136            rotateLeftButton.onClick.AddListener( RotateLeft);
 0137            rotateRightButton.onClick.AddListener( RotateRight);
 0138            miniSearchView.onClick.AddListener(ShowSearchBar);
 139
 0140            nameInputField.OnEmptyValue += DisableNextButton;
 0141            nameInputField.OnLimitReached += DisableNextButton;
 0142            nameInputField.OnInputAvailable += EnableNextButton;
 143
 0144            descriptionInputField.OnLimitReached += DisableNextButton;
 0145            descriptionInputField.OnInputAvailable += EnableNextButton;
 146
 0147            gameObject.SetActive(false);
 0148            searchView.gameObject.SetActive(false);
 0149        }
 150
 151        public override void Dispose()
 152        {
 0153            base.Dispose();
 154
 0155            modal.OnCloseAction -= CancelPublish;
 156
 0157            mapView.OnParcelHover -= ParcelHovered;
 0158            mapView.OnParcelClicked -= ParcelClicked;
 0159            landListView.OnLandSelected -= LandSelected;
 0160            searchView.OnValueSearch -= SearchLand;
 0161            searchView.OnSearchCanceled -= DeactivateSearch;
 162
 0163            backButton.onClick.RemoveAllListeners();
 0164            nextButton.onClick.RemoveAllListeners();
 165
 0166            backSecondButton.onClick.RemoveAllListeners();
 0167            publishButton.onClick.RemoveAllListeners();
 168
 0169            rotateLeftButton.onClick.RemoveAllListeners();
 0170            rotateRightButton.onClick.RemoveAllListeners();
 0171            miniSearchView.onClick.RemoveAllListeners();
 172
 0173            nameInputField.OnLimitReached -= DisableNextButton;
 0174            nameInputField.OnInputAvailable -= EnableNextButton;
 0175            nameInputField.OnEmptyValue -= DisableNextButton;
 176
 0177            descriptionInputField.OnLimitReached -= DisableNextButton;
 0178            descriptionInputField.OnInputAvailable -= EnableNextButton;
 0179        }
 180
 181        private void DeactivateSearch()
 182        {
 0183            landListView.SetActive(false);
 0184        }
 185
 186        private void Back()
 187        {
 0188            if (currentStep <= 0)
 189            {
 0190                Hide();
 0191                return;
 192            }
 193
 0194            currentStep--;
 0195            ShowCurrentStep();
 0196        }
 197
 198        private void Next()
 199        {
 0200            currentStep++;
 0201            ShowCurrentStep();
 0202        }
 203
 204        private void SearchLand(string searchInput)
 205        {
 0206            List<LandWithAccess> filteredLands = new List<LandWithAccess>();
 0207            foreach (LandWithAccess land in DataStore.i.builderInWorld.landsWithAccess.Get())
 208            {
 0209                bool shouldBeAdded = land.name.ToLower().Contains(searchInput.ToLower());
 210
 0211                foreach (Vector2Int landParcel in land.parcels)
 212                {
 0213                    if(BIWUtils.Vector2INTToString(landParcel).Contains(searchInput))
 0214                        shouldBeAdded = true;
 215                }
 216
 0217                if(shouldBeAdded && !filteredLands.Contains(land))
 0218                    filteredLands.Add(land);
 219            }
 220
 221            // We fill the list with the lands
 0222            landListView.SetContent(scene.manifest.project.cols, scene.manifest.project.rows, filteredLands);
 0223            landListView.SetActive(true);
 0224        }
 225
 226        private void ShowTopToast(string text)
 227        {
 0228            topToastText.text = text;
 0229            topToastGameObject.SetActive(true);
 0230            HideSearchBar();
 231
 0232            toastTopHideCoroutine = StartCoroutine(WaitAndHideTopToast());
 0233        }
 234
 235        private void ShowSearchBar()
 236        {
 0237            searchView.gameObject.SetActive(true);
 0238            miniSearchView.gameObject.SetActive(false);
 0239            HideTopToast();
 0240        }
 241
 242        private void HideSearchBar()
 243        {
 0244            searchView.gameObject.SetActive(false);
 0245            miniSearchView.gameObject.SetActive(true);
 0246            landListView.HideEmptyContent();
 0247            landListView.SetActive(false);
 0248        }
 249
 250        private void HideTopToast()
 251        {
 0252            if (toastTopHideCoroutine != null)
 0253                StopCoroutine(toastTopHideCoroutine);
 0254            topToastGameObject.SetActive(false);
 0255        }
 256
 257        private void ParcelClicked(Vector2Int parcel)
 258        {
 0259            if (!availableLandsToPublish.Contains(parcel))
 260            {
 0261                ShowTopToast("Projects can't be placed in a Land you don't own.");
 0262                return;
 263            }
 264
 0265            LandSelected(parcel);
 0266        }
 267
 268        public void LandSelected(Vector2Int parcel)
 269        {
 0270            foreach (LandWithAccess land in DataStore.i.builderInWorld.landsWithAccess.Get())
 271            {
 0272                foreach (Vector2Int landParcel in land.parcels)
 273                {
 0274                    if (landParcel == parcel)
 275                    {
 0276                        toastView.SetLandInfo(land.name, BIWUtils.Vector2INTToString(landParcel));
 0277                        bool isEmpty = !(land.scenes.Count == 0 || land.scenes[0].isEmpty);
 0278                        toastView.SetSubtitleActive(isEmpty);
 0279                        toastView.Show();
 0280                        break;
 281                    }
 282                }
 283
 284            }
 285
 0286            mapView.SelectLandInMap(parcel);
 0287            areCoordsSelected = true;
 0288            selectedCoords = parcel;
 0289            publishButton.interactable = true;
 0290        }
 291
 292        private void ParcelHovered(Vector2Int parcel)
 293        {
 0294            bool isAvailable = availableLandsToPublish.Contains(parcel);
 0295            mapView.SetAvailabilityToPublish(isAvailable);
 0296        }
 297
 298        private void ShowCurrentStep()
 299        {
 0300            firstStep.SetActive(false);
 0301            secondStep.SetActive(false);
 0302            switch (currentStep)
 303            {
 304                case 0: // Choose name, desc and rotation
 0305                    firstStep.SetActive(true);
 0306                    break;
 307                case 1: // Choose land to deploy
 0308                    searchView.ClearSearch();
 0309                    HideSearchBar();
 0310                    secondStep.SetActive(true);
 0311                    if (availableLandsToPublish.Count > 0)
 0312                        GoToCoords(availableLandsToPublish[0]);
 313
 0314                    if (areCoordsSelected)
 315                    {
 0316                        LandSelected(selectedCoords);
 0317                        GoToCoords(selectedCoords);
 0318                        toastView.Show(true);
 319                    }
 320                    break;
 321            }
 0322        }
 323
 324        private void RotateLeft()
 325        {
 0326            projectRotation--;
 0327            if (projectRotation < 0)
 0328                projectRotation = PublishInfo.ProjectRotation.WEST;
 0329            SetRotation(projectRotation);
 0330        }
 331
 332        private void RotateRight()
 333        {
 0334            projectRotation++;
 0335            if (projectRotation > PublishInfo.ProjectRotation.WEST)
 0336                projectRotation = PublishInfo.ProjectRotation.NORTH;
 0337            SetRotation(projectRotation);
 0338        }
 339
 340        private void SetRotation(PublishInfo.ProjectRotation rotation)
 341        {
 0342            float zRotation = 0;
 343            switch (rotation)
 344            {
 345                case PublishInfo.ProjectRotation.NORTH:
 0346                    zRotation = 0;
 0347                    break;
 348                case PublishInfo.ProjectRotation.EAST:
 0349                    zRotation = 270;
 0350                    break;
 351                case PublishInfo.ProjectRotation.SOUTH:
 0352                    zRotation = 180;
 0353                    break;
 354                case PublishInfo.ProjectRotation.WEST:
 0355                    zRotation = 90;
 356                    break;
 357            }
 0358            sceneAerialScreenshotImage.rectTransform.rotation = Quaternion.Euler(0, 0, zRotation);
 0359            OnProjectRotateChange?.Invoke(rotation);
 0360        }
 361
 362        public void SetProjectToPublish(IBuilderScene scene)
 363        {
 0364            this.scene = scene;
 365
 366            // Reset common views
 0367            toastView.Hide(true);
 0368            HideSearchBar();
 369
 370            // We reset the selected coords and disable the publish button until the coords are selected
 0371            areCoordsSelected = false;
 0372            publishButton.interactable = false;
 373
 374            // We set the screenshot
 0375            if (scene.aerialScreenshotTexture != null && BIWUtils.IsParcelSceneSquare(scene.scene.sceneData.parcels))
 376            {
 0377                aerialScreenshotGameObject.SetActive(true);
 0378                sceneAerialScreenshotImage.texture = scene.aerialScreenshotTexture;
 0379            }
 380            else
 381            {
 0382                aerialScreenshotGameObject.SetActive(false);
 383            }
 384
 0385            if (sceneScreenshotImage != null)
 0386                sceneScreenshotImage.texture = scene.sceneScreenshotTexture;
 387
 388            // We set the scene info
 0389            nameInputField.SetText(scene.manifest.project.title);
 0390            descriptionInputField.SetText(scene.manifest.project.description);
 391
 392            // We filter the available lands
 0393            CheckAvailableLandsToPublish(scene);
 394
 395            // We set the size of the project in the builder
 0396            UpdateProjectSize(scene.scene.sceneData.parcels);
 0397        }
 398
 399        public void UpdateProjectSize(Vector2Int[] parcels)
 400        {
 401            // We set the size of the project in the builder
 0402            mapView.SetProjectSize(parcels);
 0403        }
 404
 405        private void CheckAvailableLandsToPublish(IBuilderScene sceneToPublish)
 406        {
 0407            availableLandsToPublish.Clear();
 0408            availableLandsToPublish = BIWUtils.GetLandsToPublishProject(DataStore.i.builderInWorld.landsWithAccess.Get()
 0409        }
 410
 411        private void LandSelected(LandWithAccess land)
 412        {
 0413            landListView.SetActive(false);
 0414            searchView.ClearSearch();
 0415            HideSearchBar();
 416
 417            // We select the land
 0418            LandSelected(land.baseCoords);
 419
 420            // We set the map to the main land
 0421            GoToCoords(land.baseCoords);
 0422        }
 423
 424        private void GoToCoords(Vector2Int coord)
 425        {
 426            // We set the map to the main land
 0427            CoroutineStarter.Start(WaitFrameToPositionMap(coord));
 0428        }
 429
 430        public void Show()
 431        {
 0432            gameObject.SetActive(true);
 0433            mapView.SetVisible(true);
 0434            modal.Show();
 0435            if (areCoordsSelected)
 436            {
 0437                LandSelected(selectedCoords);
 0438                GoToCoords(selectedCoords);
 0439                toastView.Show(true);
 440            }
 0441        }
 442
 443        public void ResetView()
 444        {
 0445            currentStep = 0;
 0446            ShowCurrentStep();
 0447        }
 448
 449        public void Hide()
 450        {
 0451            if(!modal.isVisible)
 0452                return;
 453
 0454            modal.Hide();
 0455            mapView.SetVisible(false);
 0456            CancelPublish();
 0457        }
 458
 459        internal void EnableNextButton()
 460        {
 0461            if(nameInputField.IsInputAvailable() && descriptionInputField.IsInputAvailable())
 0462                nextButton.interactable = true;
 0463        }
 464
 0465        internal void DisableNextButton() { nextButton.interactable = false; }
 466
 467        private void PublishButtonPressed()
 468        {
 0469            Hide();
 0470            PublishInfo publishInfo = new PublishInfo();
 0471            scene.manifest.project.title = nameInputField.GetValue();
 0472            scene.manifest.project.description = descriptionInputField.GetValue();
 0473            publishInfo.coordsToPublish = selectedCoords;
 474
 0475            OnPublishButtonPressed?.Invoke(publishInfo);
 0476        }
 477
 0478        private void CancelPublish() { OnCancel?.Invoke(); }
 479
 480        private void CancelButtonPressed()
 481        {
 0482            Hide();
 0483            CancelPublish();
 0484        }
 485
 486        IEnumerator WaitFrameToPositionMap(Vector2Int coords)
 487        {
 0488            yield return null;
 0489            mapView.GoToCoords(coords);
 0490        }
 491
 492        IEnumerator WaitAndHideTopToast()
 493        {
 0494            yield return new WaitForSeconds(SECONDS_TO_HIDE_TOP_TOAST);
 0495            HideTopToast();
 0496        }
 497    }
 498}