From 325af333b903ede960ab8b1c5861ccdb4ca615bf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Apr 2017 17:39:57 +0900 Subject: [PATCH 1/7] Update API responses for chat. --- osu.Game/Online/Chat/Message.cs | 16 ++++++++++++++-- osu.Game/Overlays/ChatOverlay.cs | 6 +++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index b267cf63ac..5d781459e8 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -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; @@ -16,8 +17,11 @@ namespace osu.Game.Online.Chat [JsonProperty(@"user_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; @@ -33,4 +37,12 @@ namespace osu.Game.Online.Chat { } } + + public enum TargetType + { + [Description(@"channel")] + Channel, + [Description(@"user")] + User + } } diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index fc12789b05..db0d89edc7 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -136,11 +136,11 @@ namespace osu.Game.Overlays fetchReq = new GetMessagesRequest(careChannels, lastMessageId); fetchReq.Success += delegate (List messages) { - var ids = messages.Select(m => m.ChannelId).Distinct(); - + 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.ChannelId == id)); + careChannels.Find(c => c.Id == id)?.AddNewMessages(messages.Where(m => m.TargetId == id)); lastMessageId = messages.LastOrDefault()?.Id ?? lastMessageId; From 87f6dc9e5abc0e35da383211c77a5b4278873693 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Apr 2017 18:45:33 +0900 Subject: [PATCH 2/7] Change default channel to #lazer. --- osu.Game/Overlays/ChatOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index db0d89edc7..2f1b21dd7b 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -211,7 +211,7 @@ 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")); From 3129708ccb66ca9c2704c0cff7517b0e1e08da1e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Apr 2017 18:46:26 +0900 Subject: [PATCH 3/7] Add chat sending support. --- .../Online/API/Requests/PostMessageRequest.cs | 33 +++++++++++++ osu.Game/Online/Chat/Channel.cs | 7 ++- osu.Game/Online/Chat/Message.cs | 14 +++++- osu.Game/Overlays/ChatOverlay.cs | 49 +++++++++++++------ osu.Game/osu.Game.csproj | 1 + 5 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 osu.Game/Online/API/Requests/PostMessageRequest.cs diff --git a/osu.Game/Online/API/Requests/PostMessageRequest.cs b/osu.Game/Online/API/Requests/PostMessageRequest.cs new file mode 100644 index 0000000000..52269d9fe8 --- /dev/null +++ b/osu.Game/Online/API/Requests/PostMessageRequest.cs @@ -0,0 +1,33 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// 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 + { + 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"; + } +} \ No newline at end of file diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index d895b93336..04ebf0a389 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -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 Messages = new List(); + public SortedList Messages = new SortedList((m1, m2) => m1.Id.CompareTo(m2.Id)); //internal bool Joined; @@ -36,7 +38,10 @@ namespace osu.Game.Online.Chat public void AddNewMessages(IEnumerable messages) { + messages = messages.Except(Messages).ToList(); + Messages.AddRange(messages); + purgeOldMessages(); NewMessagesArrived?.Invoke(messages); diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index 5d781459e8..2404bbe109 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -11,7 +11,7 @@ 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")] @@ -36,6 +36,18 @@ namespace osu.Game.Online.Chat 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 diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 2f1b21dd7b..5b9d30ee8e 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -89,25 +89,44 @@ namespace osu.Game.Overlays return false; } - private void postMessage(TextBox sender, bool newText) + private void postMessage(TextBox textbox, bool newText) { - var postText = sender.Text; + var postText = textbox.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 - } - }); - } + var currentChannel = careChannels.FirstOrDefault(); - sender.Text = string.Empty; + if (currentChannel == null) return; + + var message = new Message + { + User = 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); + } } [BackgroundDependencyLoader] @@ -137,7 +156,7 @@ namespace osu.Game.Overlays fetchReq.Success += delegate (List 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)); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8421f89058..6987776376 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -72,6 +72,7 @@ + From dda3fb85ee54341678d5064d177c939c3d1541a4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Apr 2017 19:07:38 +0900 Subject: [PATCH 4/7] Add user colour support. --- osu.Game/Online/Chat/Drawables/ChatLine.cs | 5 ++++- osu.Game/Online/Chat/Message.cs | 4 ++-- osu.Game/Overlays/ChatOverlay.cs | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Chat/Drawables/ChatLine.cs b/osu.Game/Online/Chat/Drawables/ChatLine.cs index bfbcf3d707..59e83fd385 100644 --- a/osu.Game/Online/Chat/Drawables/ChatLine.cs +++ b/osu.Game/Online/Chat/Drawables/ChatLine.cs @@ -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, diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index 2404bbe109..372e43be38 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -14,7 +14,7 @@ namespace osu.Game.Online.Chat public readonly long Id; //todo: this should be inside sender. - [JsonProperty(@"user_id")] + [JsonProperty(@"sender_id")] public int UserId; [JsonProperty(@"target_type")] @@ -30,7 +30,7 @@ namespace osu.Game.Online.Chat public string Content; [JsonProperty(@"sender")] - public User User; + public User Sender; [JsonConstructor] public Message() diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 5b9d30ee8e..9b3cdaf49d 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -101,7 +101,7 @@ namespace osu.Game.Overlays var message = new Message { - User = api.LocalUser.Value, + Sender = api.LocalUser.Value, Timestamp = DateTimeOffset.Now, TargetType = TargetType.Channel, //TODO: read this from currentChannel TargetId = currentChannel.Id, From c7246fd2ac4047d4f0a6b64c703be3a168bb1b23 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Apr 2017 19:15:21 +0900 Subject: [PATCH 5/7] Reorganise ChatOverlay to not suck. --- osu.Game/Overlays/ChatOverlay.cs | 218 +++++++++++++++---------------- 1 file changed, 106 insertions(+), 112 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 9b3cdaf49d..457611dfab 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -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,6 +86,19 @@ namespace osu.Game.Overlays }); } + public void APIStateChanged(APIAccess api, APIState state) + { + switch (state) + { + case APIState.Online: + initializeChannels(); + break; + default: + messageRequest?.Cancel(); + break; + } + } + protected override bool OnFocus(InputState state) { //this is necessary as inputTextBox is masked away and therefore can't get focus :( @@ -89,6 +106,95 @@ namespace osu.Game.Overlays 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 careChannels; + + private void initializeChannels() + { + Clear(); + + careChannels = new List(); + + SpriteText loading; + Add(loading = new OsuSpriteText + { + Text = @"initialising chat...", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + TextSize = 40, + }); + + messageRequest?.Cancel(); + + ListChannelsRequest req = new ListChannelsRequest(); + req.Success += delegate (List channels) + { + Debug.Assert(careChannels.Count == 0); + + Scheduler.Add(delegate + { + loading.FadeOut(100); + addChannel(channels.Find(c => c.Name == @"#lazer")); + }); + + 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 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; @@ -128,117 +234,5 @@ namespace osu.Game.Overlays api.Queue(req); } } - - [BackgroundDependencyLoader] - private void load(APIAccess api) - { - this.api = api; - api.Register(this); - } - - private long? lastMessageId; - - private List 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 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 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) - { - case APIState.Online: - initializeChannels(); - break; - default: - messageRequest?.Cancel(); - break; - } - } - - private void initializeChannels() - { - Clear(); - - careChannels = new List(); - - //if (api.State != APIAccess.APIState.Online) - // return; - - SpriteText loading; - Add(loading = new OsuSpriteText - { - Text = @"Loading available channels...", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - TextSize = 40, - }); - - messageRequest?.Cancel(); - - ListChannelsRequest req = new ListChannelsRequest(); - req.Success += delegate (List channels) - { - Debug.Assert(careChannels.Count == 0); - - Scheduler.Add(delegate - { - loading.FadeOut(100); - 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); - }; - api.Queue(req); - } } } From 093abd6872316d586195598bc49880db5f53461a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Apr 2017 19:54:03 +0900 Subject: [PATCH 6/7] Add chat toggle button. --- osu.Game/OsuGame.cs | 1 + osu.Game/Overlays/Toolbar/Toolbar.cs | 1 + .../Overlays/Toolbar/ToolbarChatButton.cs | 23 +++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 4 files changed, 26 insertions(+) create mode 100644 osu.Game/Overlays/Toolbar/ToolbarChatButton.cs diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index cd89f4bdc7..a139c4d6ce 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -194,6 +194,7 @@ namespace osu.Game }; Dependencies.Cache(options); + Dependencies.Cache(chat); Dependencies.Cache(musicController); Dependencies.Cache(notificationManager); Dependencies.Cache(dialogOverlay); diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 1fd19af557..a5074100c7 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -72,6 +72,7 @@ namespace osu.Game.Overlays.Toolbar AutoSizeAxes = Axes.X, Children = new Drawable[] { + new ToolbarChatButton(), new ToolbarMusicButton(), new ToolbarButton { diff --git a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs new file mode 100644 index 0000000000..ca612662e1 --- /dev/null +++ b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// 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; + } + } +} \ No newline at end of file diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6987776376..b17823759d 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -73,6 +73,7 @@ + From fdf5f140dd901f3ba31a62c4cc38023aba5fac69 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Apr 2017 21:02:31 +0900 Subject: [PATCH 7/7] Update framework. --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 21a97586f7..dc4ea5be42 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 21a97586f7fa8d9aa65b4131824151d88a70b520 +Subproject commit dc4ea5be425d37f3a0dd09f6acdf6799d42e3d74