< 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:194
Uncovered lines:30
Coverable lines:224
Total lines:481
Line coverage:86.6% (194 of 224)
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%
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%2100%
SetChannelsLoadingVisibility(...)0%110100%
SetPrivateChatLoadingVisibility(...)0%330100%
UpdateHeaders()0%110100%
UpdateLayout()0%2100%
SetQueuedEntries()0%660100%
FetchProfilePicturesForVisibleEntries()0%660100%
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 GameObject walletConnectedContainer;
 55        [SerializeField] internal Button connectWalletButton;
 56        [SerializeField] internal Button whatIsWalletButton;
 57
 4258        private readonly Dictionary<string, PrivateChatModel> privateChatsCreationQueue =
 59            new Dictionary<string, PrivateChatModel>();
 60
 4261        private readonly Dictionary<string, PublicChatModel> publicChatsCreationQueue =
 62            new Dictionary<string, PublicChatModel>();
 63
 64        private bool isSortingDirty;
 65        private bool isLayoutDirty;
 66        private int currentAvatarSnapshotIndex;
 67        private bool isLoadingPrivateChannels;
 68        private bool isSearchMode;
 69        private string optionsChannelId;
 70        private Vector2 lastScrollPosition;
 71        private float loadMoreEntriesRestrictionTime;
 72        private Coroutine requireMoreEntriesRoutine;
 73        private bool isConnectWalletMode;
 74
 75        public event Action OnClose;
 76        public event Action<string> OnOpenPrivateChat;
 77        public event Action<string> OnOpenPublicChat;
 78        public event Action<string> OnSearchChatRequested;
 79        public event Action OnRequireMorePrivateChats;
 80        public event Action OnOpenChannelSearch;
 81        public event Action<string> OnLeaveChannel;
 82        public event Action OnCreateChannel;
 83        public event Action OnSignUp;
 84        public event Action OnRequireWalletReadme;
 85
 086        public RectTransform Transform => (RectTransform) transform;
 087        public bool IsActive => gameObject.activeInHierarchy;
 88
 89        public static WorldChatWindowComponentView Create()
 90        {
 3491            return Instantiate(Resources.Load<WorldChatWindowComponentView>("SocialBarV1/ConversationListHUD"));
 92        }
 93
 94        public override void Awake()
 95        {
 4096            base.Awake();
 97
 98            int SortByAlphabeticalOrder(PublicChatEntry u1, PublicChatEntry u2)
 99            {
 1100                if (u1.Model.name == NEARBY_CHANNEL)
 1101                    return -1;
 0102                if (u2.Model.name == NEARBY_CHANNEL)
 0103                    return 1;
 104
 0105                return string.Compare(u1.Model.name, u2.Model.name, StringComparison.InvariantCultureIgnoreCase);
 106            }
 107
 40108            openChannelSearchButton.onClick.AddListener(() => OnOpenChannelSearch?.Invoke());
 41109            closeButton.onClick.AddListener(() => OnClose?.Invoke());
 86110            directChatList.SortingMethod = (a, b) => b.Model.lastMessageTimestamp.CompareTo(a.Model.lastMessageTimestamp
 41111            directChatList.OnOpenChat += entry => OnOpenPrivateChat?.Invoke(entry.Model.userId);
 40112            searchResultsList.OnOpenPrivateChat += entry => OnOpenPrivateChat?.Invoke(entry.Model.userId);
 40113            searchResultsList.OnOpenPublicChat += entry => OnOpenPublicChat?.Invoke(entry.Model.channelId);
 40114            publicChannelList.SortingMethod = SortByAlphabeticalOrder;
 41115            publicChannelList.OnOpenChat += entry => OnOpenPublicChat?.Invoke(entry.Model.channelId);
 41116            searchBar.OnSearchText += text => OnSearchChatRequested?.Invoke(text);
 40117            scroll.onValueChanged.AddListener(RequestMorePrivateChats);
 41118            channelContextualMenu.OnLeave += () => OnLeaveChannel?.Invoke(optionsChannelId);
 40119            createChannelButton.onClick.AddListener(() => OnCreateChannel?.Invoke());
 41120            connectWalletButton.onClick.AddListener(() => OnSignUp?.Invoke());
 41121            whatIsWalletButton.onClick.AddListener(() => OnRequireWalletReadme?.Invoke());
 40122            UpdateHeaders();
 40123        }
 124
 125        public override void OnEnable()
 126        {
 41127            base.OnEnable();
 41128            UpdateLayout();
 41129        }
 130
 131        public void Initialize(IChatController chatController)
 132        {
 34133            directChatList.Initialize(chatController);
 34134            publicChannelList.Initialize(chatController);
 34135            searchResultsList.Initialize(chatController);
 34136        }
 137
 138        public override void Update()
 139        {
 245140            base.Update();
 141
 245142            SetQueuedEntries();
 143
 245144            if (isSortingDirty)
 145            {
 26146                directChatList.Sort();
 26147                searchResultsList.Sort();
 26148                publicChannelList.Sort();
 149            }
 150
 245151            isSortingDirty = false;
 152
 245153            if (isLayoutDirty)
 41154                ((RectTransform) scroll.transform).ForceUpdateLayout();
 245155            isLayoutDirty = false;
 156
 245157            FetchProfilePicturesForVisibleEntries();
 245158        }
 159
 2160        public void Show() => gameObject.SetActive(true);
 161
 2162        public void Hide() => gameObject.SetActive(false);
 163
 38164        public void SetPrivateChat(PrivateChatModel model) => privateChatsCreationQueue[model.user.userId] = model;
 165
 166        public void RemovePrivateChat(string userId)
 167        {
 1168            privateChatsCreationQueue.Remove(userId);
 1169            directChatList.Remove(userId);
 1170            searchResultsList.Remove(userId);
 1171            UpdateHeaders();
 1172            UpdateLayout();
 1173        }
 174
 21175        public void SetPublicChat(PublicChatModel model) => publicChatsCreationQueue[model.channelId] = model;
 176
 177        public void RemovePublicChat(string channelId)
 178        {
 0179            publicChatsCreationQueue.Remove(channelId);
 0180            publicChannelList.Remove(channelId);
 0181            UpdateHeaders();
 0182            UpdateLayout();
 0183        }
 184
 185        public void Configure(WorldChatWindowModel newModel)
 186        {
 0187            model = newModel;
 0188            RefreshControl();
 0189        }
 190
 1191        public void ShowChannelsLoading() => SetChannelsLoadingVisibility(true);
 192
 2193        public void HideChannelsLoading() => SetChannelsLoadingVisibility(false);
 194
 2195        public void ShowPrivateChatsLoading() => SetPrivateChatLoadingVisibility(true);
 196
 1197        public void HidePrivateChatsLoading() => SetPrivateChatLoadingVisibility(false);
 198
 199        public void RefreshBlockedDirectMessages(List<string> blockedUsers)
 200        {
 0201            if (blockedUsers == null) return;
 0202            directChatList.RefreshBlockedEntries(blockedUsers);
 0203        }
 204
 205        public void HideMoreChatsToLoadHint()
 206        {
 1207            loadMoreEntriesContainer.SetActive(false);
 1208            emptyDirectChatsContainer.SetActive(directChatList.Count() == 0);
 1209            UpdateLayout();
 1210        }
 211
 212        public void ShowMoreChatsToLoadHint(int count)
 213        {
 2214            loadMoreEntriesLabel.SetText(
 215                $"{count} chats hidden. Use the search bar to find them or click below to show more.");
 2216            loadMoreEntriesContainer.SetActive(true);
 2217            emptyDirectChatsContainer.SetActive(false);
 2218            UpdateLayout();
 2219        }
 220
 221        public void HideMoreChatsLoading()
 222        {
 247223            loadMoreEntriesLoading.SetActive(false);
 247224        }
 225
 226        public void ShowMoreChatsLoading()
 227        {
 2228            loadMoreEntriesLoading.SetActive(true);
 2229        }
 230
 231        public void HideSearchLoading()
 232        {
 1233            searchLoading.SetActive(false);
 1234        }
 235
 236        public void ShowSearchLoading()
 237        {
 1238            searchLoading.SetActive(true);
 1239            searchLoading.transform.SetAsLastSibling();
 1240        }
 241
 242    public void DisableSearchMode()
 243    {
 4244        isSearchMode = false;
 4245        searchResultsList.Hide();
 4246        publicChannelList.Show();
 4247        publicChannelList.Sort();
 248
 4249        if (!isLoadingPrivateChannels)
 250        {
 3251            directChatList.Show();
 3252            directChatList.Sort();
 3253            channelsHeader.SetActive(true);
 3254            directChannelHeader.SetActive(true);
 255        }
 256
 4257        searchResultsHeader.SetActive(false);
 4258        searchResultsList.Clear();
 4259        searchBar.ClearSearch(false);
 260
 4261        UpdateHeaders();
 4262    }
 263
 264    public void EnableSearchMode()
 265    {
 6266        isSearchMode = true;
 267
 6268        searchResultsList.Clear();
 6269        searchResultsList.Show();
 6270        searchResultsList.Sort();
 6271        publicChannelList.Hide();
 6272        directChatList.Hide();
 6273        channelsHeader.SetActive(false);
 6274        directChannelHeader.SetActive(false);
 6275        searchResultsHeader.SetActive(true);
 276
 6277        UpdateHeaders();
 6278        searchLoading.transform.SetAsLastSibling();
 6279    }
 280
 0281        public bool ContainsPrivateChannel(string userId) => privateChatsCreationQueue.ContainsKey(userId)
 282                                                             || directChatList.Get(userId) != null;
 283
 0284        public void SetCreateChannelButtonActive(bool isActive) => createChannelButton.gameObject.SetActive(isActive);
 285
 1286        public void SetSearchAndCreateContainerActive(bool isActive) => searchAndCreateContainer.SetActive(isActive);
 287
 288        public void ShowConnectWallet()
 289        {
 1290            isConnectWalletMode = true;
 1291            connectWalletContainer.SetActive(true);
 1292            walletConnectedContainer.SetActive(false);
 1293            searchBarContainer.SetActive(false);
 1294            directChatsCollapseButton.SetInteractability(false);
 1295            publicChatsChatsCollapseButton.SetInteractability(false);
 1296        }
 297
 298        public void HideConnectWallet()
 299        {
 2300            isConnectWalletMode = false;
 2301            connectWalletContainer.SetActive(false);
 2302            walletConnectedContainer.SetActive(true);
 2303            searchBarContainer.SetActive(true);
 2304            directChatsCollapseButton.SetInteractability(true);
 2305            publicChatsChatsCollapseButton.SetInteractability(true);
 2306        }
 307
 1308        public void SetChannelsPromoteLabelVisible(bool isVisible) => channelsPromoteLabel.SetActive(isVisible);
 309
 310        public override void RefreshControl()
 311        {
 0312            publicChannelList.Clear();
 0313            foreach (var entry in model.publicChannels)
 0314                publicChannelList.Set(entry.channelId, entry);
 0315            SetChannelsLoadingVisibility(model.isLoadingChannels);
 316
 0317            directChatList.Clear();
 0318            foreach (var entry in model.privateChats)
 0319                directChatList.Set(entry.userId, entry);
 0320            SetPrivateChatLoadingVisibility(model.isLoadingDirectChats);
 0321        }
 322
 323        private void Set(PrivateChatModel model)
 324        {
 37325            var user = model.user;
 37326            var userId = user.userId;
 327
 37328            var entry = new PrivateChatEntryModel(
 329                user.userId,
 330                user.userName,
 331                model.recentMessage != null ? model.recentMessage.body : string.Empty,
 332                user.face256SnapshotURL,
 333                model.isBlocked,
 334                model.isOnline,
 335                model.recentMessage != null ? model.recentMessage.timestamp : 0);
 336
 37337        if (isSearchMode)
 18338            searchResultsList.Set(entry);
 339        else
 19340            directChatList.Set(userId, entry);
 341
 37342            UpdateHeaders();
 37343            UpdateLayout();
 37344            SortLists();
 37345        }
 346
 347        private void Set(PublicChatModel model)
 348        {
 21349            var channelId = model.channelId;
 21350            var entryModel = new PublicChatEntryModel(channelId, model.name, model.joined, model.memberCount, showOnlyOn
 351            PublicChatEntry entry;
 352
 21353            if (isSearchMode)
 354            {
 8355                searchResultsList.Set(entryModel);
 8356                entry = (PublicChatEntry) searchResultsList.Get(channelId);
 8357            }
 358            else
 359            {
 13360                publicChannelList.Set(channelId, entryModel);
 13361                entry = publicChannelList.Get(channelId);
 362            }
 363
 21364            entry.OnOpenOptions -= OpenChannelOptions;
 21365            entry.OnOpenOptions += OpenChannelOptions;
 366
 21367            UpdateHeaders();
 21368            UpdateLayout();
 21369            SortLists();
 21370        }
 371
 372        private void OpenChannelOptions(PublicChatEntry entry)
 373        {
 1374            optionsChannelId = entry.Model.channelId;
 1375            entry.Dock(channelContextualMenu);
 1376            channelContextualMenu.SetHeaderTitle($"#{entry.Model.name.ToLower()}");
 1377            channelContextualMenu.Show();
 1378        }
 379
 0380        private void SortLists() => isSortingDirty = true;
 381
 382        private void SetChannelsLoadingVisibility(bool visible)
 383        {
 3384            model.isLoadingChannels = visible;
 3385            channelsLoadingContainer.SetActive(visible);
 3386            publicChannelList.gameObject.SetActive(!visible);
 3387        }
 388
 389        private void SetPrivateChatLoadingVisibility(bool visible)
 390        {
 3391            model.isLoadingDirectChats = visible;
 3392            directChatsLoadingContainer.SetActive(visible);
 393
 3394            if (visible)
 2395                directChatList.Hide();
 1396            else if (!isSearchMode)
 1397                directChatList.Show();
 398
 3399            scroll.enabled = !visible;
 3400            isLoadingPrivateChannels = visible;
 3401        }
 402
 403        private void UpdateHeaders()
 404        {
 109405            directChatsHeaderLabel.text = $"Direct Messages ({directChatList.Count()})";
 109406            searchResultsHeaderLabel.text = $"Results ({searchResultsList.Count()})";
 109407            searchResultsHeader.SetActive(searchResultsList.Count() > 0);
 109408            channelsHeaderLabel.text = $"Channels ({publicChannelList.Count()})";
 109409        }
 410
 0411        private void UpdateLayout() => isLayoutDirty = true;
 412
 413        private void SetQueuedEntries()
 414        {
 245415            if (privateChatsCreationQueue.Count > 0)
 416            {
 110417                for (var i = 0; i < CREATION_AMOUNT_PER_FRAME && privateChatsCreationQueue.Count > 0; i++)
 418                {
 37419                    var (userId, model) = privateChatsCreationQueue.First();
 37420                    privateChatsCreationQueue.Remove(userId);
 37421                    Set(model);
 422                }
 423            }
 424
 532425            for (var i = 0; i < CREATION_AMOUNT_PER_FRAME && publicChatsCreationQueue.Count > 0; i++)
 426            {
 21427                var (userId, model) = publicChatsCreationQueue.First();
 21428                publicChatsCreationQueue.Remove(userId);
 21429                Set(model);
 430            }
 431
 245432            HideMoreChatsLoading();
 245433        }
 434
 435        private void FetchProfilePicturesForVisibleEntries()
 436        {
 253437            if (isSearchMode) return;
 438
 512439            foreach (var entry in directChatList.Entries.Values.Skip(currentAvatarSnapshotIndex)
 440                         .Take(AVATAR_SNAPSHOTS_PER_FRAME))
 441            {
 19442                if (entry.IsVisible((RectTransform) scroll.transform))
 3443                    entry.EnableAvatarSnapshotFetching();
 444                else
 16445                    entry.DisableAvatarSnapshotFetching();
 446            }
 447
 237448            currentAvatarSnapshotIndex += AVATAR_SNAPSHOTS_PER_FRAME;
 449
 237450            if (currentAvatarSnapshotIndex >= directChatList.Entries.Count)
 237451                currentAvatarSnapshotIndex = 0;
 237452        }
 453
 454        private void RequestMorePrivateChats(Vector2 position)
 455        {
 24456            if (!loadMoreEntriesContainer.activeInHierarchy
 457                || loadMoreEntriesLoading.activeInHierarchy
 458                || Time.realtimeSinceStartup - loadMoreEntriesRestrictionTime < MIN_TIME_TO_REQUIRE_MORE_ENTRIES
 22459                || isConnectWalletMode) return;
 460
 2461            if (position.y < REQUEST_MORE_ENTRIES_SCROLL_THRESHOLD && lastScrollPosition.y >= REQUEST_MORE_ENTRIES_SCROL
 462            {
 1463                if (requireMoreEntriesRoutine != null)
 0464                    StopCoroutine(requireMoreEntriesRoutine);
 465
 1466                ShowMoreChatsLoading();
 1467                requireMoreEntriesRoutine = StartCoroutine(WaitThenRequireMoreEntries());
 468
 1469                loadMoreEntriesRestrictionTime = Time.realtimeSinceStartup;
 470            }
 471
 2472            lastScrollPosition = position;
 2473        }
 474
 475        private IEnumerator WaitThenRequireMoreEntries()
 476        {
 1477            yield return new WaitForSeconds(1f);
 1478            OnRequireMorePrivateChats?.Invoke();
 1479        }
 480    }
 481}