Merge remote-tracking branch 'upstream/master' into modular-results-screen

This commit is contained in:
Dean Herbert
2018-12-22 16:20:39 +09:00
4 changed files with 113 additions and 187 deletions

View File

@ -68,31 +68,33 @@ namespace osu.Game.Tests.Visual
chatDisplay.Channel.Value = testChannel; chatDisplay.Channel.Value = testChannel;
chatDisplay2.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, Sender = admin,
Content = "I am a wang!" 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, Sender = redUser,
Content = "I am team red." 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, Sender = redUser,
Content = "I plan to win!" 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, Sender = blueUser,
Content = "Not on my watch. Prepare to eat saaaaaaaaaand. Lots and lots of saaaaaaand." 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, Sender = admin,
Content = "Okay okay, calm down guys. Let's do this!" Content = "Okay okay, calm down guys. Let's do this!"

View File

@ -1,19 +1,15 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic; using System;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface; 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.Graphics.UserInterface;
using osuTK; using osu.Game.Overlays.Chat;
using osuTK.Graphics; using osuTK.Graphics;
namespace osu.Game.Online.Chat namespace osu.Game.Online.Chat
@ -23,22 +19,27 @@ namespace osu.Game.Online.Chat
/// </summary> /// </summary>
public class StandAloneChatDisplay : CompositeDrawable public class StandAloneChatDisplay : CompositeDrawable
{ {
private readonly bool postingTextbox;
public readonly Bindable<Channel> Channel = new Bindable<Channel>(); public readonly Bindable<Channel> Channel = new Bindable<Channel>();
private readonly FillFlowContainer messagesFlow;
private Channel lastChannel;
private readonly FocusedTextBox textbox; private readonly FocusedTextBox textbox;
protected ChannelManager ChannelManager; protected ChannelManager ChannelManager;
private ScrollContainer scroll;
private DrawableChannel drawableChannel;
private const float textbox_height = 30;
/// <summary> /// <summary>
/// Construct a new instance. /// Construct a new instance.
/// </summary> /// </summary>
/// <param name="postingTextbox">Whether a textbox for posting new messages should be displayed.</param> /// <param name="postingTextbox">Whether a textbox for posting new messages should be displayed.</param>
public StandAloneChatDisplay(bool postingTextbox = false) public StandAloneChatDisplay(bool postingTextbox = false)
{ {
this.postingTextbox = postingTextbox;
CornerRadius = 10; CornerRadius = 10;
Masking = true; Masking = true;
@ -50,23 +51,10 @@ namespace osu.Game.Online.Chat
Alpha = 0.8f, Alpha = 0.8f,
RelativeSizeAxes = Axes.Both 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) if (postingTextbox)
{ {
messagesFlow.Y -= textbox_height;
AddInternal(textbox = new FocusedTextBox AddInternal(textbox = new FocusedTextBox
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
@ -117,112 +105,43 @@ namespace osu.Game.Online.Chat
this.MoveToY(100, 500, Easing.In); this.MoveToY(100, 500, Easing.In);
} }
protected virtual Drawable CreateMessage(Message message) protected virtual ChatLine CreateMessage(Message message) => new StandAloneMessage(message);
{
return new StandAloneMessage(message);
}
private void channelChanged(Channel channel) private void channelChanged(Channel channel)
{ {
if (lastChannel != null) drawableChannel?.Expire();
lastChannel.NewMessagesArrived -= newMessages;
lastChannel = channel;
messagesFlow.Clear();
if (channel == null) return; if (channel == null) return;
channel.NewMessagesArrived += newMessages; AddInternal(drawableChannel = new StandAloneDrawableChannel(channel)
{
newMessages(channel.Messages); CreateChatLineAction = CreateMessage,
Padding = new MarginPadding { Bottom = postingTextbox ? textbox_height : 0 }
});
} }
private void newMessages(IEnumerable<Message> messages) protected class StandAloneDrawableChannel : DrawableChannel
{ {
var excessChildren = messagesFlow.Children.Count - 10; public Func<Message,ChatLine> CreateChatLineAction;
if (excessChildren > 0)
foreach (var c in messagesFlow.Children.Take(excessChildren))
c.Expire();
foreach (var message in messages) protected override ChatLine CreateChatLine(Message m) => CreateChatLineAction(m);
public StandAloneDrawableChannel(Channel channel)
: base(channel)
{ {
var formatted = MessageFormatter.FormatMessage(message); ChatLineFlow.Padding = new MarginPadding { Horizontal = 0 };
var drawable = CreateMessage(formatted);
drawable.Y = messagesFlow.Height;
messagesFlow.Add(drawable);
} }
} }
protected class StandAloneMessage : CompositeDrawable protected class StandAloneMessage : ChatLine
{ {
protected readonly Message Message; protected override float TextSize => 15;
protected OsuSpriteText SenderText;
protected Circle ColourBox;
public StandAloneMessage(Message message) protected override float HorizontalPadding => 10;
{ protected override float MessagePadding => 120;
Message = message;
}
[BackgroundDependencyLoader] public StandAloneMessage(Message message) : base(message)
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);
} }
} }
} }

