< Summary

Class:DCL.Chat.Notifications.MainChatNotificationsComponentView
Assembly:NotificationMessagesHUD
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/NotificationMessagesHUD/MainChatNotificationsComponentView.cs
Covered lines:111
Uncovered lines:80
Coverable lines:191
Total lines:386
Line coverage:58.1% (111 of 191)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
MainChatNotificationsComponentView()0%110100%
Create()0%110100%
Awake()0%330100%
Show(...)0%110100%
Hide(...)0%110100%
GetPanelTransform()0%2100%
ResetNotificationButtonFromScroll(...)0%6200%
ShowPanel()0%12300%
HidePanel()0%12300%
ShowNotifications()0%6200%
HideNotifications()0%6200%
AddNewChatNotification(...)0%4.014092.31%
AddNewChatNotification(...)0%4.014092.31%
AddNewFriendRequestNotification(...)0%20400%
AnimateNewEntry()0%8.126061.11%
ResetNotificationButton()0%220100%
IncreaseNotificationCount()0%20400%
SetScrollToEnd(...)0%110100%
PopulatePrivateNotification(...)0%2.012087.5%
PopulatePublicNotification(...)0%220100%
ClickedOnNotification(...)0%6200%
PopulateFriendRequestNotification(...)0%2100%
ClickedOnFriendRequest(...)0%6200%
FocusedOnNotification(...)0%3.333066.67%
FocusedOnPanel(...)0%4.254075%
CheckNotificationCountAndRelease()0%2.862040%
GetNotificationEntryPool()0%2.022083.33%
GetFriendRequestNotificationEntryPool()0%6200%
RefreshControl()0%2100%

File(s)

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

