Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions osu.Game.Tests/Visual/RankedPlay/TestSceneBubbleChatHistory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Chat;
using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components;

namespace osu.Game.Tests.Visual.RankedPlay
Expand All @@ -27,7 +28,11 @@ public void Setup() => Schedule(() =>
public void TestPostMessages()
{
int messageId = 1;
AddRepeatStep("post message", () => history.PostMessage(new APIUser { Id = 2 }, $"message {messageId++}"), 20);
AddRepeatStep("post message", () => history.PostMessage(new Message
{
Sender = new APIUser { Id = 2 },
Content = $"message {messageId++}"
}), 20);
}

[Test]
Expand All @@ -38,7 +43,13 @@ public void TestCollapse()
AddStep("post some messages", () =>
{
for (int i = 0; i < 10; i++)
history.PostMessage(new APIUser { Id = 2 }, $"message {i}");
{
history.PostMessage(new Message
{
Sender = new APIUser { Id = 2 },
Content = $"message {i}",
});
}
});

AddWaitStep("wait a bit", 10);
Expand Down
10 changes: 10 additions & 0 deletions osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayChat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ public void TestDiscardCardStage()

postLocalUserMessage("this is a message from the local user");
postOpponentMessage("this is a message from the opponent");
AddStep("add long message", () => testChannel.AddNewMessages(new Message(messageIdSequence++)
{
Timestamp = DateTimeOffset.Now,
Sender = new APIUser
{
Id = 2,
Username = "peppy"
},
Content = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget neque non leo placerat sollicitudin eget sit amet sem. Aenean ut ipsum et nulla lobortis viverra ut eget odio.",
}));
}

[Test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,35 @@
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Cursor;
using osu.Game.Graphics.UserInterface;
using osu.Game.Input;
using osu.Game.Input.Bindings;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Chat;
using osu.Game.Online.Multiplayer;
using osu.Game.Overlays.Chat;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Users.Drawables;
using osuTK;
using osuTK.Graphics;

namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components
{
public partial class RankedPlayChatDisplay : VisibilityContainer, IKeyBindingHandler<GlobalAction>
public partial class RankedPlayChatDisplay : VisibilityContainer, IKeyBindingHandler<GlobalAction>, IFocusManager
{
[Resolved]
private ChannelManager? channelManager { get; set; }
Expand All @@ -38,55 +45,72 @@ public partial class RankedPlayChatDisplay : VisibilityContainer, IKeyBindingHan

private readonly MultiplayerRoom room;

private Container content = null!;
private ChatTextBox textbox = null!;
private BubbleChatHistory chatHistory = null!;

private Channel? channel;

private IFocusManager parentFocusManager = null!;

private const float width = 320;

public RankedPlayChatDisplay(MultiplayerRoom room)
{
Size = new Vector2(width, 160);
AutoSizeAxes = Axes.Both;
this.room = room;
}

[BackgroundDependencyLoader]
private void load()
{
InternalChildren = new Drawable[]
InternalChild = new ChatContextMenuContainer
{
textbox = new ChatTextBox
AutoSizeAxes = Axes.Both,
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Child = content = new Container
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
RelativeSizeAxes = Axes.X,
Height = 30,
CornerRadius = 10,
ReleaseFocusOnCommit = true,
HoldFocus = false,
Focus = onFocusGained,
FocusLost = onFocusLost
},
new Container
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Bottom = 35 },
Child = chatHistory = new BubbleChatHistory
Children = new Drawable[]
{
RelativeSizeAxes = Axes.X
textbox = new ChatTextBox
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Width = width,
Height = 30,
CornerRadius = 10,
ReleaseFocusOnCommit = true,
HoldFocus = false,
Focus = onFocusGained,
FocusLost = onFocusLost
},
new Container
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
AutoSizeAxes = Axes.Y,
Width = width * 1.5f,
Padding = new MarginPadding { Bottom = 35 },
Child = chatHistory = new BubbleChatHistory
{
RelativeSizeAxes = Axes.X
}
}
}
}
},
};
}

