< Summary

Class:CarouselComponentView
Assembly:UIComponents
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/UIComponents/Scripts/Components/Carousel/CarouselComponentView.cs
Covered lines:82
Uncovered lines:100
Coverable lines:182
Total lines:502
Line coverage:45% (82 of 182)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
CarouselComponentView()0%110100%
PostInitialization()0%110100%
Configure(...)0%110100%
RefreshControl()0%22090%
PostScreenSizeChanged()0%2100%
Dispose()0%110100%
SetSpaceBetweenItems(...)0%2.032080%
SetTimeBetweenItems(...)0%2100%
SetAnimationTransitionTime(...)0%2100%
SetAnimationCurve(...)0%2100%
SetBackgroundColor(...)0%2.032080%
SetManualControlsActive(...)0%3.043083.33%
SetItems(...)0%4.024088.89%
GetItem(...)0%6200%
GetAllItems()0%2100%
StartCarousel(...)0%110100%
StopCarousel()0%2.032080%
GoToPreviousItem()0%6200%
GoToNextItem()0%6200%
ConfigureManualButtonsEvents()0%330100%
CreateItem(...)0%4.123050%
InstantiateItem(...)0%3.513061.54%
ResizeItem(...)0%220100%
ResizeAllItems()0%6200%
IntantiateItemOnEditor()0%12300%
DestroyInstantiatedItems(...)0%11.768061.11%
DestroyGameObjectOnEditor()0%12300%
RunCarouselCoroutine()0%63.6410018.75%
RunRightAnimation()0%42600%
RunLeftAnimation()0%42600%
RunAnimationCoroutine()0%30500%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/UIComponents/Scripts/Components/Carousel/CarouselComponentView.cs