#LineLine coverage
 1using Cysharp.Threading.Tasks;
 2using DCL.Helpers;
 3using DG.Tweening;
 4using System;
 5using System.Collections.Generic;
 6using System.Threading;
 7using TMPro;
 8using UnityEngine;
 9using UnityEngine.UI;
 10
 11namespace DCL.Chat.Notifications
 12{
 13    public class MainChatNotificationsComponentView : BaseComponentView, IMainChatNotificationsComponentView
 14    {
 15        [SerializeField] private RectTransform chatEntriesContainer;
 16        [SerializeField] private GameObject chatNotification;
 17        [SerializeField] private GameObject friendRequestNotification;
 18        [SerializeField] private ScrollRect scrollRectangle;
 19        [SerializeField] private Button notificationButton;
 20        [SerializeField] private ShowHideAnimator panelAnimator;
 21        [SerializeField] private ShowHideAnimator scrollbarAnimator;
 22
 23        private const string NOTIFICATION_POOL_NAME_PREFIX = "NotificationEntriesPool_";
 24        private const string FRINED_REQUEST_NOTIFICATION_POOL_NAME_PREFIX = "FriendRequestNotificationEntriesPool_";
 25        private const int MAX_NOTIFICATION_ENTRIES = 30;
 26
 27        public event Action<string> OnClickedChatMessage;
 28        public event IMainChatNotificationsComponentView.ClickedNotificationDelegate OnClickedFriendRequest;
 29        public event Action<bool> OnResetFade;
 30        public event Action<bool> OnPanelFocus;
 31
 732        internal readonly Queue<PoolableObject> poolableQueue = new Queue<PoolableObject>();
 33
 734        internal readonly Queue<BaseComponentView> notificationQueue = new Queue<BaseComponentView>();
 35
 736        private readonly Vector2 notificationOffset = new Vector2(0, -56);
 37
 38        private Pool entryPool;
 39        private bool isOverMessage;
 40        private bool isOverPanel;
 741        private int notificationCount = 1;
 42        private TMP_Text notificationMessage;
 743        private CancellationTokenSource animationCancellationToken = new CancellationTokenSource();
 144        private BaseVariable<string> openedChat => DataStore.i.HUDs.openedChat;
 45
 46        public static MainChatNotificationsComponentView Create()
 47        {
 648            return Instantiate(Resources.Load<MainChatNotificationsComponentView>("SocialBarV1/ChatNotificationHUD"));
 49        }
 50
 51        public void Awake()
 52        {
 653            onFocused += FocusedOnPanel;
 654            notificationMessage = notificationButton.GetComponentInChildren<TMP_Text>();
 655            notificationButton?.onClick.RemoveAllListeners();
 656            notificationButton?.onClick.AddListener(() => SetScrollToEnd());
 657            scrollRectangle.onValueChanged.AddListener(ResetNotificationButtonFromScroll);
 658        }
 59
 60        public override void Show(bool instant = false)
 61        {
 162            openedChat.Set("");
 163            gameObject.SetActive(true);
 164        }
 65
 66        public override void Hide(bool instant = false)
 67        {
 168            SetScrollToEnd();
 169            gameObject.SetActive(false);
 170        }
 71
 72        public Transform GetPanelTransform()
 73        {
 074            return gameObject.transform;
 75        }
 76
 77        private void ResetNotificationButtonFromScroll(Vector2 newValue)
 78        {
 079            if (newValue.y <= 0.0)
 80            {
 081                ResetNotificationButton();
 82            }
 083        }
 84
 85        public void ShowPanel()
 86        {
 087            panelAnimator?.Show();
 088            scrollbarAnimator?.Show();
 089        }
 90
 91        public void HidePanel()
 92        {
 093            panelAnimator?.Hide();
 094            scrollbarAnimator?.Hide();
 095        }
 96
 97        public void ShowNotifications()
 98        {
 099            foreach (BaseComponentView notification in notificationQueue)
 100            {
 0101                notification.Show();
 102            }
 0103        }
 104
 105        public void HideNotifications()
 106        {
 0107            foreach (BaseComponentView notification in notificationQueue)
 108            {
 0109                notification.Hide();
 110            }
 0111        }
 112
 113        public void AddNewChatNotification(PrivateChatMessageNotificationModel model)
 114        {
 1115            entryPool = GetNotificationEntryPool();
 1116            var newNotification = entryPool.Get();
 117
 1118            var entry = newNotification.gameObject.GetComponent<ChatNotificationMessageComponentView>();
 1119            poolableQueue.Enqueue(newNotification);
 1120            notificationQueue.Enqueue(entry);
 121
 1122            entry.OnClickedNotification -= ClickedOnNotification;
 1123            entry.onFocused -= FocusedOnNotification;
 1124            entry.showHideAnimator.OnWillFinishHide -= SetScrollToEnd;
 125
 1126            PopulatePrivateNotification(entry, model);
 127
 1128            entry.transform.SetParent(chatEntriesContainer, false);
 1129            entry.RefreshControl();
 1130            entry.SetTimestamp(Utils.UnixTimeStampToLocalTime(model.Timestamp));
 1131            entry.OnClickedNotification += ClickedOnNotification;
 1132            entry.onFocused += FocusedOnNotification;
 1133            entry.showHideAnimator.OnWillFinishHide += SetScrollToEnd;
 134
 1135            chatEntriesContainer.anchoredPosition += notificationOffset;
 1136            if (isOverPanel)
 137            {
 0138                notificationButton.gameObject.SetActive(true);
 0139                IncreaseNotificationCount();
 140            }
 141            else
 142            {
 1143                ResetNotificationButton();
 1144                animationCancellationToken.Cancel();
 1145                animationCancellationToken = new CancellationTokenSource();
 1146                AnimateNewEntry(entry.gameObject.transform, animationCancellationToken.Token).Forget();
 147            }
 148
 1149            OnResetFade?.Invoke(!isOverMessage && !isOverPanel);
 1150            CheckNotificationCountAndRelease();
 1151        }
 152
 153        public void AddNewChatNotification(PublicChannelMessageNotificationModel model)
 154        {
 2155            entryPool = GetNotificationEntryPool();
 2156            var newNotification = entryPool.Get();
 157
 2158            var entry = newNotification.gameObject.GetComponent<ChatNotificationMessageComponentView>();
 2159            poolableQueue.Enqueue(newNotification);
 2160            notificationQueue.Enqueue(entry);
 161
 2162            entry.OnClickedNotification -= ClickedOnNotification;
 2163            entry.onFocused -= FocusedOnNotification;
 2164            entry.showHideAnimator.OnWillFinishHide -= SetScrollToEnd;
 165
 2166            PopulatePublicNotification(entry, model);
 167
 2168            entry.transform.SetParent(chatEntriesContainer, false);
 2169            entry.RefreshControl();
 2170            entry.SetTimestamp(Utils.UnixTimeStampToLocalTime(model.Timestamp));
 2171            entry.OnClickedNotification += ClickedOnNotification;
 2172            entry.onFocused += FocusedOnNotification;
 2173            entry.showHideAnimator.OnWillFinishHide += SetScrollToEnd;
 174
 2175            chatEntriesContainer.anchoredPosition += notificationOffset;
 2176            if (isOverPanel)
 177            {
 0178                notificationButton.gameObject.SetActive(true);
 0179                IncreaseNotificationCount();
 180            }
 181            else
 182            {
 2183                ResetNotificationButton();
 2184                animationCancellationToken.Cancel();
 2185                animationCancellationToken = new CancellationTokenSource();
 2186                AnimateNewEntry(entry.gameObject.transform, animationCancellationToken.Token).Forget();
 187            }
 188
 2189            OnResetFade?.Invoke(!isOverMessage && !isOverPanel);
 2190            CheckNotificationCountAndRelease();
 2191        }
 192
 193        public void AddNewFriendRequestNotification(FriendRequestNotificationModel model)
 194        {
 0195            entryPool = GetFriendRequestNotificationEntryPool();
 0196            var newNotification = entryPool.Get();
 197
 0198            var entry = newNotification.gameObject.GetComponent<FriendRequestNotificationComponentView>();
 0199            poolableQueue.Enqueue(newNotification);
 0200            notificationQueue.Enqueue(entry);
 201
 0202            entry.OnClickedNotification -= ClickedOnFriendRequest;
 0203            entry.onFocused -= FocusedOnNotification;
 0204            entry.showHideAnimator.OnWillFinishHide -= SetScrollToEnd;
 205
 0206            PopulateFriendRequestNotification(entry, model);
 207
 0208            entry.transform.SetParent(chatEntriesContainer, false);
 0209            entry.RefreshControl();
 0210            entry.OnClickedNotification += ClickedOnFriendRequest;
 0211            entry.onFocused += FocusedOnNotification;
 0212            entry.showHideAnimator.OnWillFinishHide += SetScrollToEnd;
 213
 0214            chatEntriesContainer.anchoredPosition += notificationOffset;
 0215            if (isOverPanel)
 216            {
 0217                notificationButton.gameObject.SetActive(true);
 0218                IncreaseNotificationCount();
 219            }
 220            else
 221            {
 0222                ResetNotificationButton();
 0223                animationCancellationToken.Cancel();
 0224                animationCancellationToken = new CancellationTokenSource();
 0225                AnimateNewEntry(entry.gameObject.transform, animationCancellationToken.Token).Forget();
 226            }
 227
 0228            OnResetFade?.Invoke(!isOverMessage && !isOverPanel);
 0229            CheckNotificationCountAndRelease();
 230
 231            // TODO: refactor sfx usage into non-static
 0232            AudioScriptableObjects.FriendRequestEvent.Play();
 0233        }
 234
 235        private async UniTaskVoid AnimateNewEntry(Transform notification, CancellationToken cancellationToken)
 236        {
 3237            cancellationToken.ThrowIfCancellationRequested();
 3238            Sequence mySequence = DOTween.Sequence().AppendInterval(0.2f)
 239                .Append(notification.DOScale(1, 0.3f).SetEase(Ease.OutBack));
 240            try
 241            {
 3242                Vector2 endPosition = new Vector2(0, 0);
 3243                Vector2 currentPosition = chatEntriesContainer.anchoredPosition;
 3244                notification.localScale = Vector3.zero;
 120245                DOTween.To(() => currentPosition, x => currentPosition = x, endPosition, 0.8f).SetEase(Ease.OutCubic);
 6246                while (chatEntriesContainer.anchoredPosition.y < 0)
 247                {
 3248                    chatEntriesContainer.anchoredPosition = currentPosition;
 9249                    await UniTask.NextFrame(cancellationToken);
 250                }
 251
 0252                mySequence.Play();
 0253            }
 0254            catch (OperationCanceledException)
 255            {
 0256                if (!DOTween.IsTweening(notification))
 0257                    notification.DOScale(1, 0.3f).SetEase(Ease.OutBack);
 0258            }
 0259        }
 260
 261        private void ResetNotificationButton()
 262        {
 4263            notificationButton.gameObject.SetActive(false);
 4264            notificationCount = 0;
 265
 4266            if (notificationMessage != null)
 4267                notificationMessage.text = notificationCount.ToString();
 4268        }
 269
 270        private void IncreaseNotificationCount()
 271        {
 0272            notificationCount++;
 0273            if (notificationMessage != null)
 0274                notificationMessage.text = notificationCount <= 9 ? notificationCount.ToString() : "9+";
 0275        }
 276
 277        private void SetScrollToEnd(ShowHideAnimator animator = null)
 278        {
 1279            scrollRectangle.normalizedPosition = new Vector2(0, 0);
 1280            ResetNotificationButton();
 1281        }
 282
 283        private void PopulatePrivateNotification(ChatNotificationMessageComponentView chatNotificationComponentView,
 284            PrivateChatMessageNotificationModel model)
 285        {
 1286            chatNotificationComponentView.SetIsPrivate(true);
 1287            chatNotificationComponentView.SetMessage(model.Body);
 1288            chatNotificationComponentView.SetNotificationHeader("Private message");
 1289            chatNotificationComponentView.SetNotificationSender($"{model.Username}:");
 1290            chatNotificationComponentView.SetNotificationTargetId(model.SenderId);
 1291            if (!string.IsNullOrEmpty(model.ProfilePicture))
 0292                chatNotificationComponentView.SetImage(model.ProfilePicture);
 1293        }
 294
 295        private void PopulatePublicNotification(ChatNotificationMessageComponentView chatNotificationComponentView,
 296            PublicChannelMessageNotificationModel model)
 297        {
 2298            chatNotificationComponentView.SetIsPrivate(false);
 2299            chatNotificationComponentView.SetMessage(model.Body);
 300
 2301            var channelId = model.ChannelId;
 2302            var channelName = model.ChannelName == "nearby" ? "~nearby" : $"#{model.ChannelName}";
 303
 2304            chatNotificationComponentView.SetNotificationTargetId(channelId);
 2305            chatNotificationComponentView.SetNotificationHeader(channelName);
 2306            chatNotificationComponentView.SetNotificationSender($"{model.Username}:");
 2307        }
 308
 309        private void ClickedOnNotification(string targetId)
 310        {
 0311            OnClickedChatMessage?.Invoke(targetId);
 0312        }
 313
 314        private void PopulateFriendRequestNotification(FriendRequestNotificationComponentView friendRequestNotificationC
 315            FriendRequestNotificationModel model)
 316        {
 0317            friendRequestNotificationComponentView.SetFriendRequestId(model.FriendRequestId);
 0318            friendRequestNotificationComponentView.SetUser(model.UserId, model.UserName);
 0319            friendRequestNotificationComponentView.SetHeader(model.Header);
 0320            friendRequestNotificationComponentView.SetMessage(model.Message);
 0321            friendRequestNotificationComponentView.SetTimestamp(Utils.UnixTimeStampToLocalTime(model.Timestamp));
 0322            friendRequestNotificationComponentView.SetIsAccepted(model.IsAccepted);
 0323        }
 324
 325        private void ClickedOnFriendRequest(string friendRequestId, string userId, bool isAcceptedFromPeer) =>
 0326            OnClickedFriendRequest?.Invoke(friendRequestId, userId, isAcceptedFromPeer);
 327
 328        private void FocusedOnNotification(bool isInFocus)
 329        {
 3330            isOverMessage = isInFocus;
 3331            OnResetFade?.Invoke(!isOverMessage && !isOverPanel);
 0332        }
 333
 334        private void FocusedOnPanel(bool isInFocus)
 335        {
 6336            isOverPanel = isInFocus;
 6337            OnPanelFocus?.Invoke(isOverPanel);
 6338            OnResetFade?.Invoke(!isOverMessage && !isOverPanel);
 0339        }
 340
 341        private void CheckNotificationCountAndRelease()
 342        {
 3343            if (poolableQueue.Count >= MAX_NOTIFICATION_ENTRIES)
 344            {
 0345                BaseComponentView notificationToDequeue = notificationQueue.Dequeue();
 0346                notificationToDequeue.onFocused -= FocusedOnNotification;
 0347                entryPool.Release(poolableQueue.Dequeue());
 348            }
 3349        }
 350
 351        private Pool GetNotificationEntryPool()
 352        {
 3353            var entryPool = PoolManager.i.GetPool(NOTIFICATION_POOL_NAME_PREFIX + name + GetInstanceID());
 3354            if (entryPool != null) return entryPool;
 355
 3356            entryPool = PoolManager.i.AddPool(
 357                NOTIFICATION_POOL_NAME_PREFIX + name + GetInstanceID(),
 358                Instantiate(chatNotification).gameObject,
 359                maxPrewarmCount: MAX_NOTIFICATION_ENTRIES,
 360                isPersistent: true);
 3361            entryPool.ForcePrewarm();
 362
 3363            return entryPool;
 364        }
 365
 366        private Pool GetFriendRequestNotificationEntryPool()
 367        {
 0368            var entryPool = PoolManager.i.GetPool(FRINED_REQUEST_NOTIFICATION_POOL_NAME_PREFIX + name + GetInstanceID())
 0369            if (entryPool != null)
 0370                return entryPool;
 371
 0372            entryPool = PoolManager.i.AddPool(
 373                FRINED_REQUEST_NOTIFICATION_POOL_NAME_PREFIX + name + GetInstanceID(),
 374                Instantiate(friendRequestNotification).gameObject,
 375                maxPrewarmCount: MAX_NOTIFICATION_ENTRIES,
 376                isPersistent: true);
 0377            entryPool.ForcePrewarm();
 378
 0379            return entryPool;
 380        }
 381
 382        public override void RefreshControl()
 383        {
 0384        }
 385    }
 386}