From 3a13899ce1d48881cc60035d31a8a9fba20e0b1e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Dec 2018 16:50:38 +0900 Subject: [PATCH] Add stand-alone chat component --- .../Visual/TestCaseMatchChatDisplay.cs | 83 +++++++++ osu.Game/Online/Chat/StandAloneChatDisplay.cs | 175 ++++++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 osu.Game.Tests/Visual/TestCaseMatchChatDisplay.cs create mode 100644 osu.Game/Online/Chat/StandAloneChatDisplay.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatchChatDisplay.cs b/osu.Game.Tests/Visual/TestCaseMatchChatDisplay.cs new file mode 100644 index 0000000000..c959eeb3d4 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseMatchChatDisplay.cs @@ -0,0 +1,83 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Game.Online.Chat; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseStandAloneChatDisplay : OsuTestCase + { + private readonly Channel testChannel = new Channel(); + + private readonly User admin = new User + { + Username = "HappyStick", + Id = 2, + Colour = "f2ca34" + }; + + private readonly User redUser = new User + { + Username = "BanchoBot", + Id = 3, + }; + + private readonly User blueUser = new User + { + Username = "Zallius", + Id = 4, + }; + + public TestCaseStandAloneChatDisplay() + { + StandAloneChatDisplay chatDisplay; + + Add(chatDisplay = new StandAloneChatDisplay + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(400, 80) + }); + + chatDisplay.Channel.Value = testChannel; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + AddStep("message from admin", () => testChannel.AddLocalEcho(new LocalEchoMessage + { + Sender = admin, + Content = "I am a wang!" + })); + + AddStep("message from team red", () => testChannel.AddLocalEcho(new LocalEchoMessage + { + Sender = redUser, + Content = "I am team red." + })); + + AddStep("message from team red", () => testChannel.AddLocalEcho(new LocalEchoMessage + { + Sender = redUser, + Content = "I plan to win!" + })); + + AddStep("message from team blue", () => testChannel.AddLocalEcho(new LocalEchoMessage + { + Sender = blueUser, + Content = "Not on my watch. Prepare to eat saaaaaaaaaand. Lots and lots of saaaaaaand." + })); + + AddStep("message from admin", () => testChannel.AddLocalEcho(new LocalEchoMessage + { + Sender = admin, + Content = "Okay okay, calm down guys. Let's do this!" + })); + } + } +} diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs new file mode 100644 index 0000000000..30a730c5a1 --- /dev/null +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -0,0 +1,175 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Online.Chat +{ + /// + /// Display a chat channel in an insolated region. + /// + public class StandAloneChatDisplay : CompositeDrawable + { + public readonly Bindable Channel = new Bindable(); + private readonly FillFlowContainer messagesFlow; + private Channel lastChannel; + + public StandAloneChatDisplay() + { + CornerRadius = 10; + Masking = true; + + InternalChildren = new Drawable[] + { + new Box + { + Colour = Color4.Black, + Alpha = 0.8f, + RelativeSizeAxes = Axes.Both + }, + messagesFlow = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + LayoutEasing = Easing.Out, + LayoutDuration = 500, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Direction = FillDirection.Vertical + } + }; + + Channel.BindValueChanged(channelChanged); + } + + public void Contract() + { + this.FadeIn(300); + this.MoveToY(0, 500, Easing.OutQuint); + } + + public void Expand() + { + this.FadeOut(200); + this.MoveToY(100, 500, Easing.In); + } + + protected virtual Drawable CreateMessage(Message message) + { + return new StandAloneMessage(message); + } + + private void channelChanged(Channel channel) + { + if (lastChannel != null) + lastChannel.NewMessagesArrived -= newMessages; + + lastChannel = channel; + messagesFlow.Clear(); + + if (channel == null) return; + + channel.NewMessagesArrived += newMessages; + } + + private void newMessages(IEnumerable messages) + { + var excessChildren = messagesFlow.Children.Count - 10; + if (excessChildren > 0) + foreach (var c in messagesFlow.Children.Take(excessChildren)) + c.Expire(); + + foreach (var message in messages) + { + var formatted = MessageFormatter.FormatMessage(message); + var drawable = CreateMessage(formatted); + drawable.Y = messagesFlow.Height; + messagesFlow.Add(drawable); + } + } + + protected class StandAloneMessage : CompositeDrawable + { + protected readonly Message Message; + protected OsuSpriteText SenderText; + protected Circle ColourBox; + + public StandAloneMessage(Message message) + { + Message = message; + } + + [BackgroundDependencyLoader] + private void load() + { + Margin = new MarginPadding(3); + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + InternalChildren = new Drawable[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.X, + Width = 0.2f, + Children = new Drawable[] + { + SenderText = new OsuSpriteText + { + Font = @"Exo2.0-Bold", + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Text = Message.Sender.ToString() + } + } + }, + new Container + { + Size = new Vector2(8, OsuSpriteText.FONT_SIZE), + Margin = new MarginPadding { Horizontal = 3 }, + Children = new Drawable[] + { + ColourBox = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(8) + } + } + }, + new OsuTextFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Width = 0.5f, + Text = Message.DisplayContent + } + } + } + }; + + if (!string.IsNullOrEmpty(Message.Sender.Colour)) + SenderText.Colour = ColourBox.Colour = OsuColour.FromHex(Message.Sender.Colour); + } + } + } +}