< Summary

Class:DCL.Social.Passports.PassportNavigationComponentController
Assembly:PassportHUD
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/Passport/Passport/PassportNavigation/PassportNavigationComponentController.cs
Covered lines:0
Uncovered lines:190
Coverable lines:190
Total lines:446
Line coverage:0% (0 of 190)
Covered branches:0
Total branches:0
Covered methods:0
Total methods:22
Method coverage:0% (0 of 22)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
PassportNavigationComponentController(...)0%2100%
BackFromViewAll()0%2100%
ClickedViewAll(...)0%2100%
>c__DisplayClass38_0/<<UpdateWithUserProfile()0%19804400%
UpdateWithUserProfile(...)0%12300%
CloseAllNFTItemInfos()0%2100%
ResetNavigationTab()0%2100%
Dispose()0%20400%
LoadAndDisplayEquippedWearablesAsync()0%56700%
>c__DisplayClass43_0/<<LoadAndShowOwnedWearables()0%56700%
LoadAndShowOwnedWearables(...)0%2100%
LoadAndShowOwnedEmotes()0%30500%
LoadAndShowOwnedNamesAsync()0%30500%
LoadAndShowOwnedLandsAsync()0%30500%
FilterProfanityContentAsync()0%20400%
IsProfanityFilteringEnabled()0%2100%
OpenGoToPanel(...)0%2100%
CloseUIFromGoToPanel(...)0%6200%
ExtractLinks(...)0%30500%
CopyDescriptionToClipboard()0%6200%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/Passport/Passport/PassportNavigation/PassportNavigationComponentController.cs

