< Summary

Class:WorldChatWindowComponentView
Assembly:WorldChatWindowHUD
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/WorldChatWindowHUD/WorldChatWindowComponentView.cs
Covered lines:135
Uncovered lines:22
Coverable lines:157
Total lines:342
Line coverage:85.9% (135 of 157)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
WorldChatWindowComponentView()0%110100%
Create()0%110100%
Awake()0%220100%
OnEnable()0%110100%
Initialize(...)0%110100%
Update()0%330100%
Show()0%110100%
Hide()0%110100%
SetPrivateChat(...)0%110100%
RemovePrivateChat(...)0%110100%
SetPublicChannel(...)0%220100%
Configure(...)0%2100%
ShowPrivateChatsLoading()0%110100%
HidePrivateChatsLoading()0%110100%
RefreshBlockedDirectMessages(...)0%6200%
HideMoreChatsToLoadHint()0%110100%
ShowMoreChatsToLoadHint(...)0%110100%
HideMoreChatsLoading()0%110100%
ShowMoreChatsLoading()0%110100%
HideSearchLoading()0%110100%
ShowSearchLoading()0%110100%
DisableSearchMode()0%220100%
EnableSearchMode()0%110100%
ContainsPrivateChannel(...)0%6200%
RefreshControl()0%12300%
Set(...)0%550100%
SortLists()0%2100%
SetPrivateChatLoadingVisibility(...)0%330100%
UpdateHeaders()0%110100%
UpdateLayout()0%2100%
SetQueuedEntries()0%440100%
FetchProfilePicturesForVisibleEntries()0%6.026091.67%
RequestMorePrivateChats(...)0%7.397080%
WaitThenRequireMoreEntries()0%440100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/WorldChatWindowHUD/WorldChatWindowComponentView.cs

