< 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:380
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;
 205            // TODO: right now the channel history is disabled, but we must find a workaround to support history + max m
 206            // one approach could be to increment the max amount of messages depending on how many pages you loaded from
 207            // for example: 1 page = 30 messages, 2 pages = 60 messages, and so on..
 0208            chatHudController.AddChatMessage(message, limitMaxEntries: true);
 209
 0210            if (View.IsActive)
 211            {
 212                // The messages from 'channelId' are marked as read if the channel window is currently open
 0213                MarkChannelMessagesAsRead();
 214            }
 215
 0216            View?.SetLoadingMessagesActive(false);
 0217            View?.SetOldMessagesLoadingActive(false);
 0218        }
 219
 220        private void UpdateOldestMessage(ChatMessage message)
 221        {
 0222            if (oldestMessage == null)
 0223                oldestMessage = message;
 0224            else if (message.timestamp < oldestMessage.timestamp)
 0225                oldestMessage = message;
 0226        }
 227
 228        private void Hide()
 229        {
 0230            SetVisibility(false);
 0231            OnClosed?.Invoke();
 0232        }
 233
 0234        private void HandlePressBack() => OnPressBack?.Invoke();
 235
 236        private bool IsMessageFomCurrentChannel(ChatMessage message) =>
 0237            message.sender == channelId || message.recipient == channelId || (View.IsActive && message.messageType == Ch
 238
 2239        private void MarkChannelMessagesAsRead() => chatController.MarkChannelMessagesAsSeen(channelId);
 240
 241        private void HandleChatInputTriggered(DCLAction_Trigger action)
 242        {
 243            // race condition patch caused by unfocusing input field from invalid message on SendChatMessage
 244            // chat input trigger is the same key as sending the chat message from the input field
 0245            if (skipChatInputTrigger)
 246            {
 0247                skipChatInputTrigger = false;
 0248                return;
 249            }
 250
 0251            if (!View.IsActive) return;
 0252            chatHudController.FocusInputField();
 0253        }
 254
 255        private void RequestMessages(string channelId, int limit, string fromMessageId = null)
 256        {
 1257            View?.SetLoadingMessagesActive(true);
 1258            chatController.GetChannelMessages(channelId, limit, fromMessageId);
 1259            hideLoadingCancellationToken.Cancel();
 1260            hideLoadingCancellationToken = new CancellationTokenSource();
 1261            WaitForRequestTimeOutThenHideLoadingFeedback(hideLoadingCancellationToken.Token).Forget();
 1262        }
 263
 264        private void RequestOldConversations()
 265        {
 0266            if (IsLoadingMessages()) return;
 267
 0268            View?.SetOldMessagesLoadingActive(true);
 0269            lastRequestTime = Time.realtimeSinceStartup;
 270
 0271            chatController.GetChannelMessages(
 272                channelId,
 273                SHOW_MORE_PAGE_SIZE,
 274                oldestMessage?.messageId);
 275
 0276            hideLoadingCancellationToken.Cancel();
 0277            hideLoadingCancellationToken = new CancellationTokenSource();
 0278            WaitForRequestTimeOutThenHideLoadingFeedback(hideLoadingCancellationToken.Token).Forget();
 0279        }
 280
 281        private bool IsLoadingMessages() =>
 0282            Time.realtimeSinceStartup - lastRequestTime < REQUEST_MESSAGES_TIME_OUT;
 283
 284        private async UniTaskVoid WaitForRequestTimeOutThenHideLoadingFeedback(CancellationToken cancellationToken)
 285        {
 1286            lastRequestTime = Time.realtimeSinceStartup;
 287
 3288            await UniTask.WaitUntil(() =>
 284289                    Time.realtimeSinceStartup - lastRequestTime > REQUEST_MESSAGES_TIME_OUT,
 290                cancellationToken: cancellationToken);
 1291            if (cancellationToken.IsCancellationRequested) return;
 292
 1293            View?.SetLoadingMessagesActive(false);
 1294            View?.SetOldMessagesLoadingActive(false);
 1295        }
 296
 297        private void LeaveChannel()
 298        {
 1299            dataStore.channels.channelLeaveSource.Set(ChannelLeaveSource.Chat);
 1300            OnOpenChannelLeave?.Invoke(channelId);
 1301        }
 302
 303        private void LeaveChannelFromCommand()
 304        {
 1305            dataStore.channels.channelLeaveSource.Set(ChannelLeaveSource.Command);
 1306            chatController.LeaveChannel(channelId);
 1307        }
 308
 309        private void HandleChannelLeft(string channelId)
 310        {
 1311            if (channelId != this.channelId) return;
 1312            OnPressBack?.Invoke();
 1313        }
 314
 315        private void HandleChannelUpdated(Channel updatedChannel)
 316        {
 0317            if (updatedChannel.ChannelId != channelId)
 0318                return;
 319
 0320            View.Setup(ToPublicChatModel(updatedChannel));
 0321            channelMembersHUDController.SetMembersCount(updatedChannel.MemberCount);
 0322        }
 323
 0324        private void ShowMembersList() => channelMembersHUDController.SetVisibility(true);
 325
 0326        private void HideMembersList() => channelMembersHUDController.SetVisibility(false);
 327
 328        private void MuteChannel(bool muted)
 329        {
 2330            if (muted)
 1331                chatController.MuteChannel(channelId);
 332            else
 1333                chatController.UnmuteChannel(channelId);
 1334        }
 335
 336        private void SetVisiblePanelList(bool visible)
 337        {
 3338            var newSet = visibleTaskbarPanels.Get();
 339
 3340            if (visible)
 2341                newSet.Add("ChatChannel");
 342            else
 1343                newSet.Remove("ChatChannel");
 344
 3345            visibleTaskbarPanels.Set(newSet, true);
 3346        }
 347
 348        private PublicChatModel ToPublicChatModel(Channel channel)
 349        {
 7350            return new PublicChatModel(channelId, channel.Name, channel.Description,
 351                channel.Joined, channel.MemberCount, channel.Muted);
 352        }
 353
 354        private void ClearChatControllerListeners()
 355        {
 10356            if (chatController == null) return;
 10357            chatController.OnAddMessage -= HandleMessageReceived;
 10358            chatController.OnChannelLeft -= HandleChannelLeft;
 10359            chatController.OnChannelUpdated -= HandleChannelUpdated;
 10360        }
 361
 362        private void Focus()
 363        {
 2364            chatHudController.FocusInputField();
 2365            MarkChannelMessagesAsRead();
 2366        }
 367
 368        private void HandleMessageBlockedBySpam(ChatMessage message)
 369        {
 0370            chatHudController.AddChatMessage(new ChatEntryModel
 371            {
 372                timestamp = (ulong) DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
 373                bodyText = "You sent too many messages in a short period of time. Please wait and try again later.",
 374                messageId = Guid.NewGuid().ToString(),
 375                messageType = ChatMessage.Type.SYSTEM,
 376                subType = ChatEntryModel.SubType.RECEIVED
 377            });
 0378        }
 379    }
 380}