#LineLine coverage
 1using AvatarSystem;
 2using Cysharp.Threading.Tasks;
 3using DCL.Helpers;
 4using DCL.ProfanityFiltering;
 5using DCLServices.CopyPaste.Analytics;
 6using DCLServices.Lambdas.LandsService;
 7using DCLServices.Lambdas.NamesService;
 8using DCLServices.WearablesCatalogService;
 9using System;
 10using System.Collections.Generic;
 11using System.Linq;
 12using System.Text.RegularExpressions;
 13using System.Threading;
 14using UnityEngine;
 15
 16namespace DCL.Social.Passports
 17{
 18    public class PassportNavigationComponentController : IDisposable
 19    {
 20        private const int MAX_NFT_COUNT = 40;
 21
 22        private readonly IProfanityFilter profanityFilter;
 23        private readonly IWearableItemResolver wearableItemResolver;
 24        private readonly IWearablesCatalogService wearablesCatalogService;
 25        private readonly IEmotesCatalogService emotesCatalogService;
 26        private readonly INamesService namesService;
 27        private readonly ILandsService landsService;
 28        private readonly IUserProfileBridge userProfileBridge;
 29        private readonly DataStore dataStore;
 30        private readonly ViewAllComponentController viewAllController;
 31        private readonly IAdditionalInfoFieldIconProvider additionalInfoFieldIconProvider;
 32        private readonly IClipboard clipboard;
 33        private readonly ICopyPasteAnalyticsService copyPasteAnalyticsService;
 034        private readonly Regex linksRegex = new (@"\[(.*?)\]\((.*?)\)", RegexOptions.Multiline);
 035        private readonly List<(Sprite logo, string title, string value)> additionalFields = new ();
 036        private readonly List<UserProfileModel.Link> links = new ();
 37
 038        private UserProfile ownUserProfile => userProfileBridge.GetOwn();
 39        private readonly IPassportNavigationComponentView view;
 040        private HashSet<string> cachedAvatarEquippedWearables = new ();
 41        private string currentUserId;
 042        private CancellationTokenSource cts = new ();
 43        private Promise<WearableItem[]> wearablesPromise;
 44        private Promise<WearableItem[]> emotesPromise;
 45
 046        private bool isMyAccountEnabled => dataStore.featureFlags.flags.Get().IsFeatureEnabled("my_account");
 47
 48        public event Action<string, string> OnClickBuyNft;
 49        public event Action OnClickedLink;
 50        public event Action OnClickCollectibles;
 51
 052        public PassportNavigationComponentController(
 53            IPassportNavigationComponentView view,
 54            IProfanityFilter profanityFilter,
 55            IWearableItemResolver wearableItemResolver,
 56            IWearablesCatalogService wearablesCatalogService,
 57            IEmotesCatalogService emotesCatalogService,
 58            INamesService namesService,
 59            ILandsService landsService,
 60            IUserProfileBridge userProfileBridge,
 61            DataStore dataStore,
 62            ViewAllComponentController viewAllController,
 63            IAdditionalInfoFieldIconProvider additionalInfoFieldIconProvider,
 64            IClipboard clipboard,
 65            ICopyPasteAnalyticsService copyPasteAnalyticsService)
 66        {
 67            const string NAME_TYPE = "name";
 68            const string PARCEL_TYPE = "parcel";
 69            const string ESTATE_TYPE = "estate";
 70
 071            this.view = view;
 072            this.profanityFilter = profanityFilter;
 073            this.wearableItemResolver = wearableItemResolver;
 074            this.wearablesCatalogService = wearablesCatalogService;
 075            this.emotesCatalogService = emotesCatalogService;
 076            this.namesService = namesService;
 077            this.landsService = landsService;
 078            this.userProfileBridge = userProfileBridge;
 079            this.dataStore = dataStore;
 080            this.viewAllController = viewAllController;
 081            this.additionalInfoFieldIconProvider = additionalInfoFieldIconProvider;
 082            this.clipboard = clipboard;
 083            this.copyPasteAnalyticsService = copyPasteAnalyticsService;
 84
 085            view.OnClickBuyNft += (wearableId, wearableType) => OnClickBuyNft?.Invoke(wearableType is NAME_TYPE or PARCE
 086            view.OnClickCollectibles += () => OnClickCollectibles?.Invoke();
 087            view.OnClickedViewAll += ClickedViewAll;
 088            view.OnClickDescriptionCoordinates += OpenGoToPanel;
 089            view.OnCopyDescription += CopyDescriptionToClipboard;
 090            viewAllController.OnBackFromViewAll += BackFromViewAll;
 091            viewAllController.OnClickBuyNft += (nftId) => OnClickBuyNft?.Invoke(nftId.Category is NAME_TYPE or PARCEL_TY
 092        }
 93
 94        private void BackFromViewAll()
 95        {
 096            view.OpenCollectiblesTab();
 097        }
 98
 99        private void ClickedViewAll(PassportSection section)
 100        {
 0101            view.CloseAllSections();
 0102            viewAllController.SetViewAllVisibility(true);
 0103            viewAllController.OpenViewAllSection(section);
 0104        }
 105
 106        public void UpdateWithUserProfile(UserProfile userProfile)
 107        {
 108            async UniTaskVoid UpdateWithUserProfileAsync(CancellationToken cancellationToken)
 109            {
 0110                currentUserId = userProfile.userId;
 0111                string filteredName = await FilterProfanityContentAsync(userProfile.userName, cancellationToken);
 0112                view.SetGuestUser(userProfile.isGuest);
 0113                view.SetName(filteredName);
 0114                view.SetOwnUserTexts(userProfile.userId == ownUserProfile.userId);
 115
 0116                links.Clear();
 0117                additionalFields.Clear();
 118
 0119                if (!userProfile.isGuest)
 120                {
 0121                    string filteredDescription = await FilterProfanityContentAsync(userProfile.description, cancellation
 122
 0123                    if (isMyAccountEnabled)
 124                    {
 125                        string filteredAdditionalValue;
 126
 0127                        if (!string.IsNullOrEmpty(userProfile.AdditionalInfo.Gender))
 128                        {
 0129                            filteredAdditionalValue = await FilterProfanityContentAsync(userProfile.AdditionalInfo.Gende
 130
 0131                            additionalFields.Add((
 132                                additionalInfoFieldIconProvider.Get(AdditionalInfoField.GENDER),
 133                                AdditionalInfoField.GENDER.ToName(),
 134                                filteredAdditionalValue));
 135                        }
 136
 0137                        if (!string.IsNullOrEmpty(userProfile.AdditionalInfo.Country))
 138                        {
 0139                            filteredAdditionalValue = await FilterProfanityContentAsync(userProfile.AdditionalInfo.Count
 140
 0141                            additionalFields.Add((
 142                                additionalInfoFieldIconProvider.Get(AdditionalInfoField.COUNTRY),
 143                                AdditionalInfoField.COUNTRY.ToName(),
 144                                filteredAdditionalValue));
 145                        }
 146
 0147                        if (userProfile.AdditionalInfo.BirthDate != null && userProfile.AdditionalInfo.BirthDate != new 
 0148                            additionalFields.Add((
 149                                additionalInfoFieldIconProvider.Get(AdditionalInfoField.BIRTH_DATE),
 150                                AdditionalInfoField.BIRTH_DATE.ToName(),
 151                                userProfile.AdditionalInfo.BirthDate.Value.ToString("dd/MM/yyyy")));
 152
 0153                        if (!string.IsNullOrEmpty(userProfile.AdditionalInfo.Pronouns))
 154                        {
 0155                            filteredAdditionalValue = await FilterProfanityContentAsync(userProfile.AdditionalInfo.Prono
 156
 0157                            additionalFields.Add((
 158                                additionalInfoFieldIconProvider.Get(AdditionalInfoField.PRONOUNS),
 159                                AdditionalInfoField.PRONOUNS.ToName(),
 160                                filteredAdditionalValue));
 161                        }
 162
 0163                        if (!string.IsNullOrEmpty(userProfile.AdditionalInfo.RelationshipStatus))
 164                        {
 0165                            filteredAdditionalValue = await FilterProfanityContentAsync(userProfile.AdditionalInfo.Relat
 166
 0167                            additionalFields.Add((
 168                                additionalInfoFieldIconProvider.Get(AdditionalInfoField.RELATIONSHIP_STATUS),
 169                                AdditionalInfoField.RELATIONSHIP_STATUS.ToName(),
 170                                filteredAdditionalValue));
 171                        }
 172
 0173                        if (!string.IsNullOrEmpty(userProfile.AdditionalInfo.SexualOrientation))
 174                        {
 0175                            filteredAdditionalValue = await FilterProfanityContentAsync(userProfile.AdditionalInfo.Sexua
 176
 0177                            additionalFields.Add((
 178                                additionalInfoFieldIconProvider.Get(AdditionalInfoField.SEXUAL_ORIENTATION),
 179                                AdditionalInfoField.SEXUAL_ORIENTATION.ToName(),
 180                                filteredAdditionalValue));
 181                        }
 182
 0183                        if (!string.IsNullOrEmpty(userProfile.AdditionalInfo.Language))
 184                        {
 0185                            filteredAdditionalValue = await FilterProfanityContentAsync(userProfile.AdditionalInfo.Langu
 186
 0187                            additionalFields.Add((
 188                                additionalInfoFieldIconProvider.Get(AdditionalInfoField.LANGUAGE),
 189                                AdditionalInfoField.LANGUAGE.ToName(),
 190                                filteredAdditionalValue));
 191                        }
 192
 0193                        if (!string.IsNullOrEmpty(userProfile.AdditionalInfo.Profession))
 194                        {
 0195                            filteredAdditionalValue = await FilterProfanityContentAsync(userProfile.AdditionalInfo.Profe
 196
 0197                            additionalFields.Add((
 198                                additionalInfoFieldIconProvider.Get(AdditionalInfoField.PROFESSION),
 199                                AdditionalInfoField.PROFESSION.ToName(),
 200                                filteredAdditionalValue));
 201                        }
 202
 0203                        if (!string.IsNullOrEmpty(userProfile.AdditionalInfo.EmploymentStatus))
 204                        {
 0205                            filteredAdditionalValue = await FilterProfanityContentAsync(userProfile.AdditionalInfo.Emplo
 206
 0207                            additionalFields.Add((
 208                                additionalInfoFieldIconProvider.Get(AdditionalInfoField.EMPLOYMENT_STATUS),
 209                                AdditionalInfoField.EMPLOYMENT_STATUS.ToName(),
 210                                filteredAdditionalValue));
 211                        }
 212
 0213                        if (!string.IsNullOrEmpty(userProfile.AdditionalInfo.Hobbies))
 214                        {
 0215                            filteredAdditionalValue = await FilterProfanityContentAsync(userProfile.AdditionalInfo.Hobbi
 216
 0217                            additionalFields.Add((
 218                                additionalInfoFieldIconProvider.Get(AdditionalInfoField.HOBBIES),
 219                                AdditionalInfoField.HOBBIES.ToName(),
 220                                filteredAdditionalValue));
 221                        }
 222
 0223                        if (!string.IsNullOrEmpty(userProfile.AdditionalInfo.RealName))
 224                        {
 0225                            filteredAdditionalValue = await FilterProfanityContentAsync(userProfile.AdditionalInfo.RealN
 226
 0227                            additionalFields.Add((
 228                                additionalInfoFieldIconProvider.Get(AdditionalInfoField.REAL_NAME),
 229                                AdditionalInfoField.REAL_NAME.ToName(),
 230                                filteredAdditionalValue));
 231                        }
 232
 0233                        if (userProfile.Links != null)
 0234                            links.AddRange(userProfile.Links);
 235                    }
 236                    else
 0237                        filteredDescription = ExtractLinks(filteredDescription, links);
 238
 0239                    view.SetDescription(filteredDescription);
 0240                    view.SetAdditionalInfo(additionalFields);
 0241                    view.SetLinks(links);
 0242                    view.SetHasBlockedOwnUser(userProfile.IsBlocked(ownUserProfile.userId));
 0243                    LoadAndShowOwnedNamesAsync(userProfile, cancellationToken).Forget();
 0244                    LoadAndShowOwnedLandsAsync(userProfile, cancellationToken).Forget();
 0245                    LoadAndDisplayEquippedWearablesAsync(userProfile, cancellationToken).Forget();
 0246                }
 0247            }
 248
 0249            cts?.Cancel();
 0250            cts?.Dispose();
 0251            cts = new CancellationTokenSource();
 0252            UpdateWithUserProfileAsync(cts.Token).Forget();
 0253        }
 254
 255        public void CloseAllNFTItemInfos() =>
 0256            view.CloseAllNFTItemInfos();
 257
 258        public void ResetNavigationTab()
 259        {
 0260            view.SetInitialPage();
 0261            viewAllController.SetViewAllVisibility(false);
 0262        }
 263
 264        public void Dispose()
 265        {
 0266            cts?.Cancel();
 0267            cts?.Dispose();
 0268            cts = null;
 269
 0270            wearablesPromise?.Dispose();
 0271            dataStore.HUDs.goToPanelConfirmed.OnChange -= CloseUIFromGoToPanel;
 0272        }
 273
 274        private async UniTask LoadAndDisplayEquippedWearablesAsync(UserProfile userProfile, CancellationToken ct)
 275        {
 0276            foreach (var t in userProfile.avatar.wearables)
 277            {
 0278                if (!cachedAvatarEquippedWearables.Contains(t))
 279                {
 0280                    view.InitializeView();
 0281                    cachedAvatarEquippedWearables = new HashSet<string>(userProfile.avatar.wearables);
 0282                    LoadAndShowOwnedWearables(userProfile);
 0283                    LoadAndShowOwnedEmotes(userProfile).Forget();
 284
 0285                    WearableItem[] wearableItems = await wearableItemResolver.Resolve(userProfile.avatar.wearables, ct);
 0286                    view.SetEquippedWearables(wearableItems, userProfile.avatar.bodyShape);
 0287                    return;
 288                }
 289            }
 0290        }
 291
 292        private void LoadAndShowOwnedWearables(UserProfile userProfile)
 293        {
 294            async UniTaskVoid RequestOwnedWearablesAsync(CancellationToken ct)
 295            {
 0296                WearableItem[] containedWearables = Array.Empty<WearableItem>();
 297
 298                try
 299                {
 0300                    view.SetCollectibleWearablesLoadingActive(true);
 0301                    view.SetViewAllButtonActive(PassportSection.Wearables, false);
 0302                    var wearables = await wearablesCatalogService.RequestOwnedWearablesAsync(
 303                        userProfile.userId,
 304                        1,
 305                        MAX_NFT_COUNT,
 306                        true,
 307                        ct);
 308
 0309                    view.SetViewAllButtonActive(PassportSection.Wearables, wearables.totalAmount > MAX_NFT_COUNT);
 0310                    var wearableItems = wearables.wearables.GroupBy(i => i.id);
 311
 0312                    containedWearables = wearableItems
 0313                                        .Select(g => g.First())
 0314                                        .Where(wearable => wearablesCatalogService.IsValidWearable(wearable.id))
 315                                        .ToArray();
 0316                }
 0317                catch (OperationCanceledException) { }
 0318                catch (Exception e) { Debug.LogError(e.Message); }
 319                finally
 320                {
 0321                    view.SetCollectibleWearables(containedWearables);
 0322                    view.SetCollectibleWearablesLoadingActive(false);
 323                }
 0324            }
 325
 0326            RequestOwnedWearablesAsync(cts.Token).Forget();
 0327        }
 328
 329        private async UniTask LoadAndShowOwnedEmotes(UserProfile userProfile)
 330        {
 0331            view.SetCollectibleEmotesLoadingActive(true);
 0332            var emotes = await emotesCatalogService.RequestOwnedEmotesAsync(userProfile.userId, cts.Token);
 0333            WearableItem[] emoteItems = emotes.GroupBy(i => i.id).Select(g => g.First()).Take(MAX_NFT_COUNT).ToArray();
 0334            view.SetCollectibleEmotes(emoteItems);
 0335            view.SetCollectibleEmotesLoadingActive(false);
 0336        }
 337
 338        private async UniTask LoadAndShowOwnedNamesAsync(UserProfile userProfile, CancellationToken ct)
 339        {
 0340            NamesResponse.NameEntry[] namesResult = Array.Empty<NamesResponse.NameEntry>();
 0341            var showViewAllButton = false;
 342
 343            try
 344            {
 0345                view.SetCollectibleNamesLoadingActive(true);
 0346                view.SetViewAllButtonActive(PassportSection.Names, false);
 0347                var names = await namesService.RequestOwnedNamesAsync(
 348                    userProfile.userId,
 349                    1,
 350                    MAX_NFT_COUNT,
 351                    true,
 352                    ct);
 353
 0354                namesResult = names.names.ToArray();
 0355                showViewAllButton = names.totalAmount > MAX_NFT_COUNT;
 0356            }
 0357            catch (OperationCanceledException) { }
 0358            catch (Exception e) { Debug.LogException(e); }
 359            finally
 360            {
 0361                view.SetCollectibleNames(namesResult);
 0362                view.SetCollectibleNamesLoadingActive(false);
 0363                view.SetViewAllButtonActive(PassportSection.Names, showViewAllButton);
 364            }
 0365        }
 366
 367        private async UniTask LoadAndShowOwnedLandsAsync(UserProfile userProfile, CancellationToken ct)
 368        {
 0369            LandsResponse.LandEntry[] landsResult = Array.Empty<LandsResponse.LandEntry>();
 0370            var showViewAllButton = false;
 371
 372            try
 373            {
 0374                view.SetCollectibleLandsLoadingActive(true);
 0375                view.SetViewAllButtonActive(PassportSection.Lands, false);
 0376                var lands = await landsService.RequestOwnedLandsAsync(
 377                    userProfile.userId,
 378                    1,
 379                    MAX_NFT_COUNT,
 380                    true,
 381                    ct);
 382
 0383                landsResult = lands.lands.ToArray();
 0384                showViewAllButton = lands.totalAmount > MAX_NFT_COUNT;
 0385            }
 0386            catch (OperationCanceledException) { }
 0387            catch (Exception e) { Debug.LogError(e.Message); }
 388            finally
 389            {
 0390                view.SetCollectibleLands(landsResult);
 0391                view.SetCollectibleLandsLoadingActive(false);
 0392                view.SetViewAllButtonActive(PassportSection.Lands, showViewAllButton);
 393            }
 0394        }
 395
 396        private async UniTask<string> FilterProfanityContentAsync(string filterContent, CancellationToken cancellationTo
 0397            IsProfanityFilteringEnabled()
 398                ? await profanityFilter.Filter(filterContent, cancellationToken)
 399                : filterContent;
 400
 401        private bool IsProfanityFilteringEnabled() =>
 0402            dataStore.settings.profanityChatFilteringEnabled.Get();
 403
 404        private void OpenGoToPanel(ParcelCoordinates coordinates)
 405        {
 0406            dataStore.HUDs.gotoPanelVisible.Set(true, true);
 0407            dataStore.HUDs.gotoPanelCoordinates.Set((coordinates, null, null), true);
 408
 0409            dataStore.HUDs.goToPanelConfirmed.OnChange -= CloseUIFromGoToPanel;
 0410            dataStore.HUDs.goToPanelConfirmed.OnChange += CloseUIFromGoToPanel;
 0411        }
 412
 413        private void CloseUIFromGoToPanel(bool confirmed, bool _)
 414        {
 0415            if (!confirmed) return;
 0416            dataStore.HUDs.goToPanelConfirmed.OnChange -= CloseUIFromGoToPanel;
 0417            dataStore.exploreV2.isOpen.Set(false, true);
 0418            dataStore.HUDs.currentPlayerId.Set((null, null));
 0419        }
 420
 421        private string ExtractLinks(string description, ICollection<UserProfileModel.Link> linkBuffer = null)
 422        {
 0423            MatchCollection matches = linksRegex.Matches(description);
 424
 0425            if (matches.Count == 0) return description;
 426
 0427            foreach (Match match in matches)
 428            {
 0429                linkBuffer?.Add(new UserProfileModel.Link(match.Groups[1].Value, match.Groups[2].Value));
 0430                description = description.Replace(match.Value, "");
 431            }
 432
 0433            return description;
 434        }
 435
 436        private void CopyDescriptionToClipboard()
 437        {
 0438            UserProfile userProfile = userProfileBridge.Get(currentUserId);
 0439            if (userProfile == null) return;
 0440            string description = userProfile.description;
 0441            description = ExtractLinks(description);
 0442            clipboard.WriteText(description);
 0443            copyPasteAnalyticsService.Copy("player_data");
 0444        }
 445    }
 446}