< Summary

Class:FriendsHUDController
Assembly:FriendsHUD
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/FriendsHUD/Scripts/FriendsHUDController.cs
Covered lines:236
Uncovered lines:33
Coverable lines:269
Total lines:516
Line coverage:87.7% (236 of 269)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
FriendsHUDController(...)0%110100%
Initialize(...)0%550100%
SetVisiblePanelList(...)0%220100%
Dispose()0%770100%
SetVisibility(...)0%7.297081.82%
HandleViewClosed()0%6200%
HandleFriendsInitialized()0%9.166055.56%
HandleProfileUpdated(...)0%110100%
UpdateBlockStatus()0%13.2111073.68%
HandleRequestSent(...)0%330100%
AreAlreadyFriends(...)0%330100%
HandleUserStatusUpdated(...)0%110100%
UpdateUserStatus(...)0%9.179087.1%
HandleFriendshipUpdated(...)0%9.029093.94%
HandleFriendProfileUpdated(...)0%3.13077.78%
IsUserBlocked(...)0%3.333066.67%
OnFriendNotFound(...)0%110100%
UpdateNotificationsCounter()0%220100%
HandleOpenWhisperChat(...)0%220100%
HandleUnfriend(...)0%2100%
HandleRequestRejected(...)0%6200%
HandleRequestCancelled(...)0%6200%
HandleRequestAccepted(...)0%6200%
DisplayFriendsIfAnyIsLoaded()0%3.333066.67%
DisplayMoreFriends()0%220100%
DisplayMoreFriendRequests()0%3.143075%
DisplayFriendRequestsIfAnyIsLoaded()0%3.333066.67%
ShowOrHideMoreFriendRequestsToLoadHint()0%220100%
ShowOrHideMoreFriendsToLoadHint()0%330100%
SearchFriends(...)0%220100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/FriendsHUD/Scripts/FriendsHUDController.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using Cysharp.Threading.Tasks;
 4using DCL;
 5using SocialFeaturesAnalytics;
 6using UnityEngine;
 7
 8public class FriendsHUDController : IHUD
 9{
 10    private const int LOAD_FRIENDS_ON_DEMAND_COUNT = 30;
 11    private const int MAX_SEARCHED_FRIENDS = 100;
 12
 4513    private readonly Dictionary<string, FriendEntryModel> friends = new Dictionary<string, FriendEntryModel>();
 4514    private readonly Dictionary<string, FriendEntryModel> onlineFriends = new Dictionary<string, FriendEntryModel>();
 15    private readonly DataStore dataStore;
 16    private readonly IFriendsController friendsController;
 17    private readonly IUserProfileBridge userProfileBridge;
 18    private readonly ISocialAnalytics socialAnalytics;
 19    private readonly IChatController chatController;
 20    private readonly IMouseCatcher mouseCatcher;
 3821    private BaseVariable<HashSet<string>> visibleTaskbarPanels => dataStore.HUDs.visibleTaskbarPanels;
 22
 23    private UserProfile ownUserProfile;
 24    private bool searchingFriends;
 25    private int lastSkipForFriends;
 26    private int lastSkipForFriendRequests;
 27
 028    public IFriendsHUDComponentView View { get; private set; }
 29
 30    public event Action<string> OnPressWhisper;
 31    public event Action OnOpened;
 32    public event Action OnClosed;
 33    public event Action OnViewClosed;
 34
 4535    public FriendsHUDController(DataStore dataStore,
 36        IFriendsController friendsController,
 37        IUserProfileBridge userProfileBridge,
 38        ISocialAnalytics socialAnalytics,
 39        IChatController chatController,
 40        IMouseCatcher mouseCatcher)
 41    {
 4542        this.dataStore = dataStore;
 4543        this.friendsController = friendsController;
 4544        this.userProfileBridge = userProfileBridge;
 4545        this.socialAnalytics = socialAnalytics;
 4546        this.chatController = chatController;
 4547        this.mouseCatcher = mouseCatcher;
 4548    }
 49
 50    public void Initialize(IFriendsHUDComponentView view = null)
 51    {
 4552        view ??= FriendsHUDComponentView.Create();
 4553        View = view;
 54
 4555        view.Initialize(chatController, friendsController, socialAnalytics);
 4556        view.RefreshFriendsTab();
 4557        view.OnFriendRequestApproved += HandleRequestAccepted;
 4558        view.OnCancelConfirmation += HandleRequestCancelled;
 4559        view.OnRejectConfirmation += HandleRequestRejected;
 4560        view.OnFriendRequestSent += HandleRequestSent;
 4561        view.OnWhisper += HandleOpenWhisperChat;
 4562        view.OnClose += HandleViewClosed;
 4563        view.OnRequireMoreFriends += DisplayMoreFriends;
 4564        view.OnRequireMoreFriendRequests += DisplayMoreFriendRequests;
 4565        view.OnSearchFriendsRequested += SearchFriends;
 4566        view.OnFriendListDisplayed += DisplayFriendsIfAnyIsLoaded;
 4567        view.OnRequestListDisplayed += DisplayFriendRequestsIfAnyIsLoaded;
 68
 4569        if(mouseCatcher != null)
 4570            mouseCatcher.OnMouseLock += HandleViewClosed;
 71
 4572        ownUserProfile = userProfileBridge.GetOwn();
 4573        ownUserProfile.OnUpdate -= HandleProfileUpdated;
 4574        ownUserProfile.OnUpdate += HandleProfileUpdated;
 75
 4576        if (friendsController != null)
 77        {
 4578            friendsController.OnUpdateFriendship += HandleFriendshipUpdated;
 4579            friendsController.OnUpdateUserStatus += HandleUserStatusUpdated;
 4580            friendsController.OnFriendNotFound += OnFriendNotFound;
 81
 4582            if (friendsController.IsInitialized)
 83            {
 284                view.HideLoadingSpinner();
 285            }
 86            else
 87            {
 4388                view.ShowLoadingSpinner();
 4389                friendsController.OnInitialized -= HandleFriendsInitialized;
 4390                friendsController.OnInitialized += HandleFriendsInitialized;
 91            }
 92        }
 93
 4594        ShowOrHideMoreFriendsToLoadHint();
 4595        ShowOrHideMoreFriendRequestsToLoadHint();
 4596    }
 97
 98    private void SetVisiblePanelList(bool visible)
 99    {
 19100        HashSet<string> newSet = visibleTaskbarPanels.Get();
 19101        if (visible)
 15102            newSet.Add("FriendsPanel");
 103        else
 4104            newSet.Remove("FriendsPanel");
 105
 19106        visibleTaskbarPanels.Set(newSet, true);
 19107    }
 108
 109    public void Dispose()
 110    {
 46111        if (friendsController != null)
 112        {
 46113            friendsController.OnInitialized -= HandleFriendsInitialized;
 46114            friendsController.OnUpdateFriendship -= HandleFriendshipUpdated;
 46115            friendsController.OnUpdateUserStatus -= HandleUserStatusUpdated;
 116        }
 117
 46118        if (View != null)
 119        {
 46120            View.OnFriendRequestApproved -= HandleRequestAccepted;
 46121            View.OnCancelConfirmation -= HandleRequestCancelled;
 46122            View.OnRejectConfirmation -= HandleRequestRejected;
 46123            View.OnFriendRequestSent -= HandleRequestSent;
 46124            View.OnWhisper -= HandleOpenWhisperChat;
 46125            View.OnDeleteConfirmation -= HandleUnfriend;
 46126            View.OnClose -= HandleViewClosed;
 46127            View.OnRequireMoreFriends -= DisplayMoreFriends;
 46128            View.OnRequireMoreFriendRequests -= DisplayMoreFriendRequests;
 46129            View.OnSearchFriendsRequested -= SearchFriends;
 46130            View.OnFriendListDisplayed -= DisplayFriendsIfAnyIsLoaded;
 46131            View.OnRequestListDisplayed -= DisplayFriendRequestsIfAnyIsLoaded;
 46132            View.Dispose();
 133        }
 134
 46135        if (ownUserProfile != null)
 46136            ownUserProfile.OnUpdate -= HandleProfileUpdated;
 137
 46138        if (userProfileBridge != null)
 139        {
 128140            foreach (var friendId in friends.Keys)
 141            {
 18142                var profile = userProfileBridge.Get(friendId);
 18143                if (profile == null) continue;
 16144                profile.OnUpdate -= HandleFriendProfileUpdated;
 145            }
 146        }
 46147    }
 148
 149    public void SetVisibility(bool visible)
 150    {
 19151        SetVisiblePanelList(visible);
 19152        if (visible)
 153        {
 15154            lastSkipForFriends = 0;
 15155            lastSkipForFriendRequests = 0;
 15156            View.ClearAll();
 15157            View.Show();
 15158            UpdateNotificationsCounter();
 159
 30160            foreach (var friend in onlineFriends)
 0161                View.Set(friend.Key, friend.Value);
 162
 15163            if (View.IsFriendListActive)
 7164                DisplayMoreFriends();
 8165            else if (View.IsRequestListActive)
 5166                DisplayMoreFriendRequests();
 167
 15168            OnOpened?.Invoke();
 0169        }
 170        else
 171        {
 4172            View.Hide();
 4173            View.DisableSearchMode();
 4174            searchingFriends = false;
 4175            OnClosed?.Invoke();
 176        }
 0177    }
 178
 179    private void HandleViewClosed()
 180    {
 0181        OnViewClosed?.Invoke();
 0182        SetVisibility(false);
 0183    }
 184
 185    private void HandleFriendsInitialized()
 186    {
 1187        friendsController.OnInitialized -= HandleFriendsInitialized;
 1188        View.HideLoadingSpinner();
 189
 1190        if (View.IsActive())
 191        {
 0192            if (View.IsFriendListActive && lastSkipForFriends <= 0)
 0193                DisplayMoreFriends();
 0194            else if (View.IsRequestListActive && lastSkipForFriendRequests <= 0)
 0195                DisplayMoreFriendRequests();
 196        }
 197
 1198        UpdateNotificationsCounter();
 1199    }
 200
 2201    private void HandleProfileUpdated(UserProfile profile) => UpdateBlockStatus(profile).Forget();
 202
 203    private async UniTask UpdateBlockStatus(UserProfile profile)
 204    {
 205        const int iterationsPerFrame = 10;
 206
 207        //NOTE(Brian): HashSet to check Contains quicker.
 2208        var allBlockedUsers = profile.blocked != null
 209            ? new HashSet<string>(profile.blocked)
 210            : new HashSet<string>();
 211
 2212        var iterations = 0;
 213
 8214        foreach (var friendPair in friends)
 215        {
 2216            var friendId = friendPair.Key;
 2217            var model = friendPair.Value;
 218
 2219            model.blocked = allBlockedUsers.Contains(friendId);
 2220            await UniTask.SwitchToMainThread();
 2221            View.UpdateBlockStatus(friendId, model.blocked);
 222
 2223            iterations++;
 2224            if (iterations > 0 && iterations % iterationsPerFrame == 0)
 0225                await UniTask.NextFrame();
 2226        }
 2227    }
 228
 229    private void HandleRequestSent(string userNameOrId)
 230    {
 3231        if (AreAlreadyFriends(userNameOrId))
 232        {
 1233            View.ShowRequestSendError(FriendRequestError.AlreadyFriends);
 1234        }
 235        else
 236        {
 2237            friendsController.RequestFriendship(userNameOrId);
 238
 2239            if (ownUserProfile != null)
 2240                socialAnalytics.SendFriendRequestSent(ownUserProfile.userId, userNameOrId, 0,
 241                    PlayerActionSource.FriendsHUD);
 242
 2243            View.ShowRequestSendSuccess();
 244        }
 2245    }
 246
 247    private bool AreAlreadyFriends(string userNameOrId)
 248    {
 3249        var userId = userNameOrId;
 3250        var profile = userProfileBridge.GetByName(userNameOrId);
 251
 3252        if (profile != default)
 1253            userId = profile.userId;
 254
 3255        return friendsController != null
 256               && friendsController.ContainsStatus(userId, FriendshipStatus.FRIEND);
 257    }
 258
 259    private void HandleUserStatusUpdated(string userId, UserStatus status) =>
 6260        UpdateUserStatus(userId, status);
 261
 262    private void UpdateUserStatus(string userId, UserStatus status)
 263    {
 7264        switch (status.friendshipStatus)
 265        {
 266            case FriendshipStatus.FRIEND:
 3267                var friend = friends.ContainsKey(userId)
 268                    ? new FriendEntryModel(friends[userId])
 269                    : new FriendEntryModel();
 3270                friend.CopyFrom(status);
 3271                friend.blocked = IsUserBlocked(userId);
 3272                friends[userId] = friend;
 3273                View.Set(userId, friend);
 274
 3275                if (status.presence == PresenceStatus.ONLINE)
 2276                    onlineFriends[userId] = friend;
 277                else
 1278                    onlineFriends.Remove(userId);
 279
 1280                break;
 281            case FriendshipStatus.NOT_FRIEND:
 0282                View.Remove(userId);
 0283                friends.Remove(userId);
 0284                onlineFriends.Remove(userId);
 0285                break;
 286            case FriendshipStatus.REQUESTED_TO:
 2287                var sentRequest = friends.ContainsKey(userId)
 288                    ? new FriendRequestEntryModel(friends[userId], false)
 289                    : new FriendRequestEntryModel {isReceived = false};
 2290                sentRequest.CopyFrom(status);
 2291                sentRequest.blocked = IsUserBlocked(userId);
 2292                friends[userId] = sentRequest;
 2293                onlineFriends.Remove(userId);
 2294                View.Set(userId, sentRequest);
 2295                break;
 296            case FriendshipStatus.REQUESTED_FROM:
 2297                var receivedRequest = friends.ContainsKey(userId)
 298                    ? new FriendRequestEntryModel(friends[userId], true)
 299                    : new FriendRequestEntryModel {isReceived = true};
 2300                receivedRequest.CopyFrom(status);
 2301                receivedRequest.blocked = IsUserBlocked(userId);
 2302                friends[userId] = receivedRequest;
 2303                onlineFriends.Remove(userId);
 2304                View.Set(userId, receivedRequest);
 305                break;
 306        }
 307
 7308        UpdateNotificationsCounter();
 7309        ShowOrHideMoreFriendsToLoadHint();
 7310        ShowOrHideMoreFriendRequestsToLoadHint();
 7311    }
 312
 313    private void HandleFriendshipUpdated(string userId, FriendshipAction friendshipAction)
 314    {
 15315        var userProfile = userProfileBridge.Get(userId);
 316
 15317        if (userProfile == null)
 318        {
 0319            Debug.LogError($"UserProfile is null for {userId}! ... friendshipAction {friendshipAction}");
 0320            return;
 321        }
 322
 15323        userProfile.OnUpdate -= HandleFriendProfileUpdated;
 324
 325        switch (friendshipAction)
 326        {
 327            case FriendshipAction.NONE:
 328            case FriendshipAction.REJECTED:
 329            case FriendshipAction.CANCELLED:
 330            case FriendshipAction.DELETED:
 3331                friends.Remove(userId);
 3332                View.Remove(userId);
 3333                onlineFriends.Remove(userId);
 3334                break;
 335            case FriendshipAction.APPROVED:
 7336                var approved = friends.ContainsKey(userId)
 337                    ? new FriendEntryModel(friends[userId])
 338                    : new FriendEntryModel();
 7339                approved.CopyFrom(userProfile);
 7340                approved.blocked = IsUserBlocked(userId);
 7341                friends[userId] = approved;
 7342                View.Set(userId, approved);
 7343                userProfile.OnUpdate += HandleFriendProfileUpdated;
 7344                break;
 345            case FriendshipAction.REQUESTED_FROM:
 2346                var requestReceived = friends.ContainsKey(userId)
 347                    ? new FriendRequestEntryModel(friends[userId], true)
 348                    : new FriendRequestEntryModel {isReceived = true};
 2349                requestReceived.CopyFrom(userProfile);
 2350                requestReceived.blocked = IsUserBlocked(userId);
 2351                friends[userId] = requestReceived;
 2352                View.Set(userId, requestReceived);
 2353                userProfile.OnUpdate += HandleFriendProfileUpdated;
 2354                break;
 355            case FriendshipAction.REQUESTED_TO:
 3356                var requestSent = friends.ContainsKey(userId)
 357                    ? new FriendRequestEntryModel(friends[userId], false)
 358                    : new FriendRequestEntryModel {isReceived = false};
 3359                requestSent.CopyFrom(userProfile);
 3360                requestSent.blocked = IsUserBlocked(userId);
 3361                friends[userId] = requestSent;
 3362                View.Set(userId, requestSent);
 3363                userProfile.OnUpdate += HandleFriendProfileUpdated;
 364                break;
 365        }
 366
 15367        UpdateNotificationsCounter();
 15368        ShowOrHideMoreFriendsToLoadHint();
 15369        ShowOrHideMoreFriendRequestsToLoadHint();
 15370    }
 371
 372    private void HandleFriendProfileUpdated(UserProfile profile)
 373    {
 1374        var userId = profile.userId;
 1375        if (!friends.ContainsKey(userId)) return;
 1376        friends[userId].CopyFrom(profile);
 377
 1378        var status = friendsController.GetUserStatus(profile.userId);
 1379        if (status == null) return;
 380
 1381        UpdateUserStatus(userId, status);
 1382    }
 383
 384    private bool IsUserBlocked(string userId)
 385    {
 19386        if (ownUserProfile != null && ownUserProfile.blocked != null)
 19387            return ownUserProfile.blocked.Contains(userId);
 0388        return false;
 389    }
 390
 391    private void OnFriendNotFound(string name)
 392    {
 1393        View.DisplayFriendUserNotFound();
 1394    }
 395
 396    private void UpdateNotificationsCounter()
 397    {
 38398        if (View.IsActive())
 9399            dataStore.friendNotifications.seenFriends.Set(View.FriendCount);
 400
 38401        dataStore.friendNotifications.pendingFriendRequestCount.Set(friendsController.ReceivedRequestCount);
 38402    }
 403
 1404    private void HandleOpenWhisperChat(FriendEntryModel entry) => OnPressWhisper?.Invoke(entry.userId);
 405
 0406    private void HandleUnfriend(string userId) => friendsController.RemoveFriend(userId);
 407
 408    private void HandleRequestRejected(FriendRequestEntryModel entry)
 409    {
 0410        friendsController.RejectFriendship(entry.userId);
 411
 0412        UpdateNotificationsCounter();
 413
 0414        if (ownUserProfile != null)
 0415            socialAnalytics.SendFriendRequestRejected(ownUserProfile.userId, entry.userId,
 416                PlayerActionSource.FriendsHUD);
 0417    }
 418
 419    private void HandleRequestCancelled(FriendRequestEntryModel entry)
 420    {
 0421        friendsController.CancelRequest(entry.userId);
 422
 0423        if (ownUserProfile != null)
 0424            socialAnalytics.SendFriendRequestCancelled(ownUserProfile.userId, entry.userId,
 425                PlayerActionSource.FriendsHUD);
 0426    }
 427
 428    private void HandleRequestAccepted(FriendRequestEntryModel entry)
 429    {
 0430        friendsController.AcceptFriendship(entry.userId);
 431
 0432        if (ownUserProfile != null)
 0433            socialAnalytics.SendFriendRequestApproved(ownUserProfile.userId, entry.userId,
 434                PlayerActionSource.FriendsHUD);
 0435    }
 436
 437    private void DisplayFriendsIfAnyIsLoaded()
 438    {
 1439        if (View.FriendCount > 0) return;
 1440        if (lastSkipForFriends > 0) return;
 1441        DisplayMoreFriends();
 1442    }
 443
 444    private void DisplayMoreFriends()
 445    {
 11446        if (!friendsController.IsInitialized) return;
 447
 9448        friendsController.GetFriends(LOAD_FRIENDS_ON_DEMAND_COUNT, lastSkipForFriends);
 449
 450        // We are not handling properly the case when the friends are not fetched correctly from server.
 451        // 'lastSkipForFriends' will have an invalid value.
 9452        lastSkipForFriends += LOAD_FRIENDS_ON_DEMAND_COUNT;
 453
 9454        ShowOrHideMoreFriendsToLoadHint();
 9455    }
 456
 457    private void DisplayMoreFriendRequests()
 458    {
 7459        if (!friendsController.IsInitialized) return;
 7460        if (searchingFriends) return;
 461
 7462        friendsController.GetFriendRequests(
 463            LOAD_FRIENDS_ON_DEMAND_COUNT, lastSkipForFriendRequests,
 464            LOAD_FRIENDS_ON_DEMAND_COUNT, lastSkipForFriendRequests);
 465
 466        // We are not handling properly the case when the friend requests are not fetched correctly from server.
 467        // 'lastSkipForFriendRequests' will have an invalid value.
 7468        lastSkipForFriendRequests += LOAD_FRIENDS_ON_DEMAND_COUNT;
 469
 7470        ShowOrHideMoreFriendRequestsToLoadHint();
 7471    }
 472
 473    private void DisplayFriendRequestsIfAnyIsLoaded()
 474    {
 1475        if (View.FriendRequestCount > 0) return;
 1476        if (lastSkipForFriendRequests > 0) return;
 1477        DisplayMoreFriendRequests();
 1478    }
 479
 480    private void ShowOrHideMoreFriendRequestsToLoadHint()
 481    {
 74482        if (lastSkipForFriendRequests >= friendsController.TotalFriendRequestCount)
 73483            View.HideMoreRequestsToLoadHint();
 484        else
 1485            View.ShowMoreRequestsToLoadHint(Mathf.Clamp(friendsController.TotalFriendRequestCount - lastSkipForFriendReq
 486                0,
 487                friendsController.TotalFriendRequestCount));
 1488    }
 489
 490    private void ShowOrHideMoreFriendsToLoadHint()
 491    {
 77492        if (lastSkipForFriends >= friendsController.TotalFriendCount || searchingFriends)
 76493            View.HideMoreFriendsToLoadHint();
 494        else
 1495            View.ShowMoreFriendsToLoadHint(Mathf.Clamp(friendsController.TotalFriendCount - lastSkipForFriends,
 496                0,
 497                friendsController.TotalFriendCount));
 1498    }
 499
 500    private void SearchFriends(string search)
 501    {
 3502        if (string.IsNullOrEmpty(search))
 503        {
 1504            View.DisableSearchMode();
 1505            searchingFriends = false;
 1506            ShowOrHideMoreFriendsToLoadHint();
 1507            return;
 508        }
 509
 2510        friendsController.GetFriends(search, MAX_SEARCHED_FRIENDS);
 511
 2512        View.EnableSearchMode();
 2513        View.HideMoreFriendsToLoadHint();
 2514        searchingFriends = true;
 2515    }
 516}