diff --git a/osu.Game.Tests/Chat/TestSceneChannelManager.cs b/osu.Game.Tests/Chat/TestSceneChannelManager.cs index ef4d4f683a..5c7f0b0a2f 100644 --- a/osu.Game.Tests/Chat/TestSceneChannelManager.cs +++ b/osu.Game.Tests/Chat/TestSceneChannelManager.cs @@ -42,6 +42,7 @@ namespace osu.Game.Tests.Chat sentMessages = new List(); silencedUserIds = new List(); + ((DummyAPIAccess)API).LocalUserState.Blocks.Clear(); ((DummyAPIAccess)API).HandleRequest = req => { switch (req) @@ -63,6 +64,10 @@ namespace osu.Game.Tests.Chat silencedUserIds.Clear(); return true; + case GetMessagesRequest getMessages: + getMessages.TriggerSuccess(sentMessages); + return true; + case GetUpdatesRequest updatesRequest: updatesRequest.TriggerSuccess(new GetUpdatesResponse { @@ -161,6 +166,60 @@ namespace osu.Game.Tests.Chat AddUntilStep("/help command received", () => channel.Messages.Last().Content.Contains("Supported commands")); } + [Test] + public void TestBlockedUserMessagesAreDeletedFromInitialMessageBatch() + { + Channel channel = null; + + AddStep("create channel", () => channel = createChannel(1, ChannelType.Public)); + AddStep("post a message from blocked user", () => sentMessages.Add(new Message + { + ChannelId = channel.Id, + Content = "i am blocked", + SenderId = 1234 + })); + AddStep("mark user as blocked", () => ((DummyAPIAccess)API).LocalUserState.Blocks.Add(new APIRelation + { + TargetUser = new APIUser { Username = "blocked", Id = 1234 }, + TargetID = 1234, + })); + + AddStep("join channel and select it", () => + { + channelManager.JoinChannel(channel); + channelManager.CurrentChannel.Value = channel; + }); + AddAssert("channel has no messages", () => channel.Messages, () => Is.Empty); + } + + [Test] + public void TestBlockedUserMessagesAreDeletedImmediatelyOnBlock() + { + Channel channel = null; + + AddStep("create channel", () => channel = createChannel(1, ChannelType.Public)); + + AddStep("join channel and select it", () => + { + channelManager.JoinChannel(channel); + channelManager.CurrentChannel.Value = channel; + }); + AddStep("post a message from blocked user", () => sentMessages.Add(new Message + { + ChannelId = channel.Id, + Content = "i am blocked", + SenderId = 1234 + })); + AddUntilStep("channel has message", () => channel.Messages, () => Is.Not.Empty); + + AddStep("block user", () => ((DummyAPIAccess)API).LocalUserState.Blocks.Add(new APIRelation + { + TargetUser = new APIUser { Username = "blocked", Id = 1234 }, + TargetID = 1234, + })); + AddAssert("channel has no messages", () => channel.Messages, () => Is.Empty); + } + private void handlePostMessageRequest(PostMessageRequest request) { var message = new Message(++currentMessageId) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index fde6c4db06..eb5d6d1b9c 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -70,6 +71,7 @@ namespace osu.Game.Online.Chat private UserLookupCache users { get; set; } private readonly IBindable apiState = new Bindable(); + private readonly IBindableList localUserBlocks = new BindableList(); private ScheduledDelegate scheduledAck; private IChatClient chatClient = null!; @@ -95,6 +97,9 @@ namespace osu.Game.Online.Chat apiState.BindTo(api.State); apiState.BindValueChanged(_ => SendAck(), true); + + localUserBlocks.BindTo(api.LocalUserState.Blocks); + localUserBlocks.BindCollectionChanged((_, args) => Schedule(() => onBlocksChanged(args))); } /// @@ -311,8 +316,9 @@ namespace osu.Game.Online.Chat private void addMessages(List messages) { var channels = JoinedChannels.ToList(); + var blockedUserIds = localUserBlocks.Select(b => b.TargetID).ToList(); - foreach (var group in messages.GroupBy(m => m.ChannelId)) + foreach (var group in messages.Where(m => !blockedUserIds.Contains(m.SenderId)).GroupBy(m => m.ChannelId)) channels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); lastSilenceMessageId ??= messages.LastOrDefault()?.Id; @@ -641,6 +647,18 @@ namespace osu.Game.Online.Chat api.Queue(req); } + private void onBlocksChanged(NotifyCollectionChangedEventArgs args) + { + if (args.Action != NotifyCollectionChangedAction.Add) + return; + + foreach (APIRelation newBlock in args.NewItems!) + { + foreach (var channel in joinedChannels) + channel.RemoveMessagesFromUser(newBlock.TargetID); + } + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing);