1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 15:47:26 +08:00

Merge pull request #652 from peppy/chat-post-support

Add chat sending support.
This commit is contained in:
Dan Balasescu 2017-04-19 21:39:35 +09:00 committed by GitHub
commit 7d98e41133
10 changed files with 210 additions and 105 deletions

@ -1 +1 @@
Subproject commit 21a97586f7fa8d9aa65b4131824151d88a70b520
Subproject commit dc4ea5be425d37f3a0dd09f6acdf6799d42e3d74

View File

@ -0,0 +1,33 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Extensions;
using osu.Framework.IO.Network;
using osu.Game.Online.Chat;
namespace osu.Game.Online.API.Requests
{
public class PostMessageRequest : APIRequest<Message>
{
private readonly Message message;
public PostMessageRequest(Message message)
{
this.message = message;
}
protected override WebRequest CreateWebRequest()
{
var req = base.CreateWebRequest();
req.Method = HttpMethod.POST;
req.AddParameter(@"target_type", message.TargetType.GetDescription());
req.AddParameter(@"target_id", message.TargetId.ToString());
req.AddParameter(@"message", message.Content);
return req;
}
protected override string Target => @"chat/messages";
}
}

View File

@ -3,7 +3,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using osu.Framework.Lists;
namespace osu.Game.Online.Chat
{
@ -21,7 +23,7 @@ namespace osu.Game.Online.Chat
[JsonProperty(@"channel_id")]
public int Id;
public List<Message> Messages = new List<Message>();
public SortedList<Message> Messages = new SortedList<Message>((m1, m2) => m1.Id.CompareTo(m2.Id));
//internal bool Joined;
@ -36,7 +38,10 @@ namespace osu.Game.Online.Chat
public void AddNewMessages(IEnumerable<Message> messages)
{
messages = messages.Except(Messages).ToList();
Messages.AddRange(messages);
purgeOldMessages();
NewMessagesArrived?.Invoke(messages);

View File

@ -55,6 +55,9 @@ namespace osu.Game.Online.Chat.Drawables
private Color4 getUsernameColour(Message message)
{
if (!string.IsNullOrEmpty(message.Sender?.Colour))
return OsuColour.FromHex(message.Sender.Colour);
//todo: use User instead of Message when user_id is correctly populated.
return username_colours[message.UserId % username_colours.Length];
}
@ -91,7 +94,7 @@ namespace osu.Game.Online.Chat.Drawables
new OsuSpriteText
{
Font = @"Exo2.0-BoldItalic",
Text = $@"{Message.User.Username}:",
Text = $@"{Message.Sender.Username}:",
Colour = getUsernameColour(Message),
TextSize = text_size,
Origin = Anchor.TopRight,

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.ComponentModel;
using Newtonsoft.Json;
using osu.Game.Users;
@ -10,14 +11,17 @@ namespace osu.Game.Online.Chat
public class Message
{
[JsonProperty(@"message_id")]
public long Id;
public readonly long Id;
//todo: this should be inside sender.
[JsonProperty(@"user_id")]
[JsonProperty(@"sender_id")]
public int UserId;
[JsonProperty(@"channel_id")]
public int ChannelId;
[JsonProperty(@"target_type")]
public TargetType TargetType;
[JsonProperty(@"target_id")]
public int TargetId;
[JsonProperty(@"timestamp")]
public DateTimeOffset Timestamp;
@ -26,11 +30,31 @@ namespace osu.Game.Online.Chat
public string Content;
[JsonProperty(@"sender")]
public User User;
public User Sender;
[JsonConstructor]
public Message()
{
}
public override bool Equals(object obj)
{
var objMessage = obj as Message;
return Id == objMessage?.Id;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
public enum TargetType
{
[Description(@"channel")]
Channel,
[Description(@"user")]
User
}
}

View File

@ -194,6 +194,7 @@ namespace osu.Game
};
Dependencies.Cache(options);
Dependencies.Cache(chat);
Dependencies.Cache(musicController);
Dependencies.Cache(notificationManager);
Dependencies.Cache(dialogOverlay);

View File

@ -38,6 +38,10 @@ namespace osu.Game.Overlays
private APIAccess api;
private const int transition_length = 500;
private GetMessagesRequest fetchReq;
public ChatOverlay()
{
RelativeSizeAxes = Axes.X;
@ -82,94 +86,6 @@ namespace osu.Game.Overlays
});
}
protected override bool OnFocus(InputState state)
{
//this is necessary as inputTextBox is masked away and therefore can't get focus :(
inputTextBox.TriggerFocus();
return false;
}
private void postMessage(TextBox sender, bool newText)
{
var postText = sender.Text;
if (!string.IsNullOrEmpty(postText) && api.LocalUser.Value != null)
{
//todo: actually send to server
careChannels.FirstOrDefault()?.AddNewMessages(new[]
{
new Message
{
User = api.LocalUser.Value,
Timestamp = DateTimeOffset.Now,
Content = postText
}
});
}
sender.Text = string.Empty;
}
[BackgroundDependencyLoader]
private void load(APIAccess api)
{
this.api = api;
api.Register(this);
}
private long? lastMessageId;
private List<Channel> careChannels;
private void addChannel(Channel channel)
{
Add(new DrawableChannel(channel));
careChannels.Add(channel);
}
private GetMessagesRequest fetchReq;
public void FetchNewMessages(APIAccess api)
{
if (fetchReq != null) return;
fetchReq = new GetMessagesRequest(careChannels, lastMessageId);
fetchReq.Success += delegate (List<Message> messages)
{
var ids = messages.Select(m => m.ChannelId).Distinct();
//batch messages per channel.
foreach (var id in ids)
careChannels.Find(c => c.Id == id)?.AddNewMessages(messages.Where(m => m.ChannelId == id));
lastMessageId = messages.LastOrDefault()?.Id ?? lastMessageId;
Debug.Write("success!");
fetchReq = null;
};
fetchReq.Failure += delegate
{
Debug.Write("failure!");
fetchReq = null;
};
api.Queue(fetchReq);
}
private const int transition_length = 500;
protected override void PopIn()
{
MoveToY(0, transition_length, EasingTypes.OutQuint);
FadeIn(transition_length, EasingTypes.OutQuint);
}
protected override void PopOut()
{
MoveToY(DrawSize.Y, transition_length, EasingTypes.InSine);
FadeOut(transition_length, EasingTypes.InSine);
}
public void APIStateChanged(APIAccess api, APIState state)
{
switch (state)
@ -183,19 +99,46 @@ namespace osu.Game.Overlays
}
}
protected override bool OnFocus(InputState state)
{
//this is necessary as inputTextBox is masked away and therefore can't get focus :(
inputTextBox.TriggerFocus();
return false;
}
protected override void PopIn()
{
MoveToY(0, transition_length, EasingTypes.OutQuint);
FadeIn(transition_length, EasingTypes.OutQuint);
}
protected override void PopOut()
{
MoveToY(DrawSize.Y, transition_length, EasingTypes.InSine);
FadeOut(transition_length, EasingTypes.InSine);
}
[BackgroundDependencyLoader]
private void load(APIAccess api)
{
this.api = api;
api.Register(this);
}
private long? lastMessageId;
private List<Channel> careChannels;
private void initializeChannels()
{
Clear();
careChannels = new List<Channel>();
//if (api.State != APIAccess.APIState.Online)
// return;
SpriteText loading;
Add(loading = new OsuSpriteText
{
Text = @"Loading available channels...",
Text = @"initialising chat...",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
TextSize = 40,
@ -211,15 +154,85 @@ namespace osu.Game.Overlays
Scheduler.Add(delegate
{
loading.FadeOut(100);
addChannel(channels.Find(c => c.Name == @"#osu"));
addChannel(channels.Find(c => c.Name == @"#lazer"));
});
//addChannel(channels.Find(c => c.Name == @"#lobby"));
//addChannel(channels.Find(c => c.Name == @"#english"));
messageRequest = Scheduler.AddDelayed(() => FetchNewMessages(api), 1000, true);
messageRequest = Scheduler.AddDelayed(fetchNewMessages, 1000, true);
};
api.Queue(req);
}
private void addChannel(Channel channel)
{
Add(new DrawableChannel(channel));
careChannels.Add(channel);
}
private void fetchNewMessages()
{
if (fetchReq != null) return;
fetchReq = new GetMessagesRequest(careChannels, lastMessageId);
fetchReq.Success += delegate (List<Message> messages)
{
var ids = messages.Where(m => m.TargetType == TargetType.Channel).Select(m => m.TargetId).Distinct();
//batch messages per channel.
foreach (var id in ids)
careChannels.Find(c => c.Id == id)?.AddNewMessages(messages.Where(m => m.TargetId == id));
lastMessageId = messages.LastOrDefault()?.Id ?? lastMessageId;
Debug.Write("success!");
fetchReq = null;
};
fetchReq.Failure += delegate
{
Debug.Write("failure!");
fetchReq = null;
};
api.Queue(fetchReq);
}
private void postMessage(TextBox textbox, bool newText)
{
var postText = textbox.Text;
if (!string.IsNullOrEmpty(postText) && api.LocalUser.Value != null)
{
var currentChannel = careChannels.FirstOrDefault();
if (currentChannel == null) return;
var message = new Message
{
Sender = api.LocalUser.Value,
Timestamp = DateTimeOffset.Now,
TargetType = TargetType.Channel, //TODO: read this from currentChannel
TargetId = currentChannel.Id,
Content = postText
};
textbox.ReadOnly = true;
var req = new PostMessageRequest(message);
req.Failure += e =>
{
textbox.FlashColour(Color4.Red, 1000);
textbox.ReadOnly = false;
};
req.Success += m =>
{
currentChannel.AddNewMessages(new[] { m });
textbox.ReadOnly = false;
textbox.Text = string.Empty;
};
api.Queue(req);
}
}
}
}

