< Summary

Class:DCL.Chat.HUD.ChatChannelHUDController
Assembly:WorldChatWindowHUD
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/WorldChatWindowHUD/ChatChannelHUDController.cs
Covered lines:133
Uncovered lines:47
Coverable lines:180
Total lines:377
Line coverage:73.8% (133 of 180)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
ChatChannelHUDController(...)0%110100%
Initialize(...)0%330100%
Setup(...)0%110100%
SetVisibility(...)0%77095.83%
Dispose()0%330100%
HandleSendChatMessage(...)0%5.065086.67%
HandleMessageReceived(...)0%30500%
UpdateOldestMessage(...)0%12300%
Hide()0%6200%
HandlePressBack()0%6200%
IsMessageFomCurrentChannel(...)0%20400%
MarkChannelMessagesAsRead()0%110100%
HandleChatInputTriggered(...)0%12300%
RequestMessages(...)0%220100%
RequestOldConversations()0%30500%
IsLoadingMessages()0%2100%
WaitForRequestTimeOutThenHideLoadingFeedback()0%6.056088.89%
LeaveChannel()0%220100%
LeaveChannelFromCommand()0%110100%
HandleChannelLeft(...)0%3.143075%
HandleChannelUpdated(...)0%6200%
ShowMembersList()0%2100%
HideMembersList()0%2100%
MuteChannel(...)0%220100%
SetVisiblePanelList(...)0%220100%
ToPublicChatModel(...)0%110100%
ClearChatControllerListeners()0%2.022083.33%
Focus()0%110100%
HandleMessageBlockedBySpam(...)0%2100%

