mirror of
https://github.com/ppy/osu.git
synced 2025-01-13 14:12:56 +08:00
Merge branch 'master' into registration-loc
This commit is contained in:
commit
39ac7615ec
@ -31,10 +31,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestMaximumDistanceTrackingWithoutMovement(
|
public void TestMaximumDistanceTrackingWithoutMovement(
|
||||||
[Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)]
|
[Values(0, 5, 10)] float circleSize,
|
||||||
float circleSize,
|
[Values(0, 5, 10)] double velocity)
|
||||||
[Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)]
|
|
||||||
double velocity)
|
|
||||||
{
|
{
|
||||||
const double time_slider_start = 1000;
|
const double time_slider_start = 1000;
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -11,7 +9,10 @@ using osu.Game.Overlays;
|
|||||||
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;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
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.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
@ -27,15 +28,20 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
|
|
||||||
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
|
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
|
||||||
|
|
||||||
private CommentsContainer commentsContainer;
|
private CommentsContainer commentsContainer = null!;
|
||||||
|
|
||||||
|
private TextBox editorTextBox = null!;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp() => Schedule(() =>
|
public void SetUp() => Schedule(() =>
|
||||||
|
{
|
||||||
Child = new BasicScrollContainer
|
Child = new BasicScrollContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = commentsContainer = new CommentsContainer()
|
Child = commentsContainer = new CommentsContainer()
|
||||||
});
|
};
|
||||||
|
editorTextBox = commentsContainer.ChildrenOfType<TextBox>().First();
|
||||||
|
});
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestIdleState()
|
public void TestIdleState()
|
||||||
@ -126,6 +132,44 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
commentsContainer.ChildrenOfType<DrawableComment>().Count(d => d.Comment.Pinned == withPinned) == 1);
|
commentsContainer.ChildrenOfType<DrawableComment>().Count(d => d.Comment.Pinned == withPinned) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPost()
|
||||||
|
{
|
||||||
|
setUpCommentsResponse(new CommentBundle { Comments = new List<Comment>() });
|
||||||
|
AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123));
|
||||||
|
AddAssert("no comments placeholder shown", () => commentsContainer.ChildrenOfType<CommentsContainer.NoCommentsPlaceholder>().Any());
|
||||||
|
|
||||||
|
setUpPostResponse();
|
||||||
|
AddStep("enter text", () => editorTextBox.Current.Value = "comm");
|
||||||
|
AddStep("submit", () => commentsContainer.ChildrenOfType<RoundedButton>().First().TriggerClick());
|
||||||
|
|
||||||
|
AddUntilStep("comment sent", () =>
|
||||||
|
{
|
||||||
|
string writtenText = editorTextBox.Current.Value;
|
||||||
|
var comment = commentsContainer.ChildrenOfType<DrawableComment>().LastOrDefault();
|
||||||
|
return comment != null && comment.ChildrenOfType<SpriteText>().Any(y => y.Text == writtenText);
|
||||||
|
});
|
||||||
|
AddAssert("no comments placeholder removed", () => !commentsContainer.ChildrenOfType<CommentsContainer.NoCommentsPlaceholder>().Any());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPostWithExistingComments()
|
||||||
|
{
|
||||||
|
setUpCommentsResponse(getExampleComments());
|
||||||
|
AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123));
|
||||||
|
|
||||||
|
setUpPostResponse();
|
||||||
|
AddStep("enter text", () => editorTextBox.Current.Value = "comm");
|
||||||
|
AddStep("submit", () => commentsContainer.ChildrenOfType<CommentEditor>().Single().ChildrenOfType<RoundedButton>().First().TriggerClick());
|
||||||
|
|
||||||
|
AddUntilStep("comment sent", () =>
|
||||||
|
{
|
||||||
|
string writtenText = editorTextBox.Current.Value;
|
||||||
|
var comment = commentsContainer.ChildrenOfType<DrawableComment>().LastOrDefault();
|
||||||
|
return comment != null && comment.ChildrenOfType<SpriteText>().Any(y => y.Text == writtenText);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void setUpCommentsResponse(CommentBundle commentBundle)
|
private void setUpCommentsResponse(CommentBundle commentBundle)
|
||||||
=> AddStep("set up response", () =>
|
=> AddStep("set up response", () =>
|
||||||
{
|
{
|
||||||
@ -139,7 +183,33 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
private CommentBundle getExampleComments(bool withPinned = false)
|
private void setUpPostResponse()
|
||||||
|
=> AddStep("set up response", () =>
|
||||||
|
{
|
||||||
|
dummyAPI.HandleRequest = request =>
|
||||||
|
{
|
||||||
|
if (!(request is CommentPostRequest req))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
req.TriggerSuccess(new CommentBundle
|
||||||
|
{
|
||||||
|
Comments = new List<Comment>
|
||||||
|
{
|
||||||
|
new Comment
|
||||||
|
{
|
||||||
|
Id = 98,
|
||||||
|
Message = req.Message,
|
||||||
|
LegacyName = "FirstUser",
|
||||||
|
CreatedAt = DateTimeOffset.Now,
|
||||||
|
VotesCount = 98,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
private static CommentBundle getExampleComments(bool withPinned = false)
|
||||||
{
|
{
|
||||||
var bundle = new CommentBundle
|
var bundle = new CommentBundle
|
||||||
{
|
{
|
||||||
|
@ -113,7 +113,7 @@ namespace osu.Game.Tournament.Screens.Setup
|
|||||||
new LabelledDropdown<RulesetInfo>
|
new LabelledDropdown<RulesetInfo>
|
||||||
{
|
{
|
||||||
Label = "Ruleset",
|
Label = "Ruleset",
|
||||||
Description = "Decides what stats are displayed and which ranks are retrieved for players.",
|
Description = "Decides what stats are displayed and which ranks are retrieved for players. This requires a restart to reload data for an existing bracket.",
|
||||||
Items = rulesets.AvailableRulesets,
|
Items = rulesets.AvailableRulesets,
|
||||||
Current = LadderInfo.Ruleset,
|
Current = LadderInfo.Ruleset,
|
||||||
},
|
},
|
||||||
|
@ -16,6 +16,7 @@ using osu.Framework.IO.Stores;
|
|||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Online;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Tournament.IO;
|
using osu.Game.Tournament.IO;
|
||||||
@ -44,6 +45,14 @@ namespace osu.Game.Tournament
|
|||||||
return dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
return dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override EndpointConfiguration CreateEndpoints()
|
||||||
|
{
|
||||||
|
if (UseDevelopmentServer)
|
||||||
|
return base.CreateEndpoints();
|
||||||
|
|
||||||
|
return new ProductionEndpointConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
private TournamentSpriteText initialisationText;
|
private TournamentSpriteText initialisationText;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -156,9 +165,21 @@ namespace osu.Game.Tournament
|
|||||||
addedInfo |= addSeedingBeatmaps();
|
addedInfo |= addSeedingBeatmaps();
|
||||||
|
|
||||||
if (addedInfo)
|
if (addedInfo)
|
||||||
SaveChanges();
|
saveChanges();
|
||||||
|
|
||||||
ladder.CurrentMatch.Value = ladder.Matches.FirstOrDefault(p => p.Current.Value);
|
ladder.CurrentMatch.Value = ladder.Matches.FirstOrDefault(p => p.Current.Value);
|
||||||
|
|
||||||
|
ladder.Ruleset.BindValueChanged(r =>
|
||||||
|
{
|
||||||
|
// Refetch player rank data on next startup as the ruleset has changed.
|
||||||
|
foreach (var team in ladder.Teams)
|
||||||
|
{
|
||||||
|
foreach (var player in team.Players)
|
||||||
|
player.Rank = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveChanges();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -306,6 +327,11 @@ namespace osu.Game.Tournament
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveChanges()
|
||||||
|
{
|
||||||
foreach (var r in ladder.Rounds)
|
foreach (var r in ladder.Rounds)
|
||||||
r.Matches = ladder.Matches.Where(p => p.Round.Value == r).Select(p => p.ID).ToList();
|
r.Matches = ladder.Matches.Where(p => p.Round.Value == r).Select(p => p.ID).ToList();
|
||||||
|
|
||||||
|
@ -19,6 +19,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"join the real-time discussion");
|
public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"join the real-time discussion");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Mention"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString MentionUser => new TranslatableString(getKey(@"mention_user"), @"Mention");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
41
osu.Game/Online/API/Requests/CommentPostRequest.cs
Normal file
41
osu.Game/Online/API/Requests/CommentPostRequest.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Net.Http;
|
||||||
|
using osu.Framework.IO.Network;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
|
||||||
|
namespace osu.Game.Online.API.Requests
|
||||||
|
{
|
||||||
|
public class CommentPostRequest : APIRequest<CommentBundle>
|
||||||
|
{
|
||||||
|
public readonly CommentableType Commentable;
|
||||||
|
public readonly long CommentableId;
|
||||||
|
public readonly string Message;
|
||||||
|
public readonly long? ParentCommentId;
|
||||||
|
|
||||||
|
public CommentPostRequest(CommentableType commentable, long commentableId, string message, long? parentCommentId = null)
|
||||||
|
{
|
||||||
|
Commentable = commentable;
|
||||||
|
CommentableId = commentableId;
|
||||||
|
Message = message;
|
||||||
|
ParentCommentId = parentCommentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override WebRequest CreateWebRequest()
|
||||||
|
{
|
||||||
|
var req = base.CreateWebRequest();
|
||||||
|
req.Method = HttpMethod.Post;
|
||||||
|
|
||||||
|
req.AddParameter(@"comment[commentable_type]", Commentable.ToString().ToLowerInvariant());
|
||||||
|
req.AddParameter(@"comment[commentable_id]", $"{CommentableId}");
|
||||||
|
req.AddParameter(@"comment[message]", Message);
|
||||||
|
if (ParentCommentId.HasValue)
|
||||||
|
req.AddParameter(@"comment[parent_id]", $"{ParentCommentId}");
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string Target => "comments";
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,7 @@ namespace osu.Game.Online.Chat
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class StandAloneChatDisplay : CompositeDrawable
|
public partial class StandAloneChatDisplay : CompositeDrawable
|
||||||
{
|
{
|
||||||
|
[Cached]
|
||||||
public readonly Bindable<Channel> Channel = new Bindable<Channel>();
|
public readonly Bindable<Channel> Channel = new Bindable<Channel>();
|
||||||
|
|
||||||
protected readonly ChatTextBox TextBox;
|
protected readonly ChatTextBox TextBox;
|
||||||
|
19
osu.Game/Online/ExperimentalEndpointConfiguration.cs
Normal file
19
osu.Game/Online/ExperimentalEndpointConfiguration.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
namespace osu.Game.Online
|
||||||
|
{
|
||||||
|
public class ExperimentalEndpointConfiguration : EndpointConfiguration
|
||||||
|
{
|
||||||
|
public ExperimentalEndpointConfiguration()
|
||||||
|
{
|
||||||
|
WebsiteRootUrl = @"https://osu.ppy.sh";
|
||||||
|
APIEndpointUrl = @"https://lazer.ppy.sh";
|
||||||
|
APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk";
|
||||||
|
APIClientID = "5";
|
||||||
|
SpectatorEndpointUrl = "https://spectator.ppy.sh/spectator";
|
||||||
|
MultiplayerEndpointUrl = "https://spectator.ppy.sh/multiplayer";
|
||||||
|
MetadataEndpointUrl = "https://spectator.ppy.sh/metadata";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,13 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace osu.Game.Online
|
namespace osu.Game.Online
|
||||||
{
|
{
|
||||||
public class ProductionEndpointConfiguration : EndpointConfiguration
|
public class ProductionEndpointConfiguration : EndpointConfiguration
|
||||||
{
|
{
|
||||||
public ProductionEndpointConfiguration()
|
public ProductionEndpointConfiguration()
|
||||||
{
|
{
|
||||||
WebsiteRootUrl = @"https://osu.ppy.sh";
|
WebsiteRootUrl = APIEndpointUrl = @"https://osu.ppy.sh";
|
||||||
APIEndpointUrl = @"https://lazer.ppy.sh";
|
|
||||||
APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk";
|
APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk";
|
||||||
APIClientID = "5";
|
APIClientID = "5";
|
||||||
SpectatorEndpointUrl = "https://spectator.ppy.sh/spectator";
|
SpectatorEndpointUrl = "https://spectator.ppy.sh/spectator";
|
||||||
|
@ -98,8 +98,8 @@ namespace osu.Game
|
|||||||
|
|
||||||
public virtual bool UseDevelopmentServer => DebugUtils.IsDebugBuild;
|
public virtual bool UseDevelopmentServer => DebugUtils.IsDebugBuild;
|
||||||
|
|
||||||
internal EndpointConfiguration CreateEndpoints() =>
|
public virtual EndpointConfiguration CreateEndpoints() =>
|
||||||
UseDevelopmentServer ? new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration();
|
UseDevelopmentServer ? new DevelopmentEndpointConfiguration() : new ExperimentalEndpointConfiguration();
|
||||||
|
|
||||||
public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version();
|
public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version();
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
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;
|
||||||
@ -24,6 +25,7 @@ using osu.Game.Online.Chat;
|
|||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
using ChatStrings = osu.Game.Localisation.ChatStrings;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Chat
|
namespace osu.Game.Overlays.Chat
|
||||||
{
|
{
|
||||||
@ -65,6 +67,9 @@ namespace osu.Game.Overlays.Chat
|
|||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private UserProfileOverlay? profileOverlay { get; set; }
|
private UserProfileOverlay? profileOverlay { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private Bindable<Channel?>? currentChannel { get; set; }
|
||||||
|
|
||||||
private readonly APIUser user;
|
private readonly APIUser user;
|
||||||
private readonly OsuSpriteText drawableText;
|
private readonly OsuSpriteText drawableText;
|
||||||
|
|
||||||
@ -156,6 +161,14 @@ namespace osu.Game.Overlays.Chat
|
|||||||
if (!user.Equals(api.LocalUser.Value))
|
if (!user.Equals(api.LocalUser.Value))
|
||||||
items.Add(new OsuMenuItem(UsersStrings.CardSendMessage, MenuItemType.Standard, openUserChannel));
|
items.Add(new OsuMenuItem(UsersStrings.CardSendMessage, MenuItemType.Standard, openUserChannel));
|
||||||
|
|
||||||
|
if (currentChannel?.Value != null)
|
||||||
|
{
|
||||||
|
items.Add(new OsuMenuItem(ChatStrings.MentionUser, MenuItemType.Standard, () =>
|
||||||
|
{
|
||||||
|
currentChannel.Value.TextBoxMessage.Value += $"@{user.Username} ";
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
return items.ToArray();
|
return items.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
@ -17,16 +18,22 @@ using osu.Framework.Extensions.IEnumerableExtensions;
|
|||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
using APIUser = osu.Game.Online.API.Requests.Responses.APIUser;
|
using osu.Game.Users.Drawables;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Comments
|
namespace osu.Game.Overlays.Comments
|
||||||
{
|
{
|
||||||
|
[Cached]
|
||||||
public partial class CommentsContainer : CompositeDrawable
|
public partial class CommentsContainer : CompositeDrawable
|
||||||
{
|
{
|
||||||
private readonly Bindable<CommentableType> type = new Bindable<CommentableType>();
|
private readonly Bindable<CommentableType> type = new Bindable<CommentableType>();
|
||||||
private readonly BindableLong id = new BindableLong();
|
private readonly BindableLong id = new BindableLong();
|
||||||
|
public IBindable<CommentableType> Type => type;
|
||||||
|
public IBindable<long> Id => id;
|
||||||
|
|
||||||
public readonly Bindable<CommentsSortCriteria> Sort = new Bindable<CommentsSortCriteria>();
|
public readonly Bindable<CommentsSortCriteria> Sort = new Bindable<CommentsSortCriteria>();
|
||||||
public readonly BindableBool ShowDeleted = new BindableBool();
|
public readonly BindableBool ShowDeleted = new BindableBool();
|
||||||
@ -46,12 +53,14 @@ namespace osu.Game.Overlays.Comments
|
|||||||
private DeletedCommentsCounter deletedCommentsCounter;
|
private DeletedCommentsCounter deletedCommentsCounter;
|
||||||
private CommentsShowMoreButton moreButton;
|
private CommentsShowMoreButton moreButton;
|
||||||
private TotalCommentsCounter commentCounter;
|
private TotalCommentsCounter commentCounter;
|
||||||
|
private UpdateableAvatar avatar;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OverlayColourProvider colourProvider)
|
private void load(OverlayColourProvider colourProvider)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
AddRangeInternal(new Drawable[]
|
AddRangeInternal(new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
@ -86,6 +95,32 @@ namespace osu.Game.Overlays.Comments
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Padding = new MarginPadding { Horizontal = 50, Vertical = 20 },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
avatar = new UpdateableAvatar(api.LocalUser.Value)
|
||||||
|
{
|
||||||
|
Size = new Vector2(50),
|
||||||
|
CornerExponent = 2,
|
||||||
|
CornerRadius = 25,
|
||||||
|
Masking = true,
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Padding = new MarginPadding { Left = 60 },
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Child = new NewCommentEditor
|
||||||
|
{
|
||||||
|
OnPost = prependPostedComments
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
new CommentsHeader
|
new CommentsHeader
|
||||||
{
|
{
|
||||||
Sort = { BindTarget = Sort },
|
Sort = { BindTarget = Sort },
|
||||||
@ -151,6 +186,7 @@ namespace osu.Game.Overlays.Comments
|
|||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
User.BindValueChanged(_ => refetchComments());
|
User.BindValueChanged(_ => refetchComments());
|
||||||
|
User.BindValueChanged(e => avatar.User = e.NewValue);
|
||||||
Sort.BindValueChanged(_ => refetchComments(), true);
|
Sort.BindValueChanged(_ => refetchComments(), true);
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
}
|
}
|
||||||
@ -245,7 +281,6 @@ namespace osu.Game.Overlays.Comments
|
|||||||
{
|
{
|
||||||
pinnedContent.AddRange(loaded.Where(d => d.Comment.Pinned));
|
pinnedContent.AddRange(loaded.Where(d => d.Comment.Pinned));
|
||||||
content.AddRange(loaded.Where(d => !d.Comment.Pinned));
|
content.AddRange(loaded.Where(d => !d.Comment.Pinned));
|
||||||
|
|
||||||
deletedCommentsCounter.Count.Value += topLevelComments.Select(d => d.Comment).Count(c => c.IsDeleted && c.IsTopLevel);
|
deletedCommentsCounter.Count.Value += topLevelComments.Select(d => d.Comment).Count(c => c.IsDeleted && c.IsTopLevel);
|
||||||
|
|
||||||
if (bundle.HasMore)
|
if (bundle.HasMore)
|
||||||
@ -288,6 +323,34 @@ namespace osu.Game.Overlays.Comments
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void prependPostedComments(CommentBundle bundle)
|
||||||
|
{
|
||||||
|
var topLevelComments = new List<DrawableComment>();
|
||||||
|
|
||||||
|
foreach (var comment in bundle.Comments)
|
||||||
|
{
|
||||||
|
// Exclude possible duplicated comments.
|
||||||
|
if (CommentDictionary.ContainsKey(comment.Id))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
topLevelComments.Add(getDrawableComment(comment));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (topLevelComments.Any())
|
||||||
|
{
|
||||||
|
LoadComponentsAsync(topLevelComments, loaded =>
|
||||||
|
{
|
||||||
|
if (content.Count > 0 && content[0] is NoCommentsPlaceholder placeholder)
|
||||||
|
content.Remove(placeholder, true);
|
||||||
|
|
||||||
|
foreach (var comment in loaded)
|
||||||
|
{
|
||||||
|
content.Insert((int)-Clock.CurrentTime, comment);
|
||||||
|
}
|
||||||
|
}, (loadCancellation = new CancellationTokenSource()).Token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private DrawableComment getDrawableComment(Comment comment)
|
private DrawableComment getDrawableComment(Comment comment)
|
||||||
{
|
{
|
||||||
if (CommentDictionary.TryGetValue(comment.Id, out var existing))
|
if (CommentDictionary.TryGetValue(comment.Id, out var existing))
|
||||||
@ -317,7 +380,7 @@ namespace osu.Game.Overlays.Comments
|
|||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
private partial class NoCommentsPlaceholder : CompositeDrawable
|
internal partial class NoCommentsPlaceholder : CompositeDrawable
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
@ -336,5 +399,41 @@ namespace osu.Game.Overlays.Comments
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private partial class NewCommentEditor : CommentEditor
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private CommentsContainer commentsContainer { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
|
public Action<CommentBundle> OnPost;
|
||||||
|
|
||||||
|
//TODO should match web, left empty due to no multiline support
|
||||||
|
protected override LocalisableString FooterText => default;
|
||||||
|
|
||||||
|
protected override LocalisableString CommitButtonText => CommonStrings.ButtonsPost;
|
||||||
|
|
||||||
|
protected override LocalisableString TextBoxPlaceholder => CommentsStrings.PlaceholderNew;
|
||||||
|
|
||||||
|
protected override void OnCommit(string text)
|
||||||
|
{
|
||||||
|
ShowLoadingSpinner = true;
|
||||||
|
CommentPostRequest req = new CommentPostRequest(commentsContainer.Type.Value, commentsContainer.Id.Value, text);
|
||||||
|
req.Failure += e => Schedule(() =>
|
||||||
|
{
|
||||||
|
ShowLoadingSpinner = false;
|
||||||
|
Logger.Error(e, "Posting comment failed.");
|
||||||
|
});
|
||||||
|
req.Success += cb => Schedule(() =>
|
||||||
|
{
|
||||||
|
ShowLoadingSpinner = false;
|
||||||
|
Current.Value = string.Empty;
|
||||||
|
OnPost?.Invoke(cb);
|
||||||
|
});
|
||||||
|
api.Queue(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,11 @@ namespace osu.Game.Overlays.Comments
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool WasDeleted { get; protected set; }
|
public bool WasDeleted { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tracks this comment's level of nesting. 0 means that this comment has no parents.
|
||||||
|
/// </summary>
|
||||||
|
public int Level { get; private set; }
|
||||||
|
|
||||||
private FillFlowContainer childCommentsVisibilityContainer = null!;
|
private FillFlowContainer childCommentsVisibilityContainer = null!;
|
||||||
private FillFlowContainer childCommentsContainer = null!;
|
private FillFlowContainer childCommentsContainer = null!;
|
||||||
private LoadRepliesButton loadRepliesButton = null!;
|
private LoadRepliesButton loadRepliesButton = null!;
|
||||||
@ -70,7 +75,7 @@ namespace osu.Game.Overlays.Comments
|
|||||||
private GridContainer content = null!;
|
private GridContainer content = null!;
|
||||||
private VotePill votePill = null!;
|
private VotePill votePill = null!;
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved]
|
||||||
private IDialogOverlay? dialogOverlay { get; set; }
|
private IDialogOverlay? dialogOverlay { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -79,7 +84,7 @@ namespace osu.Game.Overlays.Comments
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private GameHost host { get; set; } = null!;
|
private GameHost host { get; set; } = null!;
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved]
|
||||||
private OnScreenDisplay? onScreenDisplay { get; set; }
|
private OnScreenDisplay? onScreenDisplay { get; set; }
|
||||||
|
|
||||||
public DrawableComment(Comment comment)
|
public DrawableComment(Comment comment)
|
||||||
@ -88,12 +93,16 @@ namespace osu.Game.Overlays.Comments
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OverlayColourProvider colourProvider)
|
private void load(OverlayColourProvider colourProvider, DrawableComment? parentComment)
|
||||||
{
|
{
|
||||||
LinkFlowContainer username;
|
LinkFlowContainer username;
|
||||||
FillFlowContainer info;
|
FillFlowContainer info;
|
||||||
CommentMarkdownContainer message;
|
CommentMarkdownContainer message;
|
||||||
|
|
||||||
|
Level = parentComment?.Level + 1 ?? 0;
|
||||||
|
|
||||||
|
float childrenPadding = Level < 6 ? 20 : 5;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
@ -248,7 +257,7 @@ namespace osu.Game.Overlays.Comments
|
|||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Padding = new MarginPadding { Left = 20 },
|
Padding = new MarginPadding { Left = childrenPadding },
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
childCommentsContainer = new FillFlowContainer
|
childCommentsContainer = new FillFlowContainer
|
||||||
|
110
osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs
Normal file
110
osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public partial class ExtendedDetails : CompositeDrawable
|
||||||
|
{
|
||||||
|
public Bindable<UserProfileData?> User { get; } = new Bindable<UserProfileData?>();
|
||||||
|
|
||||||
|
private SpriteText rankedScore = null!;
|
||||||
|
private SpriteText hitAccuracy = null!;
|
||||||
|
private SpriteText playCount = null!;
|
||||||
|
private SpriteText totalScore = null!;
|
||||||
|
private SpriteText totalHits = null!;
|
||||||
|
private SpriteText maximumCombo = null!;
|
||||||
|
private SpriteText replaysWatched = null!;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
var font = OsuFont.Default.With(size: 12);
|
||||||
|
const float vertical_spacing = 4;
|
||||||
|
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
// this should really be a grid, but trying to avoid one to avoid the performance hit.
|
||||||
|
InternalChild = new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(20, 0),
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Name = @"Labels",
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(0, vertical_spacing),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsRankedScore },
|
||||||
|
new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsHitAccuracy },
|
||||||
|
new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsPlayCount },
|
||||||
|
new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsTotalScore },
|
||||||
|
new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsTotalHits },
|
||||||
|
new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsMaximumCombo },
|
||||||
|
new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsReplaysWatchedByOthers },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Name = @"Values",
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(0, vertical_spacing),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
rankedScore = new OsuSpriteText { Font = font },
|
||||||
|
hitAccuracy = new OsuSpriteText { Font = font },
|
||||||
|
playCount = new OsuSpriteText { Font = font },
|
||||||
|
totalScore = new OsuSpriteText { Font = font },
|
||||||
|
totalHits = new OsuSpriteText { Font = font },
|
||||||
|
maximumCombo = new OsuSpriteText { Font = font },
|
||||||
|
replaysWatched = new OsuSpriteText { Font = font },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
User.BindValueChanged(user => updateStatistics(user.NewValue?.User.Statistics), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateStatistics(UserStatistics? statistics)
|
||||||
|
{
|
||||||
|
if (statistics == null)
|
||||||
|
{
|
||||||
|
Alpha = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Alpha = 1;
|
||||||
|
|
||||||
|
rankedScore.Text = statistics.RankedScore.ToLocalisableString(@"N0");
|
||||||
|
hitAccuracy.Text = statistics.DisplayAccuracy;
|
||||||
|
playCount.Text = statistics.PlayCount.ToLocalisableString(@"N0");
|
||||||
|
totalScore.Text = statistics.TotalScore.ToLocalisableString(@"N0");
|
||||||
|
totalHits.Text = statistics.TotalHits.ToLocalisableString(@"N0");
|
||||||
|
maximumCombo.Text = statistics.MaxCombo.ToLocalisableString(@"N0");
|
||||||
|
replaysWatched.Text = statistics.ReplaysWatched.ToLocalisableString(@"N0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
186
osu.Game/Overlays/Profile/Header/Components/MainDetails.cs
Normal file
186
osu.Game/Overlays/Profile/Header/Components/MainDetails.cs
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Online.Leaderboards;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public partial class MainDetails : CompositeDrawable
|
||||||
|
{
|
||||||
|
private readonly Dictionary<ScoreRank, ScoreRankInfo> scoreRankInfos = new Dictionary<ScoreRank, ScoreRankInfo>();
|
||||||
|
private ProfileValueDisplay medalInfo = null!;
|
||||||
|
private ProfileValueDisplay ppInfo = null!;
|
||||||
|
private ProfileValueDisplay detailGlobalRank = null!;
|
||||||
|
private ProfileValueDisplay detailCountryRank = null!;
|
||||||
|
private RankGraph rankGraph = null!;
|
||||||
|
|
||||||
|
public readonly Bindable<UserProfileData?> User = new Bindable<UserProfileData?>();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
|
InternalChild = new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
AutoSizeDuration = 200,
|
||||||
|
AutoSizeEasing = Easing.OutQuint,
|
||||||
|
Masking = true,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(0, 15),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(20),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
detailGlobalRank = new ProfileValueDisplay(true)
|
||||||
|
{
|
||||||
|
Title = UsersStrings.ShowRankGlobalSimple,
|
||||||
|
},
|
||||||
|
detailCountryRank = new ProfileValueDisplay(true)
|
||||||
|
{
|
||||||
|
Title = UsersStrings.ShowRankCountrySimple,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 60,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
rankGraph = new RankGraph
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(10, 0),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
medalInfo = new ProfileValueDisplay
|
||||||
|
{
|
||||||
|
Title = UsersStrings.ShowStatsMedals,
|
||||||
|
},
|
||||||
|
ppInfo = new ProfileValueDisplay
|
||||||
|
{
|
||||||
|
Title = "pp",
|
||||||
|
},
|
||||||
|
new TotalPlayTime
|
||||||
|
{
|
||||||
|
User = { BindTarget = User }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(5),
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
scoreRankInfos[ScoreRank.XH] = new ScoreRankInfo(ScoreRank.XH),
|
||||||
|
scoreRankInfos[ScoreRank.X] = new ScoreRankInfo(ScoreRank.X),
|
||||||
|
scoreRankInfos[ScoreRank.SH] = new ScoreRankInfo(ScoreRank.SH),
|
||||||
|
scoreRankInfos[ScoreRank.S] = new ScoreRankInfo(ScoreRank.S),
|
||||||
|
scoreRankInfos[ScoreRank.A] = new ScoreRankInfo(ScoreRank.A),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
User.BindValueChanged(e => updateDisplay(e.NewValue), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDisplay(UserProfileData? data)
|
||||||
|
{
|
||||||
|
var user = data?.User;
|
||||||
|
|
||||||
|
medalInfo.Content = user?.Achievements?.Length.ToString() ?? "0";
|
||||||
|
ppInfo.Content = user?.Statistics?.PP?.ToLocalisableString("#,##0") ?? (LocalisableString)"0";
|
||||||
|
|
||||||
|
foreach (var scoreRankInfo in scoreRankInfos)
|
||||||
|
scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0;
|
||||||
|
|
||||||
|
detailGlobalRank.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-";
|
||||||
|
detailCountryRank.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-";
|
||||||
|
|
||||||
|
rankGraph.Statistics.Value = user?.Statistics;
|
||||||
|
}
|
||||||
|
|
||||||
|
private partial class ScoreRankInfo : CompositeDrawable
|
||||||
|
{
|
||||||
|
private readonly OsuSpriteText rankCount;
|
||||||
|
|
||||||
|
public int RankCount
|
||||||
|
{
|
||||||
|
set => rankCount.Text = value.ToLocalisableString("#,##0");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScoreRankInfo(ScoreRank rank)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
InternalChild = new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Width = 44,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new DrawableRank(rank)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 22,
|
||||||
|
},
|
||||||
|
rankCount = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,33 +1,17 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.LocalisationExtensions;
|
|
||||||
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.Localisation;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using osu.Game.Online.Leaderboards;
|
|
||||||
using osu.Game.Overlays.Profile.Header.Components;
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
|
||||||
using osu.Game.Scoring;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Profile.Header
|
namespace osu.Game.Overlays.Profile.Header
|
||||||
{
|
{
|
||||||
public partial class DetailHeaderContainer : CompositeDrawable
|
public partial class DetailHeaderContainer : CompositeDrawable
|
||||||
{
|
{
|
||||||
private readonly Dictionary<ScoreRank, ScoreRankInfo> scoreRankInfos = new Dictionary<ScoreRank, ScoreRankInfo>();
|
|
||||||
private ProfileValueDisplay medalInfo = null!;
|
|
||||||
private ProfileValueDisplay ppInfo = null!;
|
|
||||||
private ProfileValueDisplay detailGlobalRank = null!;
|
|
||||||
private ProfileValueDisplay detailCountryRank = null!;
|
|
||||||
private RankGraph rankGraph = null!;
|
|
||||||
|
|
||||||
public readonly Bindable<UserProfileData?> User = new Bindable<UserProfileData?>();
|
public readonly Bindable<UserProfileData?> User = new Bindable<UserProfileData?>();
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -35,8 +19,6 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
User.ValueChanged += e => updateDisplay(e.NewValue);
|
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
@ -44,149 +26,52 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = colourProvider.Background5,
|
Colour = colourProvider.Background5,
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
AutoSizeDuration = 200,
|
|
||||||
AutoSizeEasing = Easing.OutQuint,
|
|
||||||
Masking = true,
|
|
||||||
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 },
|
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 },
|
||||||
Direction = FillDirection.Vertical,
|
Child = new GridContainer
|
||||||
Spacing = new Vector2(0, 15),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
RowDimensions = new[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Spacing = new Vector2(20),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
detailGlobalRank = new ProfileValueDisplay(true)
|
|
||||||
{
|
|
||||||
Title = UsersStrings.ShowRankGlobalSimple,
|
|
||||||
},
|
|
||||||
detailCountryRank = new ProfileValueDisplay(true)
|
|
||||||
{
|
|
||||||
Title = UsersStrings.ShowRankCountrySimple,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
new Container
|
ColumnDimensions = new[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
new Dimension(),
|
||||||
Height = 60,
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
Children = new Drawable[]
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
{
|
|
||||||
rankGraph = new RankGraph
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
new Container
|
Content = new[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
new Drawable[]
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
new MainDetails
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
User = { BindTarget = User }
|
||||||
|
},
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = 2,
|
||||||
|
Colour = colourProvider.Background6,
|
||||||
|
Margin = new MarginPadding { Horizontal = 15 }
|
||||||
|
},
|
||||||
|
new ExtendedDetails
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Direction = FillDirection.Horizontal,
|
User = { BindTarget = User }
|
||||||
Spacing = new Vector2(10, 0),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
medalInfo = new ProfileValueDisplay
|
|
||||||
{
|
|
||||||
Title = UsersStrings.ShowStatsMedals,
|
|
||||||
},
|
|
||||||
ppInfo = new ProfileValueDisplay
|
|
||||||
{
|
|
||||||
Title = "pp",
|
|
||||||
},
|
|
||||||
new TotalPlayTime
|
|
||||||
{
|
|
||||||
User = { BindTarget = User }
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.CentreRight,
|
|
||||||
Origin = Anchor.CentreRight,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Spacing = new Vector2(5),
|
|
||||||
Children = new[]
|
|
||||||
{
|
|
||||||
scoreRankInfos[ScoreRank.XH] = new ScoreRankInfo(ScoreRank.XH),
|
|
||||||
scoreRankInfos[ScoreRank.X] = new ScoreRankInfo(ScoreRank.X),
|
|
||||||
scoreRankInfos[ScoreRank.SH] = new ScoreRankInfo(ScoreRank.SH),
|
|
||||||
scoreRankInfos[ScoreRank.S] = new ScoreRankInfo(ScoreRank.S),
|
|
||||||
scoreRankInfos[ScoreRank.A] = new ScoreRankInfo(ScoreRank.A),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateDisplay(UserProfileData? data)
|
|
||||||
{
|
|
||||||
var user = data?.User;
|
|
||||||
|
|
||||||
medalInfo.Content = user?.Achievements?.Length.ToString() ?? "0";
|
|
||||||
ppInfo.Content = user?.Statistics?.PP?.ToLocalisableString("#,##0") ?? (LocalisableString)"0";
|
|
||||||
|
|
||||||
foreach (var scoreRankInfo in scoreRankInfos)
|
|
||||||
scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0;
|
|
||||||
|
|
||||||
detailGlobalRank.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-";
|
|
||||||
detailCountryRank.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-";
|
|
||||||
|
|
||||||
rankGraph.Statistics.Value = user?.Statistics;
|
|
||||||
}
|
|
||||||
|
|
||||||
private partial class ScoreRankInfo : CompositeDrawable
|
|
||||||
{
|
|
||||||
private readonly OsuSpriteText rankCount;
|
|
||||||
|
|
||||||
public int RankCount
|
|
||||||
{
|
|
||||||
set => rankCount.Text = value.ToLocalisableString("#,##0");
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScoreRankInfo(ScoreRank rank)
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both;
|
|
||||||
InternalChild = new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Width = 44,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new DrawableRank(rank)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 22,
|
|
||||||
},
|
|
||||||
rankCount = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,18 +5,15 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Extensions.LocalisationExtensions;
|
|
||||||
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.Localisation;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Overlays.Profile.Header.Components;
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
|
||||||
using osu.Game.Users.Drawables;
|
using osu.Game.Users.Drawables;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -38,7 +35,6 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
private OsuSpriteText titleText = null!;
|
private OsuSpriteText titleText = null!;
|
||||||
private UpdateableFlag userFlag = null!;
|
private UpdateableFlag userFlag = null!;
|
||||||
private OsuSpriteText userCountryText = null!;
|
private OsuSpriteText userCountryText = null!;
|
||||||
private FillFlowContainer userStats = null!;
|
|
||||||
private GroupBadgeFlow groupBadgeFlow = null!;
|
private GroupBadgeFlow groupBadgeFlow = null!;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -164,16 +160,6 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
userStats = new FillFlowContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopRight,
|
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Width = 300,
|
|
||||||
Margin = new MarginPadding { Right = UserProfileOverlay.CONTENT_X_MARGIN },
|
|
||||||
Padding = new MarginPadding { Vertical = 15 },
|
|
||||||
Spacing = new Vector2(0, 2)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
User.BindValueChanged(user => updateUser(user.NewValue));
|
User.BindValueChanged(user => updateUser(user.NewValue));
|
||||||
@ -192,43 +178,6 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
titleText.Text = user?.Title ?? string.Empty;
|
titleText.Text = user?.Title ?? string.Empty;
|
||||||
titleText.Colour = Color4Extensions.FromHex(user?.Colour ?? "fff");
|
titleText.Colour = Color4Extensions.FromHex(user?.Colour ?? "fff");
|
||||||
groupBadgeFlow.User.Value = user;
|
groupBadgeFlow.User.Value = user;
|
||||||
|
|
||||||
userStats.Clear();
|
|
||||||
|
|
||||||
if (user?.Statistics != null)
|
|
||||||
{
|
|
||||||
userStats.Add(new UserStatsLine(UsersStrings.ShowStatsRankedScore, user.Statistics.RankedScore.ToLocalisableString("#,##0")));
|
|
||||||
userStats.Add(new UserStatsLine(UsersStrings.ShowStatsHitAccuracy, user.Statistics.DisplayAccuracy));
|
|
||||||
userStats.Add(new UserStatsLine(UsersStrings.ShowStatsPlayCount, user.Statistics.PlayCount.ToLocalisableString("#,##0")));
|
|
||||||
userStats.Add(new UserStatsLine(UsersStrings.ShowStatsTotalScore, user.Statistics.TotalScore.ToLocalisableString("#,##0")));
|
|
||||||
userStats.Add(new UserStatsLine(UsersStrings.ShowStatsTotalHits, user.Statistics.TotalHits.ToLocalisableString("#,##0")));
|
|
||||||
userStats.Add(new UserStatsLine(UsersStrings.ShowStatsMaximumCombo, user.Statistics.MaxCombo.ToLocalisableString("#,##0")));
|
|
||||||
userStats.Add(new UserStatsLine(UsersStrings.ShowStatsReplaysWatchedByOthers, user.Statistics.ReplaysWatched.ToLocalisableString("#,##0")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private partial class UserStatsLine : Container
|
|
||||||
{
|
|
||||||
public UserStatsLine(LocalisableString left, LocalisableString right)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X;
|
|
||||||
AutoSizeAxes = Axes.Y;
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new OsuSpriteText
|
|
||||||
{
|
|
||||||
Font = OsuFont.GetFont(size: 15),
|
|
||||||
Text = left,
|
|
||||||
},
|
|
||||||
new OsuSpriteText
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopRight,
|
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold),
|
|
||||||
Text = right,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -596,6 +596,9 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
public void FlushPendingFilterOperations()
|
public void FlushPendingFilterOperations()
|
||||||
{
|
{
|
||||||
|
if (!IsLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
if (PendingFilter?.Completed == false)
|
if (PendingFilter?.Completed == false)
|
||||||
{
|
{
|
||||||
applyActiveCriteria(false);
|
applyActiveCriteria(false);
|
||||||
|
@ -863,6 +863,7 @@ namespace osu.Game.Screens.Select
|
|||||||
// if we have a pending filter operation, we want to run it now.
|
// if we have a pending filter operation, we want to run it now.
|
||||||
// it could change selection (ie. if the ruleset has been changed).
|
// it could change selection (ie. if the ruleset has been changed).
|
||||||
Carousel.FlushPendingFilterOperations();
|
Carousel.FlushPendingFilterOperations();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user