< Summary

Class:UserContextMenu
Assembly:UserContextMenu
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/UserContextMenu/Scripts/UserContextMenu.cs
Covered lines:111
Uncovered lines:56
Coverable lines:167
Total lines:438
Line coverage:66.4% (111 of 167)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
UserContextMenu()0%110100%
Show(...)0%110100%
Show(...)0%4.034087.5%
SetConfirmationDialog(...)0%2100%
Hide()0%2.062075%
SetFriendshipContentActive(...)0%110100%
Awake()0%220100%
Update()0%2100%
OnDisable()0%110100%
OnPassportButtonPressed()0%220100%
OnReportUserButtonPressed()0%440100%
OnDeleteUserButtonPressed()0%12300%
OnAddFriendButtonPressed()0%20400%
OnCancelFriendRequestButtonPressed()0%2100%
CancelFriendRequestAsync()0%56700%
OnMessageButtonPressed()0%6200%
OnBlockUserButtonPressed()0%6.325062.5%
UpdateBlockButton()0%330100%
HideIfClickedOutside()0%12300%
ProcessActiveElements(...)0%330100%
Setup(...)0%12120100%
SetupFriendship(...)0%17.6915077.14%
OnFriendActionUpdate(...)0%7.077088.89%
GetSocialAnalytics()0%2.152066.67%
OnValidate()0%2.062075%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/UserContextMenu/Scripts/UserContextMenu.cs