View File

@ -1,72 +1,38 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Linq; using System.Linq;
using osuTK;
using osuTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Chat; using osu.Game.Online.Chat;
using osu.Game.Users; using osu.Game.Users;
using osu.Framework.Graphics.Cursor; using osuTK;
using osu.Framework.Graphics.UserInterface; using osuTK.Graphics;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.Chat namespace osu.Game.Overlays.Chat
{ {
public class ChatLine : Container public class ChatLine : CompositeDrawable
{ {
private static readonly Color4[] username_colours = public const float LEFT_PADDING = default_message_padding + default_horizontal_padding * 2;
{
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"), private const float default_message_padding = 200;
OsuColour.FromHex("f2e394"),
OsuColour.FromHex("f2ae72"),
OsuColour.FromHex("f98f8a"),
OsuColour.FromHex("7daef4"),
OsuColour.FromHex("a691f2"),
OsuColour.FromHex("c894d3"),
OsuColour.FromHex("d895b0"),
OsuColour.FromHex("53c4a1"), protected virtual float MessagePadding => default_message_padding;
OsuColour.FromHex("eace5c"),
OsuColour.FromHex("ea8c47"),
OsuColour.FromHex("fc4f4f"),
OsuColour.FromHex("3d94ea"),
OsuColour.FromHex("7760ea"),
OsuColour.FromHex("af52c6"),
OsuColour.FromHex("e25696"),
OsuColour.FromHex("677c66"), private const float default_horizontal_padding = 15;
OsuColour.FromHex("9b8732"),
OsuColour.FromHex("8c5129"),
OsuColour.FromHex("8c3030"),
OsuColour.FromHex("1f5d91"),
OsuColour.FromHex("4335a5"),
OsuColour.FromHex("812a96"),
OsuColour.FromHex("992861"),
};
public const float LEFT_PADDING = message_padding + padding * 2; protected virtual float HorizontalPadding => default_horizontal_padding;
private const float padding = 15; protected virtual float TextSize => 20;
private const float message_padding = 200;
private const float action_padding = 3;
private const float text_size = 20;
private Color4 customUsernameColour; private Color4 customUsernameColour;
@ -75,14 +41,13 @@ namespace osu.Game.Overlays.Chat
public ChatLine(Message message) public ChatLine(Message message)
{ {
Message = message; Message = message;
Padding = new MarginPadding { Left = HorizontalPadding, Right = HorizontalPadding };
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y; 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 Message message;
private OsuSpriteText username; private OsuSpriteText username;
@ -106,10 +71,9 @@ namespace osu.Game.Overlays.Chat
} }
} }
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader]
private void load(OsuColour colours, ChannelManager chatManager) private void load(OsuColour colours)
{ {
this.chatManager = chatManager;
customUsernameColour = colours.ChatBlue; customUsernameColour = colours.ChatBlue;
} }
@ -125,7 +89,7 @@ namespace osu.Game.Overlays.Chat
{ {
Font = @"Exo2.0-BoldItalic", Font = @"Exo2.0-BoldItalic",
Colour = hasBackground ? customUsernameColour : username_colours[message.Sender.Id % username_colours.Length], Colour = hasBackground ? customUsernameColour : username_colours[message.Sender.Id % username_colours.Length],
TextSize = text_size, TextSize = TextSize,
}; };
if (hasBackground) if (hasBackground)
@ -163,11 +127,11 @@ namespace osu.Game.Overlays.Chat
}; };
} }
Children = new Drawable[] InternalChildren = new Drawable[]
{ {
new Container new Container
{ {
Size = new Vector2(message_padding, text_size), Size = new Vector2(MessagePadding, TextSize),
Children = new Drawable[] Children = new Drawable[]
{ {
timestamp = new OsuSpriteText timestamp = new OsuSpriteText
@ -176,7 +140,7 @@ namespace osu.Game.Overlays.Chat
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
Font = @"Exo2.0-SemiBold", Font = @"Exo2.0-SemiBold",
FixedWidth = true, FixedWidth = true,
TextSize = text_size * 0.75f, TextSize = TextSize * 0.75f,
}, },
new MessageSender(message.Sender) new MessageSender(message.Sender)
{ {
@ -191,7 +155,7 @@ namespace osu.Game.Overlays.Chat
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Left = message_padding + padding }, Padding = new MarginPadding { Left = MessagePadding + HorizontalPadding },
Children = new Drawable[] Children = new Drawable[]
{ {
contentFlow = new LinkFlowContainer(t => contentFlow = new LinkFlowContainer(t =>
@ -204,7 +168,7 @@ namespace osu.Game.Overlays.Chat
t.Colour = OsuColour.FromHex(message.Sender.Colour); t.Colour = OsuColour.FromHex(message.Sender.Colour);
} }
t.TextSize = text_size; t.TextSize = TextSize;
}) })
{ {
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
@ -257,5 +221,44 @@ namespace osu.Game.Overlays.Chat
new OsuMenuItem("Start Chat", MenuItemType.Standard, startChatAction), 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"),
};
} }
} }

