mirror of
https://github.com/osukey/osukey.git
synced 2025-08-07 00:23:59 +09:00
Merge pull request #1154 from peppy/chat-local-echo-v2
Add local chat echo support
This commit is contained in:
Submodule osu-framework updated: bce1e26732...f1527e5456
@ -26,6 +26,8 @@ namespace osu.Game.Online.Chat
|
|||||||
|
|
||||||
public readonly SortedList<Message> Messages = new SortedList<Message>(Comparer<Message>.Default);
|
public readonly SortedList<Message> Messages = new SortedList<Message>(Comparer<Message>.Default);
|
||||||
|
|
||||||
|
private readonly List<LocalEchoMessage> pendingMessages = new List<LocalEchoMessage>();
|
||||||
|
|
||||||
public Bindable<bool> Joined = new Bindable<bool>();
|
public Bindable<bool> Joined = new Bindable<bool>();
|
||||||
|
|
||||||
public bool ReadOnly => Name != "#lazer";
|
public bool ReadOnly => Name != "#lazer";
|
||||||
@ -38,6 +40,16 @@ namespace osu.Game.Online.Chat
|
|||||||
}
|
}
|
||||||
|
|
||||||
public event Action<IEnumerable<Message>> NewMessagesArrived;
|
public event Action<IEnumerable<Message>> NewMessagesArrived;
|
||||||
|
public event Action<LocalEchoMessage, Message> PendingMessageResolved;
|
||||||
|
public event Action<Message> MessageRemoved;
|
||||||
|
|
||||||
|
public void AddLocalEcho(LocalEchoMessage message)
|
||||||
|
{
|
||||||
|
pendingMessages.Add(message);
|
||||||
|
Messages.Add(message);
|
||||||
|
|
||||||
|
NewMessagesArrived?.Invoke(new[] { message });
|
||||||
|
}
|
||||||
|
|
||||||
public void AddNewMessages(params Message[] messages)
|
public void AddNewMessages(params Message[] messages)
|
||||||
{
|
{
|
||||||
@ -52,11 +64,42 @@ namespace osu.Game.Online.Chat
|
|||||||
|
|
||||||
private void purgeOldMessages()
|
private void purgeOldMessages()
|
||||||
{
|
{
|
||||||
int messageCount = Messages.Count;
|
// never purge local echos
|
||||||
|
int messageCount = Messages.Count - pendingMessages.Count;
|
||||||
if (messageCount > MAX_HISTORY)
|
if (messageCount > MAX_HISTORY)
|
||||||
Messages.RemoveRange(0, messageCount - MAX_HISTORY);
|
Messages.RemoveRange(0, messageCount - MAX_HISTORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replace or remove a message from the channel.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="echo">The local echo message (client-side).</param>
|
||||||
|
/// <param name="final">The response message, or null if the message became invalid.</param>
|
||||||
|
public void ReplaceMessage(LocalEchoMessage echo, Message final)
|
||||||
|
{
|
||||||
|
if (!pendingMessages.Remove(echo))
|
||||||
|
throw new InvalidOperationException("Attempted to remove echo that wasn't present");
|
||||||
|
|
||||||
|
Messages.Remove(echo);
|
||||||
|
|
||||||
|
if (final == null)
|
||||||
|
{
|
||||||
|
MessageRemoved?.Invoke(echo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Messages.Contains(final))
|
||||||
|
{
|
||||||
|
// message already inserted, so let's throw away this update.
|
||||||
|
// we may want to handle this better in the future, but for the time being api requests are single-threaded so order is assumed.
|
||||||
|
MessageRemoved?.Invoke(echo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Messages.Add(final);
|
||||||
|
PendingMessageResolved?.Invoke(echo, final);
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString() => Name;
|
public override string ToString() => Name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
osu.Game/Online/Chat/LocalEchoMessage.cs
Normal file
12
osu.Game/Online/Chat/LocalEchoMessage.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
namespace osu.Game.Online.Chat
|
||||||
|
{
|
||||||
|
public class LocalEchoMessage : Message
|
||||||
|
{
|
||||||
|
public LocalEchoMessage() : base(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,7 @@ namespace osu.Game.Online.Chat
|
|||||||
public class Message : IComparable<Message>, IEquatable<Message>
|
public class Message : IComparable<Message>, IEquatable<Message>
|
||||||
{
|
{
|
||||||
[JsonProperty(@"message_id")]
|
[JsonProperty(@"message_id")]
|
||||||
public readonly long Id;
|
public readonly long? Id;
|
||||||
|
|
||||||
//todo: this should be inside sender.
|
//todo: this should be inside sender.
|
||||||
[JsonProperty(@"sender_id")]
|
[JsonProperty(@"sender_id")]
|
||||||
@ -37,14 +37,22 @@ namespace osu.Game.Online.Chat
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public Message(long id)
|
public Message(long? id)
|
||||||
{
|
{
|
||||||
Id = id;
|
Id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CompareTo(Message other) => Id.CompareTo(other.Id);
|
public int CompareTo(Message other)
|
||||||
|
{
|
||||||
|
if (!Id.HasValue)
|
||||||
|
return other.Id.HasValue ? 1 : Timestamp.CompareTo(other.Timestamp);
|
||||||
|
if (!other.Id.HasValue)
|
||||||
|
return -1;
|
||||||
|
|
||||||
public bool Equals(Message other) => Id == other?.Id;
|
return Id.Value.CompareTo(other.Id.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool Equals(Message other) => Id == other?.Id;
|
||||||
|
|
||||||
public override int GetHashCode() => Id.GetHashCode();
|
public override int GetHashCode() => Id.GetHashCode();
|
||||||
}
|
}
|
||||||
|
@ -2,26 +2,24 @@
|
|||||||
// 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 OpenTK;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
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.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Online.Chat;
|
using osu.Game.Online.Chat;
|
||||||
using OpenTK;
|
|
||||||
using OpenTK.Graphics;
|
|
||||||
using osu.Framework.Graphics.Effects;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osu.Game.Graphics.Containers;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Chat
|
namespace osu.Game.Overlays.Chat
|
||||||
{
|
{
|
||||||
public class ChatLine : Container
|
public class ChatLine : Container
|
||||||
{
|
{
|
||||||
public readonly Message Message;
|
private static readonly Color4[] username_colours =
|
||||||
|
{
|
||||||
private static readonly Color4[] username_colours = {
|
|
||||||
OsuColour.FromHex("588c7e"),
|
OsuColour.FromHex("588c7e"),
|
||||||
OsuColour.FromHex("b2a367"),
|
OsuColour.FromHex("b2a367"),
|
||||||
OsuColour.FromHex("c98f65"),
|
OsuColour.FromHex("c98f65"),
|
||||||
@ -69,6 +67,8 @@ namespace osu.Game.Overlays.Chat
|
|||||||
|
|
||||||
private Color4 customUsernameColour;
|
private Color4 customUsernameColour;
|
||||||
|
|
||||||
|
private OsuSpriteText timestamp;
|
||||||
|
|
||||||
public ChatLine(Message message)
|
public ChatLine(Message message)
|
||||||
{
|
{
|
||||||
Message = message;
|
Message = message;
|
||||||
@ -79,6 +79,26 @@ namespace osu.Game.Overlays.Chat
|
|||||||
Padding = new MarginPadding { Left = padding, Right = padding };
|
Padding = new MarginPadding { Left = padding, Right = padding };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Message message;
|
||||||
|
private OsuSpriteText username;
|
||||||
|
private OsuTextFlowContainer contentFlow;
|
||||||
|
|
||||||
|
public Message Message
|
||||||
|
{
|
||||||
|
get { return message; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (message == value) return;
|
||||||
|
|
||||||
|
message = value;
|
||||||
|
|
||||||
|
if (!IsLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
updateMessageContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(OsuColour colours, UserProfileOverlay profile)
|
private void load(OsuColour colours, UserProfileOverlay profile)
|
||||||
{
|
{
|
||||||
@ -86,49 +106,54 @@ namespace osu.Game.Overlays.Chat
|
|||||||
loadProfile = u => profile?.ShowUser(u);
|
loadProfile = u => profile?.ShowUser(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool senderHasBackground => !string.IsNullOrEmpty(message.Sender.Colour);
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
bool hasBackground = !string.IsNullOrEmpty(Message.Sender.Colour);
|
bool hasBackground = senderHasBackground;
|
||||||
Drawable username = new OsuSpriteText
|
|
||||||
|
Drawable effectedUsername = username = new OsuSpriteText
|
||||||
{
|
{
|
||||||
Font = @"Exo2.0-BoldItalic",
|
Font = @"Exo2.0-BoldItalic",
|
||||||
Text = $@"{Message.Sender.Username}" + (hasBackground ? "" : ":"),
|
Colour = hasBackground ? customUsernameColour : username_colours[message.Sender.Id % username_colours.Length],
|
||||||
Colour = hasBackground ? customUsernameColour : username_colours[Message.UserId % username_colours.Length],
|
|
||||||
TextSize = text_size,
|
TextSize = text_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (hasBackground)
|
if (hasBackground)
|
||||||
{
|
{
|
||||||
// Background effect
|
// Background effect
|
||||||
username = username.WithEffect(new EdgeEffect
|
effectedUsername = new Container
|
||||||
{
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
CornerRadius = 4,
|
CornerRadius = 4,
|
||||||
Parameters = new EdgeEffectParameters
|
EdgeEffect = new EdgeEffectParameters
|
||||||
{
|
|
||||||
Radius = 1,
|
|
||||||
Colour = OsuColour.FromHex(Message.Sender.Colour),
|
|
||||||
Type = EdgeEffectType.Shadow,
|
|
||||||
}
|
|
||||||
}, d =>
|
|
||||||
{
|
|
||||||
d.Padding = new MarginPadding { Left = 3, Right = 3, Bottom = 1, Top = -3 };
|
|
||||||
d.Y = 3;
|
|
||||||
})
|
|
||||||
// Drop shadow effect
|
|
||||||
.WithEffect(new EdgeEffect
|
|
||||||
{
|
|
||||||
CornerRadius = 4,
|
|
||||||
Parameters = new EdgeEffectParameters
|
|
||||||
{
|
{
|
||||||
Roundness = 1,
|
Roundness = 1,
|
||||||
Offset = new Vector2(0, 3),
|
Offset = new Vector2(0, 3),
|
||||||
Radius = 3,
|
Radius = 3,
|
||||||
Colour = Color4.Black.Opacity(0.3f),
|
Colour = Color4.Black.Opacity(0.3f),
|
||||||
Type = EdgeEffectType.Shadow,
|
Type = EdgeEffectType.Shadow,
|
||||||
|
},
|
||||||
|
// Drop shadow effect
|
||||||
|
Child = new Container
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
CornerRadius = 4,
|
||||||
|
EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Radius = 1,
|
||||||
|
Colour = OsuColour.FromHex(message.Sender.Colour),
|
||||||
|
Type = EdgeEffectType.Shadow,
|
||||||
|
},
|
||||||
|
Padding = new MarginPadding { Left = 3, Right = 3, Bottom = 1, Top = -3 },
|
||||||
|
Y = 3,
|
||||||
|
Child = username,
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -138,23 +163,21 @@ namespace osu.Game.Overlays.Chat
|
|||||||
Size = new Vector2(message_padding, text_size),
|
Size = new Vector2(message_padding, text_size),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new OsuSpriteText
|
timestamp = new OsuSpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Font = @"Exo2.0-SemiBold",
|
Font = @"Exo2.0-SemiBold",
|
||||||
Text = $@"{Message.Timestamp.LocalDateTime:HH:mm:ss}",
|
|
||||||
FixedWidth = true,
|
FixedWidth = true,
|
||||||
TextSize = text_size * 0.75f,
|
TextSize = text_size * 0.75f,
|
||||||
Alpha = 0.4f,
|
|
||||||
},
|
},
|
||||||
new ClickableContainer
|
new ClickableContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Child = username,
|
Child = effectedUsername,
|
||||||
Action = () => loadProfile(Message.Sender),
|
Action = () => loadProfile(message.Sender),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -165,18 +188,27 @@ namespace osu.Game.Overlays.Chat
|
|||||||
Padding = new MarginPadding { Left = message_padding + padding },
|
Padding = new MarginPadding { Left = message_padding + padding },
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new OsuTextFlowContainer(t =>
|
contentFlow = new OsuTextFlowContainer(t => { t.TextSize = text_size; })
|
||||||
{
|
{
|
||||||
t.TextSize = text_size;
|
|
||||||
})
|
|
||||||
{
|
|
||||||
Text = Message.Content,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
updateMessageContent();
|
||||||
|
FinishTransforms(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMessageContent()
|
||||||
|
{
|
||||||
|
this.FadeTo(message is LocalEchoMessage ? 0.4f : 1.0f, 500, Easing.OutQuint);
|
||||||
|
timestamp.FadeTo(message is LocalEchoMessage ? 0 : 1, 500, Easing.OutQuint);
|
||||||
|
|
||||||
|
timestamp.Text = $@"{message.Timestamp.LocalDateTime:HH:mm:ss}";
|
||||||
|
username.Text = $@"{message.Sender.Username}" + (senderHasBackground ? "" : ":");
|
||||||
|
contentFlow.Text = message.Content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -14,8 +16,19 @@ namespace osu.Game.Overlays.Chat
|
|||||||
{
|
{
|
||||||
public class DrawableChannel : Container
|
public class DrawableChannel : Container
|
||||||
{
|
{
|
||||||
|
private class ChatLineContainer : FillFlowContainer<ChatLine>
|
||||||
|
{
|
||||||
|
protected override int Compare(Drawable x, Drawable y)
|
||||||
|
{
|
||||||
|
var xC = (ChatLine)x;
|
||||||
|
var yC = (ChatLine)y;
|
||||||
|
|
||||||
|
return xC.Message.CompareTo(yC.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public readonly Channel Channel;
|
public readonly Channel Channel;
|
||||||
private readonly FillFlowContainer<ChatLine> flow;
|
private readonly ChatLineContainer flow;
|
||||||
private readonly ScrollContainer scroll;
|
private readonly ScrollContainer scroll;
|
||||||
|
|
||||||
public DrawableChannel(Channel channel)
|
public DrawableChannel(Channel channel)
|
||||||
@ -32,20 +45,19 @@ namespace osu.Game.Overlays.Chat
|
|||||||
// Some chat lines have effects that slightly protrude to the bottom,
|
// Some chat lines have effects that slightly protrude to the bottom,
|
||||||
// which we do not want to mask away, hence the padding.
|
// which we do not want to mask away, hence the padding.
|
||||||
Padding = new MarginPadding { Bottom = 5 },
|
Padding = new MarginPadding { Bottom = 5 },
|
||||||
Children = new Drawable[]
|
Child = flow = new ChatLineContainer
|
||||||
{
|
{
|
||||||
flow = new FillFlowContainer<ChatLine>
|
Padding = new MarginPadding { Left = 20, Right = 20 },
|
||||||
{
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Padding = new MarginPadding { Left = 20, Right = 20 }
|
Direction = FillDirection.Vertical,
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
channel.NewMessagesArrived += newMessagesArrived;
|
Channel.NewMessagesArrived += newMessagesArrived;
|
||||||
|
Channel.MessageRemoved += messageRemoved;
|
||||||
|
Channel.PendingMessageResolved += pendingMessageResolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -63,14 +75,17 @@ namespace osu.Game.Overlays.Chat
|
|||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
{
|
{
|
||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
Channel.NewMessagesArrived -= newMessagesArrived;
|
Channel.NewMessagesArrived -= newMessagesArrived;
|
||||||
|
Channel.MessageRemoved -= messageRemoved;
|
||||||
|
Channel.PendingMessageResolved -= pendingMessageResolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void newMessagesArrived(IEnumerable<Message> newMessages)
|
private void newMessagesArrived(IEnumerable<Message> newMessages)
|
||||||
{
|
{
|
||||||
|
// Add up to last Channel.MAX_HISTORY messages
|
||||||
var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY));
|
var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY));
|
||||||
|
|
||||||
//up to last Channel.MAX_HISTORY messages
|
|
||||||
flow.AddRange(displayMessages.Select(m => new ChatLine(m)));
|
flow.AddRange(displayMessages.Select(m => new ChatLine(m)));
|
||||||
|
|
||||||
if (!IsLoaded) return;
|
if (!IsLoaded) return;
|
||||||
@ -90,6 +105,24 @@ namespace osu.Game.Overlays.Chat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void pendingMessageResolved(Message existing, Message updated)
|
||||||
|
{
|
||||||
|
var found = flow.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);
|
||||||
|
found.Message = updated;
|
||||||
|
flow.Add(found);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void messageRemoved(Message removed)
|
||||||
|
{
|
||||||
|
flow.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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,23 +6,23 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
using OpenTK.Graphics;
|
||||||
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.Input;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Online.Chat;
|
using osu.Game.Online.Chat;
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Framework.Graphics.UserInterface;
|
|
||||||
using OpenTK.Graphics;
|
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Overlays.Chat;
|
using osu.Game.Overlays.Chat;
|
||||||
using osu.Game.Graphics.Containers;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
@ -37,7 +37,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private readonly LoadingAnimation loading;
|
private readonly LoadingAnimation loading;
|
||||||
|
|
||||||
private readonly FocusedTextBox inputTextBox;
|
private readonly FocusedTextBox textbox;
|
||||||
|
|
||||||
private APIAccess api;
|
private APIAccess api;
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ namespace osu.Game.Overlays
|
|||||||
},
|
},
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
inputTextBox = new FocusedTextBox
|
textbox = new FocusedTextBox
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Height = 1,
|
Height = 1,
|
||||||
@ -175,7 +175,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
if (state == Visibility.Visible)
|
if (state == Visibility.Visible)
|
||||||
{
|
{
|
||||||
inputTextBox.HoldFocus = false;
|
textbox.HoldFocus = false;
|
||||||
if (1f - chatHeight.Value < channel_selection_min_height)
|
if (1f - chatHeight.Value < channel_selection_min_height)
|
||||||
{
|
{
|
||||||
chatContainer.ResizeHeightTo(1f - channel_selection_min_height, 800, Easing.OutQuint);
|
chatContainer.ResizeHeightTo(1f - channel_selection_min_height, 800, Easing.OutQuint);
|
||||||
@ -186,7 +186,7 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
inputTextBox.HoldFocus = true;
|
textbox.HoldFocus = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -242,8 +242,8 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
protected override void OnFocus(InputState state)
|
protected override void OnFocus(InputState state)
|
||||||
{
|
{
|
||||||
//this is necessary as inputTextBox is masked away and therefore can't get focus :(
|
//this is necessary as textbox is masked away and therefore can't get focus :(
|
||||||
GetContainingInputManager().ChangeFocus(inputTextBox);
|
GetContainingInputManager().ChangeFocus(textbox);
|
||||||
base.OnFocus(state);
|
base.OnFocus(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,7 +252,7 @@ namespace osu.Game.Overlays
|
|||||||
this.MoveToY(0, transition_length, Easing.OutQuint);
|
this.MoveToY(0, transition_length, Easing.OutQuint);
|
||||||
this.FadeIn(transition_length, Easing.OutQuint);
|
this.FadeIn(transition_length, Easing.OutQuint);
|
||||||
|
|
||||||
inputTextBox.HoldFocus = true;
|
textbox.HoldFocus = true;
|
||||||
base.PopIn();
|
base.PopIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +261,7 @@ namespace osu.Game.Overlays
|
|||||||
this.MoveToY(Height, transition_length, Easing.InSine);
|
this.MoveToY(Height, transition_length, Easing.InSine);
|
||||||
this.FadeOut(transition_length, Easing.InSine);
|
this.FadeOut(transition_length, Easing.InSine);
|
||||||
|
|
||||||
inputTextBox.HoldFocus = false;
|
textbox.HoldFocus = false;
|
||||||
base.PopOut();
|
base.PopOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,7 +336,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
currentChannel = value;
|
currentChannel = value;
|
||||||
|
|
||||||
inputTextBox.Current.Disabled = currentChannel.ReadOnly;
|
textbox.Current.Disabled = currentChannel.ReadOnly;
|
||||||
channelTabs.Current.Value = value;
|
channelTabs.Current.Value = value;
|
||||||
|
|
||||||
var loaded = loadedChannels.Find(d => d.Channel == value);
|
var loaded = loadedChannels.Find(d => d.Channel == value);
|
||||||
@ -414,6 +414,7 @@ namespace osu.Game.Overlays
|
|||||||
if (fetchReq != null) return;
|
if (fetchReq != null) return;
|
||||||
|
|
||||||
fetchReq = new GetMessagesRequest(careChannels, lastMessageId);
|
fetchReq = new GetMessagesRequest(careChannels, lastMessageId);
|
||||||
|
|
||||||
fetchReq.Success += delegate (List<Message> messages)
|
fetchReq.Success += delegate (List<Message> messages)
|
||||||
{
|
{
|
||||||
foreach (var group in messages.Where(m => m.TargetType == TargetType.Channel).GroupBy(m => m.TargetId))
|
foreach (var group in messages.Where(m => m.TargetType == TargetType.Channel).GroupBy(m => m.TargetId))
|
||||||
@ -424,6 +425,7 @@ namespace osu.Game.Overlays
|
|||||||
Debug.Write("success!");
|
Debug.Write("success!");
|
||||||
fetchReq = null;
|
fetchReq = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchReq.Failure += delegate
|
fetchReq.Failure += delegate
|
||||||
{
|
{
|
||||||
Debug.Write("failure!");
|
Debug.Write("failure!");
|
||||||
@ -437,51 +439,42 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
var postText = textbox.Text;
|
var postText = textbox.Text;
|
||||||
|
|
||||||
|
textbox.Text = string.Empty;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(postText))
|
if (string.IsNullOrEmpty(postText))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var target = currentChannel;
|
||||||
|
|
||||||
|
if (target == null) return;
|
||||||
|
|
||||||
if (!api.IsLoggedIn)
|
if (!api.IsLoggedIn)
|
||||||
{
|
{
|
||||||
currentChannel?.AddNewMessages(new ErrorMessage("Please login to participate in chat!"));
|
target.AddNewMessages(new ErrorMessage("Please login to participate in chat!"));
|
||||||
textbox.Text = string.Empty;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentChannel == null) return;
|
|
||||||
|
|
||||||
if (postText[0] == '/')
|
if (postText[0] == '/')
|
||||||
{
|
{
|
||||||
// TODO: handle commands
|
// TODO: handle commands
|
||||||
currentChannel.AddNewMessages(new ErrorMessage("Chat commands are not supported yet!"));
|
target.AddNewMessages(new ErrorMessage("Chat commands are not supported yet!"));
|
||||||
textbox.Text = string.Empty;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var message = new Message
|
var message = new LocalEchoMessage
|
||||||
{
|
{
|
||||||
Sender = api.LocalUser.Value,
|
Sender = api.LocalUser.Value,
|
||||||
Timestamp = DateTimeOffset.Now,
|
Timestamp = DateTimeOffset.Now,
|
||||||
TargetType = TargetType.Channel, //TODO: read this from currentChannel
|
TargetType = TargetType.Channel, //TODO: read this from channel
|
||||||
TargetId = currentChannel.Id,
|
TargetId = target.Id,
|
||||||
Content = postText
|
Content = postText
|
||||||
};
|
};
|
||||||
|
|
||||||
textbox.ReadOnly = true;
|
|
||||||
var req = new PostMessageRequest(message);
|
var req = new PostMessageRequest(message);
|
||||||
|
|
||||||
req.Failure += e =>
|
target.AddLocalEcho(message);
|
||||||
{
|
req.Failure += e => target.ReplaceMessage(message, null);
|
||||||
textbox.FlashColour(Color4.Red, 1000);
|
req.Success += m => target.ReplaceMessage(message, m);
|
||||||
textbox.ReadOnly = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
req.Success += m =>
|
|
||||||
{
|
|
||||||
currentChannel.AddNewMessages(m);
|
|
||||||
|
|
||||||
textbox.ReadOnly = false;
|
|
||||||
textbox.Text = string.Empty;
|
|
||||||
};
|
|
||||||
|
|
||||||
api.Queue(req);
|
api.Queue(req);
|
||||||
}
|
}
|
||||||
|
@ -101,6 +101,7 @@
|
|||||||
<Compile Include="Online\API\Requests\GetUsersRequest.cs" />
|
<Compile Include="Online\API\Requests\GetUsersRequest.cs" />
|
||||||
<Compile Include="Online\API\Requests\PostMessageRequest.cs" />
|
<Compile Include="Online\API\Requests\PostMessageRequest.cs" />
|
||||||
<Compile Include="Online\Chat\ErrorMessage.cs" />
|
<Compile Include="Online\Chat\ErrorMessage.cs" />
|
||||||
|
<Compile Include="Online\Chat\LocalEchoMessage.cs" />
|
||||||
<Compile Include="Overlays\Chat\ChatTabControl.cs" />
|
<Compile Include="Overlays\Chat\ChatTabControl.cs" />
|
||||||
<Compile Include="Overlays\KeyBinding\GlobalKeyBindingsSection.cs" />
|
<Compile Include="Overlays\KeyBinding\GlobalKeyBindingsSection.cs" />
|
||||||
<Compile Include="Overlays\KeyBinding\KeyBindingRow.cs" />
|
<Compile Include="Overlays\KeyBinding\KeyBindingRow.cs" />
|
||||||
|
Reference in New Issue
Block a user