#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Collections.Generic;
 4using System.Linq;
 5using DCL.Helpers;
 6using TMPro;
 7using UnityEngine;
 8using UnityEngine.UI;
 9
 10public class WorldChatWindowComponentView : BaseComponentView, IWorldChatWindowView, IComponentModelConfig<WorldChatWind
 11{
 12    private const int CREATION_AMOUNT_PER_FRAME = 5;
 13    private const int AVATAR_SNAPSHOTS_PER_FRAME = 5;
 14    private const float REQUEST_MORE_ENTRIES_SCROLL_THRESHOLD = 0.005f;
 15    private const float MIN_TIME_TO_REQUIRE_MORE_ENTRIES = 0.5f;
 16
 17    [SerializeField] internal CollapsablePublicChannelListComponentView publicChannelList;
 18    [SerializeField] internal CollapsableDirectChatListComponentView directChatList;
 19    [SerializeField] internal CollapsableChatSearchListComponentView searchResultsList;
 20    [SerializeField] internal GameObject searchLoading;
 21    [SerializeField] internal Button closeButton;
 22    [SerializeField] internal GameObject directChatsLoadingContainer;
 23    [SerializeField] internal GameObject directChannelHeader;
 24    [SerializeField] internal GameObject searchResultsHeader;
 25    [SerializeField] internal TMP_Text directChatsHeaderLabel;
 26    [SerializeField] internal TMP_Text searchResultsHeaderLabel;
 27    [SerializeField] internal ScrollRect scroll;
 28    [SerializeField] internal SearchBarComponentView searchBar;
 29    [SerializeField] private WorldChatWindowModel model;
 30
 31    [Header("Load More Entries")]
 32    [SerializeField] internal GameObject loadMoreEntriesContainer;
 33    [SerializeField] internal TMP_Text loadMoreEntriesLabel;
 34    [SerializeField] internal GameObject loadMoreEntriesLoading;
 35
 2936    private readonly Dictionary<string, PrivateChatModel> creationQueue = new Dictionary<string, PrivateChatModel>();
 37    private bool isSortingDirty;
 38    private bool isLayoutDirty;
 39    private int currentAvatarSnapshotIndex;
 40    private bool isLoadingPrivateChannels;
 41    private bool isSearchMode;
 42    private Vector2 lastScrollPosition;
 43    private float loadMoreEntriesRestrictionTime;
 44    private Coroutine requireMoreEntriesRoutine;
 45
 46    public event Action OnClose;
 47    public event Action<string> OnOpenPrivateChat;
 48    public event Action<string> OnOpenPublicChannel;
 49
 50    public event Action<string> OnSearchChannelRequested;
 51    public event Action OnRequireMorePrivateChats;
 52
 053    public RectTransform Transform => (RectTransform) transform;
 054    public bool IsActive => gameObject.activeInHierarchy;
 55
 56    public static WorldChatWindowComponentView Create()
 57    {
 2758        return Instantiate(Resources.Load<WorldChatWindowComponentView>("SocialBarV1/ConversationListHUD"));
 59    }
 60
 61    public override void Awake()
 62    {
 2763        base.Awake();
 2864        closeButton.onClick.AddListener(() => OnClose?.Invoke());
 7365        directChatList.SortingMethod = (a, b) => b.Model.lastMessageTimestamp.CompareTo(a.Model.lastMessageTimestamp);
 2866        directChatList.OnOpenChat += entry => OnOpenPrivateChat?.Invoke(entry.Model.userId);
 2767        searchResultsList.OnOpenPrivateChat += entry => OnOpenPrivateChat?.Invoke(entry.Model.userId);
 2768        searchResultsList.OnOpenPublicChat += entry => OnOpenPublicChannel?.Invoke(entry.Model.channelId);
 2869        publicChannelList.OnOpenChat += entry => OnOpenPublicChannel?.Invoke(entry.Model.channelId);
 2870        searchBar.OnSearchText += text => OnSearchChannelRequested?.Invoke(text);
 2771        scroll.onValueChanged.AddListener(RequestMorePrivateChats);
 2772        UpdateHeaders();
 2773    }
 74
 75    public override void OnEnable()
 76    {
 2877        base.OnEnable();
 2878        UpdateLayout();
 2879    }
 80
 81    public void Initialize(IChatController chatController)
 82    {
 2783        directChatList.Initialize(chatController);
 2784        publicChannelList.Initialize(chatController);
 2785        searchResultsList.Initialize(chatController);
 2786    }
 87
 88    public override void Update()
 89    {
 27990        base.Update();
 91
 27992        SetQueuedEntries();
 93
 27994        if (isSortingDirty)
 95        {
 1896            directChatList.Sort();
 1897            searchResultsList.Sort();
 1898            publicChannelList.Sort();
 99        }
 100
 279101        isSortingDirty = false;
 102
 279103        if (isLayoutDirty)
 33104            ((RectTransform) scroll.transform).ForceUpdateLayout();
 279105        isLayoutDirty = false;
 106
 279107        FetchProfilePicturesForVisibleEntries();
 279108    }
 109
 2110    public void Show() => gameObject.SetActive(true);
 111
 2112    public void Hide() => gameObject.SetActive(false);
 113
 38114    public void SetPrivateChat(PrivateChatModel model) => creationQueue[model.user.userId] = model;
 115
 116    public void RemovePrivateChat(string userId)
 117    {
 1118        directChatList.Remove(userId);
 1119        searchResultsList.Remove(userId);
 1120        UpdateHeaders();
 1121        UpdateLayout();
 1122    }
 123
 124    public void SetPublicChannel(PublicChatChannelModel model)
 125    {
 20126        var entryModel = new PublicChannelEntry.PublicChannelEntryModel(model.channelId, name = model.name);
 127
 20128        if (isSearchMode)
 8129            searchResultsList.Set(entryModel);
 130        else
 12131            publicChannelList.Set(model.channelId, entryModel);
 132
 20133        UpdateLayout();
 20134    }
 135
 136    public void Configure(WorldChatWindowModel newModel)
 137    {
 0138        model = newModel;
 0139        RefreshControl();
 0140    }
 141
 2142    public void ShowPrivateChatsLoading() => SetPrivateChatLoadingVisibility(true);
 143
 1144    public void HidePrivateChatsLoading() => SetPrivateChatLoadingVisibility(false);
 145
 146    public void RefreshBlockedDirectMessages(List<string> blockedUsers)
 147    {
 0148        if (blockedUsers == null) return;
 0149        directChatList.RefreshBlockedEntries(blockedUsers);
 0150    }
 151
 152    public void HideMoreChatsToLoadHint()
 153    {
 1154        loadMoreEntriesContainer.SetActive(false);
 1155        UpdateLayout();
 1156    }
 157
 158    public void ShowMoreChatsToLoadHint(int count)
 159    {
 2160        loadMoreEntriesLabel.SetText($"{count} chats hidden. Use the search bar to find them or click below to show more
 2161        loadMoreEntriesContainer.SetActive(true);
 2162        UpdateLayout();
 2163    }
 164
 165    public void HideMoreChatsLoading()
 166    {
 20167        loadMoreEntriesLoading.SetActive(false);
 20168    }
 169
 170    public void ShowMoreChatsLoading()
 171    {
 2172        loadMoreEntriesLoading.SetActive(true);
 2173    }
 174
 175    public void HideSearchLoading()
 176    {
 1177        searchLoading.SetActive(false);
 1178    }
 179
 180    public void ShowSearchLoading()
 181    {
 1182        searchLoading.SetActive(true);
 1183        searchLoading.transform.SetAsLastSibling();
 1184    }
 185
 186    public void DisableSearchMode()
 187    {
 3188        isSearchMode = false;
 3189        searchResultsList.Hide();
 3190        publicChannelList.Show();
 3191        publicChannelList.Sort();
 192
 3193        if (!isLoadingPrivateChannels)
 194        {
 3195            directChatList.Show();
 3196            directChatList.Sort();
 3197            directChannelHeader.SetActive(true);
 198        }
 199
 3200        searchResultsHeader.SetActive(false);
 3201        searchResultsList.Clear();
 202
 3203        UpdateHeaders();
 3204    }
 205
 206    public void EnableSearchMode()
 207    {
 6208        isSearchMode = true;
 209
 6210        searchResultsList.Clear();
 6211        searchResultsList.Show();
 6212        searchResultsList.Sort();
 6213        publicChannelList.Hide();
 6214        directChatList.Hide();
 6215        directChannelHeader.SetActive(false);
 6216        searchResultsHeader.SetActive(true);
 217
 6218        UpdateHeaders();
 6219        searchLoading.transform.SetAsLastSibling();
 6220    }
 221
 0222    public bool ContainsPrivateChannel(string userId) => creationQueue.ContainsKey(userId)
 223                                                         || directChatList.Get(userId) != null;
 224
 225    public override void RefreshControl()
 226    {
 0227        publicChannelList.Clear();
 0228        foreach (var entry in model.publicChannels)
 0229            publicChannelList.Set(entry.channelId, entry);
 0230        directChatList.Clear();
 0231        foreach (var entry in model.privateChats)
 0232            directChatList.Set(entry.userId, entry);
 0233        SetPrivateChatLoadingVisibility(model.isLoadingDirectChats);
 0234    }
 235
 236    private void Set(PrivateChatModel model)
 237    {
 37238        var user = model.user;
 37239        var userId = user.userId;
 240
 37241        var entry = new PrivateChatEntry.PrivateChatEntryModel(
 242            user.userId,
 243            user.userName,
 244            model.recentMessage != null ? model.recentMessage.body : string.Empty,
 245            user.face256SnapshotURL,
 246            model.isBlocked,
 247            model.isOnline,
 248            model.recentMessage != null ? model.recentMessage.timestamp : 0);
 249
 37250        if (isSearchMode)
 18251            searchResultsList.Set(entry);
 252        else
 19253            directChatList.Set(userId, entry);
 254
 37255        UpdateHeaders();
 37256        UpdateLayout();
 37257        SortLists();
 37258    }
 259
 0260    private void SortLists() => isSortingDirty = true;
 261
 262    private void SetPrivateChatLoadingVisibility(bool visible)
 263    {
 3264        model.isLoadingDirectChats = visible;
 3265        directChatsLoadingContainer.SetActive(visible);
 266
 3267        if (visible)
 2268            directChatList.Hide();
 1269        else if (!isSearchMode)
 1270            directChatList.Show();
 271
 3272        scroll.enabled = !visible;
 3273        isLoadingPrivateChannels = visible;
 3274    }
 275
 276    private void UpdateHeaders()
 277    {
 74278        directChatsHeaderLabel.text = $"Direct Messages ({directChatList.Count()})";
 74279        searchResultsHeaderLabel.text = $"Results ({searchResultsList.Count()})";
 74280    }
 281
 0282    private void UpdateLayout() => isLayoutDirty = true;
 283
 284    private void SetQueuedEntries()
 285    {
 540286        if (creationQueue.Count == 0) return;
 287
 110288        for (var i = 0; i < CREATION_AMOUNT_PER_FRAME && creationQueue.Count > 0; i++)
 289        {
 37290            var (userId, model) = creationQueue.First();
 37291            creationQueue.Remove(userId);
 37292            Set(model);
 293        }
 294
 18295        HideMoreChatsLoading();
 18296    }
 297
 298    private void FetchProfilePicturesForVisibleEntries()
 299    {
 287300        if (isSearchMode) return;
 301
 580302        foreach (var entry in directChatList.Entries.Values.Skip(currentAvatarSnapshotIndex)
 303                     .Take(AVATAR_SNAPSHOTS_PER_FRAME))
 304        {
 19305            if (entry.IsVisible((RectTransform) scroll.transform))
 19306                entry.EnableAvatarSnapshotFetching();
 307            else
 0308                entry.DisableAvatarSnapshotFetching();
 309        }
 310
 271311        currentAvatarSnapshotIndex += AVATAR_SNAPSHOTS_PER_FRAME;
 312
 271313        if (currentAvatarSnapshotIndex >= directChatList.Entries.Count)
 271314            currentAvatarSnapshotIndex = 0;
 271315    }
 316
 317    private void RequestMorePrivateChats(Vector2 position)
 318    {
 2319        if (!loadMoreEntriesContainer.activeInHierarchy ||
 320            loadMoreEntriesLoading.activeInHierarchy ||
 0321            Time.realtimeSinceStartup - loadMoreEntriesRestrictionTime < MIN_TIME_TO_REQUIRE_MORE_ENTRIES) return;
 322
 2323        if (position.y < REQUEST_MORE_ENTRIES_SCROLL_THRESHOLD && lastScrollPosition.y >= REQUEST_MORE_ENTRIES_SCROLL_TH
 324        {
 1325            if (requireMoreEntriesRoutine != null)
 0326                StopCoroutine(requireMoreEntriesRoutine);
 327
 1328            ShowMoreChatsLoading();
 1329            requireMoreEntriesRoutine = StartCoroutine(WaitThenRequireMoreEntries());
 330
 1331            loadMoreEntriesRestrictionTime = Time.realtimeSinceStartup;
 332        }
 333
 2334        lastScrollPosition = position;
 2335    }
 336
 337    private IEnumerator WaitThenRequireMoreEntries()
 338    {
 1339        yield return new WaitForSeconds(1f);
 1340        OnRequireMorePrivateChats?.Invoke();
 1341    }
 342}