View File

@ -72,6 +72,7 @@ namespace osu.Game.Overlays.Toolbar
AutoSizeAxes = Axes.X,
Children = new Drawable[]
{
new ToolbarChatButton(),
new ToolbarMusicButton(),
new ToolbarButton
{

View File

@ -0,0 +1,23 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Game.Graphics;
namespace osu.Game.Overlays.Toolbar
{
internal class ToolbarChatButton : ToolbarOverlayToggleButton
{
public ToolbarChatButton()
{
Icon = FontAwesome.fa_comments;
}
[BackgroundDependencyLoader]
private void load(ChatOverlay chat)
{
StateContainer = chat;
Action = chat.ToggleVisibility;
}
}
}

View File

@ -72,6 +72,8 @@
<Compile Include="Audio\SampleInfo.cs" />
<Compile Include="Beatmaps\Drawables\BeatmapBackgroundSprite.cs" />
<Compile Include="Beatmaps\DifficultyCalculator.cs" />
<Compile Include="Online\API\Requests\PostMessageRequest.cs" />
<Compile Include="Overlays\Toolbar\ToolbarChatButton.cs" />
<Compile Include="Rulesets\Beatmaps\BeatmapConverter.cs" />
<Compile Include="Rulesets\Beatmaps\BeatmapProcessor.cs" />
<Compile Include="Beatmaps\Legacy\LegacyBeatmap.cs" />