#LineLine coverage
 1using System.Collections;
 2using System.Collections.Generic;
 3using UnityEngine;
 4using UnityEngine.UI;
 5
 6public interface ICarouselComponentView
 7{
 8    /// <summary>
 9    /// Fill the model and updates the carousel with this data.
 10    /// </summary>
 11    /// <param name="model">Data to configure the carousel.</param>
 12    void Configure(CarouselComponentModel model);
 13
 14    /// <summary>
 15    /// Set the distance between carousel items.
 16    /// </summary>
 17    /// <param name="newSpace">Distance between items.</param>
 18    void SetSpaceBetweenItems(float newSpace);
 19
 20    /// <summary>
 21    /// Set the time that will be pass between carousel items.
 22    /// </summary>
 23    /// <param name="newTime">Time between items.</param>
 24    void SetTimeBetweenItems(float newTime);
 25
 26    /// <summary>
 27    /// Set the time that will be pass during the transition between items.
 28    /// </summary>
 29    /// <param name="newTime">Transition time between items.</param>
 30    void SetAnimationTransitionTime(float newTime);
 31
 32    /// <summary>
 33    /// Set the animation curve that will be used for the animation between items.
 34    /// </summary>
 35    /// <param name="newCurve">Animation curve between items.</param>
 36    void SetAnimationCurve(AnimationCurve newCurve);
 37
 38    /// <summary>
 39    /// Set the color of the carousel background.
 40    /// </summary>
 41    /// <param name="newColor">Background color.</param>
 42    void SetBackgroundColor(Color newColor);
 43
 44    /// <summary>
 45    /// Activates/Deactivates the controls to go to the next/previous item manually.
 46    /// </summary>
 47    /// <param name="isActived">True for activating the manual controls.</param>
 48    void SetManualControlsActive(bool isActived);
 49
 50    /// <summary>
 51    /// Set the items of the carousel.
 52    /// </summary>
 53    /// <param name="items">List of UI components.</param>
 54    /// <param name="instantiateNewCopyOfItems">Indicates if the items provided will be instantiated as a new copy or no
 55    void SetItems(List<BaseComponentView> items, bool instantiateNewCopyOfItems = true);
 56
 57    /// <summary>
 58    /// Get an item of the carousel.
 59    /// </summary>
 60    /// <param name="index">Index of the list of items.</param>
 61    /// <returns>A specific UI component.</returns>
 62    BaseComponentView GetItem(int index);
 63
 64    /// <summary>
 65    /// Get all the items of the carousel.
 66    /// </summary>
 67    /// <returns>The list of items.</returns>
 68    List<BaseComponentView> GetAllItems();
 69
 70    /// <summary>
 71    /// Start carousel animation.
 72    /// </summary>
 73    /// <param name="fromIndex">It specifies from where item the carousel will start.</param>
 74    /// <param name="startInmediately">True to directly execute the first transition.</param>
 75    /// <param name="direction">Set the direction of the carousel animations: right or left.</param>
 76    /// <param name="changeDirectionAfterFirstTransition">True to change the carousel direction just after the first tra
 77    void StartCarousel(int fromIndex, bool startInmediately, CarouselDirection direction, bool changeDirectionAfterFirst
 78
 79    /// <summary>
 80    /// Stop carousel animation.
 81    /// </summary>
 82    void StopCarousel();
 83
 84    /// <summary>
 85    /// Force the carousel to show the previous item.
 86    /// </summary>
 87    void GoToPreviousItem();
 88
 89    /// <summary>
 90    /// Force the carousel to show the next item.
 91    /// </summary>
 92    void GoToNextItem();
 93}
 94
 95public enum CarouselDirection
 96{
 97    Right,
 98    Left
 99}
 100
 101public class CarouselComponentView : BaseComponentView, ICarouselComponentView
 102{
 103    [Header("Prefab References")]
 104    [SerializeField] internal RectTransform itemsContainer;
 105    [SerializeField] internal HorizontalLayoutGroup horizontalLayout;
 106    [SerializeField] internal ScrollRect itemsScroll;
 107    [SerializeField] internal RectTransform viewport;
 108    [SerializeField] internal Image background;
 109    [SerializeField] internal Button previousButton;
 110    [SerializeField] internal Button nextButton;
 111
 112    [Header("Configuration")]
 113    [SerializeField] internal CarouselComponentModel model;
 114
 25115    internal List<BaseComponentView> instantiatedItems = new List<BaseComponentView>();
 116    internal Coroutine itemsCoroutine;
 117    internal int currentItemIndex = 0;
 118    internal float currentFinalNormalizedPos;
 119    internal bool isInTransition = false;
 120    internal bool destroyOnlyUnnecesaryItems = false;
 121
 122    public override void PostInitialization()
 123    {
 1124        Configure(model);
 1125        ConfigureManualButtonsEvents();
 1126        StartCarousel();
 1127    }
 128
 129    public void Configure(CarouselComponentModel model)
 130    {
 1131        this.model = model;
 1132        RefreshControl();
 1133    }
 134
 135    public override void RefreshControl()
 136    {
 1137        if (model == null)
 0138            return;
 139
 1140        SetSpaceBetweenItems(model.spaceBetweenItems);
 1141        SetTimeBetweenItems(model.timeBetweenItems);
 1142        SetAnimationTransitionTime(model.animationTransitionTime);
 1143        SetAnimationCurve(model.animationCurve);
 1144        SetBackgroundColor(model.backgroundColor);
 1145        SetManualControlsActive(model.showManualControls);
 1146        SetItems(model.items);
 1147    }
 148
 149    public override void PostScreenSizeChanged()
 150    {
 0151        base.PostScreenSizeChanged();
 152
 0153        ResizeAllItems();
 0154    }
 155
 156    public override void Dispose()
 157    {
 1158        base.Dispose();
 159
 1160        StopCarousel();
 1161        DestroyInstantiatedItems(true);
 1162    }
 163
 164    public void SetSpaceBetweenItems(float newSpace)
 165    {
 1166        model.spaceBetweenItems = newSpace;
 167
 1168        if (horizontalLayout == null)
 0169            return;
 170
 1171        horizontalLayout.spacing = newSpace;
 1172    }
 173
 0174    public void SetTimeBetweenItems(float newTime) { model.timeBetweenItems = newTime; }
 175
 0176    public void SetAnimationTransitionTime(float newTime) { model.animationTransitionTime = newTime; }
 177
 0178    public void SetAnimationCurve(AnimationCurve newCurve) { model.animationCurve = newCurve; }
 179
 180    public void SetBackgroundColor(Color newColor)
 181    {
 1182        model.backgroundColor = newColor;
 183
 1184        if (background == null)
 0185            return;
 186
 1187        background.color = newColor;
 1188    }
 189
 190    public void SetManualControlsActive(bool isActived)
 191    {
 1192        model.showManualControls = isActived;
 193
 1194        if (previousButton == null || nextButton == null)
 0195            return;
 196
 1197        previousButton.gameObject.SetActive(isActived);
 1198        nextButton.gameObject.SetActive(isActived);
 1199    }
 200
 201    public void SetItems(List<BaseComponentView> items, bool instantiateNewCopyOfItems = true)
 202    {
 1203        model.items = items;
 204
 1205        DestroyInstantiatedItems(!destroyOnlyUnnecesaryItems);
 206
 8207        for (int i = 0; i < items.Count; i++)
 208        {
 3209            CreateItem(items[i], $"Item{i}", instantiateNewCopyOfItems && !destroyOnlyUnnecesaryItems);
 210        }
 211
 1212        if (!instantiateNewCopyOfItems)
 0213            destroyOnlyUnnecesaryItems = true;
 1214    }
 215
 216    public BaseComponentView GetItem(int index)
 217    {
 0218        if (index >= instantiatedItems.Count)
 0219            return null;
 220
 0221        return instantiatedItems[index];
 222    }
 223
 0224    public List<BaseComponentView> GetAllItems() { return instantiatedItems; }
 225
 226    public void StartCarousel(
 227        int fromIndex = 0,
 228        bool startInmediately = false,
 229        CarouselDirection direction = CarouselDirection.Right,
 230        bool changeDirectionAfterFirstTransition = false)
 231    {
 1232        itemsCoroutine = CoroutineStarter.Start(RunCarouselCoroutine(fromIndex, startInmediately, direction, changeDirec
 1233    }
 234
 235    public void StopCarousel()
 236    {
 1237        if (itemsCoroutine == null)
 0238            return;
 239
 1240        CoroutineStarter.Stop(itemsCoroutine);
 1241        itemsCoroutine = null;
 1242    }
 243
 244    public void GoToPreviousItem()
 245    {
 0246        if (isInTransition)
 0247            return;
 248
 0249        StopCarousel();
 0250        StartCarousel(
 251            fromIndex: currentItemIndex,
 252            startInmediately: true,
 253            direction: CarouselDirection.Left,
 254            changeDirectionAfterFirstTransition: true);
 0255    }
 256
 257    public void GoToNextItem()
 258    {
 0259        if (isInTransition)
 0260            return;
 261
 0262        StopCarousel();
 0263        StartCarousel(
 264            fromIndex: currentItemIndex,
 265            startInmediately: true,
 266            direction: CarouselDirection.Right,
 267            changeDirectionAfterFirstTransition: false);
 0268    }
 269
 270    internal void ConfigureManualButtonsEvents()
 271    {
 1272        if (previousButton != null)
 273        {
 1274            previousButton.onClick.RemoveAllListeners();
 1275            previousButton.onClick.AddListener(GoToPreviousItem);
 276        }
 277
 1278        if (nextButton != null)
 279        {
 1280            nextButton.onClick.RemoveAllListeners();
 1281            nextButton.onClick.AddListener(GoToNextItem);
 282        }
 1283    }
 284
 285    internal void CreateItem(BaseComponentView newItem, string name, bool instantiateNewCopyOfItem = true)
 286    {
 3287        if (Application.isPlaying)
 288        {
 3289            InstantiateItem(newItem, name, instantiateNewCopyOfItem);
 3290        }
 291        else
 292        {
 0293            if (isActiveAndEnabled)
 0294                StartCoroutine(IntantiateItemOnEditor(newItem, name));
 295        }
 0296    }
 297
 298    internal void InstantiateItem(BaseComponentView newItem, string name, bool instantiateNewCopyOfItem = true)
 299    {
 3300        if (newItem == null)
 0301            return;
 302
 303        BaseComponentView newGO;
 3304        if (instantiateNewCopyOfItem)
 305        {
 3306            newGO = Instantiate(newItem, itemsContainer);
 3307        }
 308        else
 309        {
 0310            newGO = newItem;
 0311            newGO.transform.SetParent(itemsContainer);
 0312            newGO.transform.localPosition = Vector3.zero;
 0313            newGO.transform.localScale = Vector3.one;
 314        }
 315
 3316        newGO.name = name;
 3317        instantiatedItems.Add(newGO);
 3318        ResizeItem(newGO);
 3319    }
 320
 321    internal void ResizeItem(BaseComponentView item)
 322    {
 3323        ((RectTransform)item.transform).sizeDelta = new Vector2(viewport.rect.width, viewport.rect.height);
 324
 3325        itemsContainer.offsetMin = Vector2.zero;
 3326        if (instantiatedItems.Count > 1)
 327        {
 2328            float extraSpace = (instantiatedItems.Count - 1) * model.spaceBetweenItems;
 2329            itemsContainer.offsetMax = new Vector2(viewport.rect.width * (instantiatedItems.Count - 1) + extraSpace, 0);
 330        }
 3331    }
 332
 333    internal void ResizeAllItems()
 334    {
 0335        foreach (BaseComponentView item in instantiatedItems)
 336        {
 0337            ResizeItem(item);
 338        }
 0339    }
 340
 341    internal IEnumerator IntantiateItemOnEditor(BaseComponentView newItem, string name)
 342    {
 0343        yield return null;
 0344        InstantiateItem(newItem, name);
 0345    }
 346
 347    internal void DestroyInstantiatedItems(bool forzeToDestroyAll)
 348    {
 2349        if (forzeToDestroyAll)
 350        {
 22351            foreach (Transform child in itemsContainer)
 352            {
 9353                if (Application.isPlaying)
 354                {
 9355                    Destroy(child.gameObject);
 9356                }
 357                else
 358                {
 0359                    if (isActiveAndEnabled)
 0360                        StartCoroutine(DestroyGameObjectOnEditor(child.gameObject));
 361                }
 362            }
 363        }
 364        else
 365        {
 0366            foreach (BaseComponentView child in instantiatedItems)
 367            {
 0368                if (!model.items.Contains(child))
 369                {
 0370                    Destroy(child.gameObject);
 371                }
 372            }
 373        }
 374
 2375        instantiatedItems.Clear();
 376
 2377        itemsContainer.offsetMin = Vector2.zero;
 2378        itemsContainer.offsetMax = Vector2.zero;
 2379    }
 380
 381    internal IEnumerator DestroyGameObjectOnEditor(GameObject go)
 382    {
 0383        yield return null;
 0384        DestroyImmediate(go);
 0385    }
 386
 387    internal IEnumerator RunCarouselCoroutine(
 388        int fromIndex = 0,
 389        bool startInmediately = false,
 390        CarouselDirection direction = CarouselDirection.Right,
 391        bool changeDirectionAfterFirstTransition = false)
 392    {
 1393        currentItemIndex = fromIndex;
 394
 0395        while (true)
 396        {
 1397            if (!startInmediately)
 1398                yield return new WaitForSeconds(model.timeBetweenItems);
 399            else
 0400                startInmediately = false;
 401
 0402            if (instantiatedItems.Count > 0)
 403            {
 0404                if (direction == CarouselDirection.Right)
 405                {
 0406                    yield return RunRightAnimation();
 407
 0408                    if (changeDirectionAfterFirstTransition)
 409                    {
 0410                        direction = CarouselDirection.Left;
 0411                        changeDirectionAfterFirstTransition = false;
 412                    }
 0413                }
 414                else
 415                {
 0416                    yield return RunLeftAnimation();
 417
 0418                    if (changeDirectionAfterFirstTransition)
 419                    {
 0420                        direction = CarouselDirection.Right;
 0421                        changeDirectionAfterFirstTransition = false;
 422                    }
 423                }
 424            }
 425        }
 426    }
 427
 428    internal IEnumerator RunRightAnimation()
 429    {
 0430        if (currentItemIndex == instantiatedItems.Count - 1)
 431        {
 0432            currentItemIndex = 1;
 0433            itemsScroll.horizontalNormalizedPosition = 0f;
 0434            itemsContainer.GetChild(itemsContainer.childCount - 1).SetAsFirstSibling();
 435
 0436            yield return RunAnimationCoroutine(CarouselDirection.Right);
 0437        }
 438        else
 439        {
 0440            yield return RunAnimationCoroutine(CarouselDirection.Right);
 441
 0442            currentItemIndex++;
 0443            if (currentItemIndex >= instantiatedItems.Count - 1)
 444            {
 0445                currentItemIndex = 0;
 0446                itemsScroll.horizontalNormalizedPosition = 0f;
 0447                itemsContainer.GetChild(itemsContainer.childCount - 1).SetAsFirstSibling();
 448            }
 449        }
 0450    }
 451
 452    internal IEnumerator RunLeftAnimation()
 453    {
 0454        if (currentItemIndex == 0)
 455        {
 0456            currentItemIndex = instantiatedItems.Count - 2;
 0457            itemsScroll.horizontalNormalizedPosition = 1f;
 0458            itemsContainer.GetChild(0).SetAsLastSibling();
 459
 0460            yield return RunAnimationCoroutine(CarouselDirection.Left);
 0461        }
 462        else
 463        {
 0464            yield return RunAnimationCoroutine(CarouselDirection.Left);
 465
 0466            currentItemIndex--;
 0467            if (currentItemIndex <= 0)
 468            {
 0469                currentItemIndex = instantiatedItems.Count - 1;
 0470                itemsScroll.horizontalNormalizedPosition = 1f;
 0471                itemsContainer.GetChild(0).SetAsLastSibling();
 472            }
 473        }
 0474    }
 475
 476    internal IEnumerator RunAnimationCoroutine(CarouselDirection direction)
 477    {
 0478        isInTransition = true;
 0479        float currentAnimationTime = 0f;
 0480        float initialNormalizedPos = itemsScroll.horizontalNormalizedPosition;
 481
 0482        if (direction == CarouselDirection.Right)
 0483            currentFinalNormalizedPos = initialNormalizedPos + (1f / (instantiatedItems.Count - 1));
 484        else
 0485            currentFinalNormalizedPos = initialNormalizedPos - (1f / (instantiatedItems.Count - 1));
 486
 0487        while (currentAnimationTime <= model.animationTransitionTime)
 488        {
 0489            itemsScroll.horizontalNormalizedPosition = Mathf.Clamp01(Mathf.Lerp(
 490                initialNormalizedPos,
 491                currentFinalNormalizedPos,
 492                model.animationCurve.Evaluate(currentAnimationTime / model.animationTransitionTime)));
 493
 0494            currentAnimationTime += Time.deltaTime;
 495
 0496            yield return null;
 497        }
 498
 0499        itemsScroll.horizontalNormalizedPosition = currentFinalNormalizedPos;
 0500        isInTransition = false;
 0501    }
 502}