Skip to content

Commit 43280fb

Browse files
aixaCodenicoechezaRominaMarchetti
authored
feat: block players visually UI (#6130)
* update avatar scene to prevent rendering players when blocked * Setup * Polish Blocked List UI * Update avatars' block icon * Update blocked label style * Passport changes to support blocking guest * Updated the blocked message * Bunch of fixes to UI * Update Unblock button style * Fixed data not refreshed properly * Add block icon dark variant * Polish unblock button on private chat hud * Fix blocked users vertical scroll * Capitalize Notifications and Profile words on section buttons * Update copies applying Karo's corrections * Review fixes --------- Co-authored-by: Nicolas Echezarreta <nicoecheza@gmail.com> Co-authored-by: Romina Marchetti <rma.marchetti@gmail.com>
1 parent 05608b6 commit 43280fb

File tree

67 files changed

+8612
-1426
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+8612
-1426
lines changed

browser-interface/packages/shared/comms/peers.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
positionReportToCommsPositionRfc4,
1717
squareDistanceRfc4
1818
} from './interface/utils'
19+
import { isBlocked } from 'shared/friends/utils'
1920

2021
/**
2122
* peerInformationMap contains data received of the current peers that we have
@@ -123,7 +124,7 @@ function sendPeerUserData(address: string) {
123124
avatarMessageObservable.notifyObservers({
124125
type: AvatarMessageType.USER_DATA,
125126
userId: peer.ethereumAddress,
126-
data: peer,
127+
data: { ...peer, visible: !isBlocked(profile.userId) },
127128
profile
128129
})
129130
}

browser-interface/packages/ui/avatar/avatarSystem.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type Position = {
2222
rotationW: number
2323
}
2424

25-
const avatarMap = new Map<string, AvatarEntity>()
25+
export const avatarMap = new Map<string, AvatarEntity>()
2626

2727
export class AvatarEntity extends Entity {
2828
visible = true

browser-interface/packages/ui/decentraland-ui.scene.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { executeTask } from '@dcl/legacy-ecs'
2-
import { avatarMessageObservable } from './avatar/avatarSystem'
2+
import { avatarMap, avatarMessageObservable } from './avatar/avatarSystem'
33

44
declare const dcl: DecentralandInterface
55

@@ -23,7 +23,9 @@ void executeTask(async () => {
2323
if (payload !== lastProcessed) {
2424
try {
2525
lastProcessed = payload
26-
avatarMessageObservable.emit('message', JSON.parse(payload))
26+
const msg = JSON.parse(payload)
27+
const invisible = avatarMap.get(msg.userId)?.visible === false && msg.visible === false
28+
if (!invisible) avatarMessageObservable.emit('message', msg)
2729
} catch (err) {
2830
console.error(err)
2931
}

unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/ChatWidgetHUD/ChatHUDView.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public class ChatHUDView : BaseComponentView, IChatHUDComponentView
3434
[SerializeField] internal InputAction_Trigger closeMentionSuggestionsInput;
3535
[SerializeField] internal ChatMentionSuggestionComponentView chatMentionSuggestions;
3636
[SerializeField] internal WebGLIMEInput webGlImeInput;
37+
[SerializeField] internal Button unblockButton;
3738
[SerializeField] private Model model;
3839

3940
private readonly Dictionary<string, ChatEntry> entries = new ();
@@ -109,7 +110,7 @@ void Action(string s) =>
109110
public event Action<string> OnMentionSuggestionSelected;
110111
public event Action<ChatEntryModel> OnCopyMessageRequested;
111112
public event Action<ChatMessage> OnSendMessage;
112-
113+
public event Action<string> OnUnblockUser;
113114
public int EntryCount => entries.Count;
114115
public IChatEntryFactory ChatEntryFactory { get; set; }
115116
public IComparer<ChatEntryModel> SortingStrategy { get; set; }
@@ -127,6 +128,11 @@ public override void Awake()
127128
model.enableFadeoutMode = true;
128129
contextMenu.SetPassportOpenSource(true);
129130

131+
unblockButton.onClick.AddListener(() =>
132+
{
133+
OnUnblockUser?.Invoke(model.conversationUserId);
134+
});
135+
130136
#if (UNITY_WEBGL && !UNITY_EDITOR)
131137
// WebGLInput plugin breaks many features:
132138
// @mentions navigation with ARROW keys
@@ -244,6 +250,12 @@ public void HideMentionSuggestions()
244250
chatMentionSuggestions.Hide();
245251
}
246252

253+
public void SetBlockedStatus(bool blocked)
254+
{
255+
inputField.gameObject.SetActive(!blocked);
256+
unblockButton.gameObject.SetActive(blocked);
257+
}
258+
247259
public void AddMentionToInputField(int fromIndex, int length, string userId, string userName)
248260
{
249261
string message = inputField.text;
@@ -342,6 +354,11 @@ protected void Populate(ChatEntry entry, ChatEntryModel model)
342354
entry.SetFadeout(this.model.enableFadeoutMode);
343355
}
344356

357+
public void SetConversationUserId(string userId)
358+
{
359+
model.conversationUserId = userId;
360+
}
361+
345362
protected void Dock(ChatEntry entry)
346363
{
347364
entry.transform.SetParent(chatEntriesContainer, false);
@@ -530,6 +547,7 @@ private struct Model
530547
public string inputFieldText;
531548
public bool enableFadeoutMode;
532549
public ChatEntryModel[] entries;
550+
public string conversationUserId;
533551
}
534552
}
535553
}

unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/ChatWidgetHUD/IChatHUDComponentView.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using DCL.Social.Chat;
2-
using DCL.Interface;
1+
using DCL.Interface;
32
using System;
43
using System.Collections.Generic;
54

@@ -17,15 +16,14 @@ public interface IChatHUDComponentView
1716
event Action OnNextChatInHistory;
1817
event Action<string> OnMentionSuggestionSelected;
1918
event Action<ChatEntryModel> OnCopyMessageRequested;
19+
event Action<string> OnUnblockUser;
2020

2121
int EntryCount { get; }
2222
IComparer<ChatEntryModel> SortingStrategy { set; }
2323
bool UseLegacySorting { set; }
24-
2524
void OnMessageCancelHover();
26-
2725
void SetEntry(ChatEntryModel model, bool setScrollPositionToBottom = false);
28-
26+
void SetConversationUserId(string userId);
2927
void Dispose();
3028

3129
void RemoveOldestEntry();
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using DCL.Helpers;
2+
using System;
3+
using UnityEngine;
4+
5+
namespace DCL.MyAccount
6+
{
7+
public class BlockedListComponentView : BaseComponentView, IBlockedListComponentView
8+
{
9+
[Header("General")]
10+
[SerializeField] internal GameObject mainContainer;
11+
[SerializeField] internal GameObject loadingContainer;
12+
[SerializeField] internal RectTransform contentTransform;
13+
[SerializeField] internal GameObject scrollBar;
14+
[SerializeField] internal CollapsableSortedBlockedEntryList blockedList;
15+
16+
public event Action<string> OnUnblockUser;
17+
18+
public void SetupBlockedList()
19+
{
20+
blockedList.OnUnblockUser = OnUnblockUser;
21+
int SortByAlphabeticalOrder(BlockedUserEntry u1, BlockedUserEntry u2)
22+
{
23+
return string.Compare(u1.Model.userName, u2.Model.userName, StringComparison.InvariantCultureIgnoreCase);
24+
}
25+
26+
blockedList.SortingMethod = SortByAlphabeticalOrder;
27+
}
28+
29+
public void Set(BlockedUserEntryModel user)
30+
{
31+
blockedList.Set(user.userId, user);
32+
RefreshContentLayout();
33+
}
34+
35+
public void Remove(string userId)
36+
{
37+
blockedList.Remove(userId);
38+
RefreshContentLayout();
39+
}
40+
41+
public void ClearAllEntries()
42+
{
43+
blockedList.Clear();
44+
}
45+
46+
public override void Show(bool instant = false)
47+
{
48+
gameObject.SetActive(true);
49+
50+
if (scrollBar != null)
51+
scrollBar.SetActive(true);
52+
}
53+
54+
public override void Hide(bool instant = false)
55+
{
56+
gameObject.SetActive(false);
57+
58+
if (scrollBar != null)
59+
scrollBar.SetActive(false);
60+
}
61+
62+
public void SetLoadingActive(bool isActive)
63+
{
64+
loadingContainer.SetActive(isActive);
65+
mainContainer.SetActive(!isActive);
66+
}
67+
68+
public void RefreshContentLayout() =>
69+
Utils.ForceRebuildLayoutImmediate(contentTransform);
70+
71+
public override void RefreshControl()
72+
{
73+
}
74+
}
75+
}

unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/MyAccountHUD/BlockedListComponentView.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
using Cysharp.Threading.Tasks;
2+
using DCL.Social.Friends;
3+
using DCL.Tasks;
4+
using SocialFeaturesAnalytics;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Threading;
8+
9+
namespace DCL.MyAccount
10+
{
11+
public class BlockedListController
12+
{
13+
private readonly IBlockedListComponentView view;
14+
private readonly DataStore dataStore;
15+
private readonly IUserProfileBridge userProfileBridge;
16+
17+
private readonly IBlockedListApiBridge blockedListApiBridge;
18+
private readonly ISocialAnalytics socialAnalytics;
19+
private readonly IFriendsController friendsController;
20+
21+
private CancellationTokenSource lifeTimeCancellationToken;
22+
23+
private UserProfile ownUserProfile => userProfileBridge.GetOwn();
24+
25+
public BlockedListController(
26+
IBlockedListComponentView view,
27+
DataStore dataStore,
28+
IUserProfileBridge userProfileBridge,
29+
IBlockedListApiBridge blockedListApiBridge,
30+
ISocialAnalytics socialAnalytics,
31+
IFriendsController friendsController)
32+
{
33+
this.view = view;
34+
this.dataStore = dataStore;
35+
this.userProfileBridge = userProfileBridge;
36+
this.blockedListApiBridge = blockedListApiBridge;
37+
this.socialAnalytics = socialAnalytics;
38+
this.friendsController = friendsController;
39+
40+
dataStore.myAccount.isMyAccountSectionVisible.OnChange += OnMyAccountSectionVisibleChanged;
41+
dataStore.myAccount.openSection.OnChange += OnMyAccountSectionTabChanged;
42+
43+
ownUserProfile.OnUpdate += OnOwnUserProfileUpdated;
44+
view.OnUnblockUser += UnblockUser;
45+
}
46+
47+
private void OnMyAccountSectionVisibleChanged(bool isVisible, bool _)
48+
{
49+
if (isVisible)
50+
OpenSection();
51+
else
52+
CloseSection();
53+
}
54+
55+
private void OpenSection()
56+
{
57+
lifeTimeCancellationToken = lifeTimeCancellationToken.SafeRestart();
58+
UpdateBlockedUserList(ownUserProfile.blocked, lifeTimeCancellationToken.Token);
59+
}
60+
61+
private void OnMyAccountSectionTabChanged(string currentOpenSection, string _)
62+
{
63+
if (currentOpenSection != MyAccountSection.BlockedList.ToString())
64+
return;
65+
}
66+
67+
private void CloseSection()
68+
{
69+
lifeTimeCancellationToken.SafeCancelAndDispose();
70+
71+
view.ClearAllEntries();
72+
}
73+
74+
75+
private void OnOwnUserProfileUpdated(UserProfile userProfile)
76+
{
77+
if (userProfile == null)
78+
return;
79+
}
80+
81+
private void UnblockUser(string userId)
82+
{
83+
if (!ownUserProfile.IsBlocked(userId)) return;
84+
85+
dataStore.notifications.GenericConfirmation.Set(GenericConfirmationNotificationData.CreateUnBlockUserData(
86+
userProfileBridge.Get(userId)?.userName,
87+
() =>
88+
{
89+
ownUserProfile.Unblock(userId);
90+
view.Remove(userId);
91+
blockedListApiBridge.SendUnblockPlayer(userId);
92+
socialAnalytics.SendPlayerUnblocked(friendsController.IsFriend(userId), PlayerActionSource.MyProfile, userId);
93+
94+
}), true);
95+
}
96+
97+
public void Dispose()
98+
{
99+
dataStore.myAccount.isMyAccountSectionVisible.OnChange -= OnMyAccountSectionVisibleChanged;
100+
dataStore.myAccount.openSection.OnChange -= OnMyAccountSectionTabChanged;
101+
ownUserProfile.OnUpdate -= OnOwnUserProfileUpdated;
102+
}
103+
104+
private async void UpdateBlockedUserList(List<string> blockedUsersList, CancellationToken token)
105+
{
106+
view.SetupBlockedList();
107+
108+
async UniTaskVoid UpdateChannelMembersAsync(IEnumerable<string> blockedUsers,
109+
CancellationToken cancellationToken)
110+
{
111+
view.SetLoadingActive(false);
112+
113+
foreach (string member in blockedUsers)
114+
{
115+
UserProfile memberProfile = userProfileBridge.Get(member);
116+
117+
try { memberProfile ??= await userProfileBridge.RequestFullUserProfileAsync(member, cancellationToken); }
118+
catch (Exception e) when (e is not OperationCanceledException)
119+
{
120+
var fallbackBlockedUserEntry = new BlockedUserEntryModel
121+
{
122+
thumbnailUrl = "",
123+
userId = member,
124+
userName = member,
125+
};
126+
127+
view.Set(fallbackBlockedUserEntry);
128+
}
129+
130+
if (memberProfile != null)
131+
{
132+
var userToAdd = new BlockedUserEntryModel
133+
{
134+
thumbnailUrl = memberProfile.face256SnapshotURL,
135+
userId = memberProfile.userId,
136+
userName = memberProfile.userName,
137+
};
138+
139+
view.Set(userToAdd);
140+
}
141+
}
142+
143+
view.SetLoadingActive(false);
144+
}
145+
146+
UpdateChannelMembersAsync(blockedUsersList, token).Forget();
147+
}
148+
}
149+
}

unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/MyAccountHUD/BlockedListController.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)