< Summary

Class:DCL.Chat.HUD.WorldChatWindowComponentView
Assembly:WorldChatWindowHUD
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/WorldChatWindowHUD/WorldChatWindowComponentView.cs
Covered lines:192
Uncovered lines:37
Coverable lines:229
Total lines:493
Line coverage:83.8% (192 of 229)
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%
SetPublicChat(...)0%110100%
RemovePublicChat(...)0%2100%
Configure(...)0%2100%
ShowChannelsLoading()0%110100%
HideChannelsLoading()0%110100%
ShowPrivateChatsLoading()0%110100%
HidePrivateChatsLoading()0%110100%
RefreshBlockedDirectMessages(...)0%6200%
RefreshPrivateChatPresence(...)0%12300%
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%
SetCreateChannelButtonActive(...)0%2100%
SetSearchAndCreateContainerActive(...)0%110100%
ShowConnectWallet()0%110100%
HideConnectWallet()0%110100%
SetChannelsPromoteLabelVisible(...)0%110100%
RefreshControl()0%12300%
Set(...)0%550100%
Set(...)0%220100%
OpenChannelOptions(...)0%110100%
SortLists()0%110100%
SetChannelsLoadingVisibility(...)0%110100%
SetPrivateChatLoadingVisibility(...)0%330100%
UpdateHeaders()0%110100%
UpdateLayout()0%110100%
SetQueuedEntries()0%660100%
FetchProfilePicturesForVisibleEntries()0%6.026091.67%
RequestMorePrivateChats(...)0%8.068090%
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 UIComponents.CollapsableSortedList;
 8using UnityEngine;
 9using UnityEngine.UI;
 10
 11namespace DCL.Chat.HUD
 12{
 13    public class WorldChatWindowComponentView : BaseComponentView, IWorldChatWindowView, IComponentModelConfig<WorldChat
 14    {
 15        private const int CREATION_AMOUNT_PER_FRAME = 5;
 16        private const int AVATAR_SNAPSHOTS_PER_FRAME = 5;
 17        private const string NEARBY_CHANNEL = "nearby";
 18        private const float REQUEST_MORE_ENTRIES_SCROLL_THRESHOLD = 0.005f;
 19        private const float MIN_TIME_TO_REQUIRE_MORE_ENTRIES = 0.5f;
 20
 21        [SerializeField] internal CollapsablePublicChannelListComponentView publicChannelList;
 22        [SerializeField] internal CollapsableDirectChatListComponentView directChatList;
 23        [SerializeField] internal CollapsableChatSearchListComponentView searchResultsList;
 24        [SerializeField] internal GameObject searchLoading;
 25        [SerializeField] internal Button closeButton;
 26        [SerializeField] internal GameObject channelsLoadingContainer;
 27        [SerializeField] internal GameObject directChatsLoadingContainer;
 28        [SerializeField] internal GameObject emptyDirectChatsContainer;
 29        [SerializeField] internal GameObject channelsHeader;
 30        [SerializeField] internal GameObject directChannelHeader;
 31        [SerializeField] internal GameObject searchResultsHeader;
 32        [SerializeField] internal TMP_Text channelsHeaderLabel;
 33        [SerializeField] internal TMP_Text directChatsHeaderLabel;
 34        [SerializeField] internal TMP_Text searchResultsHeaderLabel;
 35        [SerializeField] internal ScrollRect scroll;
 36        [SerializeField] internal SearchBarComponentView searchBar;
 37        [SerializeField] internal GameObject searchAndCreateContainer;
 38        [SerializeField] internal Button openChannelSearchButton;
 39        [SerializeField] internal ChannelContextualMenu channelContextualMenu;
 40        [SerializeField] internal Button createChannelButton;
 41        [SerializeField] internal GameObject searchBarContainer;
 42        [SerializeField] internal CollapsableListToggleButton directChatsCollapseButton;
 43        [SerializeField] internal CollapsableListToggleButton publicChatsChatsCollapseButton;
 44        [SerializeField] private WorldChatWindowModel model;
 45        [SerializeField] private GameObject channelsPromoteLabel;
 46
 47        [Header("Load More Entries")]
 48        [SerializeField] internal GameObject loadMoreEntriesContainer;
 49        [SerializeField] internal TMP_Text loadMoreEntriesLabel;
 50        [SerializeField] internal GameObject loadMoreEntriesLoading;
 51
 52        [Header("Guest")]
 53        [SerializeField] internal GameObject connectWalletContainer;
 54        [SerializeField] internal Button connectWalletButton;
 55        [SerializeField] internal Button whatIsWalletButton;
 56
 4257        private readonly Dictionary<string, PrivateChatModel> privateChatsCreationQueue =
 58            new Dictionary<string, PrivateChatModel>();
 59
 4260        private readonly Dictionary<string, PublicChatModel> publicChatsCreationQueue =
 61            new Dictionary<string, PublicChatModel>();
 62
 63        private bool isSortingDirty;
 64        private bool isLayoutDirty;
 65        private int currentAvatarSnapshotIndex;
 66        private bool isLoadingPrivateChannels;
 67        private bool isSearchMode;
 68        private string optionsChannelId;
 69        private Vector2 lastScrollPosition;
 70        private float loadMoreEntriesRestrictionTime;
 71        private Coroutine requireMoreEntriesRoutine;
 72        private bool isConnectWalletMode;
 73
 74        public event Action OnClose;
 75        public event Action<string> OnOpenPrivateChat;
 76        public event Action<string> OnOpenPublicChat;
 77        public event Action<string> OnSearchChatRequested;
 78        public event Action OnRequireMorePrivateChats;
 79        public event Action OnOpenChannelSearch;
 80        public event Action<string> OnLeaveChannel;
 81        public event Action OnCreateChannel;
 82        public event Action OnSignUp;
 83        public event Action OnRequireWalletReadme;
 84
 085        public RectTransform Transform => (RectTransform) transform;
 086        public bool IsActive => gameObject.activeInHierarchy;
 87
 88        public static WorldChatWindowComponentView Create()
 89        {
 3490            return Instantiate(Resources.Load<WorldChatWindowComponentView>("SocialBarV1/ConversationListHUD"));
 91        }
 92
 93        public override void Awake()
 94        {
 4095            base.Awake();
 96
 97            int SortByAlphabeticalOrder(PublicChatEntry u1, PublicChatEntry u2)
 98            {
 199                if (u1.Model.name == NEARBY_CHANNEL)
 1100                    return -1;
 0101                if (u2.Model.name == NEARBY_CHANNEL)
 0102                    return 1;
 103
 0104                return string.Compare(u1.Model.name, u2.Model.name, StringComparison.InvariantCultureIgnoreCase);
 105            }
 106
 40107            openChannelSearchButton.onClick.AddListener(() => OnOpenChannelSearch?.Invoke());
 41108            closeButton.onClick.AddListener(() => OnClose?.Invoke());
 86109            directChatList.SortingMethod = (a, b) => b.Model.lastMessageTimestamp.CompareTo(a.Model.lastMessageTimestamp
 41110            directChatList.OnOpenChat += entry => OnOpenPrivateChat?.Invoke(entry.Model.userId);
 40111            searchResultsList.OnOpenPrivateChat += entry => OnOpenPrivateChat?.Invoke(entry.Model.userId);
 40112            searchResultsList.OnOpenPublicChat += entry => OnOpenPublicChat?.Invoke(entry.Model.channelId);
 40113            publicChannelList.SortingMethod = SortByAlphabeticalOrder;
 41114            publicChannelList.OnOpenChat += entry => OnOpenPublicChat?.Invoke(entry.Model.channelId);
 41115            searchBar.OnSearchText += text => OnSearchChatRequested?.Invoke(text);
 40116            scroll.onValueChanged.AddListener(RequestMorePrivateChats);
 41117            channelContextualMenu.OnLeave += () => OnLeaveChannel?.Invoke(optionsChannelId);
 40118            createChannelButton.onClick.AddListener(() => OnCreateChannel?.Invoke());
 41119            connectWalletButton.onClick.AddListener(() => OnSignUp?.Invoke());
 41120            whatIsWalletButton.onClick.AddListener(() => OnRequireWalletReadme?.Invoke());
 40121            UpdateHeaders();
 40122        }
 123
 124        public override void OnEnable()
 125        {
 41126            base.OnEnable();
 41127            UpdateLayout();
 41128        }
 129
 130        public void Initialize(IChatController chatController)
 131        {
 34132            directChatList.Initialize(chatController);
 34133            publicChannelList.Initialize(chatController);
 34134            searchResultsList.Initialize(chatController);
 34135        }
 136
 137        public override void Update()
 138        {
 116139            base.Update();
 140
 116141            SetQueuedEntries();
 142
 116143            if (isSortingDirty)
 144            {
 26145                directChatList.Sort();
 26146                searchResultsList.Sort();
 26147                publicChannelList.Sort();
 148            }
 149
 116150            isSortingDirty = false;
 151
 116152            if (isLayoutDirty)
 41153                ((RectTransform) scroll.transform).ForceUpdateLayout();
 116154            isLayoutDirty = false;
 155
 116156            FetchProfilePicturesForVisibleEntries();
 116157        }
 158
 2159        public void Show() => gameObject.SetActive(true);
 160
 2161        public void Hide() => gameObject.SetActive(false);
 162
 38163        public void SetPrivateChat(PrivateChatModel model) => privateChatsCreationQueue[model.user.userId] = model;
 164
 165        public void RemovePrivateChat(string userId)
 166        {
 1167            privateChatsCreationQueue.Remove(userId);
 1168            directChatList.Remove(userId);
 1169            searchResultsList.Remove(userId);
 1170            UpdateHeaders();
 1171            UpdateLayout();
 1172        }
 173
 21174        public void SetPublicChat(PublicChatModel model) => publicChatsCreationQueue[model.channelId] = model;
 175
 176        public void RemovePublicChat(string channelId)
 177        {
 0178            publicChatsCreationQueue.Remove(channelId);
 0179            publicChannelList.Remove(channelId);
 0180            UpdateHeaders();
 0181            UpdateLayout();
 0182        }
 183
 184        public void Configure(WorldChatWindowModel newModel)
 185        {
 0186            model = newModel;
 0187            RefreshControl();
 0188        }
 189
 1190        public void ShowChannelsLoading() => SetChannelsLoadingVisibility(true);
 191
 2192        public void HideChannelsLoading() => SetChannelsLoadingVisibility(false);
 193
 2194        public void ShowPrivateChatsLoading() => SetPrivateChatLoadingVisibility(true);
 195
 1196        public void HidePrivateChatsLoading() => SetPrivateChatLoadingVisibility(false);
 197
 198        public void RefreshBlockedDirectMessages(List<string> blockedUsers)
 199        {
 0200            if (blockedUsers == null) return;
 0201            directChatList.RefreshBlockedEntries(blockedUsers);
 0202        }
 203
 204        public void RefreshPrivateChatPresence(string userId, bool isOnline)
 205        {
 0206            if (!ContainsPrivateChannel(userId))
 0207                return;
 208
 0209            if (privateChatsCreationQueue.ContainsKey(userId))
 210            {
 0211                PrivateChatModel refreshedPrivateChatModel = privateChatsCreationQueue[userId];
 0212                refreshedPrivateChatModel.isOnline = isOnline;
 0213                privateChatsCreationQueue[userId] = refreshedPrivateChatModel;
 214            }
 215            else
 0216                directChatList.RefreshPresence(userId, isOnline);
 0217        }
 218
 219        public void HideMoreChatsToLoadHint()
 220        {
 1221            loadMoreEntriesContainer.SetActive(false);
 1222            emptyDirectChatsContainer.SetActive(directChatList.Count() == 0);
 1223            UpdateLayout();
 1224        }
 225
 226        public void ShowMoreChatsToLoadHint(int count)
 227        {
 2228            loadMoreEntriesLabel.SetText(
 229                $"{count} chats hidden. Use the search bar to find them or click below to show more.");
 2230            loadMoreEntriesContainer.SetActive(true);
 2231            emptyDirectChatsContainer.SetActive(false);
 2232            UpdateLayout();
 2233        }
 234
 235        public void HideMoreChatsLoading()
 236        {
 118237            loadMoreEntriesLoading.SetActive(false);
 118238        }
 239
 240        public void ShowMoreChatsLoading()
 241        {
 2242            loadMoreEntriesLoading.SetActive(true);
 2243        }
 244
 245        public void HideSearchLoading()
 246        {
 1247            searchLoading.SetActive(false);
 1248        }
 249
 250        public void ShowSearchLoading()
 251        {
 1252            searchLoading.SetActive(true);
 1253            searchLoading.transform.SetAsLastSibling();
 1254        }
 255
 256    public void DisableSearchMode()
 257    {
 4258        isSearchMode = false;
 4259        searchResultsList.Hide();
 4260        publicChannelList.Show();
 4261        publicChannelList.Sort();
 262
 4263        if (!isLoadingPrivateChannels)
 264        {
 3265            directChatList.Show();
 3266            directChatList.Sort();
 3267            channelsHeader.SetActive(true);
 3268            directChannelHeader.SetActive(true);
 269        }
 270
 4271        searchResultsHeader.SetActive(false);
 4272        searchResultsList.Clear();
 4273        searchBar.ClearSearch(false);
 274
 4275        UpdateHeaders();
 4276    }
 277
 278    public void EnableSearchMode()
 279    {
 6280        isSearchMode = true;
 281
 6282        searchResultsList.Clear();
 6283        searchResultsList.Show();
 6284        searchResultsList.Sort();
 6285        publicChannelList.Hide();
 6286        directChatList.Hide();
 6287        channelsHeader.SetActive(false);
 6288        directChannelHeader.SetActive(false);
 6289        searchResultsHeader.SetActive(true);
 290
 6291        UpdateHeaders();
 6292        searchLoading.transform.SetAsLastSibling();
 6293    }
 294
 0295        public bool ContainsPrivateChannel(string userId) => privateChatsCreationQueue.ContainsKey(userId)
 296                                                             || directChatList.Get(userId) != null;
 297
 0298        public void SetCreateChannelButtonActive(bool isActive) => createChannelButton.gameObject.SetActive(isActive);
 299
 1300        public void SetSearchAndCreateContainerActive(bool isActive) => searchAndCreateContainer.SetActive(isActive);
 301
 302        public void ShowConnectWallet()
 303        {
 1304            isConnectWalletMode = true;
 1305            connectWalletContainer.SetActive(true);
 1306            searchBarContainer.SetActive(false);
 1307            directChatsCollapseButton.SetInteractability(false);
 1308            publicChatsChatsCollapseButton.SetInteractability(false);
 1309        }
 310
 311        public void HideConnectWallet()
 312        {
 2313            isConnectWalletMode = false;
 2314            connectWalletContainer.SetActive(false);
 2315            searchBarContainer.SetActive(true);
 2316            directChatsCollapseButton.SetInteractability(true);
 2317            publicChatsChatsCollapseButton.SetInteractability(true);
 2318        }
 319
 1320        public void SetChannelsPromoteLabelVisible(bool isVisible) => channelsPromoteLabel.SetActive(isVisible);
 321
 322        public override void RefreshControl()
 323        {
 0324            publicChannelList.Clear();
 0325            foreach (var entry in model.publicChannels)
 0326                publicChannelList.Set(entry.channelId, entry);
 0327            SetChannelsLoadingVisibility(model.isLoadingChannels);
 328
 0329            directChatList.Clear();
 0330            foreach (var entry in model.privateChats)
 0331                directChatList.Set(entry.userId, entry);
 0332            SetPrivateChatLoadingVisibility(model.isLoadingDirectChats);
 0333        }
 334
 335        private void Set(PrivateChatModel model)
 336        {
 37337            var user = model.user;
 37338            var userId = user.userId;
 339
 37340            var entry = new PrivateChatEntryModel(
 341                user.userId,
 342                user.userName,
 343                model.recentMessage != null ? model.recentMessage.body : string.Empty,
 344                user.face256SnapshotURL,
 345                model.isBlocked,
 346                model.isOnline,
 347                model.recentMessage != null ? model.recentMessage.timestamp : 0);
 348
 37349            if (isSearchMode)
 18350                searchResultsList.Set(entry);
 351            else
 19352                directChatList.Set(userId, entry);
 353
 37354            UpdateHeaders();
 37355            UpdateLayout();
 37356            SortLists();
 37357        }
 358
 359        private void Set(PublicChatModel model)
 360        {
 21361            var channelId = model.channelId;
 21362            var entryModel = new PublicChatEntryModel(channelId, model.name, model.joined, model.memberCount, showOnlyOn
 363            PublicChatEntry entry;
 364
 21365            if (isSearchMode)
 366            {
 8367                searchResultsList.Set(entryModel);
 8368                entry = (PublicChatEntry) searchResultsList.Get(channelId);
 369            }
 370            else
 371            {
 13372                publicChannelList.Set(channelId, entryModel);
 13373                entry = publicChannelList.Get(channelId);
 374            }
 375
 21376            entry.OnOpenOptions -= OpenChannelOptions;
 21377            entry.OnOpenOptions += OpenChannelOptions;
 378
 21379            UpdateHeaders();
 21380            UpdateLayout();
 21381            SortLists();
 21382        }
 383
 384        private void OpenChannelOptions(PublicChatEntry entry)
 385        {
 1386            optionsChannelId = entry.Model.channelId;
 1387            entry.Dock(channelContextualMenu);
 1388            channelContextualMenu.SetHeaderTitle($"#{entry.Model.name.ToLower()}");
 1389            channelContextualMenu.Show();
 1390        }
 391
 58392        private void SortLists() => isSortingDirty = true;
 393
 394        private void SetChannelsLoadingVisibility(bool visible)
 395        {
 3396            model.isLoadingChannels = visible;
 3397            channelsLoadingContainer.SetActive(visible);
 3398            publicChannelList.gameObject.SetActive(!visible);
 3399        }
 400
 401        private void SetPrivateChatLoadingVisibility(bool visible)
 402        {
 3403            model.isLoadingDirectChats = visible;
 3404            directChatsLoadingContainer.SetActive(visible);
 405
 3406            if (visible)
 2407                directChatList.Hide();
 1408            else if (!isSearchMode)
 1409                directChatList.Show();
 410
 3411            scroll.enabled = !visible;
 3412            isLoadingPrivateChannels = visible;
 3413        }
 414
 415        private void UpdateHeaders()
 416        {
 109417            directChatsHeaderLabel.text = $"Direct Messages ({directChatList.Count()})";
 109418            searchResultsHeaderLabel.text = $"Results ({searchResultsList.Count()})";
 109419            searchResultsHeader.SetActive(searchResultsList.Count() > 0);
 109420            channelsHeaderLabel.text = $"Channels ({publicChannelList.Count()})";
 109421        }
 422
 103423        private void UpdateLayout() => isLayoutDirty = true;
 424
 425        private void SetQueuedEntries()
 426        {
 116427            if (privateChatsCreationQueue.Count > 0)
 428            {
 110429                for (var i = 0; i < CREATION_AMOUNT_PER_FRAME && privateChatsCreationQueue.Count > 0; i++)
 430                {
 37431                    var (userId, model) = privateChatsCreationQueue.First();
 37432                    privateChatsCreationQueue.Remove(userId);
 37433                    Set(model);
 434                }
 435            }
 436
 274437            for (var i = 0; i < CREATION_AMOUNT_PER_FRAME && publicChatsCreationQueue.Count > 0; i++)
 438            {
 21439                var (userId, model) = publicChatsCreationQueue.First();
 21440                publicChatsCreationQueue.Remove(userId);
 21441                Set(model);
 442            }
 443
 116444            HideMoreChatsLoading();
 116445        }
 446
 447        private void FetchProfilePicturesForVisibleEntries()
 448        {
 124449            if (isSearchMode) return;
 450
 254451            foreach (var entry in directChatList.Entries.Values.Skip(currentAvatarSnapshotIndex)
 452                         .Take(AVATAR_SNAPSHOTS_PER_FRAME))
 453            {
 19454                if (entry.IsVisible((RectTransform) scroll.transform))
 19455                    entry.EnableAvatarSnapshotFetching();
 456                else
 0457                    entry.DisableAvatarSnapshotFetching();
 458            }
 459
 108460            currentAvatarSnapshotIndex += AVATAR_SNAPSHOTS_PER_FRAME;
 461
 108462            if (currentAvatarSnapshotIndex >= directChatList.Entries.Count)
 108463                currentAvatarSnapshotIndex = 0;
 108464        }
 465
 466        private void RequestMorePrivateChats(Vector2 position)
 467        {
 24468            if (!loadMoreEntriesContainer.activeInHierarchy
 469                || loadMoreEntriesLoading.activeInHierarchy
 470                || Time.realtimeSinceStartup - loadMoreEntriesRestrictionTime < MIN_TIME_TO_REQUIRE_MORE_ENTRIES
 22471                || isConnectWalletMode) return;
 472
 2473            if (position.y < REQUEST_MORE_ENTRIES_SCROLL_THRESHOLD && lastScrollPosition.y >= REQUEST_MORE_ENTRIES_SCROL
 474            {
 1475                if (requireMoreEntriesRoutine != null)
 0476                    StopCoroutine(requireMoreEntriesRoutine);
 477
 1478                ShowMoreChatsLoading();
 1479                requireMoreEntriesRoutine = StartCoroutine(WaitThenRequireMoreEntries());
 480
 1481                loadMoreEntriesRestrictionTime = Time.realtimeSinceStartup;
 482            }
 483
 2484            lastScrollPosition = position;
 2485        }
 486
 487        private IEnumerator WaitThenRequireMoreEntries()
 488        {
 1489            yield return new WaitForSeconds(1f);
 1490            OnRequireMorePrivateChats?.Invoke();
 1491        }
 492    }
 493}