diff --git a/osu.Game.Tests/Visual/TestCaseStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/TestCaseStandAloneChatDisplay.cs index 16ce720ab1..b5ce1f1eaf 100644 --- a/osu.Game.Tests/Visual/TestCaseStandAloneChatDisplay.cs +++ b/osu.Game.Tests/Visual/TestCaseStandAloneChatDisplay.cs @@ -68,31 +68,33 @@ namespace osu.Game.Tests.Visual chatDisplay.Channel.Value = testChannel; chatDisplay2.Channel.Value = testChannel; - AddStep("message from admin", () => testChannel.AddLocalEcho(new LocalEchoMessage + int sequence = 0; + + AddStep("message from admin", () => testChannel.AddNewMessages(new Message(sequence++) { Sender = admin, Content = "I am a wang!" })); - AddStep("message from team red", () => testChannel.AddLocalEcho(new LocalEchoMessage + AddStep("message from team red", () => testChannel.AddNewMessages(new Message(sequence++) { Sender = redUser, Content = "I am team red." })); - AddStep("message from team red", () => testChannel.AddLocalEcho(new LocalEchoMessage + AddStep("message from team red", () => testChannel.AddNewMessages(new Message(sequence++) { Sender = redUser, Content = "I plan to win!" })); - AddStep("message from team blue", () => testChannel.AddLocalEcho(new LocalEchoMessage + AddStep("message from team blue", () => testChannel.AddNewMessages(new Message(sequence++) { Sender = blueUser, Content = "Not on my watch. Prepare to eat saaaaaaaaaand. Lots and lots of saaaaaaand." })); - AddStep("message from admin", () => testChannel.AddLocalEcho(new LocalEchoMessage + AddStep("message from admin", () => testChannel.AddNewMessages(new Message(sequence++) { 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 index 332334a043..1ec138ab57 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -1,19 +1,15 @@ // 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 System; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osuTK; +using osu.Game.Overlays.Chat; using osuTK.Graphics; namespace osu.Game.Online.Chat @@ -23,22 +19,27 @@ namespace osu.Game.Online.Chat /// public class StandAloneChatDisplay : CompositeDrawable { + private readonly bool postingTextbox; + public readonly Bindable Channel = new Bindable(); - private readonly FillFlowContainer messagesFlow; - - private Channel lastChannel; - private readonly FocusedTextBox textbox; protected ChannelManager ChannelManager; + private ScrollContainer scroll; + + private DrawableChannel drawableChannel; + + private const float textbox_height = 30; + /// /// Construct a new instance. /// /// Whether a textbox for posting new messages should be displayed. public StandAloneChatDisplay(bool postingTextbox = false) { + this.postingTextbox = postingTextbox; CornerRadius = 10; Masking = true; @@ -50,23 +51,10 @@ namespace osu.Game.Online.Chat 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 - } }; - const float textbox_height = 30; - if (postingTextbox) { - messagesFlow.Y -= textbox_height; AddInternal(textbox = new FocusedTextBox { RelativeSizeAxes = Axes.X, @@ -117,112 +105,43 @@ namespace osu.Game.Online.Chat this.MoveToY(100, 500, Easing.In); } - protected virtual Drawable CreateMessage(Message message) - { - return new StandAloneMessage(message); - } + protected virtual ChatLine CreateMessage(Message message) => new StandAloneMessage(message); private void channelChanged(Channel channel) { - if (lastChannel != null) - lastChannel.NewMessagesArrived -= newMessages; - - lastChannel = channel; - messagesFlow.Clear(); + drawableChannel?.Expire(); if (channel == null) return; - channel.NewMessagesArrived += newMessages; - - newMessages(channel.Messages); + AddInternal(drawableChannel = new StandAloneDrawableChannel(channel) + { + CreateChatLineAction = CreateMessage, + Padding = new MarginPadding { Bottom = postingTextbox ? textbox_height : 0 } + }); } - private void newMessages(IEnumerable messages) + protected class StandAloneDrawableChannel : DrawableChannel { - var excessChildren = messagesFlow.Children.Count - 10; - if (excessChildren > 0) - foreach (var c in messagesFlow.Children.Take(excessChildren)) - c.Expire(); + public Func CreateChatLineAction; - foreach (var message in messages) + protected override ChatLine CreateChatLine(Message m) => CreateChatLineAction(m); + + public StandAloneDrawableChannel(Channel channel) + : base(channel) { - var formatted = MessageFormatter.FormatMessage(message); - var drawable = CreateMessage(formatted); - drawable.Y = messagesFlow.Height; - messagesFlow.Add(drawable); + ChatLineFlow.Padding = new MarginPadding { Horizontal = 0 }; } } - protected class StandAloneMessage : CompositeDrawable + protected class StandAloneMessage : ChatLine { - protected readonly Message Message; - protected OsuSpriteText SenderText; - protected Circle ColourBox; + protected override float TextSize => 15; - public StandAloneMessage(Message message) + protected override float HorizontalPadding => 10; + protected override float MessagePadding => 120; + + public StandAloneMessage(Message message) : base(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); } } } diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index c11de48430..29579056bf 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -1,72 +1,38 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . +// Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; using System.Linq; -using osuTK; -using osuTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.Chat; using osu.Game.Users; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics.UserInterface; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Overlays.Chat { - public class ChatLine : Container + public class ChatLine : CompositeDrawable { - private static readonly Color4[] username_colours = - { - OsuColour.FromHex("588c7e"), - OsuColour.FromHex("b2a367"), - OsuColour.FromHex("c98f65"), - OsuColour.FromHex("bc5151"), - OsuColour.FromHex("5c8bd6"), - OsuColour.FromHex("7f6ab7"), - OsuColour.FromHex("a368ad"), - OsuColour.FromHex("aa6880"), + public const float LEFT_PADDING = default_message_padding + default_horizontal_padding * 2; - OsuColour.FromHex("6fad9b"), - OsuColour.FromHex("f2e394"), - OsuColour.FromHex("f2ae72"), - OsuColour.FromHex("f98f8a"), - OsuColour.FromHex("7daef4"), - OsuColour.FromHex("a691f2"), - OsuColour.FromHex("c894d3"), - OsuColour.FromHex("d895b0"), + private const float default_message_padding = 200; - OsuColour.FromHex("53c4a1"), - OsuColour.FromHex("eace5c"), - OsuColour.FromHex("ea8c47"), - OsuColour.FromHex("fc4f4f"), - OsuColour.FromHex("3d94ea"), - OsuColour.FromHex("7760ea"), - OsuColour.FromHex("af52c6"), - OsuColour.FromHex("e25696"), + protected virtual float MessagePadding => default_message_padding; - OsuColour.FromHex("677c66"), - OsuColour.FromHex("9b8732"), - OsuColour.FromHex("8c5129"), - OsuColour.FromHex("8c3030"), - OsuColour.FromHex("1f5d91"), - OsuColour.FromHex("4335a5"), - OsuColour.FromHex("812a96"), - OsuColour.FromHex("992861"), - }; + private const float default_horizontal_padding = 15; - public const float LEFT_PADDING = message_padding + padding * 2; + protected virtual float HorizontalPadding => default_horizontal_padding; - private const float padding = 15; - private const float message_padding = 200; - private const float action_padding = 3; - private const float text_size = 20; + protected virtual float TextSize => 20; private Color4 customUsernameColour; @@ -75,14 +41,13 @@ namespace osu.Game.Overlays.Chat public ChatLine(Message message) { Message = message; - + Padding = new MarginPadding { Left = HorizontalPadding, Right = HorizontalPadding }; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - - Padding = new MarginPadding { Left = padding, Right = padding }; } - private ChannelManager chatManager; + [Resolved(CanBeNull = true)] + private ChannelManager chatManager { get; set; } private Message message; private OsuSpriteText username; @@ -106,10 +71,9 @@ namespace osu.Game.Overlays.Chat } } - [BackgroundDependencyLoader(true)] - private void load(OsuColour colours, ChannelManager chatManager) + [BackgroundDependencyLoader] + private void load(OsuColour colours) { - this.chatManager = chatManager; customUsernameColour = colours.ChatBlue; } @@ -125,7 +89,7 @@ namespace osu.Game.Overlays.Chat { Font = @"Exo2.0-BoldItalic", Colour = hasBackground ? customUsernameColour : username_colours[message.Sender.Id % username_colours.Length], - TextSize = text_size, + TextSize = TextSize, }; if (hasBackground) @@ -163,11 +127,11 @@ namespace osu.Game.Overlays.Chat }; } - Children = new Drawable[] + InternalChildren = new Drawable[] { new Container { - Size = new Vector2(message_padding, text_size), + Size = new Vector2(MessagePadding, TextSize), Children = new Drawable[] { timestamp = new OsuSpriteText @@ -176,7 +140,7 @@ namespace osu.Game.Overlays.Chat Origin = Anchor.CentreLeft, Font = @"Exo2.0-SemiBold", FixedWidth = true, - TextSize = text_size * 0.75f, + TextSize = TextSize * 0.75f, }, new MessageSender(message.Sender) { @@ -191,7 +155,7 @@ namespace osu.Game.Overlays.Chat { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = message_padding + padding }, + Padding = new MarginPadding { Left = MessagePadding + HorizontalPadding }, Children = new Drawable[] { contentFlow = new LinkFlowContainer(t => @@ -204,7 +168,7 @@ namespace osu.Game.Overlays.Chat t.Colour = OsuColour.FromHex(message.Sender.Colour); } - t.TextSize = text_size; + t.TextSize = TextSize; }) { AutoSizeAxes = Axes.Y, @@ -257,5 +221,44 @@ namespace osu.Game.Overlays.Chat new OsuMenuItem("Start Chat", MenuItemType.Standard, startChatAction), }; } + + private static readonly Color4[] username_colours = + { + OsuColour.FromHex("588c7e"), + OsuColour.FromHex("b2a367"), + OsuColour.FromHex("c98f65"), + OsuColour.FromHex("bc5151"), + OsuColour.FromHex("5c8bd6"), + OsuColour.FromHex("7f6ab7"), + OsuColour.FromHex("a368ad"), + OsuColour.FromHex("aa6880"), + + OsuColour.FromHex("6fad9b"), + OsuColour.FromHex("f2e394"), + OsuColour.FromHex("f2ae72"), + OsuColour.FromHex("f98f8a"), + OsuColour.FromHex("7daef4"), + OsuColour.FromHex("a691f2"), + OsuColour.FromHex("c894d3"), + OsuColour.FromHex("d895b0"), + + OsuColour.FromHex("53c4a1"), + OsuColour.FromHex("eace5c"), + OsuColour.FromHex("ea8c47"), + OsuColour.FromHex("fc4f4f"), + OsuColour.FromHex("3d94ea"), + OsuColour.FromHex("7760ea"), + OsuColour.FromHex("af52c6"), + OsuColour.FromHex("e25696"), + + OsuColour.FromHex("677c66"), + OsuColour.FromHex("9b8732"), + OsuColour.FromHex("8c5129"), + OsuColour.FromHex("8c3030"), + OsuColour.FromHex("1f5d91"), + OsuColour.FromHex("4335a5"), + OsuColour.FromHex("812a96"), + OsuColour.FromHex("992861"), + }; } } diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 2418eda2b6..c8fc15a0bc 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Chat public class DrawableChannel : Container { public readonly Channel Channel; - private readonly ChatLineContainer flow; + protected readonly ChatLineContainer ChatLineFlow; private readonly ScrollContainer scroll; public DrawableChannel(Channel channel) @@ -38,7 +38,7 @@ namespace osu.Game.Overlays.Chat { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Child = flow = new ChatLineContainer + Child = ChatLineFlow = new ChatLineContainer { Padding = new MarginPadding { Left = 20, Right = 20 }, RelativeSizeAxes = Axes.X, @@ -72,17 +72,19 @@ namespace osu.Game.Overlays.Chat Channel.PendingMessageResolved -= pendingMessageResolved; } + protected virtual ChatLine CreateChatLine(Message m) => new ChatLine(m); + private void newMessagesArrived(IEnumerable newMessages) { // Add up to last Channel.MAX_HISTORY messages var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MaxHistory)); - flow.AddRange(displayMessages.Select(m => new ChatLine(m))); + ChatLineFlow.AddRange(displayMessages.Select(CreateChatLine)); - if (scroll.IsScrolledToEnd(10) || !flow.Children.Any() || newMessages.Any(m => m is LocalMessage)) + if (scroll.IsScrolledToEnd(10) || !ChatLineFlow.Children.Any() || newMessages.Any(m => m is LocalMessage)) scrollToEnd(); - var staleMessages = flow.Children.Where(c => c.LifetimeEnd == double.MaxValue).ToArray(); + var staleMessages = ChatLineFlow.Children.Where(c => c.LifetimeEnd == double.MaxValue).ToArray(); int count = staleMessages.Length - Channel.MaxHistory; for (int i = 0; i < count; i++) @@ -96,25 +98,25 @@ namespace osu.Game.Overlays.Chat private void pendingMessageResolved(Message existing, Message updated) { - var found = flow.Children.LastOrDefault(c => c.Message == existing); + var found = ChatLineFlow.Children.LastOrDefault(c => c.Message == existing); if (found != null) { Trace.Assert(updated.Id.HasValue, "An updated message was returned with no ID."); - flow.Remove(found); + ChatLineFlow.Remove(found); found.Message = updated; - flow.Add(found); + ChatLineFlow.Add(found); } } private void messageRemoved(Message removed) { - flow.Children.FirstOrDefault(c => c.Message == removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); + ChatLineFlow.Children.FirstOrDefault(c => c.Message == removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); } private void scrollToEnd() => ScheduleAfterChildren(() => scroll.ScrollToEnd()); - private class ChatLineContainer : FillFlowContainer + protected class ChatLineContainer : FillFlowContainer { protected override int Compare(Drawable x, Drawable y) {