File(s)

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

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Threading;
 4using Cysharp.Threading.Tasks;
 5using DCL.Interface;
 6using SocialFeaturesAnalytics;
 7using UnityEngine;
 8using Channel = DCL.Chat.Channels.Channel;
 9
 10namespace DCL.Chat.HUD
 11{
 12    public class ChatChannelHUDController : IHUD
 13    {
 14        private const int INITIAL_PAGE_SIZE = 30;
 15        private const int SHOW_MORE_PAGE_SIZE = 10;
 16        private const float REQUEST_MESSAGES_TIME_OUT = 2;
 17
 018        public IChatChannelWindowView View { get; private set; }
 19
 20        private readonly DataStore dataStore;
 621        private BaseVariable<HashSet<string>> visibleTaskbarPanels => dataStore.HUDs.visibleTaskbarPanels;
 22        private readonly IUserProfileBridge userProfileBridge;
 23        private readonly IChatController chatController;
 24        private readonly IMouseCatcher mouseCatcher;
 25        private readonly InputAction_Trigger toggleChatTrigger;
 26        private readonly ISocialAnalytics socialAnalytics;
 27        private readonly IProfanityFilter profanityFilter;
 28        private ChatHUDController chatHudController;
 29        private ChannelMembersHUDController channelMembersHUDController;
 730        private CancellationTokenSource hideLoadingCancellationToken = new CancellationTokenSource();
 31        private bool skipChatInputTrigger;
 32        private float lastRequestTime;
 33        private string channelId;
 34        private Channel channel;
 35        private ChatMessage oldestMessage;
 36
 37        public event Action OnPressBack;
 38        public event Action OnClosed;
 39        public event Action<string> OnOpenChannelLeave;
 40
 741        public ChatChannelHUDController(DataStore dataStore,
 42            IUserProfileBridge userProfileBridge,
 43            IChatController chatController,
 44            IMouseCatcher mouseCatcher,
 45            InputAction_Trigger toggleChatTrigger,
 46            ISocialAnalytics socialAnalytics,
 47            IProfanityFilter profanityFilter)
 48        {
 749            this.dataStore = dataStore;
 750            this.userProfileBridge = userProfileBridge;
 751            this.chatController = chatController;
 752            this.mouseCatcher = mouseCatcher;
 753            this.toggleChatTrigger = toggleChatTrigger;
 754            this.socialAnalytics = socialAnalytics;
 755            this.profanityFilter = profanityFilter;
 756        }
 57
 58        public void Initialize(IChatChannelWindowView view = null)
 59        {
 760            view ??= ChatChannelComponentView.Create();
 761            View = view;
 762            view.OnBack -= HandlePressBack;
 763            view.OnBack += HandlePressBack;
 764            view.OnClose -= Hide;
 765            view.OnClose += Hide;
 766            view.OnRequireMoreMessages += RequestOldConversations;
 767            view.OnLeaveChannel += LeaveChannel;
 768            view.OnShowMembersList += ShowMembersList;
 769            view.OnHideMembersList += HideMembersList;
 770            view.OnMuteChanged += MuteChannel;
 71
 772            chatHudController = new ChatHUDController(dataStore, userProfileBridge, false, profanityFilter);
 773            chatHudController.Initialize(view.ChatHUD);
 774            chatHudController.OnSendMessage += HandleSendChatMessage;
 775            chatHudController.OnMessageSentBlockedBySpam += HandleMessageBlockedBySpam;
 76
 777            if (mouseCatcher != null)
 778                mouseCatcher.OnMouseLock += Hide;
 79
 780            toggleChatTrigger.OnTriggered += HandleChatInputTriggered;
 81
 782            channelMembersHUDController = new ChannelMembersHUDController(view.ChannelMembersHUD, chatController, userPr
 783        }
 84
 85        public void Setup(string channelId)
 86        {
 687            channelMembersHUDController.SetChannelId(channelId);
 688            this.channelId = channelId;
 689            lastRequestTime = 0;
 90
 691            channel = chatController.GetAllocatedChannel(channelId);
 692            View.Setup(ToPublicChatModel(channel));
 93
 694            chatHudController.ClearAllEntries();
 695            oldestMessage = null;
 696        }
 97
 98        public void SetVisibility(bool visible)
 99        {
 3100            SetVisiblePanelList(visible);
 101
 3102            if (visible)
 103            {
 2104                ClearChatControllerListeners();
 105
 2106                chatController.OnAddMessage += HandleMessageReceived;
 2107                chatController.OnChannelLeft += HandleChannelLeft;
 2108                chatController.OnChannelUpdated += HandleChannelUpdated;
 109
 2110                if (channelMembersHUDController.IsVisible)
 0111                    channelMembersHUDController.SetAutomaticReloadingActive(true);
 112
 2113                View?.SetLoadingMessagesActive(false);
 2114                View?.SetOldMessagesLoadingActive(false);
 115
 2116                if (!string.IsNullOrEmpty(channelId))
 117                {
 1118                    var channel = chatController.GetAllocatedChannel(channelId);
 1119                    View.Setup(ToPublicChatModel(channel));
 120
 1121                    RequestMessages(
 122                        channelId,
 123                        INITIAL_PAGE_SIZE);
 124                }
 125
 2126                View.Show();
 2127                Focus();
 2128            }
 129            else
 130            {
 1131                ClearChatControllerListeners();
 132
 1133                channelMembersHUDController.SetAutomaticReloadingActive(false);
 1134                chatHudController.UnfocusInputField();
 1135                OnClosed?.Invoke();
 1136                View.Hide();
 137            }
 138
 3139            dataStore.channels.channelToBeOpenedFromLink.Set(null, notifyEvent: false);
 3140        }
 141
 142        public void Dispose()
 143        {
 7144            ClearChatControllerListeners();
 145
 7146            if (mouseCatcher != null)
 7147                mouseCatcher.OnMouseLock -= Hide;
 148
 7149            toggleChatTrigger.OnTriggered -= HandleChatInputTriggered;
 150
 7151            chatHudController.OnSendMessage -= HandleSendChatMessage;
 7152            chatHudController.OnMessageSentBlockedBySpam -= HandleMessageBlockedBySpam;
 153
 7154            if (View != null)
 155            {
 7156                View.OnBack -= HandlePressBack;
 7157                View.OnClose -= Hide;
 7158                View.OnRequireMoreMessages -= RequestOldConversations;
 7159                View.OnLeaveChannel -= LeaveChannel;
 7160                View.OnMuteChanged -= MuteChannel;
 7161                View.Dispose();
 162            }
 163
 7164            hideLoadingCancellationToken.Dispose();
 7165            channelMembersHUDController.Dispose();
 7166        }
 167
 168        private void HandleSendChatMessage(ChatMessage message)
 169        {
 2170            message.messageType = ChatMessage.Type.PUBLIC;
 2171            message.recipient = channelId;
 172
 2173            var isValidMessage = !string.IsNullOrEmpty(message.body)
 174                                 && !string.IsNullOrWhiteSpace(message.body)
 175                                 && !string.IsNullOrEmpty(message.recipient);
 176
 2177            if (isValidMessage)
 178            {
 2179                chatHudController.ResetInputField();
 2180                chatHudController.FocusInputField();
 2181            }
 182            else
 183            {
 0184                SetVisibility(false);
 0185                return;
 186            }
 187
 2188            if (message.body.ToLower().Equals("/leave"))
 189            {
 1190                LeaveChannelFromCommand();
 1191                return;
 192            }
 193
 1194            chatController.Send(message);
 1195            socialAnalytics.SendMessageSentToChannel(channel.Name, message.body.Length, "channel");
 1196        }
 197
 198        private void HandleMessageReceived(ChatMessage message)
 199        {
 0200            if (!IsMessageFomCurrentChannel(message)) return;
 201
 0202            UpdateOldestMessage(message);
 203
 0204            message.isChannelMessage = true;
 0205            chatHudController.AddChatMessage(message, limitMaxEntries: false);
 206
 0207            if (View.IsActive)
 208            {
 209                // The messages from 'channelId' are marked as read if the channel window is currently open
 0210                MarkChannelMessagesAsRead();
 211            }
 212
 0213            View?.SetLoadingMessagesActive(false);
 0214            View?.SetOldMessagesLoadingActive(false);
 0215        }
 216
 217        private void UpdateOldestMessage(ChatMessage message)
 218        {
 0219            if (oldestMessage == null)
 0220                oldestMessage = message;
 0221            else if (message.timestamp < oldestMessage.timestamp)
 0222                oldestMessage = message;
 0223        }
 224
 225        private void Hide()
 226        {
 0227            SetVisibility(false);
 0228            OnClosed?.Invoke();
 0229        }
 230
 0231        private void HandlePressBack() => OnPressBack?.Invoke();
 232
 233        private bool IsMessageFomCurrentChannel(ChatMessage message) =>
 0234            message.sender == channelId || message.recipient == channelId || (View.IsActive && message.messageType == Ch
 235
 2236        private void MarkChannelMessagesAsRead() => chatController.MarkChannelMessagesAsSeen(channelId);
 237
 238        private void HandleChatInputTriggered(DCLAction_Trigger action)
 239        {
 240            // race condition patch caused by unfocusing input field from invalid message on SendChatMessage
 241            // chat input trigger is the same key as sending the chat message from the input field
 0242            if (skipChatInputTrigger)
 243            {
 0244                skipChatInputTrigger = false;
 0245                return;
 246            }
 247
 0248            if (!View.IsActive) return;
 0249            chatHudController.FocusInputField();
 0250        }
 251
 252        private void RequestMessages(string channelId, int limit, string fromMessageId = null)
 253        {
 1254            View?.SetLoadingMessagesActive(true);
 1255            chatController.GetChannelMessages(channelId, limit, fromMessageId);
 1256            hideLoadingCancellationToken.Cancel();
 1257            hideLoadingCancellationToken = new CancellationTokenSource();
 1258            WaitForRequestTimeOutThenHideLoadingFeedback(hideLoadingCancellationToken.Token).Forget();
 1259        }
 260
 261        private void RequestOldConversations()
 262        {
 0263            if (IsLoadingMessages()) return;
 264
 0265            View?.SetOldMessagesLoadingActive(true);
 0266            lastRequestTime = Time.realtimeSinceStartup;
 267
 0268            chatController.GetChannelMessages(
 269                channelId,
 270                SHOW_MORE_PAGE_SIZE,
 271                oldestMessage?.messageId);
 272
 0273            hideLoadingCancellationToken.Cancel();
 0274            hideLoadingCancellationToken = new CancellationTokenSource();
 0275            WaitForRequestTimeOutThenHideLoadingFeedback(hideLoadingCancellationToken.Token).Forget();
 0276        }
 277
 278        private bool IsLoadingMessages() =>
 0279            Time.realtimeSinceStartup - lastRequestTime < REQUEST_MESSAGES_TIME_OUT;
 280
 281        private async UniTaskVoid WaitForRequestTimeOutThenHideLoadingFeedback(CancellationToken cancellationToken)
 282        {
 1283            lastRequestTime = Time.realtimeSinceStartup;
 284
 3285            await UniTask.WaitUntil(() =>
 76286                    Time.realtimeSinceStartup - lastRequestTime > REQUEST_MESSAGES_TIME_OUT,
 287                cancellationToken: cancellationToken);
 1288            if (cancellationToken.IsCancellationRequested) return;
 289
 1290            View?.SetLoadingMessagesActive(false);
 1291            View?.SetOldMessagesLoadingActive(false);
 1292        }
 293
 294        private void LeaveChannel()
 295        {
 1296            dataStore.channels.channelLeaveSource.Set(ChannelLeaveSource.Chat);
 1297            OnOpenChannelLeave?.Invoke(channelId);
 1298        }
 299
 300        private void LeaveChannelFromCommand()
 301        {
 1302            dataStore.channels.channelLeaveSource.Set(ChannelLeaveSource.Command);
 1303            chatController.LeaveChannel(channelId);
 1304        }
 305
 306        private void HandleChannelLeft(string channelId)
 307        {
 1308            if (channelId != this.channelId) return;
 1309            OnPressBack?.Invoke();
 1310        }
 311
 312        private void HandleChannelUpdated(Channel updatedChannel)
 313        {
 0314            if (updatedChannel.ChannelId != channelId)
 0315                return;
 316
 0317            View.Setup(ToPublicChatModel(updatedChannel));
 0318            channelMembersHUDController.SetMembersCount(updatedChannel.MemberCount);
 0319        }
 320
 0321        private void ShowMembersList() => channelMembersHUDController.SetVisibility(true);
 322
 0323        private void HideMembersList() => channelMembersHUDController.SetVisibility(false);
 324
 325        private void MuteChannel(bool muted)
 326        {
 2327            if (muted)
 1328                chatController.MuteChannel(channelId);
 329            else
 1330                chatController.UnmuteChannel(channelId);
 1331        }
 332
 333        private void SetVisiblePanelList(bool visible)
 334        {
 3335            var newSet = visibleTaskbarPanels.Get();
 336
 3337            if (visible)
 2338                newSet.Add("ChatChannel");
 339            else
 1340                newSet.Remove("ChatChannel");
 341
 3342            visibleTaskbarPanels.Set(newSet, true);
 3343        }
 344
 345        private PublicChatModel ToPublicChatModel(Channel channel)
 346        {
 7347            return new PublicChatModel(channelId, channel.Name, channel.Description,
 348                channel.Joined, channel.MemberCount, channel.Muted);
 349        }
 350
 351        private void ClearChatControllerListeners()
 352        {
 10353            if (chatController == null) return;
 10354            chatController.OnAddMessage -= HandleMessageReceived;
 10355            chatController.OnChannelLeft -= HandleChannelLeft;
 10356            chatController.OnChannelUpdated -= HandleChannelUpdated;
 10357        }
 358
 359        private void Focus()
 360        {
 2361            chatHudController.FocusInputField();
 2362            MarkChannelMessagesAsRead();
 2363        }
 364
 365        private void HandleMessageBlockedBySpam(ChatMessage message)
 366        {
 0367            chatHudController.AddChatMessage(new ChatEntryModel
 368            {
 369                timestamp = (ulong) DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
 370                bodyText = "You sent too many messages in a short period of time. Please wait and try again later.",
 371                messageId = Guid.NewGuid().ToString(),
 372                messageType = ChatMessage.Type.SYSTEM,
 373                subType = ChatEntryModel.SubType.RECEIVED
 374            });
 0375        }
 376    }
 377}