protected override void LoadComplete()
{
base.LoadComplete();

parentFocusManager = GetContainingFocusManager()!;

resetPlaceholderText();
textbox.OnCommit += onCommit;

Expand All @@ -113,7 +137,7 @@ private void onCommit(TextBox sender, bool newText)
private void onNewMessagesArrived(IEnumerable<Message> bundle)
{
foreach (var message in bundle)
chatHistory.PostMessage(message.Sender, message.Content);
chatHistory.PostMessage(message);
}

private void onFocusGained()
Expand Down Expand Up @@ -163,6 +187,20 @@ public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
{
}

public void TriggerFocusContention(Drawable? triggerSource)
{
if (triggerSource == null || triggerSource.IsRootedAt(content))
parentFocusManager.TriggerFocusContention(triggerSource);
}

public bool ChangeFocus(Drawable? potentialFocusTarget)
{
if (potentialFocusTarget == null || potentialFocusTarget.IsRootedAt(content))
return parentFocusManager.ChangeFocus(potentialFocusTarget);

return false;
}

protected override void PopIn()
{
FinishTransforms();
Expand All @@ -189,6 +227,15 @@ protected override void Dispose(bool isDisposing)
channel.NewMessagesArrived -= onNewMessagesArrived;
}

private partial class ChatContextMenuContainer : OsuContextMenuContainer
{
public ChatContextMenuContainer()
{
Content.Anchor = Anchor.BottomRight;
Content.Origin = Anchor.BottomRight;
}
}

private partial class ChatTextBox : StandAloneChatDisplay.ChatTextBox
{
protected override void LoadComplete()
Expand Down Expand Up @@ -220,7 +267,7 @@ public partial class BubbleChatHistory : CompositeDrawable

private readonly Container<MessageBubble> messageContainer;

private bool expanded;
private readonly BindableBool expanded = new BindableBool();

private Sample messageReceivedSample = null!;
private double? lastSamplePlayback;
Expand All @@ -247,7 +294,7 @@ private void load(AudioManager audio)
/// </summary>
public void Collapse()
{
expanded = false;
expanded.Value = false;

foreach (var child in messageContainer.Reverse().Take(max_length).Reverse())
{
Expand All @@ -265,7 +312,7 @@ public void Collapse()
/// </summary>
public void Expand()
{
expanded = true;
expanded.Value = true;

foreach (var child in messageContainer.Reverse().Take(max_length))
child.Show();
Expand All @@ -274,15 +321,15 @@ public void Expand()
/// <summary>
/// Posts a message.
/// </summary>
/// <param name="user">The user that posted the message.</param>
/// <param name="content">The message content.</param>
public void PostMessage(APIUser user, string content)
/// <param name="message">The message.</param>
public void PostMessage(Message message)
{
var newMessage = new MessageBubble(user, content)
var newMessage = new MessageBubble(message)
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
PostTime = Time.Current
PostTime = Time.Current,
Expanded = { BindTarget = expanded },
};

messageContainer.Add(newMessage);
Expand Down Expand Up @@ -314,7 +361,7 @@ public void PostMessage(APIUser user, string content)
playSample();

// If not in the expanded state, hide the new message after a short while.
if (!expanded)
if (!expanded.Value)
{
using (BeginDelayedSequence(time_before_disappear))
newMessage.Hide();
Expand All @@ -330,19 +377,25 @@ private void playSample()
lastSamplePlayback = Time.Current;
}

private partial class MessageBubble : CompositeDrawable
private partial class MessageBubble : CompositeDrawable, IHasContextMenu, IHasPopover
{
private readonly APIUser user;
private readonly string message;
private readonly Message message;

/// <summary>
/// The time at which this message was posted.
/// </summary>
public required double PostTime { get; init; }

public MessageBubble(APIUser user, string message)
/// <summary>
/// Whether the message history is currently in an expanded state.
/// </summary>
public readonly IBindable<bool> Expanded = new BindableBool();

private const int text_offset = 20;
private const int padding = 8;

public MessageBubble(Message message)
{
this.user = user;
this.message = message;
AutoSizeAxes = Axes.Both;

Expand All @@ -368,14 +421,14 @@ private void load()
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = api.LocalUser.Value.Id == user.Id
Colour = api.LocalUser.Value.Id == message.SenderId
? RankedPlayColourScheme.BLUE.PrimaryDarkest
: RankedPlayColourScheme.RED.PrimaryDarkest,
},
new Container
{
AutoSizeAxes = Axes.Both,
Padding = new MarginPadding(8),
Padding = new MarginPadding(padding),
Children = new Drawable[]
{
new CircularContainer
Expand All @@ -384,20 +437,20 @@ private void load()
Origin = Anchor.CentreLeft,
Size = new Vector2(16),
Masking = true,
Child = new UpdateableAvatar(user)
Child = new UpdateableAvatar(message.Sender)
{
DelayedLoad = false,
RelativeSizeAxes = Axes.Both
}
},
new OsuTextFlowContainer
{
X = 20,
MaximumSize = new Vector2(width * 1.5f, 0),
X = text_offset,
MaximumSize = new Vector2(width * 1.5f - text_offset - padding * 2, 0),
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
Text = message,
Text = message.Content,
}
}
}
Expand All @@ -416,6 +469,31 @@ public override void Hide()
{
this.FadeOut(200, Easing.OutQuint);
}

public MenuItem[]? ContextMenuItems
{
get
{
if (!Expanded.Value)
return null;

if (message.Sender.Equals(APIUser.SYSTEM_USER))
return null;

if (message.Sender.Equals(api.LocalUser.Value))
return null;

return [new OsuMenuItem(UsersStrings.ReportButtonText, MenuItemType.Destructive, this.ShowPopover)];
}
}

public Popover? GetPopover()
{
if (message.Sender.Equals(api.LocalUser.Value))
return null;

return new ReportChatPopover(message);
}
}
}
}
Expand Down
Loading