< Summary

Class:PublicChatChannelController
Assembly:WorldChatWindowHUD
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/WorldChatWindowHUD/PublicChatChannelController.cs
Covered lines:142
Uncovered lines:47
Coverable lines:189
Total lines:354
Line coverage:75.1% (142 of 189)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
PublicChatChannelController(...)0%110100%
Initialize(...)0%330100%
Setup(...)0%12300%
Dispose()0%440100%
SendChatMessage(...)0%550100%
SetVisibility(...)0%330100%
SetVisibility(...)0%110100%
ReloadAllChats()0%42600%
ActivatePreviewModeInstantly()0%220100%
MarkChatMessagesAsRead()0%110100%
HandleViewClosed()0%220100%
HandleViewBacked()0%6200%
HandleMessageInputUpdated(...)0%330100%
IsOldPrivateMessage(...)0%220100%
HandleMessageReceived(...)0%7.277082.35%
HandleInputFieldSelected()0%110100%
HandleInputFieldDeselected()0%2.062075%
HandleViewFocused(...)0%42600%
HandleViewClicked()0%6200%
WaitThenActivatePreview()0%6.736072.73%
WaitThenFadeOutMessages()0%6.736072.73%
ActivatePreview()0%220100%
ActivatePreviewOnMessages()0%6200%
DeactivatePreview()0%220100%
HandleChatInputTriggered(...)0%6200%

File(s)

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

