< Summary

Class:DCL.Backpack.BackpackEmotesSectionController
Assembly:BackpackEditorHUDV2
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/BackpackEditorHUDV2/BackpackEmotesSectionController.cs
Covered lines:0
Uncovered lines:90
Coverable lines:90
Total lines:224
Line coverage:0% (0 of 90)
Covered branches:0
Total branches:0
Covered methods:0
Total methods:15
Method coverage:0% (0 of 15)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
BackpackEmotesSectionController(...)0%2100%
Dispose()0%2100%
LoadUserProfile(...)0%2100%
QueryNftCollections(...)0%6200%
<LoadEmotes()0%4202000%
LoadEmotes()0%2100%
RestoreEmoteSlots()0%2100%
SetEquippedBodyShape(...)0%2100%
NewEmoteAdded(...)0%6200%
EmotePreviewed(...)0%6200%
EmoteEquipped(...)0%6200%
EmoteUnEquipped(...)0%6200%
EmoteSell(...)0%20400%
FetchCustomEmoteItems()0%56700%
FetchCustomEmoteCollections()0%90900%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/BackpackEditorHUDV2/BackpackEmotesSectionController.cs

#LineLine coverage
 1using AvatarSystem;
 2using Cysharp.Threading.Tasks;
 3using DCL.Emotes;
 4using DCL.EmotesCustomization;
 5using DCL.Interface;
 6using DCL.Tasks;
 7using DCLServices.CustomNftCollection;
 8using System;
 9using System.Collections.Generic;
 10using System.Linq;
 11using System.Threading;
 12using UnityEngine;
 13using UnityEngine.Pool;
 14
 15namespace DCL.Backpack
 16{
 17    public class BackpackEmotesSectionController : IBackpackEmotesSectionController
 18    {
 19        private const string URL_SELL_COLLECTIBLE_GENERIC = "https://market.decentraland.org/account";
 20        private const string URL_SELL_SPECIFIC_COLLECTIBLE = "https://market.decentraland.org/contracts/{collectionId}/t
 21
 22        public event Action<string> OnNewEmoteAdded;
 23        public event Action<string> OnEmotePreviewed;
 24        public event Action<string> OnEmoteEquipped;
 25        public event Action<string> OnEmoteUnEquipped;
 26
 27        private readonly DataStore dataStore;
 28        private readonly IUserProfileBridge userProfileBridge;
 29        private readonly IEmotesCatalogService emotesCatalogService;
 30        private readonly ICustomNftCollectionService customNftCollectionService;
 31        private readonly IEmotesCustomizationComponentController emotesCustomizationComponentController;
 032        private CancellationTokenSource loadEmotesCts = new ();
 033        private List<Nft> ownedNftCollectionsL1 = new ();
 034        private List<Nft> ownedNftCollectionsL2 = new ();
 35
 036        public BackpackEmotesSectionController(
 37            DataStore dataStore,
 38            Transform emotesSectionTransform,
 39            IUserProfileBridge userProfileBridge,
 40            IEmotesCatalogService emotesCatalogService,
 41            IAvatarEmotesController emotesController,
 42            ICustomNftCollectionService customNftCollectionService)
 43        {
 044            this.dataStore = dataStore;
 045            this.userProfileBridge = userProfileBridge;
 046            this.emotesCatalogService = emotesCatalogService;
 047            this.customNftCollectionService = customNftCollectionService;
 48
 049            emotesCustomizationComponentController = new EmotesCustomizationComponentController(
 50                dataStore.emotesCustomization,
 51                emotesController,
 52                dataStore.exploreV2,
 53                dataStore.HUDs,
 54                emotesSectionTransform,
 55                "EmotesCustomization/EmotesCustomizationSectionV2");
 56
 057            emotesCustomizationComponentController.SetEquippedBodyShape(userProfileBridge.GetOwn().avatar.bodyShape);
 58
 059            userProfileBridge.GetOwn().OnUpdate += LoadUserProfile;
 60
 061            dataStore.emotesCustomization.currentLoadedEmotes.OnAdded += NewEmoteAdded;
 062            emotesCustomizationComponentController.onEmotePreviewed += EmotePreviewed;
 063            emotesCustomizationComponentController.onEmoteEquipped += EmoteEquipped;
 064            emotesCustomizationComponentController.onEmoteUnequipped += EmoteUnEquipped;
 065            emotesCustomizationComponentController.onEmoteSell += EmoteSell;
 066        }
 67
 68        public void Dispose()
 69        {
 070            loadEmotesCts.SafeCancelAndDispose();
 071            loadEmotesCts = null;
 72
 073            dataStore.emotesCustomization.currentLoadedEmotes.OnAdded -= NewEmoteAdded;
 074            emotesCustomizationComponentController.onEmotePreviewed -= EmotePreviewed;
 075            emotesCustomizationComponentController.onEmoteEquipped -= EmoteEquipped;
 076            emotesCustomizationComponentController.onEmoteUnequipped -= EmoteUnEquipped;
 077            emotesCustomizationComponentController.onEmoteSell -= EmoteSell;
 078        }
 79
 80        private void LoadUserProfile(UserProfile userProfile) =>
 081            QueryNftCollections(userProfile.userId);
 82
 83        private void QueryNftCollections(string userId)
 84        {
 085            if (string.IsNullOrEmpty(userId))
 086                return;
 87
 088            Environment.i.platform.serviceProviders.theGraph.QueryNftCollections(userProfileBridge.GetOwn().userId, NftC
 089                       .Then(nft => ownedNftCollectionsL1 = nft)
 90                       .Catch(Debug.LogError);
 91
 092            Environment.i.platform.serviceProviders.theGraph.QueryNftCollections(userProfileBridge.GetOwn().userId, NftC
 093                       .Then((nft) => ownedNftCollectionsL2 = nft)
 94                       .Catch(Debug.LogError);
 095        }
 96
 97        public void LoadEmotes()
 98        {
 99            async UniTaskVoid LoadEmotesAsync(CancellationToken ct = default)
 100            {
 101                try
 102                {
 0103                    EmbeddedEmotesSO embeddedEmotesSo = await emotesCatalogService.GetEmbeddedEmotes();
 0104                    List<WearableItem> allEmotes = new ();
 0105                    allEmotes.AddRange(await emotesCatalogService.RequestOwnedEmotesAsync(userProfileBridge.GetOwn().use
 106
 0107                    Dictionary<string, WearableItem> consolidatedEmotes = new Dictionary<string, WearableItem>();
 108
 0109                    foreach (EmbeddedEmote emote in embeddedEmotesSo.GetAllEmotes())
 0110                        consolidatedEmotes[emote.id] = emote;
 111
 0112                    foreach (var emote in allEmotes)
 113                    {
 0114                        if (consolidatedEmotes.TryGetValue(emote.id, out WearableItem consolidatedEmote))
 0115                            consolidatedEmote.amount += emote.amount;
 116                        else
 117                        {
 0118                            emote.amount = 1;
 0119                            consolidatedEmotes[emote.id] = emote;
 120                        }
 121                    }
 122
 0123                    allEmotes = consolidatedEmotes.Values.ToList();
 124
 125                    try
 126                    {
 0127                        await FetchCustomEmoteItems(allEmotes, ct);
 0128                        await FetchCustomEmoteCollections(allEmotes, ct);
 0129                    }
 0130                    catch (Exception e) when (e is not OperationCanceledException) { Debug.LogException(e); }
 0131                    finally { UpdateEmotes(); }
 132
 133                    void UpdateEmotes()
 134                    {
 0135                        dataStore.emotesCustomization.UnequipMissingEmotes(allEmotes);
 0136                        emotesCustomizationComponentController.SetEmotes(allEmotes.ToArray());
 0137                    }
 0138                }
 0139                catch (OperationCanceledException) { }
 0140                catch (Exception e) { Debug.LogException(e); }
 0141            }
 142
 0143            loadEmotesCts = loadEmotesCts.SafeRestart();
 0144            LoadEmotesAsync(loadEmotesCts.Token).Forget();
 0145        }
 146
 147        public void RestoreEmoteSlots() =>
 0148            emotesCustomizationComponentController.RestoreEmoteSlots();
 149
 150        public void SetEquippedBodyShape(string bodyShapeId) =>
 0151            emotesCustomizationComponentController.SetEquippedBodyShape(bodyShapeId);
 152
 153        // TODO: Delete?
 154        private void NewEmoteAdded(string emoteId) =>
 0155            OnNewEmoteAdded?.Invoke(emoteId);
 156
 157        // TODO: Delete?
 158        private void EmotePreviewed(string emoteId) =>
 0159            OnEmotePreviewed?.Invoke(emoteId);
 160
 161        // TODO: Delete?
 162        private void EmoteEquipped(string emoteId) =>
 0163            OnEmoteEquipped?.Invoke(emoteId);
 164
 165        // TODO: Delete?
 166        private void EmoteUnEquipped(string emoteId) =>
 0167            OnEmoteUnEquipped?.Invoke(emoteId);
 168
 169        private void EmoteSell(string collectibleId)
 170        {
 0171            var ownedCollectible = ownedNftCollectionsL1.FirstOrDefault(nft => nft.urn == collectibleId) ??
 0172                                   ownedNftCollectionsL2.FirstOrDefault(nft => nft.urn == collectibleId);
 173
 0174            WebInterface.OpenURL(ownedCollectible != null ? URL_SELL_SPECIFIC_COLLECTIBLE.Replace("{collectionId}", owne
 0175        }
 176
 177        private async UniTask FetchCustomEmoteItems(ICollection<WearableItem> emotes,
 178            CancellationToken cancellationToken)
 179        {
 0180            IReadOnlyList<string> customItems = await customNftCollectionService.GetConfiguredCustomNftItemsAsync(cancel
 181
 0182            WearableItem[] retrievedEmotes = await UniTask.WhenAll(customItems.Select(nftId =>
 0183                nftId.StartsWith("urn", StringComparison.OrdinalIgnoreCase)
 184                    ? emotesCatalogService.RequestEmoteAsync(nftId, cancellationToken)
 185                    : emotesCatalogService.RequestEmoteFromBuilderAsync(nftId, cancellationToken)));
 186
 0187            foreach (WearableItem emote in retrievedEmotes)
 188            {
 0189                if (emote == null)
 190                {
 0191                    Debug.LogWarning("Custom emote item skipped is null");
 0192                    continue;
 193                }
 194
 0195                emotes.Add(emote);
 196            }
 0197        }
 198
 199        private async UniTask FetchCustomEmoteCollections(
 200            List<WearableItem> emotes,
 201            CancellationToken cancellationToken)
 202        {
 0203            IReadOnlyList<string> customCollections =
 204                await customNftCollectionService.GetConfiguredCustomNftCollectionAsync(cancellationToken);
 205
 0206            HashSet<string> publishedCollections = HashSetPool<string>.Get();
 0207            HashSet<string> collectionsInBuilder = HashSetPool<string>.Get();
 208
 0209            foreach (string collectionId in customCollections)
 210            {
 0211                if (collectionId.StartsWith("urn", StringComparison.OrdinalIgnoreCase))
 0212                    publishedCollections.Add(collectionId);
 213                else
 0214                    collectionsInBuilder.Add(collectionId);
 215            }
 216
 0217            await UniTask.WhenAll(emotesCatalogService.RequestEmoteCollectionAsync(publishedCollections, cancellationTok
 218                emotesCatalogService.RequestEmoteCollectionInBuilderAsync(collectionsInBuilder, cancellationToken, emote
 219
 0220            HashSetPool<string>.Release(publishedCollections);
 0221            HashSetPool<string>.Release(collectionsInBuilder);
 0222        }
 223    }
 224}