#LineLine coverage
 1using Cysharp.Threading.Tasks;
 2using DCL;
 3using DCL.Interface;
 4using DCL.Social.Friends;
 5using DCL.Tasks;
 6using SocialFeaturesAnalytics;
 7using System;
 8using System.Collections.Generic;
 9using System.Linq;
 10using System.Threading;
 11using TMPro;
 12using UnityEngine;
 13using UnityEngine.EventSystems;
 14using UnityEngine.UI;
 15using Environment = DCL.Environment;
 16
 17/// <summary>
 18/// Contextual menu with different options about an user.
 19/// </summary>
 20[RequireComponent(typeof(RectTransform))]
 21// TODO: refactor into MVC
 22public class UserContextMenu : MonoBehaviour
 23{
 24    private const string CURRENT_PLAYER_ID = "CurrentPlayerInfoCardId";
 25    private const string BLOCK_BTN_BLOCK_TEXT = "Block";
 26    private const string BLOCK_BTN_UNBLOCK_TEXT = "Unblock";
 27    private const string DELETE_MSG_PATTERN = "Are you sure you want to delete {0} as a friend?";
 28
 29    [Flags]
 30    public enum MenuConfigFlags
 31    {
 32        Name = 1,
 33        Friendship = 2,
 34        Message = 4,
 35        Passport = 8,
 36        Block = 16,
 37        Report = 32
 38    }
 39
 40    const MenuConfigFlags headerFlags = MenuConfigFlags.Name | MenuConfigFlags.Friendship;
 41    const MenuConfigFlags usesFriendsApiFlags = MenuConfigFlags.Friendship | MenuConfigFlags.Message;
 42
 43    [Header("Optional: Set Confirmation Dialog")]
 44    [SerializeField] internal UserContextConfirmationDialog confirmationDialog;
 45
 46    [Header("Enable Actions")]
 23147    [SerializeField] internal MenuConfigFlags menuConfigFlags = MenuConfigFlags.Passport | MenuConfigFlags.Block | MenuC
 48
 49    [Header("Containers")]
 50    [SerializeField] internal GameObject headerContainer;
 51    [SerializeField] internal GameObject friendshipContainer;
 52    [SerializeField] internal GameObject friendAddContainer;
 53    [SerializeField] internal GameObject friendRemoveContainer;
 54    [SerializeField] internal GameObject friendRequestedContainer;
 55
 56    [Header("Texts")]
 57    [SerializeField] internal TextMeshProUGUI userName;
 58    [SerializeField] internal TextMeshProUGUI blockText;
 59
 60    [Header("Buttons")]
 61    [SerializeField] internal Button passportButton;
 62    [SerializeField] internal Button blockButton;
 63    [SerializeField] internal Button reportButton;
 64    [SerializeField] internal Button addFriendButton;
 65    [SerializeField] internal Button cancelFriendButton;
 66    [SerializeField] internal Button deleteFriendButton;
 67    [SerializeField] internal Button messageButton;
 68
 69    public static event Action<string> OnOpenPrivateChatRequest;
 70
 2371    public bool isVisible => gameObject.activeSelf;
 072    public string UserId => userId;
 73
 74    public event Action OnShowMenu;
 75    public event Action<string> OnPassport;
 76    public event Action<string> OnReport;
 77    public event Action<string, bool> OnBlock;
 78    public event Action<string> OnUnfriend;
 79    public event Action OnHide;
 80
 81    private static StringVariable currentPlayerId;
 82    private string userId;
 83    private bool isBlocked;
 84    private MenuConfigFlags currentConfigFlags;
 85    private IConfirmationDialog currentConfirmationDialog;
 23186    private CancellationTokenSource friendOperationsCancellationToken = new ();
 087    private bool isNewFriendRequestsEnabled => DataStore.i.featureFlags.flags.Get().IsFeatureEnabled("new_friend_request
 8288    private bool isFriendsEnabled => DataStore.i.featureFlags.flags.Get().IsFeatureEnabled("friends_enabled");
 89    internal ISocialAnalytics socialAnalytics;
 90
 91    /// <summary>
 92    /// Show context menu
 93    /// </summary>
 94    /// <param name="userId"> user id</param>
 95    public void Show(string userId)
 96    {
 597        Show(userId, menuConfigFlags);
 598    }
 99
 100    /// <summary>
 101    /// Show context menu
 102    /// </summary>
 103    /// <param name="userId"> user id</param>
 104    /// <param name="configFlags">set buttons to enable in menu</param>
 105    public void Show(string userId, MenuConfigFlags configFlags)
 106    {
 7107        this.userId = userId;
 7108        ProcessActiveElements(configFlags);
 7109        Setup(userId, configFlags);
 110
 7111        if (currentConfirmationDialog == null && confirmationDialog != null) { SetConfirmationDialog(confirmationDialog)
 112
 7113        gameObject.SetActive(true);
 7114        OnShowMenu?.Invoke();
 1115    }
 116
 117    /// <summary>
 118    /// Set confirmation popup to reference use
 119    /// </summary>
 120    /// <param name="confirmationPopup">confirmation popup reference</param>
 121    public void SetConfirmationDialog(IConfirmationDialog confirmationPopup)
 122    {
 0123        this.currentConfirmationDialog = confirmationPopup;
 0124    }
 125
 126    /// <summary>
 127    /// Hides the context menu.
 128    /// </summary>
 129    public void Hide()
 130    {
 20131        friendOperationsCancellationToken = friendOperationsCancellationToken.SafeRestart();
 20132        gameObject.SetActive(false);
 20133        OnHide?.Invoke();
 0134    }
 135
 136    /// <summary>
 137    /// Shows/Hides the friendship container
 138    /// </summary>
 139    public void SetFriendshipContentActive(bool isActive) =>
 2140        friendshipContainer.SetActive(isActive);
 141
 142    private void Awake()
 143    {
 10144        if (!currentPlayerId)
 1145            currentPlayerId = Resources.Load<StringVariable>(CURRENT_PLAYER_ID);
 146
 10147        passportButton.onClick.AddListener(OnPassportButtonPressed);
 10148        blockButton.onClick.AddListener(OnBlockUserButtonPressed);
 10149        reportButton.onClick.AddListener(OnReportUserButtonPressed);
 10150        deleteFriendButton.onClick.AddListener(OnDeleteUserButtonPressed);
 10151        addFriendButton.onClick.AddListener(OnAddFriendButtonPressed);
 10152        cancelFriendButton.onClick.AddListener(OnCancelFriendRequestButtonPressed);
 10153        messageButton.onClick.AddListener(OnMessageButtonPressed);
 10154    }
 155
 156    private void Update()
 157    {
 0158        HideIfClickedOutside();
 0159    }
 160
 161    private void OnDisable()
 162    {
 10163        FriendsController.i.OnUpdateFriendship -= OnFriendActionUpdate;
 10164    }
 165
 166    private void OnPassportButtonPressed()
 167    {
 1168        OnPassport?.Invoke(userId);
 1169        currentPlayerId.Set(userId);
 1170        Hide();
 171
 1172        AudioScriptableObjects.dialogOpen.Play(true);
 1173    }
 174
 175    private void OnReportUserButtonPressed()
 176    {
 1177        OnReport?.Invoke(userId);
 1178        WebInterface.SendReportPlayer(userId, UserProfileController.userProfilesCatalog.Get(userId)?.userName);
 1179        GetSocialAnalytics().SendPlayerReport(PlayerReportIssueType.None, 0, PlayerActionSource.ProfileContextMenu);
 1180        Hide();
 1181    }
 182
 183    private void OnDeleteUserButtonPressed()
 184    {
 0185        DataStore.i.notifications.GenericConfirmation.Set(GenericConfirmationNotificationData.CreateUnFriendData(
 186            UserProfileController.userProfilesCatalog.Get(userId)?.userName,
 187            () =>
 188            {
 0189                FriendsController.i.RemoveFriend(userId);
 0190                OnUnfriend?.Invoke(userId);
 0191            }), true);
 192
 0193        GetSocialAnalytics().SendFriendDeleted(UserProfile.GetOwnUserProfile().userId, userId, PlayerActionSource.Profil
 0194        Hide();
 0195    }
 196
 197    private void OnAddFriendButtonPressed()
 198    {
 199        // NOTE: if we don't add this, the friend request has strange behaviors
 0200        UserProfileController.i.AddUserProfileToCatalog(new UserProfileModel()
 201        {
 202            userId = userId,
 203            name = UserProfileController.userProfilesCatalog.Get(userId)?.userName
 204        });
 205
 0206        if (isNewFriendRequestsEnabled)
 207        {
 0208            DataStore.i.HUDs.sendFriendRequest.Set(userId, true);
 0209            DataStore.i.HUDs.sendFriendRequestSource.Set((int)PlayerActionSource.ProfileContextMenu);
 210        }
 211        else
 212        {
 0213            FriendsController.i.RequestFriendship(userId);
 0214            GetSocialAnalytics().SendFriendRequestSent(UserProfile.GetOwnUserProfile().userId, userId, 0, PlayerActionSo
 215        }
 0216    }
 217
 218    private void OnCancelFriendRequestButtonPressed()
 219    {
 0220        friendOperationsCancellationToken = friendOperationsCancellationToken.SafeRestart();
 0221        CancelFriendRequestAsync(userId, friendOperationsCancellationToken.Token).Forget();
 0222    }
 223
 224    private async UniTaskVoid CancelFriendRequestAsync(string userId, CancellationToken cancellationToken = default)
 225    {
 0226        if (isNewFriendRequestsEnabled)
 227        {
 228            try
 229            {
 0230                FriendRequest request = await FriendsController.i.CancelRequestByUserIdAsync(userId, cancellationToken);
 231
 0232                GetSocialAnalytics()
 233                   .SendFriendRequestCancelled(request.From, request.To,
 234                        PlayerActionSource.ProfileContextMenu.ToString());
 0235            }
 0236            catch (Exception e) when (e is not OperationCanceledException)
 237            {
 0238                e.ReportFriendRequestErrorToAnalyticsByUserId(userId, PlayerActionSource.ProfileContextMenu.ToString(),
 239                    FriendsController.i, socialAnalytics);
 240
 0241                throw;
 242            }
 243        }
 244        else
 245        {
 0246            FriendsController.i.CancelRequestByUserId(userId);
 247
 0248            GetSocialAnalytics()
 249               .SendFriendRequestCancelled(UserProfile.GetOwnUserProfile().userId, userId,
 250                    PlayerActionSource.ProfileContextMenu.ToString());
 251        }
 0252    }
 253
 254    private void OnMessageButtonPressed()
 255    {
 0256        OnOpenPrivateChatRequest?.Invoke(userId);
 0257        Hide();
 0258    }
 259
 260    private void OnBlockUserButtonPressed()
 261    {
 1262        bool blockUser = !isBlocked;
 263
 1264        if (blockUser)
 265        {
 1266            DataStore.i.notifications.GenericConfirmation.Set(GenericConfirmationNotificationData.CreateBlockUserData(
 267                UserProfileController.userProfilesCatalog.Get(userId)?.userName,
 268                () =>
 269                {
 1270                    WebInterface.SendBlockPlayer(userId);
 1271                    GetSocialAnalytics().SendPlayerBlocked(FriendsController.i.IsFriend(userId), PlayerActionSource.Prof
 1272                    OnBlock?.Invoke(userId, blockUser);
 1273                }), true);
 274        }
 275        else
 276        {
 0277            WebInterface.SendUnblockPlayer(userId);
 0278            GetSocialAnalytics().SendPlayerUnblocked(FriendsController.i.IsFriend(userId), PlayerActionSource.ProfileCon
 0279            OnBlock?.Invoke(userId, blockUser);
 280        }
 281
 1282        Hide();
 1283    }
 284
 285    private void UpdateBlockButton()
 286    {
 5287        blockText.text = isBlocked ? BLOCK_BTN_UNBLOCK_TEXT : BLOCK_BTN_BLOCK_TEXT;
 5288    }
 289
 290    private void HideIfClickedOutside()
 291    {
 0292        if (!Input.GetMouseButtonDown(0)) return;
 293
 0294        var pointerEventData = new PointerEventData(EventSystem.current)
 295        {
 296            position = Input.mousePosition
 297        };
 298
 0299        var raycastResults = new List<RaycastResult>();
 0300        EventSystem.current.RaycastAll(pointerEventData, raycastResults);
 301
 0302        if (raycastResults.All(result => result.gameObject != gameObject))
 0303            Hide();
 0304    }
 305
 306    private void ProcessActiveElements(MenuConfigFlags flags)
 307    {
 38308        headerContainer.SetActive((flags & headerFlags) != 0);
 38309        userName.gameObject.SetActive((flags & MenuConfigFlags.Name) != 0);
 38310        friendshipContainer.SetActive((flags & MenuConfigFlags.Friendship) != 0 && isFriendsEnabled);
 38311        deleteFriendButton.gameObject.SetActive((flags & MenuConfigFlags.Friendship) != 0 && isFriendsEnabled);
 38312        passportButton.gameObject.SetActive((flags & MenuConfigFlags.Passport) != 0);
 38313        blockButton.gameObject.SetActive((flags & MenuConfigFlags.Block) != 0);
 38314        reportButton.gameObject.SetActive((flags & MenuConfigFlags.Report) != 0);
 38315        messageButton.gameObject.SetActive((flags & MenuConfigFlags.Message) != 0);
 38316    }
 317
 318    private void Setup(string userId, MenuConfigFlags configFlags)
 319    {
 7320        this.userId = userId;
 321
 7322        UserProfile profile = UserProfileController.userProfilesCatalog.Get(userId);
 7323        bool userHasWallet = profile?.hasConnectedWeb3 ?? false;
 324
 8325        if (!userHasWallet || !UserProfile.GetOwnUserProfile().hasConnectedWeb3) { configFlags &= ~usesFriendsApiFlags; 
 326
 7327        currentConfigFlags = configFlags;
 7328        ProcessActiveElements(configFlags);
 329
 7330        if ((configFlags & MenuConfigFlags.Block) != 0)
 331        {
 5332            isBlocked = UserProfile.GetOwnUserProfile().blocked.Contains(userId);
 5333            UpdateBlockButton();
 334        }
 335
 7336        if ((configFlags & MenuConfigFlags.Name) != 0)
 337        {
 5338            string name = profile?.userName;
 5339            userName.text = name;
 340        }
 341
 7342        if ((configFlags & usesFriendsApiFlags) != 0)
 343        {
 6344            UserStatus status = FriendsController.i.GetUserStatus(userId);
 6345            SetupFriendship(status?.friendshipStatus ?? FriendshipStatus.NOT_FRIEND);
 6346            FriendsController.i.OnUpdateFriendship -= OnFriendActionUpdate;
 6347            FriendsController.i.OnUpdateFriendship += OnFriendActionUpdate;
 348        }
 7349    }
 350
 351    private void SetupFriendship(FriendshipStatus friendshipStatus)
 352    {
 12353        bool friendshipEnabled = (currentConfigFlags & MenuConfigFlags.Friendship) != 0 && isFriendsEnabled;
 12354        bool messageEnabled = (currentConfigFlags & MenuConfigFlags.Message) != 0 && isFriendsEnabled;
 355
 12356        if (friendshipStatus == FriendshipStatus.FRIEND)
 357        {
 2358            if (friendshipEnabled)
 359            {
 1360                friendAddContainer.SetActive(false);
 1361                friendRemoveContainer.SetActive(true);
 1362                friendRequestedContainer.SetActive(false);
 1363                deleteFriendButton.gameObject.SetActive(true);
 364            }
 365
 3366            if (messageEnabled) { messageButton.gameObject.SetActive(true); }
 367        }
 10368        else if (friendshipStatus == FriendshipStatus.REQUESTED_TO)
 369        {
 2370            if (friendshipEnabled)
 371            {
 1372                friendAddContainer.SetActive(false);
 1373                friendRemoveContainer.SetActive(false);
 1374                friendRequestedContainer.SetActive(true);
 1375                deleteFriendButton.gameObject.SetActive(false);
 376            }
 377
 3378            if (messageEnabled) { messageButton.gameObject.SetActive(false); }
 379        }
 8380        else if (friendshipStatus == FriendshipStatus.NOT_FRIEND)
 381        {
 8382            if (friendshipEnabled)
 383            {
 6384                friendAddContainer.SetActive(true);
 6385                friendRemoveContainer.SetActive(false);
 6386                friendRequestedContainer.SetActive(false);
 6387                deleteFriendButton.gameObject.SetActive(false);
 388            }
 389
 14390            if (messageEnabled) { messageButton.gameObject.SetActive(false); }
 391        }
 0392        else if (friendshipStatus == FriendshipStatus.REQUESTED_FROM)
 393        {
 0394            if (friendshipEnabled)
 395            {
 0396                friendAddContainer.SetActive(true);
 0397                friendRemoveContainer.SetActive(false);
 0398                friendRequestedContainer.SetActive(false);
 0399                deleteFriendButton.gameObject.SetActive(false);
 400            }
 401
 0402            if (messageEnabled) { messageButton.gameObject.SetActive(false); }
 403        }
 4404    }
 405
 406    private void OnFriendActionUpdate(string userId, FriendshipAction action)
 407    {
 6408        if (this.userId != userId) { return; }
 409
 8410        if (action == FriendshipAction.APPROVED) { SetupFriendship(FriendshipStatus.FRIEND); }
 6411        else if (action == FriendshipAction.REQUESTED_TO) { SetupFriendship(FriendshipStatus.REQUESTED_TO); }
 4412        else if (action == FriendshipAction.DELETED || action == FriendshipAction.CANCELLED || action == FriendshipActio
 2413    }
 414
 415    private ISocialAnalytics GetSocialAnalytics()
 416    {
 2417        if (socialAnalytics == null)
 418        {
 0419            socialAnalytics = new SocialAnalytics(
 420                Environment.i.platform.serviceProviders.analytics,
 421                new UserProfileWebInterfaceBridge());
 422        }
 423
 2424        return socialAnalytics;
 425    }
 426
 427#if UNITY_EDITOR
 428
 429    //This is just to process buttons and container visibility on editor
 430    private void OnValidate()
 431    {
 24432        if (headerContainer == null)
 0433            return;
 434
 24435        ProcessActiveElements(menuConfigFlags);
 24436    }
 437#endif
 438}