< Summary

Class:ChatHUDView
Assembly:ChatHUD
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/ChatWidgetHUD/ChatHUDView.cs
Covered lines:90
Uncovered lines:48
Coverable lines:138
Total lines:308
Line coverage:65.2% (90 of 138)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
ChatHUDView()0%110100%
ChatHUDView()0%110100%
Create()0%110100%
Initialize(...)0%110100%
OnInputFieldSubmit(...)0%660100%
OnInputFieldSelect(...)0%2100%
OnInputFieldDeselect(...)0%2100%
ResetInputField()0%2100%
OnEnable()0%110100%
FocusInputField()0%110100%
EntryIsVisible(...)0%110100%
SetFadeoutMode(...)0%4.074083.33%
AddEntry(...)0%19.1514070.27%
MessagesSentTooFast(...)0%2100%
IsSpamming(...)0%6.744044.44%
CreateBaseDateTime()0%2100%
OnOpenContextMenu(...)0%2100%
OnMessageTriggerHover(...)0%12300%
OnMessageCoordinatesTriggerHover(...)0%2100%
OnMessageCancelHover()0%2100%
OnMessageCancelGotoHover()0%2100%
SortEntries()0%440100%
CleanAllEntries()0%3.053081.82%
SetGotoPanelStatus(...)0%110100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/ChatWidgetHUD/ChatHUDView.cs