#LineLine coverage
 1using System;
 2using System.Threading;
 3using Cysharp.Threading.Tasks;
 4using DCL;
 5using DCL.Chat;
 6using DCL.Interface;
 7using SocialFeaturesAnalytics;
 8using UnityEngine;
 9
 10public class PublicChatChannelController : IHUD
 11{
 012    public IChannelChatWindowView View { get; private set; }
 13
 14    private enum ChatWindowVisualState { NONE_VISIBLE, INPUT_MODE, PREVIEW_MODE }
 15
 16    public event Action OnBack;
 17    public event Action OnClosed;
 18    public event Action<bool> OnPreviewModeChanged;
 19
 20    private readonly IChatController chatController;
 21    private readonly IUserProfileBridge userProfileBridge;
 22    private readonly DataStore dataStore;
 23    private readonly IProfanityFilter profanityFilter;
 24    private readonly IMouseCatcher mouseCatcher;
 25    private readonly InputAction_Trigger toggleChatTrigger;
 26    private ChatHUDController chatHudController;
 27    private double initTimeInSeconds;
 28    private string channelId;
 29    private ChatWindowVisualState currentState;
 1630    private CancellationTokenSource deactivatePreviewCancellationToken = new CancellationTokenSource();
 1631    private CancellationTokenSource deactivateFadeOutCancellationToken = new CancellationTokenSource();
 32
 1633    private string lastPrivateMessageRecipient = string.Empty;
 34
 235    private UserProfile ownProfile => userProfileBridge.GetOwn();
 36
 1637    public PublicChatChannelController(IChatController chatController,
 38        IUserProfileBridge userProfileBridge,
 39        DataStore dataStore,
 40        IProfanityFilter profanityFilter,
 41        IMouseCatcher mouseCatcher,
 42        InputAction_Trigger toggleChatTrigger)
 43    {
 1644        this.chatController = chatController;
 1645        this.userProfileBridge = userProfileBridge;
 1646        this.dataStore = dataStore;
 1647        this.profanityFilter = profanityFilter;
 1648        this.mouseCatcher = mouseCatcher;
 1649        this.toggleChatTrigger = toggleChatTrigger;
 1650    }
 51
 52    public void Initialize(IChannelChatWindowView view = null)
 53    {
 1654        view ??= PublicChatChannelComponentView.Create();
 1655        View = view;
 1656        view.OnClose += HandleViewClosed;
 1657        view.OnBack += HandleViewBacked;
 1658        view.OnFocused += HandleViewFocused;
 1659        View.OnClickOverWindow += HandleViewClicked;
 60
 61
 1662        chatHudController = new ChatHUDController(dataStore,
 63            userProfileBridge,
 64            true,
 65            profanityFilter);
 1666        chatHudController.Initialize(view.ChatHUD);
 1667        chatHudController.OnSendMessage += SendChatMessage;
 1668        chatHudController.OnMessageUpdated += HandleMessageInputUpdated;
 1669        chatHudController.OnInputFieldSelected -= HandleInputFieldSelected;
 1670        chatHudController.OnInputFieldSelected += HandleInputFieldSelected;
 1671        chatHudController.OnInputFieldDeselected -= HandleInputFieldDeselected;
 1672        chatHudController.OnInputFieldDeselected += HandleInputFieldDeselected;
 73
 1674        chatController.OnAddMessage -= HandleMessageReceived;
 1675        chatController.OnAddMessage += HandleMessageReceived;
 76
 1677        if (mouseCatcher != null)
 1678            mouseCatcher.OnMouseLock += ActivatePreview;
 79
 1680        toggleChatTrigger.OnTriggered += HandleChatInputTriggered;
 81
 1682        initTimeInSeconds = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() / 1000.0;
 83
 1684        currentState = ChatWindowVisualState.PREVIEW_MODE;
 1685        WaitThenFadeOutMessages(deactivateFadeOutCancellationToken.Token).Forget();
 1686    }
 87
 88    public void Setup(string channelId)
 89    {
 090        if (string.IsNullOrEmpty(channelId) || channelId == this.channelId) return;
 091        this.channelId = channelId;
 92
 93        // TODO: retrieve data from a channel provider
 094        View.Configure(new PublicChatChannelModel(this.channelId, ChatUtils.NEARBY_CHANNEL_ID,
 95            "Talk to the people around you. If you move far away from someone you will lose contact. All whispers will b
 96
 097        ReloadAllChats().Forget();
 098    }
 99
 100    public void Dispose()
 101    {
 15102        View.OnClose -= HandleViewClosed;
 15103        View.OnBack -= HandleViewBacked;
 104
 15105        if (chatController != null)
 15106            chatController.OnAddMessage -= HandleMessageReceived;
 107
 15108        chatHudController.OnSendMessage -= SendChatMessage;
 15109        chatHudController.OnMessageUpdated -= HandleMessageInputUpdated;
 15110        chatHudController.OnInputFieldSelected -= HandleInputFieldSelected;
 15111        chatHudController.OnInputFieldDeselected -= HandleInputFieldDeselected;
 112
 15113        if (mouseCatcher != null)
 15114            mouseCatcher.OnMouseLock -= ActivatePreview;
 115
 15116        toggleChatTrigger.OnTriggered -= HandleChatInputTriggered;
 117
 15118        if (View != null)
 119        {
 15120            View.OnFocused -= HandleViewFocused;
 15121            View.OnClickOverWindow -= HandleViewClicked;
 15122            View.Dispose();
 123        }
 15124    }
 125
 126    private void SendChatMessage(ChatMessage message)
 127    {
 3128        var isValidMessage = !string.IsNullOrEmpty(message.body) && !string.IsNullOrWhiteSpace(message.body);
 3129        var isPrivateMessage = message.messageType == ChatMessage.Type.PRIVATE;
 130
 3131        if (isPrivateMessage && isValidMessage)
 1132            lastPrivateMessageRecipient = message.recipient;
 133        else
 2134            lastPrivateMessageRecipient = null;
 135
 3136        if (isValidMessage)
 137        {
 2138            chatHudController.ResetInputField();
 2139            chatHudController.FocusInputField();
 2140        }
 141        else
 142        {
 1143            chatHudController.ResetInputField(true);
 1144            ActivatePreview();
 1145            return;
 146        }
 147
 2148        if (isPrivateMessage)
 1149            message.body = $"/w {message.recipient} {message.body}";
 150
 2151        chatController.Send(message);
 2152    }
 153
 154    public void SetVisibility(bool visible, bool focusInputField)
 155    {
 11156        if (visible)
 157        {
 8158            View.Show();
 8159            MarkChatMessagesAsRead();
 160
 8161            if (focusInputField)
 1162                chatHudController.FocusInputField();
 1163        }
 164        else
 165        {
 3166            chatHudController.UnfocusInputField();
 3167            View.Hide();
 168        }
 10169    }
 170
 9171    public void SetVisibility(bool visible) => SetVisibility(visible, false);
 172
 173    private async UniTaskVoid ReloadAllChats()
 174    {
 0175        chatHudController.ClearAllEntries();
 176
 177        const int entriesPerFrame = 10;
 178        // TODO: filter entries by channelId
 0179        var list = chatController.GetAllocatedEntries();
 0180        if (list.Count == 0) return;
 181
 0182        for (var i = list.Count - 1; i >= 0; i--)
 183        {
 0184            var message = list[i];
 0185            if (i % entriesPerFrame == 0) await UniTask.NextFrame();
 0186            HandleMessageReceived(message);
 0187        }
 0188    }
 189
 190    public void ActivatePreviewModeInstantly()
 191    {
 3192        deactivatePreviewCancellationToken.Cancel();
 3193        deactivatePreviewCancellationToken = new CancellationTokenSource();
 3194        deactivateFadeOutCancellationToken.Cancel();
 3195        deactivateFadeOutCancellationToken = new CancellationTokenSource();
 196
 3197        View.ActivatePreviewInstantly();
 3198        chatHudController.ActivatePreview();
 3199        currentState = ChatWindowVisualState.PREVIEW_MODE;
 3200        WaitThenFadeOutMessages(deactivateFadeOutCancellationToken.Token).Forget();
 3201        OnPreviewModeChanged?.Invoke(true);
 2202    }
 203
 8204    private void MarkChatMessagesAsRead() => chatController.MarkMessagesAsSeen(channelId);
 205
 1206    private void HandleViewClosed() => OnClosed?.Invoke();
 207
 0208    private void HandleViewBacked() => OnBack?.Invoke();
 209
 210    private void HandleMessageInputUpdated(string message)
 211    {
 1212        if (!string.IsNullOrEmpty(lastPrivateMessageRecipient) && message == "/r ")
 1213            chatHudController.SetInputFieldText($"/w {lastPrivateMessageRecipient} ");
 1214    }
 215
 216    private bool IsOldPrivateMessage(ChatMessage message)
 217    {
 5218        if (message.messageType != ChatMessage.Type.PRIVATE) return false;
 3219        var timestampInSeconds = message.timestamp / 1000.0;
 3220        return timestampInSeconds < initTimeInSeconds;
 221    }
 222
 223    private void HandleMessageReceived(ChatMessage message)
 224    {
 5225        if (IsOldPrivateMessage(message)) return;
 226
 3227        chatHudController.AddChatMessage(message, View.IsActive);
 228
 3229        if (View.IsActive)
 0230            MarkChatMessagesAsRead();
 231
 3232        if (message.messageType == ChatMessage.Type.PRIVATE && message.recipient == ownProfile.userId)
 1233            lastPrivateMessageRecipient = userProfileBridge.Get(message.sender).userName;
 234
 3235        deactivatePreviewCancellationToken.Cancel();
 3236        deactivatePreviewCancellationToken = new CancellationTokenSource();
 3237        deactivateFadeOutCancellationToken.Cancel();
 3238        deactivateFadeOutCancellationToken = new CancellationTokenSource();
 239
 3240        if (currentState.Equals(ChatWindowVisualState.NONE_VISIBLE))
 241        {
 0242            ActivatePreview();
 0243        }
 3244        else if (currentState.Equals(ChatWindowVisualState.PREVIEW_MODE))
 245        {
 3246            WaitThenFadeOutMessages(deactivateFadeOutCancellationToken.Token).Forget();
 247        }
 3248    }
 249
 250    private void HandleInputFieldSelected()
 251    {
 1252        deactivatePreviewCancellationToken.Cancel();
 1253        deactivatePreviewCancellationToken = new CancellationTokenSource();
 1254        DeactivatePreview();
 1255    }
 256
 257    private void HandleInputFieldDeselected()
 258    {
 1259        if (View.IsFocused)
 0260            return;
 1261        WaitThenActivatePreview(deactivatePreviewCancellationToken.Token).Forget();
 1262    }
 263
 264    private void HandleViewFocused(bool focused)
 265    {
 0266        if (focused)
 267        {
 0268            deactivatePreviewCancellationToken.Cancel();
 0269            deactivatePreviewCancellationToken = new CancellationTokenSource();
 0270            deactivateFadeOutCancellationToken.Cancel();
 0271            deactivateFadeOutCancellationToken = new CancellationTokenSource();
 0272            if (currentState.Equals(ChatWindowVisualState.NONE_VISIBLE))
 273            {
 0274                ActivatePreviewOnMessages();
 275            }
 0276        }
 277        else
 278        {
 0279            if (chatHudController.IsInputSelected)
 0280                return;
 281
 0282            if (currentState.Equals(ChatWindowVisualState.INPUT_MODE))
 283            {
 0284                WaitThenActivatePreview(deactivatePreviewCancellationToken.Token).Forget();
 0285                return;
 286            }
 287
 0288            if (currentState.Equals(ChatWindowVisualState.PREVIEW_MODE))
 289            {
 0290                WaitThenFadeOutMessages(deactivateFadeOutCancellationToken.Token).Forget();
 291            }
 292        }
 0293    }
 294
 295    private void HandleViewClicked()
 296    {
 0297        if (currentState.Equals(ChatWindowVisualState.INPUT_MODE))
 0298            return;
 0299        DeactivatePreview();
 0300    }
 301
 302    private async UniTaskVoid WaitThenActivatePreview(CancellationToken cancellationToken)
 303    {
 3304        await UniTask.Delay(3000, cancellationToken: cancellationToken);
 1305        await UniTask.SwitchToMainThread(cancellationToken);
 1306        if (cancellationToken.IsCancellationRequested) return;
 1307        currentState = ChatWindowVisualState.PREVIEW_MODE;
 1308        ActivatePreview();
 1309    }
 310
 311    private async UniTaskVoid WaitThenFadeOutMessages(CancellationToken cancellationToken)
 312    {
 62313        await UniTask.Delay(30000, cancellationToken: cancellationToken);
 1314        await UniTask.SwitchToMainThread(cancellationToken);
 1315        if (cancellationToken.IsCancellationRequested) return;
 1316        chatHudController.FadeOutMessages();
 1317        currentState = ChatWindowVisualState.NONE_VISIBLE;
 1318    }
 319
 320    public void ActivatePreview()
 321    {
 4322        View.ActivatePreview();
 4323        chatHudController.ActivatePreview();
 4324        currentState = ChatWindowVisualState.PREVIEW_MODE;
 4325        WaitThenFadeOutMessages(deactivateFadeOutCancellationToken.Token).Forget();
 4326        OnPreviewModeChanged?.Invoke(true);
 4327    }
 328
 329    public void ActivatePreviewOnMessages()
 330    {
 0331        chatHudController.ActivatePreview();
 0332        OnPreviewModeChanged?.Invoke(true);
 0333        currentState = ChatWindowVisualState.PREVIEW_MODE;
 0334    }
 335
 336    public void DeactivatePreview()
 337    {
 3338        deactivatePreviewCancellationToken.Cancel();
 3339        deactivatePreviewCancellationToken = new CancellationTokenSource();
 3340        deactivateFadeOutCancellationToken.Cancel();
 3341        deactivateFadeOutCancellationToken = new CancellationTokenSource();
 342
 3343        View.DeactivatePreview();
 3344        chatHudController.DeactivatePreview();
 3345        OnPreviewModeChanged?.Invoke(false);
 3346        currentState = ChatWindowVisualState.INPUT_MODE;
 3347    }
 348
 349    private void HandleChatInputTriggered(DCLAction_Trigger action)
 350    {
 0351        if (!View.IsActive) return;
 0352        chatHudController.FocusInputField();
 0353    }
 354}