< Summary

Class:DCL.Chat.Notifications.ChatNotificationController
Assembly:NotificationMessagesHUD
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/NotificationMessagesHUD/ChatNotificationController.cs
Covered lines:145
Uncovered lines:15
Coverable lines:160
Total lines:346
Line coverage:90.6% (145 of 160)
Covered branches:0
Total branches:0
Covered methods:21
Total methods:22
Method coverage:95.4% (21 of 22)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
ChatNotificationController(...)0%110100%
SetVisibility(...)0%5.024060%
Dispose()0%110100%
VisiblePanelsChanged(...)0%2100%
HandleMessageAdded(...)0%11.811081.25%
AddNotificationAsync()0%57.644080.85%
HandleFriendRequestReceived(...)0%7.077088.89%
HandleSentFriendRequestApproved(...)0%220100%
ResetFadeOut(...)0%330100%
TogglePanelBackground(...)0%3.333066.67%
WaitThenFadeOutNotifications()0%10.378066.67%
ExtractPeerId(...)0%220100%
ResetVisibility(...)0%110100%
IsProfanityFilteringEnabled()0%110100%
HandleClickedFriendRequest(...)0%6.056088.89%
OpenChat(...)0%110100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/NotificationMessagesHUD/ChatNotificationController.cs

#LineLine coverage
 1using Cysharp.Threading.Tasks;
 2using DCL.Helpers;
 3using DCL.Interface;
 4using DCL.ProfanityFiltering;
 5using DCL.SettingsCommon;
 6using DCL.Social.Chat.Mentions;
 7using DCL.Social.Friends;
 8using System;
 9using System.Collections.Generic;
 10using System.Threading;
 11using UnityEngine;
 12using AudioSettings = DCL.SettingsCommon.AudioSettings;
 13using Channel = DCL.Chat.Channels.Channel;
 14
 15namespace DCL.Chat.Notifications
 16{
 17    public class ChatNotificationController : IHUD
 18    {
 19        private const int FADEOUT_DELAY = 8000;
 20
 21        private readonly DataStore dataStore;
 22        private readonly IChatController chatController;
 23        private readonly IFriendsController friendsController;
 24        private readonly IMainChatNotificationsComponentView mainChatNotificationView;
 25        private readonly ITopNotificationsComponentView topNotificationView;
 26        private readonly IUserProfileBridge userProfileBridge;
 27        private readonly IProfanityFilter profanityFilter;
 28        private readonly ISettingsRepository<AudioSettings> audioSettings;
 2229        private readonly TimeSpan maxNotificationInterval = new (0, 1, 0);
 2230        private readonly HashSet<string> notificationEntries = new ();
 2231        private readonly CancellationTokenSource addMessagesCancellationToken = new ();
 32
 6633        private BaseVariable<bool> shouldShowNotificationPanel => dataStore.HUDs.shouldShowNotificationPanel;
 2234        private BaseVariable<Transform> notificationPanelTransform => dataStore.HUDs.notificationPanelTransform;
 8235        private BaseVariable<Transform> topNotificationPanelTransform => dataStore.HUDs.topNotificationPanelTransform;
 4436        private BaseVariable<HashSet<string>> visibleTaskbarPanels => dataStore.HUDs.visibleTaskbarPanels;
 1437        private BaseVariable<string> openedChat => dataStore.HUDs.openChat;
 2238        private CancellationTokenSource fadeOutCancellationToken = new ();
 39        private UserProfile internalOwnUserProfile;
 40
 41        private UserProfile ownUserProfile
 42        {
 43            get
 44            {
 3845                internalOwnUserProfile ??= userProfileBridge.GetOwn();
 3846                return internalOwnUserProfile;
 47            }
 48        }
 49
 2250        public ChatNotificationController(DataStore dataStore,
 51            IMainChatNotificationsComponentView mainChatNotificationView,
 52            ITopNotificationsComponentView topNotificationView,
 53            IChatController chatController,
 54            IFriendsController friendsController,
 55            IUserProfileBridge userProfileBridge,
 56            IProfanityFilter profanityFilter,
 57            ISettingsRepository<AudioSettings> audioSettings)
 58        {
 2259            this.dataStore = dataStore;
 2260            this.chatController = chatController;
 2261            this.friendsController = friendsController;
 2262            this.userProfileBridge = userProfileBridge;
 2263            this.profanityFilter = profanityFilter;
 2264            this.audioSettings = audioSettings;
 2265            this.mainChatNotificationView = mainChatNotificationView;
 2266            this.topNotificationView = topNotificationView;
 2267            mainChatNotificationView.OnResetFade += ResetFadeOut;
 2268            topNotificationView.OnResetFade += ResetFadeOut;
 2269            mainChatNotificationView.OnPanelFocus += TogglePanelBackground;
 2270            mainChatNotificationView.OnClickedFriendRequest += HandleClickedFriendRequest;
 2271            topNotificationView.OnClickedFriendRequest += HandleClickedFriendRequest;
 2272            mainChatNotificationView.OnClickedChatMessage += OpenChat;
 2273            topNotificationView.OnClickedChatMessage += OpenChat;
 2274            chatController.OnAddMessage += HandleMessageAdded;
 2275            friendsController.OnFriendRequestReceived += HandleFriendRequestReceived;
 2276            friendsController.OnSentFriendRequestApproved += HandleSentFriendRequestApproved;
 2277            notificationPanelTransform.Set(mainChatNotificationView.GetPanelTransform());
 2278            topNotificationPanelTransform.Set(topNotificationView.GetPanelTransform());
 2279            visibleTaskbarPanels.OnChange += VisiblePanelsChanged;
 2280            shouldShowNotificationPanel.OnChange += ResetVisibility;
 2281            ResetVisibility(shouldShowNotificationPanel.Get(), false);
 2282        }
 83
 84        public void SetVisibility(bool visible)
 85        {
 2286            ResetFadeOut(visible);
 87
 2288            if (visible)
 89            {
 2290                if (shouldShowNotificationPanel.Get())
 2291                    mainChatNotificationView.Show();
 92
 2293                topNotificationView.Hide();
 2294                mainChatNotificationView.ShowNotifications();
 95            }
 96            else
 97            {
 098                mainChatNotificationView.Hide();
 99
 0100                if (!visibleTaskbarPanels.Get().Contains("WorldChatPanel"))
 0101                    topNotificationView.Show();
 102            }
 0103        }
 104
 105        public void Dispose()
 106        {
 22107            chatController.OnAddMessage -= HandleMessageAdded;
 22108            friendsController.OnFriendRequestReceived -= HandleFriendRequestReceived;
 22109            friendsController.OnSentFriendRequestApproved -= HandleSentFriendRequestApproved;
 22110            visibleTaskbarPanels.OnChange -= VisiblePanelsChanged;
 22111            mainChatNotificationView.OnResetFade -= ResetFadeOut;
 22112            topNotificationView.OnResetFade -= ResetFadeOut;
 22113            mainChatNotificationView.OnClickedChatMessage -= OpenChat;
 22114            topNotificationView.OnClickedChatMessage -= OpenChat;
 22115            addMessagesCancellationToken.Cancel();
 22116            addMessagesCancellationToken.Dispose();
 22117        }
 118
 119        private void VisiblePanelsChanged(HashSet<string> newList, HashSet<string> oldList)
 120        {
 0121            SetVisibility(newList.Count == 0);
 0122        }
 123
 124        private void HandleMessageAdded(ChatMessage[] messages)
 125        {
 59126            foreach (var message in messages)
 127            {
 15128                if (message.messageType != ChatMessage.Type.PRIVATE &&
 0129                    message.messageType != ChatMessage.Type.PUBLIC) return;
 130
 15131                var span = Utils.UnixToDateTimeWithTime((ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()) -
 132                           Utils.UnixToDateTimeWithTime(message.timestamp);
 133
 16134                if (span >= maxNotificationInterval) return;
 135
 14136                var channel = chatController.GetAllocatedChannel(
 137                    string.IsNullOrEmpty(message.recipient) && message.messageType == ChatMessage.Type.PUBLIC
 138                        ? "nearby"
 139                        : message.recipient);
 140
 14141                if (channel?.Muted ?? false) return;
 142
 143                // TODO: entries may have an inconsistent state. We should update the entry with new data
 14144                if (notificationEntries.Contains(message.messageId)) return;
 14145                notificationEntries.Add(message.messageId);
 146
 14147                AddNotificationAsync(message, channel, addMessagesCancellationToken.Token).Forget();
 148            }
 14149        }
 150
 151        private async UniTaskVoid AddNotificationAsync(ChatMessage message, Channel channel = null, CancellationToken ca
 152        {
 14153            string body = message.body;
 14154            string openedChatId = openedChat.Get();
 14155            bool isOwnPlayerMentioned = MentionsUtils.IsUserMentionedInText(ownUserProfile.userName, body);
 156
 14157            if (message.messageType == ChatMessage.Type.PRIVATE)
 158            {
 4159                string peerId = ExtractPeerId(message);
 160
 161                try
 162                {
 163                    // incoming friend request's message is added as a DM. This check filters it
 5164                    if (await friendsController.GetFriendshipStatus(peerId, cancellationToken) != FriendshipStatus.FRIEN
 3165                }
 0166                catch (Exception e) when (e is not OperationCanceledException)
 167                {
 0168                    Debug.LogException(e);
 0169                }
 170
 3171                UserProfile peerProfile = userProfileBridge.Get(peerId);
 3172                bool isMyMessage = message.sender == ownUserProfile.userId;
 3173                UserProfile senderProfile = isMyMessage ? ownUserProfile : userProfileBridge.Get(message.sender);
 3174                string peerName = peerProfile?.userName ?? peerId;
 3175                string peerProfilePicture = peerProfile?.face256SnapshotURL;
 3176                string senderName = senderProfile?.userName ?? message.sender;
 177
 3178                var privateModel = new PrivateChatMessageNotificationModel(
 179                    message.messageId,
 180                    isMyMessage ? peerId : message.sender,
 181                    body,
 182                    message.timestamp,
 183                    senderName,
 184                    peerName,
 185                    isMyMessage,
 186                    isOwnPlayerMentioned,
 187                    peerProfilePicture);
 188
 3189                mainChatNotificationView.AddNewChatNotification(privateModel);
 190
 3191                if (message.sender != openedChatId && message.recipient != openedChatId)
 3192                    if (topNotificationPanelTransform.Get().gameObject.activeInHierarchy)
 3193                        topNotificationView.AddNewChatNotification(privateModel);
 3194            }
 10195            else if (message.messageType == ChatMessage.Type.PUBLIC)
 196            {
 10197                bool isMyMessage = message.sender == ownUserProfile.userId;
 10198                UserProfile senderProfile = isMyMessage ? ownUserProfile : userProfileBridge.Get(message.sender);
 10199                string senderName = senderProfile?.userName ?? message.sender;
 10200                bool shouldPlayMentionSfx = isOwnPlayerMentioned;
 201
 10202                if (isOwnPlayerMentioned)
 203                {
 3204                    AudioSettings.ChatNotificationType chatNotificationSfxType = audioSettings.Data.chatNotificationType
 205
 3206                    shouldPlayMentionSfx = chatNotificationSfxType is AudioSettings.ChatNotificationType.All
 207                        or AudioSettings.ChatNotificationType.MentionsOnly;
 208                }
 209
 10210                if (IsProfanityFilteringEnabled())
 211                {
 2212                    senderName = await profanityFilter.Filter(senderName, cancellationToken);
 2213                    body = await profanityFilter.Filter(message.body, cancellationToken);
 214                }
 215
 10216                var publicModel = new PublicChannelMessageNotificationModel(
 217                    message.messageId,
 218                    body,
 219                    channel?.Name ?? message.recipient,
 220                    channel?.ChannelId,
 221                    message.timestamp,
 222                    isMyMessage,
 223                    senderName,
 224                    isOwnPlayerMentioned,
 225                    shouldPlayMentionSfx);
 226
 10227                mainChatNotificationView.AddNewChatNotification(publicModel);
 228
 10229                if ((string.IsNullOrEmpty(message.recipient) && openedChatId != ChatUtils.NEARBY_CHANNEL_ID)
 230                    || (!string.IsNullOrEmpty(message.recipient) && openedChatId != message.recipient))
 10231                    if (topNotificationPanelTransform.Get().gameObject.activeInHierarchy)
 10232                        topNotificationView.AddNewChatNotification(publicModel);
 10233            }
 14234        }
 235
 236        private void HandleFriendRequestReceived(FriendRequest friendRequest)
 237        {
 2238            if (friendRequest.From == ownUserProfile.userId ||
 239                friendRequest.To != ownUserProfile.userId)
 0240                return;
 241
 2242            var friendRequestProfile = userProfileBridge.Get(friendRequest.From);
 2243            var friendRequestName = friendRequestProfile?.userName ?? friendRequest.From;
 244
 2245            FriendRequestNotificationModel friendRequestNotificationModel = new FriendRequestNotificationModel(
 246                friendRequest.FriendRequestId,
 247                friendRequest.From,
 248                friendRequestName,
 249                "Friend Request received",
 250                "wants to be your friend.",
 251                friendRequest.Timestamp,
 252                false);
 253
 2254            mainChatNotificationView.AddNewFriendRequestNotification(friendRequestNotificationModel);
 255
 2256            if (topNotificationPanelTransform.Get().gameObject.activeInHierarchy)
 2257                topNotificationView.AddNewFriendRequestNotification(friendRequestNotificationModel);
 2258        }
 259
 260        private void HandleSentFriendRequestApproved(FriendRequest friendRequest)
 261        {
 1262            string recipientUserId = friendRequest.To;
 1263            var friendRequestProfile = userProfileBridge.Get(recipientUserId);
 264
 1265            FriendRequestNotificationModel friendRequestNotificationModel = new FriendRequestNotificationModel(
 266                friendRequest.FriendRequestId,
 267                recipientUserId,
 268                friendRequestProfile.userName,
 269                "Friend Request accepted",
 270                "and you are friends now!",
 271                DateTime.UtcNow,
 272                true);
 273
 1274            mainChatNotificationView.AddNewFriendRequestNotification(friendRequestNotificationModel);
 275
 1276            if (topNotificationPanelTransform.Get().gameObject.activeInHierarchy)
 1277                topNotificationView.AddNewFriendRequestNotification(friendRequestNotificationModel);
 1278        }
 279
 280        private void ResetFadeOut(bool fadeOutAfterDelay = false)
 281        {
 22282            mainChatNotificationView.ShowNotifications();
 283
 22284            if (topNotificationPanelTransform.Get().gameObject.activeInHierarchy)
 22285                topNotificationView.ShowNotification();
 286
 22287            fadeOutCancellationToken.Cancel();
 22288            fadeOutCancellationToken = new CancellationTokenSource();
 289
 22290            if (fadeOutAfterDelay)
 22291                WaitThenFadeOutNotifications(fadeOutCancellationToken.Token).Forget();
 22292        }
 293
 294        private void TogglePanelBackground(bool isInFocus)
 295        {
 2296            if (mainChatNotificationView.GetNotificationsCount() == 0)
 1297                return;
 298
 1299            if (isInFocus)
 1300                mainChatNotificationView.ShowPanel();
 301            else
 0302                mainChatNotificationView.HidePanel();
 0303        }
 304
 305        private async UniTaskVoid WaitThenFadeOutNotifications(CancellationToken cancellationToken)
 306        {
 66307            await UniTask.Delay(FADEOUT_DELAY, cancellationToken: cancellationToken);
 22308            await UniTask.SwitchToMainThread(cancellationToken);
 309
 22310            if (cancellationToken.IsCancellationRequested)
 0311                return;
 312
 22313            mainChatNotificationView.HideNotifications();
 314
 22315            if (topNotificationPanelTransform.Get() != null &&
 316                topNotificationPanelTransform.Get().gameObject.activeInHierarchy)
 0317                topNotificationView.HideNotification();
 22318        }
 319
 320        private string ExtractPeerId(ChatMessage message) =>
 4321            message.sender != ownUserProfile.userId ? message.sender : message.recipient;
 322
 323        private void ResetVisibility(bool current, bool previous) =>
 22324            SetVisibility(current);
 325
 326        private bool IsProfanityFilteringEnabled() =>
 10327            dataStore.settings.profanityChatFilteringEnabled.Get();
 328
 329        private void HandleClickedFriendRequest(string friendRequestId, string userId, bool isAcceptedFromPeer)
 330        {
 2331            if (string.IsNullOrEmpty(friendRequestId)) return;
 332
 2333            bool wasFound = friendsController.TryGetAllocatedFriendRequest(friendRequestId, out FriendRequest _);
 334
 2335            bool isFriend = friendsController.IsFriend(userId);
 336
 2337            if (wasFound && !isFriend && !isAcceptedFromPeer)
 1338                dataStore.HUDs.openReceivedFriendRequestDetail.Set(friendRequestId, true);
 1339            else if (isFriend)
 1340                OpenChat(userId);
 1341        }
 342
 343        private void OpenChat(string chatId) =>
 1344            dataStore.HUDs.openChat.Set(chatId, true);
 345    }
 346}