#LineLine coverage
 1using DCL.Helpers;
 2using DCL.Interface;
 3using System;
 4using System.Collections.Generic;
 5using System.Linq;
 6using TMPro;
 7using UnityEngine;
 8using UnityEngine.Events;
 9using UnityEngine.UI;
 10using System.Text.RegularExpressions;
 11using UnityEngine.EventSystems;
 12using DCL;
 13
 14public class ChatHUDView : MonoBehaviour
 15{
 116    static string VIEW_PATH = "Chat Widget";
 3517    string ENTRY_PATH = "Chat Entry";
 18    private const int MAX_CONTINUOUS_MESSAGES = 6;
 19    private const int MIN_MILLISECONDS_BETWEEN_MESSAGES = 1500;
 20    private const int TEMPORARILY_MUTE_MINUTES = 10;
 21
 3522    public bool detectWhisper = true;
 23    public TMP_InputField inputField;
 24    public RectTransform chatEntriesContainer;
 25
 26    public ScrollRect scrollRect;
 27    public ChatHUDController controller;
 28    public GameObject messageHoverPanel;
 29    public GameObject messageHoverGotoPanel;
 30    public TextMeshProUGUI messageHoverText;
 31    public TextMeshProUGUI messageHoverGotoText;
 32    public UserContextMenu contextMenu;
 33    public UserContextConfirmationDialog confirmationDialog;
 34
 3535    [NonSerialized] public List<ChatEntry> entries = new List<ChatEntry>();
 3536    [NonSerialized] public List<DateSeparatorEntry> dateSeparators = new List<DateSeparatorEntry>();
 37
 3538    ChatMessage currentMessage = new ChatMessage();
 3539    Regex whisperRegex = new Regex(@"(?i)^\/(whisper|w) (\S+)( *)(.*)");
 40    Match whisperRegexMatch;
 3541    private List<ChatEntry.Model> lastMessages = new List<ChatEntry.Model>();
 3542    private Dictionary<string, ulong> temporarilyMutedSenders = new Dictionary<string, ulong>();
 43
 44    public event UnityAction<string> OnPressPrivateMessage;
 45    public event UnityAction<ChatMessage> OnSendMessage;
 46
 47    public static ChatHUDView Create()
 48    {
 1449        var view = Instantiate(Resources.Load<GameObject>(VIEW_PATH)).GetComponent<ChatHUDView>();
 1450        return view;
 51    }
 52
 53    public void Initialize(ChatHUDController controller, UnityAction<ChatMessage> OnSendMessage)
 54    {
 3255        this.controller = controller;
 3256        this.OnSendMessage += OnSendMessage;
 3257        inputField.onSubmit.AddListener(OnInputFieldSubmit);
 3258        inputField.onSelect.AddListener(OnInputFieldSelect);
 3259        inputField.onDeselect.AddListener(OnInputFieldDeselect);
 3260    }
 61
 62    private void OnInputFieldSubmit(string message)
 63    {
 464        currentMessage.body = message;
 465        currentMessage.sender = UserProfile.GetOwnUserProfile().userId;
 466        currentMessage.messageType = ChatMessage.Type.NONE;
 467        currentMessage.recipient = string.Empty;
 68
 469        if (detectWhisper && !string.IsNullOrWhiteSpace(message))
 70        {
 471            whisperRegexMatch = whisperRegex.Match(message);
 72
 473            if (whisperRegexMatch.Success)
 74            {
 275                currentMessage.messageType = ChatMessage.Type.PRIVATE;
 276                currentMessage.recipient = whisperRegexMatch.Groups[2].Value;
 277                currentMessage.body = whisperRegexMatch.Groups[4].Value;
 78            }
 79        }
 80
 81        // A TMP_InputField is automatically marked as 'wasCanceled' when the ESC key is pressed
 482        if (inputField.wasCanceled)
 183            currentMessage.body = string.Empty;
 84
 485        OnSendMessage?.Invoke(currentMessage);
 486    }
 87
 088    private void OnInputFieldSelect(string message) { AudioScriptableObjects.inputFieldFocus.Play(true); }
 89
 090    private void OnInputFieldDeselect(string message) { AudioScriptableObjects.inputFieldUnfocus.Play(true); }
 91
 92    public void ResetInputField()
 93    {
 094        inputField.text = string.Empty;
 095        inputField.caretColor = Color.white;
 096    }
 97
 8098    void OnEnable() { Utils.ForceUpdateLayout(transform as RectTransform); }
 99
 100    public void FocusInputField()
 101    {
 5102        inputField.ActivateInputField();
 5103        inputField.Select();
 5104    }
 105
 106    bool enableFadeoutMode = false;
 107
 108    bool EntryIsVisible(ChatEntry entry)
 109    {
 1110        int visibleCorners =
 111            (entry.transform as RectTransform).CountCornersVisibleFrom(scrollRect.viewport.transform as RectTransform);
 1112        return visibleCorners > 0;
 113    }
 114
 115    public void SetFadeoutMode(bool enabled)
 116    {
 9117        enableFadeoutMode = enabled;
 118
 22119        for (int i = 0; i < entries.Count; i++)
 120        {
 2121            ChatEntry entry = entries[i];
 122
 2123            if (enabled)
 124            {
 0125                entry.SetFadeout(EntryIsVisible(entry));
 0126            }
 127            else
 128            {
 2129                entry.SetFadeout(false);
 130            }
 131        }
 132
 9133        if (enabled)
 134        {
 3135            confirmationDialog.Hide();
 136        }
 9137    }
 138
 139    public virtual void AddEntry(ChatEntry.Model chatEntryModel, bool setScrollPositionToBottom = false)
 140    {
 31141        if (IsSpamming(chatEntryModel.senderName))
 0142            return;
 143
 31144        var chatEntryGO = Instantiate(Resources.Load(ENTRY_PATH) as GameObject, chatEntriesContainer);
 31145        ChatEntry chatEntry = chatEntryGO.GetComponent<ChatEntry>();
 146
 31147        if (enableFadeoutMode && EntryIsVisible(chatEntry))
 0148            chatEntry.SetFadeout(true);
 149        else
 31150            chatEntry.SetFadeout(false);
 151
 31152        chatEntry.Populate(chatEntryModel);
 153
 31154        if (chatEntryModel.messageType == ChatMessage.Type.PRIVATE)
 5155            chatEntry.OnPress += OnPressPrivateMessage;
 156
 31157        if (chatEntryModel.messageType == ChatMessage.Type.PUBLIC || chatEntryModel.messageType == ChatMessage.Type.PRIV
 31158            chatEntry.OnPressRightButton += OnOpenContextMenu;
 159
 31160        chatEntry.OnTriggerHover += OnMessageTriggerHover;
 31161        chatEntry.OnTriggerHoverGoto += OnMessageCoordinatesTriggerHover;
 31162        chatEntry.OnCancelHover += OnMessageCancelHover;
 31163        chatEntry.OnCancelGotoHover += OnMessageCancelGotoHover;
 164
 31165        entries.Add(chatEntry);
 166
 31167        SortEntries();
 168
 31169        Utils.ForceUpdateLayout(chatEntry.transform as RectTransform, delayed: false);
 170
 31171        if (setScrollPositionToBottom && scrollRect.verticalNormalizedPosition > 0)
 0172            scrollRect.verticalNormalizedPosition = 0;
 173
 31174        if (string.IsNullOrEmpty(chatEntryModel.senderId))
 26175            return;
 176
 5177        if (lastMessages.Count == 0)
 178        {
 4179            lastMessages.Add(chatEntryModel);
 4180        }
 1181        else if(lastMessages[lastMessages.Count-1].senderName == chatEntryModel.senderName)
 182        {
 0183            if (MessagesSentTooFast(lastMessages[lastMessages.Count - 1].timestamp, chatEntryModel.timestamp))
 184            {
 0185                lastMessages.Add(chatEntryModel);
 186
 0187                if (lastMessages.Count == MAX_CONTINUOUS_MESSAGES)
 188                {
 0189                    temporarilyMutedSenders.Add(chatEntryModel.senderName, chatEntryModel.timestamp);
 0190                    lastMessages.Clear();
 191                }
 0192            }
 193            else
 194            {
 0195                lastMessages.Clear();
 196            }
 0197        }
 198        else
 199        {
 1200            lastMessages.Clear();
 201        }
 1202    }
 203
 204    bool MessagesSentTooFast(ulong oldMessageTimeStamp, ulong newMessageTimeStamp)
 205    {
 0206        System.DateTime oldDateTime = CreateBaseDateTime().AddMilliseconds(oldMessageTimeStamp).ToLocalTime();
 0207        System.DateTime newDateTime = CreateBaseDateTime().AddMilliseconds(newMessageTimeStamp).ToLocalTime();
 208
 0209        return (newDateTime - oldDateTime).TotalMilliseconds < MIN_MILLISECONDS_BETWEEN_MESSAGES;
 210    }
 211
 212    private bool IsSpamming(string senderName)
 213    {
 31214        if (string.IsNullOrEmpty(senderName))
 0215            return false;
 216
 31217        bool isSpamming = false;
 218
 31219        if (temporarilyMutedSenders.ContainsKey(senderName))
 220        {
 0221            System.DateTime muteTimestamp = CreateBaseDateTime().AddMilliseconds(temporarilyMutedSenders[senderName]).To
 0222            if ((System.DateTime.Now - muteTimestamp).Minutes < TEMPORARILY_MUTE_MINUTES)
 0223                isSpamming = true;
 224            else
 0225                temporarilyMutedSenders.Remove(senderName);
 226        }
 227
 31228        return isSpamming;
 229    }
 230
 231    private System.DateTime CreateBaseDateTime()
 232    {
 0233        return new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
 234    }
 235
 236    private void OnOpenContextMenu(ChatEntry chatEntry)
 237    {
 0238        contextMenu.transform.position = chatEntry.contextMenuPositionReference.position;
 0239        contextMenu.transform.parent = this.transform;
 0240        contextMenu.Show(chatEntry.model.senderId);
 0241    }
 242
 243    protected virtual void OnMessageTriggerHover(ChatEntry chatEntry)
 244    {
 0245        if (contextMenu == null || contextMenu.isVisible)
 0246            return;
 247
 0248        messageHoverText.text = chatEntry.messageLocalDateTime;
 0249        messageHoverPanel.transform.position = chatEntry.hoverPanelPositionReference.position;
 0250        messageHoverPanel.SetActive(true);
 0251    }
 252
 253    protected virtual void OnMessageCoordinatesTriggerHover(ChatEntry chatEntry, ParcelCoordinates parcelCoordinates)
 254    {
 0255        messageHoverGotoText.text = $"{parcelCoordinates.ToString()} INFO";
 0256        messageHoverGotoPanel.transform.position = new Vector3(Input.mousePosition.x, chatEntry.hoverPanelPositionRefere
 0257        messageHoverGotoPanel.SetActive(true);
 0258    }
 259
 260    public void OnMessageCancelHover()
 261    {
 0262        messageHoverPanel.SetActive(false);
 0263        messageHoverText.text = string.Empty;
 0264    }
 265
 266    public void OnMessageCancelGotoHover()
 267    {
 0268        messageHoverGotoPanel.SetActive(false);
 0269        messageHoverGotoText.text = string.Empty;
 0270    }
 271
 272    public void SortEntries()
 273    {
 158274        entries = entries.OrderBy(x => x.model.timestamp).ToList();
 275
 31276        int count = entries.Count;
 316277        for (int i = 0; i < count; i++)
 278        {
 127279            if (entries[i].transform.GetSiblingIndex() != i)
 280            {
 44281                entries[i].transform.SetSiblingIndex(i);
 44282                Utils.ForceUpdateLayout(entries[i].transform as RectTransform, delayed: false);
 283            }
 284        }
 31285    }
 286
 287    public void CleanAllEntries()
 288    {
 18289        foreach (var entry in entries)
 290        {
 1291            Destroy(entry.gameObject);
 292        }
 293
 8294        entries.Clear();
 295
 16296        foreach (DateSeparatorEntry separator in dateSeparators)
 297        {
 0298            Destroy(separator.gameObject);
 299        }
 300
 8301        dateSeparators.Clear();
 8302    }
 303
 304    public void SetGotoPanelStatus(bool isActive)
 305    {
 6306        DataStore.i.HUDs.gotoPanelVisible.Set(isActive);
 6307    }
 308}