View File

@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Chat
public class DrawableChannel : Container public class DrawableChannel : Container
{ {
public readonly Channel Channel; public readonly Channel Channel;
private readonly ChatLineContainer flow; protected readonly ChatLineContainer ChatLineFlow;
private readonly ScrollContainer scroll; private readonly ScrollContainer scroll;
public DrawableChannel(Channel channel) public DrawableChannel(Channel channel)
@ -38,7 +38,7 @@ namespace osu.Game.Overlays.Chat
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Child = flow = new ChatLineContainer Child = ChatLineFlow = new ChatLineContainer
{ {
Padding = new MarginPadding { Left = 20, Right = 20 }, Padding = new MarginPadding { Left = 20, Right = 20 },
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
@ -72,17 +72,19 @@ namespace osu.Game.Overlays.Chat
Channel.PendingMessageResolved -= pendingMessageResolved; Channel.PendingMessageResolved -= pendingMessageResolved;
} }
protected virtual ChatLine CreateChatLine(Message m) => new ChatLine(m);
private void newMessagesArrived(IEnumerable<Message> newMessages) private void newMessagesArrived(IEnumerable<Message> newMessages)
{ {
// Add up to last Channel.MAX_HISTORY messages // Add up to last Channel.MAX_HISTORY messages
var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MaxHistory)); 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(); 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; int count = staleMessages.Length - Channel.MaxHistory;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
@ -96,25 +98,25 @@ namespace osu.Game.Overlays.Chat
private void pendingMessageResolved(Message existing, Message updated) 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) if (found != null)
{ {
Trace.Assert(updated.Id.HasValue, "An updated message was returned with no ID."); Trace.Assert(updated.Id.HasValue, "An updated message was returned with no ID.");
flow.Remove(found); ChatLineFlow.Remove(found);
found.Message = updated; found.Message = updated;
flow.Add(found); ChatLineFlow.Add(found);
} }
} }
private void messageRemoved(Message removed) 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 void scrollToEnd() => ScheduleAfterChildren(() => scroll.ScrollToEnd());
private class ChatLineContainer : FillFlowContainer<ChatLine> protected class ChatLineContainer : FillFlowContainer<ChatLine>
{ {
protected override int Compare(Drawable x, Drawable y) protected override int Compare(Drawable x, Drawable y)
{ {