mirror of
https://github.com/ppy/osu.git
synced 2026-05-14 07:24:04 +08:00
Compare commits
7 Commits
@@ -1,21 +1,86 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.Chat;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
{
|
||||
[Description("Testing chat api and overlay")]
|
||||
public class TestCaseChatDisplay : OsuTestCase
|
||||
{
|
||||
public TestCaseChatDisplay()
|
||||
private DummyChatOverlay chat;
|
||||
|
||||
private DependencyContainer dependencies;
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) =>
|
||||
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Add(new ChatOverlay
|
||||
DummyAPIAccess api;
|
||||
|
||||
dependencies.CacheAs<IAPIProvider>(api = new DummyAPIAccess());
|
||||
|
||||
Add(chat = new DummyChatOverlay
|
||||
{
|
||||
State = Visibility.Visible
|
||||
});
|
||||
|
||||
AddStep("Set Username DummyUser", () => api.LocalUser.Value.Username = "DummyUser");
|
||||
AddStep("Type \"Hello\"", () => chat.PostMessage("Hello"));
|
||||
AddStep("Set Long Username", () => api.LocalUser.Value.Username = "Over15LengthUserName");
|
||||
AddStep("Type \"Over15LengthUserName\"", () => chat.PostMessage("Over15LengthUserName"));
|
||||
AddStep("Set Wide Username", () => api.LocalUser.Value.Username = "WWWWWWWWWWWWWWW");
|
||||
AddStep("Type \"Wide!\"", () => chat.PostMessage("Wide!"));
|
||||
|
||||
var channel = new Channel
|
||||
{
|
||||
Name = "#Dummy",
|
||||
Topic = "Test Chat",
|
||||
Type = "Test",
|
||||
Id = 0
|
||||
};
|
||||
|
||||
channel.AddNewMessages(
|
||||
new DummyMessage("This message for test from offline."),
|
||||
new DummyMessage("TestMessage"),
|
||||
new DummyMessage("TestMessage"),
|
||||
new DummyMessage("TestMessage")
|
||||
);
|
||||
|
||||
chat.OpenChannel(channel);
|
||||
}
|
||||
|
||||
private class DummyChatOverlay : ChatOverlay
|
||||
{
|
||||
public new void PostMessage(string postText) => base.PostMessage(postText);
|
||||
}
|
||||
|
||||
private class DummyMessage : Message
|
||||
{
|
||||
private static long messageCounter;
|
||||
|
||||
public DummyMessage(string text, string username = null, bool isAction = false, bool isImportant = false, int number = 0)
|
||||
: base(messageCounter++)
|
||||
{
|
||||
Content = text;
|
||||
IsAction = isAction;
|
||||
Timestamp = DateTimeOffset.Now;
|
||||
Sender = new User
|
||||
{
|
||||
Username = username ?? $"User {number}",
|
||||
Id = number,
|
||||
Colour = isImportant ? "#250cc9" : null,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Threading;
|
||||
@@ -16,7 +15,7 @@ using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Online.API
|
||||
{
|
||||
public class APIAccess : IUpdateable
|
||||
public class APIAccess : IAPIProvider
|
||||
{
|
||||
private readonly OAuth authentication;
|
||||
|
||||
@@ -34,7 +33,7 @@ namespace osu.Game.Online.API
|
||||
|
||||
public string Password;
|
||||
|
||||
public Bindable<User> LocalUser = new Bindable<User>(createGuestUser());
|
||||
public Bindable<User> LocalUser { get; } = new Bindable<User>(createGuestUser());
|
||||
|
||||
public string Token
|
||||
{
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Online.API
|
||||
{
|
||||
public class DummyAPIAccess : IAPIProvider
|
||||
{
|
||||
public Bindable<User> LocalUser { get; } = new Bindable<User>(new User
|
||||
{
|
||||
Username = @"Dummy",
|
||||
Id = 1,
|
||||
});
|
||||
|
||||
public bool IsLoggedIn => true;
|
||||
|
||||
public void Update()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Queue(APIRequest request)
|
||||
{
|
||||
}
|
||||
|
||||
public void Register(IOnlineComponent component)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using osu.Framework;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Online.API
|
||||
{
|
||||
public interface IAPIProvider : IUpdateable
|
||||
{
|
||||
/// <summary>
|
||||
/// The local user.
|
||||
/// </summary>
|
||||
Bindable<User> LocalUser { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the local user is logged in.
|
||||
/// </summary>
|
||||
bool IsLoggedIn { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Queue a new request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request to perform.</param>
|
||||
void Queue(APIRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// Register a component to receive state changes.
|
||||
/// </summary>
|
||||
/// <param name="component">The component to register.</param>
|
||||
void Register(IOnlineComponent component);
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,7 @@ namespace osu.Game
|
||||
Username = LocalConfig.Get<string>(OsuSetting.Username),
|
||||
Token = LocalConfig.Get<string>(OsuSetting.Token)
|
||||
});
|
||||
dependencies.CacheAs<IAPIProvider>(API);
|
||||
|
||||
dependencies.Cache(RulesetStore = new RulesetStore(contextFactory));
|
||||
dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage));
|
||||
|
||||
@@ -63,9 +63,10 @@ namespace osu.Game.Overlays.Chat
|
||||
public const float LEFT_PADDING = message_padding + padding * 2;
|
||||
|
||||
private const float padding = 15;
|
||||
private const float message_padding = 200;
|
||||
private const float message_padding = 250;
|
||||
private const float action_padding = 3;
|
||||
private const float text_size = 20;
|
||||
private const int max_username_length = 15;
|
||||
|
||||
private Color4 customUsernameColour;
|
||||
|
||||
@@ -87,6 +88,8 @@ namespace osu.Game.Overlays.Chat
|
||||
|
||||
public LinkFlowContainer ContentFlow => contentFlow;
|
||||
|
||||
private ChatOverlay chat;
|
||||
|
||||
public Message Message
|
||||
{
|
||||
get => message;
|
||||
@@ -123,6 +126,7 @@ namespace osu.Game.Overlays.Chat
|
||||
Font = @"Exo2.0-BoldItalic",
|
||||
Colour = hasBackground ? customUsernameColour : username_colours[message.Sender.Id % username_colours.Length],
|
||||
TextSize = text_size,
|
||||
FixedWidth = true,
|
||||
};
|
||||
|
||||
if (hasBackground)
|
||||
@@ -215,7 +219,12 @@ namespace osu.Game.Overlays.Chat
|
||||
FinishTransforms(true);
|
||||
}
|
||||
|
||||
private ChatOverlay chat;
|
||||
private string normalizeUsername(string usernameText)
|
||||
{
|
||||
if(usernameText.Length <= max_username_length)
|
||||
return usernameText;
|
||||
return usernameText.Substring(0, max_username_length - 3) + "...";
|
||||
}
|
||||
|
||||
private void updateMessageContent()
|
||||
{
|
||||
@@ -223,7 +232,7 @@ namespace osu.Game.Overlays.Chat
|
||||
timestamp.FadeTo(message is LocalEchoMessage ? 0 : 1, 500, Easing.OutQuint);
|
||||
|
||||
timestamp.Text = $@"{message.Timestamp.LocalDateTime:HH:mm:ss}";
|
||||
username.Text = $@"{message.Sender.Username}" + (senderHasBackground || message.IsAction ? "" : ":");
|
||||
username.Text = $@"{normalizeUsername(message.Sender.Username)}" + (senderHasBackground || message.IsAction ? "" : ":");
|
||||
|
||||
// remove non-existent channels from the link list
|
||||
message.Links.RemoveAll(link => link.Action == LinkAction.OpenChannel && chat?.AvailableChannels.Any(c => c.Name == link.Argument) != true);
|
||||
|
||||
@@ -39,9 +39,9 @@ namespace osu.Game.Overlays
|
||||
|
||||
private readonly LoadingAnimation loading;
|
||||
|
||||
private readonly FocusedTextBox textbox;
|
||||
protected readonly FocusedTextBox Textbox;
|
||||
|
||||
private APIAccess api;
|
||||
protected IAPIProvider Api;
|
||||
|
||||
private const int transition_length = 500;
|
||||
|
||||
@@ -64,7 +64,8 @@ namespace osu.Game.Overlays
|
||||
private readonly Container channelSelectionContainer;
|
||||
private readonly ChannelSelectionOverlay channelSelection;
|
||||
|
||||
public override bool Contains(Vector2 screenSpacePos) => chatContainer.ReceiveMouseInputAt(screenSpacePos) || channelSelection.State == Visibility.Visible && channelSelection.ReceiveMouseInputAt(screenSpacePos);
|
||||
public override bool Contains(Vector2 screenSpacePos) =>
|
||||
chatContainer.ReceiveMouseInputAt(screenSpacePos) || channelSelection.State == Visibility.Visible && channelSelection.ReceiveMouseInputAt(screenSpacePos);
|
||||
|
||||
public ChatOverlay()
|
||||
{
|
||||
@@ -133,13 +134,13 @@ namespace osu.Game.Overlays
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
textbox = new FocusedTextBox
|
||||
Textbox = new FocusedTextBox
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 1,
|
||||
PlaceholderText = "type your message",
|
||||
Exit = () => State = Visibility.Hidden,
|
||||
OnCommit = postMessage,
|
||||
OnCommit = handleTextboxMessage,
|
||||
ReleaseFocusOnCommit = false,
|
||||
HoldFocus = true,
|
||||
}
|
||||
@@ -179,12 +180,12 @@ namespace osu.Game.Overlays
|
||||
|
||||
if (state == Visibility.Visible)
|
||||
{
|
||||
textbox.HoldFocus = false;
|
||||
Textbox.HoldFocus = false;
|
||||
if (1f - ChatHeight.Value < channel_selection_min_height)
|
||||
transformChatHeightTo(1f - channel_selection_min_height, 800, Easing.OutQuint);
|
||||
}
|
||||
else
|
||||
textbox.HoldFocus = true;
|
||||
Textbox.HoldFocus = true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -246,7 +247,7 @@ namespace osu.Game.Overlays
|
||||
protected override void OnFocus(InputState state)
|
||||
{
|
||||
//this is necessary as textbox is masked away and therefore can't get focus :(
|
||||
GetContainingInputManager().ChangeFocus(textbox);
|
||||
GetContainingInputManager().ChangeFocus(Textbox);
|
||||
base.OnFocus(state);
|
||||
}
|
||||
|
||||
@@ -255,7 +256,7 @@ namespace osu.Game.Overlays
|
||||
this.MoveToY(0, transition_length, Easing.OutQuint);
|
||||
this.FadeIn(transition_length, Easing.OutQuint);
|
||||
|
||||
textbox.HoldFocus = true;
|
||||
Textbox.HoldFocus = true;
|
||||
base.PopIn();
|
||||
}
|
||||
|
||||
@@ -264,14 +265,14 @@ namespace osu.Game.Overlays
|
||||
this.MoveToY(Height, transition_length, Easing.InSine);
|
||||
this.FadeOut(transition_length, Easing.InSine);
|
||||
|
||||
textbox.HoldFocus = false;
|
||||
Textbox.HoldFocus = false;
|
||||
base.PopOut();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(APIAccess api, OsuConfigManager config, OsuColour colours)
|
||||
private void load(IAPIProvider api, OsuConfigManager config, OsuColour colours)
|
||||
{
|
||||
this.api = api;
|
||||
Api = api;
|
||||
api.Register(this);
|
||||
|
||||
ChatHeight = config.GetBindable<double>(OsuSetting.ChatDisplayHeight);
|
||||
@@ -299,7 +300,7 @@ namespace osu.Game.Overlays
|
||||
messageRequest?.Cancel();
|
||||
|
||||
ListChannelsRequest req = new ListChannelsRequest();
|
||||
req.Success += delegate (List<Channel> channels)
|
||||
req.Success += delegate(List<Channel> channels)
|
||||
{
|
||||
AvailableChannels = channels;
|
||||
|
||||
@@ -324,17 +325,14 @@ namespace osu.Game.Overlays
|
||||
messageRequest = Scheduler.AddDelayed(fetchNewMessages, 1000, true);
|
||||
};
|
||||
|
||||
api.Queue(req);
|
||||
Api.Queue(req);
|
||||
}
|
||||
|
||||
private Channel currentChannel;
|
||||
|
||||
protected Channel CurrentChannel
|
||||
{
|
||||
get
|
||||
{
|
||||
return currentChannel;
|
||||
}
|
||||
get { return currentChannel; }
|
||||
|
||||
set
|
||||
{
|
||||
@@ -343,14 +341,14 @@ namespace osu.Game.Overlays
|
||||
if (value == null)
|
||||
{
|
||||
currentChannel = null;
|
||||
textbox.Current.Disabled = true;
|
||||
Textbox.Current.Disabled = true;
|
||||
currentChannelContainer.Clear(false);
|
||||
return;
|
||||
}
|
||||
|
||||
currentChannel = value;
|
||||
|
||||
textbox.Current.Disabled = currentChannel.ReadOnly;
|
||||
Textbox.Current.Disabled = currentChannel.ReadOnly;
|
||||
channelTabs.Current.Value = value;
|
||||
|
||||
var loaded = loadedChannels.Find(d => d.Channel == value);
|
||||
@@ -422,18 +420,15 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
var req = new GetMessagesRequest(new List<Channel> { channel }, null);
|
||||
|
||||
req.Success += delegate (List<Message> messages)
|
||||
req.Success += delegate(List<Message> messages)
|
||||
{
|
||||
loading.Hide();
|
||||
channel.AddNewMessages(messages.ToArray());
|
||||
Debug.Write("success!");
|
||||
};
|
||||
req.Failure += delegate
|
||||
{
|
||||
Debug.Write("failure!");
|
||||
};
|
||||
req.Failure += delegate { Debug.Write("failure!"); };
|
||||
|
||||
api.Queue(req);
|
||||
Api.Queue(req);
|
||||
}
|
||||
|
||||
private void fetchNewMessages()
|
||||
@@ -442,32 +437,32 @@ namespace osu.Game.Overlays
|
||||
|
||||
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))
|
||||
careChannels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray());
|
||||
|
||||
lastMessageId = messages.LastOrDefault()?.Id ?? lastMessageId;
|
||||
|
||||
Debug.Write("success!");
|
||||
fetchReq = null;
|
||||
};
|
||||
|
||||
fetchReq.Failure += delegate
|
||||
{
|
||||
Debug.Write("failure!");
|
||||
fetchReq = null;
|
||||
};
|
||||
|
||||
api.Queue(fetchReq);
|
||||
Api.Queue(fetchReq);
|
||||
}
|
||||
|
||||
private void postMessage(TextBox textbox, bool newText)
|
||||
private void handleTextboxMessage(TextBox textbox, bool newText)
|
||||
{
|
||||
var postText = textbox.Text;
|
||||
|
||||
textbox.Text = string.Empty;
|
||||
PostMessage(postText);
|
||||
}
|
||||
|
||||
protected void PostMessage(string postText)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(postText))
|
||||
return;
|
||||
|
||||
@@ -475,7 +470,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
if (target == null) return;
|
||||
|
||||
if (!api.IsLoggedIn)
|
||||
if (!Api.IsLoggedIn)
|
||||
{
|
||||
target.AddNewMessages(new ErrorMessage("Please login to participate in chat!"));
|
||||
return;
|
||||
@@ -515,7 +510,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
var message = new LocalEchoMessage
|
||||
{
|
||||
Sender = api.LocalUser.Value,
|
||||
Sender = Api.LocalUser.Value,
|
||||
Timestamp = DateTimeOffset.Now,
|
||||
TargetType = TargetType.Channel, //TODO: read this from channel
|
||||
TargetId = target.Id,
|
||||
@@ -529,7 +524,7 @@ namespace osu.Game.Overlays
|
||||
req.Failure += e => target.ReplaceMessage(message, null);
|
||||
req.Success += m => target.ReplaceMessage(message, m);
|
||||
|
||||
api.Queue(req);
|
||||
Api.Queue(req);
|
||||
}
|
||||
|
||||
private void transformChatHeightTo(double newChatHeight, double duration = 0, Easing easing = Easing.None)
|
||||
|
||||
@@ -281,6 +281,8 @@
|
||||
<Compile Include="Database\SingletonContextFactory.cs" />
|
||||
<Compile Include="Graphics\Containers\LinkFlowContainer.cs" />
|
||||
<Compile Include="Graphics\Textures\LargeTextureStore.cs" />
|
||||
<Compile Include="Online\API\DummyAPIAccess.cs" />
|
||||
<Compile Include="Online\API\IAPIProvider.cs" />
|
||||
<Compile Include="Online\API\Requests\GetUserRequest.cs" />
|
||||
<Compile Include="Migrations\20180125143340_Settings.cs" />
|
||||
<Compile Include="Migrations\20180125143340_Settings.Designer.cs">
|
||||
|
||||
Reference in New Issue
Block a user