diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index 1b9ca8717a..fa68c931d8 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -137,6 +137,11 @@ namespace osu.Game.Tests.Visual.Online @"top_ranks", @"medals" }, + RankHighest = new APIUser.UserRankHighest + { + Rank = 1, + UpdatedAt = DateTimeOffset.Now, + }, Statistics = new UserStatistics { IsRanked = true, diff --git a/osu.Game/Online/API/Requests/Responses/APIUser.cs b/osu.Game/Online/API/Requests/Responses/APIUser.cs index 56eec19fa1..4a31718f28 100644 --- a/osu.Game/Online/API/Requests/Responses/APIUser.cs +++ b/osu.Game/Online/API/Requests/Responses/APIUser.cs @@ -34,6 +34,19 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"previous_usernames")] public string[] PreviousUsernames; + [JsonProperty(@"rank_highest")] + [CanBeNull] + public UserRankHighest RankHighest; + + public class UserRankHighest + { + [JsonProperty(@"rank")] + public int Rank; + + [JsonProperty(@"updated_at")] + public DateTimeOffset UpdatedAt; + } + [JsonProperty(@"country_code")] private string countryCodeString; diff --git a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs index b89973c5e5..2505c1bc8c 100644 --- a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs +++ b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs @@ -143,6 +143,13 @@ namespace osu.Game.Overlays.Profile.Header.Components scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0; detailGlobalRank.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; + + var rankHighest = user?.RankHighest; + + detailGlobalRank.ContentTooltipText = rankHighest != null + ? UsersStrings.ShowRankHighest(rankHighest.Rank.ToLocalisableString("\\##,##0"), rankHighest.UpdatedAt.ToLocalisableString(@"d MMM yyyy")) + : string.Empty; + detailCountryRank.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; rankGraph.Statistics.Value = user?.Statistics; diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileValueDisplay.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileValueDisplay.cs index 4b1a0409a3..b2c23458b1 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileValueDisplay.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileValueDisplay.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -13,7 +14,7 @@ namespace osu.Game.Overlays.Profile.Header.Components public partial class ProfileValueDisplay : CompositeDrawable { private readonly OsuSpriteText title; - private readonly OsuSpriteText content; + private readonly ContentText content; public LocalisableString Title { @@ -25,6 +26,11 @@ namespace osu.Game.Overlays.Profile.Header.Components set => content.Text = value; } + public LocalisableString ContentTooltipText + { + set => content.TooltipText = value; + } + public ProfileValueDisplay(bool big = false, int minimumWidth = 60) { AutoSizeAxes = Axes.Both; @@ -38,9 +44,9 @@ namespace osu.Game.Overlays.Profile.Header.Components { Font = OsuFont.GetFont(size: 12) }, - content = new OsuSpriteText + content = new ContentText { - Font = OsuFont.GetFont(size: big ? 30 : 20, weight: FontWeight.Light) + Font = OsuFont.GetFont(size: big ? 30 : 20, weight: FontWeight.Light), }, new Container // Add a minimum size to the FillFlowContainer { @@ -56,5 +62,10 @@ namespace osu.Game.Overlays.Profile.Header.Components title.Colour = colourProvider.Content1; content.Colour = colourProvider.Content2; } + + private partial class ContentText : OsuSpriteText, IHasTooltip + { + public LocalisableString TooltipText { get; set; } + } } } diff --git a/osu.Game/Overlays/Profile/Header/Components/TotalPlayTime.cs b/osu.Game/Overlays/Profile/Header/Components/TotalPlayTime.cs index 08ca59d89b..a3c22d61d2 100644 --- a/osu.Game/Overlays/Profile/Header/Components/TotalPlayTime.cs +++ b/osu.Game/Overlays/Profile/Header/Components/TotalPlayTime.cs @@ -5,25 +5,19 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Header.Components { - public partial class TotalPlayTime : CompositeDrawable, IHasTooltip + public partial class TotalPlayTime : CompositeDrawable { public readonly Bindable User = new Bindable(); - public LocalisableString TooltipText { get; set; } - private ProfileValueDisplay info = null!; public TotalPlayTime() { AutoSizeAxes = Axes.Both; - - TooltipText = "0 hours"; } [BackgroundDependencyLoader] @@ -32,6 +26,7 @@ namespace osu.Game.Overlays.Profile.Header.Components InternalChild = info = new ProfileValueDisplay(minimumWidth: 140) { Title = UsersStrings.ShowStatsPlayTime, + ContentTooltipText = "0 hours", }; User.BindValueChanged(updateTime, true); @@ -40,7 +35,7 @@ namespace osu.Game.Overlays.Profile.Header.Components private void updateTime(ValueChangedEvent user) { int? playTime = user.NewValue?.User.Statistics?.PlayTime; - TooltipText = (playTime ?? 0) / 3600 + " hours"; + info.ContentTooltipText = (playTime ?? 0) / 3600 + " hours"; info.Content = formatTime(playTime); } diff --git a/osu.Game/Users/UserRankPanel.cs b/osu.Game/Users/UserRankPanel.cs index 84ff3114fc..b440261a4c 100644 --- a/osu.Game/Users/UserRankPanel.cs +++ b/osu.Game/Users/UserRankPanel.cs @@ -166,6 +166,9 @@ namespace osu.Game.Users globalRankDisplay = new ProfileValueDisplay(true) { Title = UsersStrings.ShowRankGlobalSimple, + // TODO: implement highest rank tooltip + // `RankHighest` resides in `APIUser`, but `api.LocalUser` doesn't update + // maybe move to `UserStatistics` in api, so `SoloStatisticsWatcher` can update the value }, countryRankDisplay = new ProfileValueDisplay(true) {