< Summary

Class:PrivateChatWindowController
Assembly:PrivateChatWindowHUD
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/PrivateChatWindow/PrivateChatWindowController.cs
Covered lines:134
Uncovered lines:35
Coverable lines:169
Total lines:364
Line coverage:79.2% (134 of 169)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
PrivateChatWindowController(...)0%110100%
Initialize(...)0%330100%
Setup(...)0%330100%
SetVisibility(...)0%770100%
Dispose()0%550100%
HandleSendChatMessage(...)0%6.686073.33%
MinimizeView()0%2100%
HandleMessageReceived(...)0%6.686073.33%
Hide()0%2.152066.67%
Show()0%2100%
HandlePressBack()0%220100%
Unfriend(...)0%2100%
IsMessageFomCurrentConversation(...)0%330100%
MarkUserChatMessagesAsRead()0%110100%
MarkMessagesAsSeenDelayed()0%20400%
HandleInputFieldSelected()0%2100%
HandleViewFocused(...)0%6200%
SetVisiblePanelList(...)0%220100%
HandleChatInputTriggered(...)0%12300%
RequestPrivateMessages(...)0%220100%
RequestOldConversations()0%3.033085.71%
IsLoadingMessages()0%110100%
WaitForRequestTimeOutThenHideLoadingFeedback()0%550100%
HandleMessageBlockedBySpam(...)0%2100%
ResetPagination()0%110100%
Focus()0%110100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/PrivateChatWindow/PrivateChatWindowController.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Threading;
 4using Cysharp.Threading.Tasks;
 5using DCL;
 6using DCL.Interface;
 7using SocialFeaturesAnalytics;
 8using UnityEngine;
 9
 10public class PrivateChatWindowController : IHUD
 11{
 12    private const int USER_PRIVATE_MESSAGES_TO_REQUEST_FOR_INITIAL_LOAD = 30;
 13    private const float REQUEST_MESSAGES_TIME_OUT = 2;
 14    internal const int USER_PRIVATE_MESSAGES_TO_REQUEST_FOR_SHOW_MORE = 10;
 15
 016    public IPrivateChatComponentView View { get; private set; }
 17
 18    private readonly DataStore dataStore;
 19    private readonly IUserProfileBridge userProfileBridge;
 20    private readonly IChatController chatController;
 21    private readonly IFriendsController friendsController;
 22    private readonly ISocialAnalytics socialAnalytics;
 23    private readonly IMouseCatcher mouseCatcher;
 24    private readonly InputAction_Trigger toggleChatTrigger;
 25    private ChatHUDController chatHudController;
 26    private UserProfile conversationProfile;
 27    private bool skipChatInputTrigger;
 28    private float lastRequestTime;
 1629    private CancellationTokenSource deactivateFadeOutCancellationToken = new CancellationTokenSource();
 1630    private CancellationTokenSource markMessagesAsSeenCancellationToken = new CancellationTokenSource();
 31    private bool shouldRequestMessages;
 1632    private ulong oldestTimestamp = ulong.MaxValue;
 33    private string oldestMessageId;
 34    private string conversationUserId;
 3235    private BaseVariable<HashSet<string>> visibleTaskbarPanels => dataStore.HUDs.visibleTaskbarPanels;
 36
 37    public event Action OnBack;
 38    public event Action OnClosed;
 39
 1640    public PrivateChatWindowController(DataStore dataStore,
 41        IUserProfileBridge userProfileBridge,
 42        IChatController chatController,
 43        IFriendsController friendsController,
 44        ISocialAnalytics socialAnalytics,
 45        IMouseCatcher mouseCatcher,
 46        InputAction_Trigger toggleChatTrigger)
 47    {
 1648        this.dataStore = dataStore;
 1649        this.userProfileBridge = userProfileBridge;
 1650        this.chatController = chatController;
 1651        this.friendsController = friendsController;
 1652        this.socialAnalytics = socialAnalytics;
 1653        this.mouseCatcher = mouseCatcher;
 1654        this.toggleChatTrigger = toggleChatTrigger;
 1655    }
 56
 57    public void Initialize(IPrivateChatComponentView view = null)
 58    {
 1759        view ??= PrivateChatWindowComponentView.Create();
 1760        View = view;
 1761        View.Initialize(friendsController, socialAnalytics);
 1762        view.OnPressBack -= HandlePressBack;
 1763        view.OnPressBack += HandlePressBack;
 1764        view.OnClose -= Hide;
 1765        view.OnClose += Hide;
 1766        view.OnMinimize += MinimizeView;
 1767        view.OnUnfriend += Unfriend;
 68
 1769        if (mouseCatcher != null)
 1770            mouseCatcher.OnMouseLock += Hide;
 71
 1772        view.OnRequireMoreMessages += RequestOldConversations;
 73
 1774        chatHudController = new ChatHUDController(dataStore, userProfileBridge, false);
 1775        chatHudController.Initialize(view.ChatHUD);
 1776        chatHudController.OnInputFieldSelected += HandleInputFieldSelected;
 1777        chatHudController.OnSendMessage += HandleSendChatMessage;
 1778        chatHudController.OnMessageSentBlockedBySpam += HandleMessageBlockedBySpam;
 79
 1780        chatController.OnAddMessage -= HandleMessageReceived;
 1781        chatController.OnAddMessage += HandleMessageReceived;
 82
 1783        toggleChatTrigger.OnTriggered += HandleChatInputTriggered;
 1784    }
 85
 86    public void Setup(string newConversationUserId)
 87    {
 1488        if (string.IsNullOrEmpty(newConversationUserId) || newConversationUserId == conversationUserId)
 189            return;
 90
 1391        var newConversationUserProfile = userProfileBridge.Get(newConversationUserId);
 92
 1393        conversationUserId = newConversationUserId;
 1394        conversationProfile = newConversationUserProfile;
 1395        chatHudController.ClearAllEntries();
 1396        shouldRequestMessages = true;
 1397    }
 98
 99    public void SetVisibility(bool visible)
 100    {
 19101        if (View.IsActive == visible)
 3102            return;
 103
 16104        SetVisiblePanelList(visible);
 105
 16106        if (visible)
 107        {
 11108            View?.SetLoadingMessagesActive(false);
 11109            View?.SetOldMessagesLoadingActive(false);
 110
 11111            if (conversationProfile != null)
 112            {
 10113                var userStatus = friendsController.GetUserStatus(conversationUserId);
 10114                View.Setup(conversationProfile,
 115                    userStatus.presence == PresenceStatus.ONLINE,
 116                    userProfileBridge.GetOwn().IsBlocked(conversationUserId));
 117
 10118                if (shouldRequestMessages)
 119                {
 9120                    ResetPagination();
 9121                    RequestPrivateMessages(
 122                        conversationUserId,
 123                        USER_PRIVATE_MESSAGES_TO_REQUEST_FOR_INITIAL_LOAD,
 124                        null);
 125
 9126                    shouldRequestMessages = false;
 127                }
 128            }
 129
 11130            View.Show();
 11131            Focus();
 11132        }
 133        else
 134        {
 5135            chatHudController.UnfocusInputField();
 5136            View.Hide();
 137        }
 5138    }
 139
 140    public void Dispose()
 141    {
 16142        if (chatHudController != null)
 143        {
 16144            chatHudController.OnInputFieldSelected -= HandleInputFieldSelected;
 16145            chatHudController.OnSendMessage -= HandleSendChatMessage;
 16146            chatHudController.OnMessageSentBlockedBySpam -= HandleMessageBlockedBySpam;
 147        }
 148
 16149        if (chatController != null)
 16150            chatController.OnAddMessage -= HandleMessageReceived;
 151
 16152        if (mouseCatcher != null)
 16153            mouseCatcher.OnMouseLock -= Hide;
 154
 16155        toggleChatTrigger.OnTriggered -= HandleChatInputTriggered;
 156
 16157        if (View != null)
 158        {
 16159            View.OnPressBack -= HandlePressBack;
 16160            View.OnClose -= Hide;
 16161            View.OnMinimize -= MinimizeView;
 16162            View.OnUnfriend -= Unfriend;
 16163            View.OnFocused -= HandleViewFocused;
 16164            View.OnRequireMoreMessages -= RequestOldConversations;
 16165            View.Dispose();
 166        }
 16167    }
 168
 169    private void HandleSendChatMessage(ChatMessage message)
 170    {
 1171        if (string.IsNullOrEmpty(conversationProfile.userName))
 0172            return;
 173
 1174        message.messageType = ChatMessage.Type.PRIVATE;
 1175        message.recipient = conversationProfile.userName;
 176
 1177        bool isValidMessage = !string.IsNullOrEmpty(message.body)
 178                              && !string.IsNullOrWhiteSpace(message.body)
 179                              && !string.IsNullOrEmpty(message.recipient);
 180
 1181        if (isValidMessage)
 182        {
 1183            chatHudController.ResetInputField();
 1184            chatHudController.FocusInputField();
 1185        }
 186        else
 187        {
 0188            SetVisibility(false);
 0189            OnClosed?.Invoke();
 0190            return;
 191        }
 192
 193        // If Kernel allowed for private messages without the whisper param we could avoid this line
 1194        message.body = $"/w {message.recipient} {message.body}";
 195
 1196        chatController.Send(message);
 1197    }
 198
 0199    private void MinimizeView() => SetVisibility(false);
 200
 201    private void HandleMessageReceived(ChatMessage message)
 202    {
 3203        if (!IsMessageFomCurrentConversation(message))
 0204            return;
 205
 3206        chatHudController.AddChatMessage(message, limitMaxEntries: false);
 207
 3208        if (message.timestamp < oldestTimestamp)
 209        {
 1210            oldestTimestamp = message.timestamp;
 1211            oldestMessageId = message.messageId;
 212        }
 213
 3214        if (View.IsActive)
 215        {
 0216            markMessagesAsSeenCancellationToken.Cancel();
 0217            markMessagesAsSeenCancellationToken = new CancellationTokenSource();
 218            // since there could be many messages coming in a row, avoid making the call instantly for each message
 219            // instead make just one call after the iteration finishes
 0220            MarkMessagesAsSeenDelayed(markMessagesAsSeenCancellationToken.Token).Forget();
 221        }
 222
 3223        View?.SetLoadingMessagesActive(false);
 3224        View?.SetOldMessagesLoadingActive(false);
 225
 3226        deactivateFadeOutCancellationToken.Cancel();
 3227        deactivateFadeOutCancellationToken = new CancellationTokenSource();
 3228    }
 229
 230    private void Hide()
 231    {
 2232        SetVisibility(false);
 2233        OnClosed?.Invoke();
 0234    }
 235
 236    private void Show()
 237    {
 0238        SetVisibility(true);
 0239    }
 240
 1241    private void HandlePressBack() => OnBack?.Invoke();
 242
 243    private void Unfriend(string friendId)
 244    {
 0245        friendsController.RemoveFriend(friendId);
 0246        Hide();
 0247    }
 248
 249    private bool IsMessageFomCurrentConversation(ChatMessage message)
 250    {
 3251        return message.messageType == ChatMessage.Type.PRIVATE &&
 252               (message.sender == conversationUserId || message.recipient == conversationUserId);
 253    }
 254
 255    private void MarkUserChatMessagesAsRead() =>
 11256        chatController.MarkMessagesAsSeen(conversationUserId);
 257
 258    private async UniTask MarkMessagesAsSeenDelayed(CancellationToken cancellationToken)
 259    {
 0260        await UniTask.NextFrame(cancellationToken);
 0261        if (cancellationToken.IsCancellationRequested) return;
 0262        MarkUserChatMessagesAsRead();
 0263    }
 264
 265    private void HandleInputFieldSelected()
 266    {
 0267        Show();
 268        // The messages from 'conversationUserId' are marked as read if the player clicks on the input field of the priv
 269        //MarkUserChatMessagesAsRead();
 0270    }
 271
 272    private void HandleViewFocused(bool focused)
 273    {
 0274        if (focused)
 275        {
 0276            deactivateFadeOutCancellationToken.Cancel();
 0277            deactivateFadeOutCancellationToken = new CancellationTokenSource();
 278        }
 0279    }
 280
 281    private void SetVisiblePanelList(bool visible)
 282    {
 16283        HashSet<string> newSet = visibleTaskbarPanels.Get();
 16284        if (visible)
 11285            newSet.Add("PrivateChatChannel");
 286        else
 5287            newSet.Remove("PrivateChatChannel");
 288
 16289        visibleTaskbarPanels.Set(newSet, true);
 16290    }
 291
 292    private void HandleChatInputTriggered(DCLAction_Trigger action)
 293    {
 294        // race condition patch caused by unfocusing input field from invalid message on SendChatMessage
 295        // chat input trigger is the same key as sending the chat message from the input field
 0296        if (skipChatInputTrigger)
 297        {
 0298            skipChatInputTrigger = false;
 0299            return;
 300        }
 301
 0302        if (!View.IsActive)
 0303            return;
 0304        chatHudController.FocusInputField();
 0305    }
 306
 307    internal void RequestPrivateMessages(string userId, int limit, string fromMessageId)
 308    {
 10309        View?.SetLoadingMessagesActive(true);
 10310        chatController.GetPrivateMessages(userId, limit, fromMessageId);
 10311        WaitForRequestTimeOutThenHideLoadingFeedback().Forget();
 10312    }
 313
 314    internal void RequestOldConversations()
 315    {
 1316        if (IsLoadingMessages()) return;
 317
 1318        chatController.GetPrivateMessages(
 319            conversationUserId,
 320            USER_PRIVATE_MESSAGES_TO_REQUEST_FOR_SHOW_MORE,
 321            oldestMessageId);
 322
 1323        lastRequestTime = Time.realtimeSinceStartup;
 1324        View?.SetOldMessagesLoadingActive(true);
 1325        WaitForRequestTimeOutThenHideLoadingFeedback().Forget();
 1326    }
 327
 328    private bool IsLoadingMessages() =>
 1329        Time.realtimeSinceStartup - lastRequestTime < REQUEST_MESSAGES_TIME_OUT;
 330
 331    private async UniTaskVoid WaitForRequestTimeOutThenHideLoadingFeedback()
 332    {
 11333        lastRequestTime = Time.realtimeSinceStartup;
 334
 1918335        await UniTask.WaitUntil(() => Time.realtimeSinceStartup - lastRequestTime > REQUEST_MESSAGES_TIME_OUT);
 336
 11337        View?.SetLoadingMessagesActive(false);
 11338        View?.SetOldMessagesLoadingActive(false);
 11339    }
 340
 341    private void HandleMessageBlockedBySpam(ChatMessage message)
 342    {
 0343        chatHudController.AddChatMessage(new ChatEntryModel
 344        {
 345            timestamp = (ulong) DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
 346            bodyText = "You sent too many messages in a short period of time. Please wait and try again later.",
 347            messageId = Guid.NewGuid().ToString(),
 348            messageType = ChatMessage.Type.SYSTEM,
 349            subType = ChatEntryModel.SubType.RECEIVED
 350        });
 0351    }
 352
 353    private void ResetPagination()
 354    {
 9355        oldestTimestamp = long.MaxValue;
 9356        oldestMessageId = null;
 9357    }
 358
 359    private void Focus()
 360    {
 11361        chatHudController.FocusInputField();
 11362        MarkUserChatMessagesAsRead();
 11363    }
 364}