From 1722f3a125255174ddf9db18db6126b7023f3823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 17:53:50 +0100 Subject: [PATCH 1/5] Add ruleset to `UserProfile` --- .../Visual/Online/TestSceneHistoricalSection.cs | 5 +++-- .../Online/TestScenePlayHistorySubsection.cs | 17 +++++++++-------- .../Visual/Online/TestSceneUserProfileHeader.cs | 11 ++++++----- .../Visual/Online/TestSceneUserRanks.cs | 3 ++- osu.Game/Overlays/Profile/UserProfile.cs | 9 +++++++-- osu.Game/Overlays/UserProfileOverlay.cs | 15 +++++++++++---- 6 files changed, 38 insertions(+), 22 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs index 92bb41b7d5..438e191650 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs @@ -11,6 +11,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Profile; using osu.Game.Overlays.Profile.Sections; +using osu.Game.Rulesets.Osu; namespace osu.Game.Tests.Visual.Online { @@ -38,8 +39,8 @@ namespace osu.Game.Tests.Visual.Online Child = section = new HistoricalSection(), }); - AddStep("Show peppy", () => section.UserProfile.Value = new UserProfile(new APIUser { Id = 2 })); - AddStep("Show WubWoofWolf", () => section.UserProfile.Value = new UserProfile(new APIUser { Id = 39828 })); + AddStep("Show peppy", () => section.UserProfile.Value = new UserProfile(new APIUser { Id = 2 }, new OsuRuleset().RulesetInfo)); + AddStep("Show WubWoofWolf", () => section.UserProfile.Value = new UserProfile(new APIUser { Id = 39828 }, new OsuRuleset().RulesetInfo)); } } } diff --git a/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs b/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs index a486d77f97..5c6ffdcd80 100644 --- a/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs +++ b/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs @@ -13,6 +13,7 @@ using osu.Framework.Testing; using osu.Framework.Graphics.Shapes; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Profile; +using osu.Game.Rulesets.Osu; namespace osu.Game.Tests.Visual.Online { @@ -44,49 +45,49 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestNullValues() { - AddStep("Load user", () => user.Value = new UserProfile(user_with_null_values)); + AddStep("Load user", () => user.Value = new UserProfile(user_with_null_values, new OsuRuleset().RulesetInfo)); AddAssert("Section is hidden", () => section.Alpha == 0); } [Test] public void TestEmptyValues() { - AddStep("Load user", () => user.Value = new UserProfile(user_with_empty_values)); + AddStep("Load user", () => user.Value = new UserProfile(user_with_empty_values, new OsuRuleset().RulesetInfo)); AddAssert("Section is hidden", () => section.Alpha == 0); } [Test] public void TestOneValue() { - AddStep("Load user", () => user.Value = new UserProfile(user_with_one_value)); + AddStep("Load user", () => user.Value = new UserProfile(user_with_one_value, new OsuRuleset().RulesetInfo)); AddAssert("Section is hidden", () => section.Alpha == 0); } [Test] public void TestTwoValues() { - AddStep("Load user", () => user.Value = new UserProfile(user_with_two_values)); + AddStep("Load user", () => user.Value = new UserProfile(user_with_two_values, new OsuRuleset().RulesetInfo)); AddAssert("Section is visible", () => section.Alpha == 1); } [Test] public void TestConstantValues() { - AddStep("Load user", () => user.Value = new UserProfile(user_with_constant_values)); + AddStep("Load user", () => user.Value = new UserProfile(user_with_constant_values, new OsuRuleset().RulesetInfo)); AddAssert("Section is visible", () => section.Alpha == 1); } [Test] public void TestConstantZeroValues() { - AddStep("Load user", () => user.Value = new UserProfile(user_with_zero_values)); + AddStep("Load user", () => user.Value = new UserProfile(user_with_zero_values, new OsuRuleset().RulesetInfo)); AddAssert("Section is visible", () => section.Alpha == 1); } [Test] public void TestFilledValues() { - AddStep("Load user", () => user.Value = new UserProfile(user_with_filled_values)); + AddStep("Load user", () => user.Value = new UserProfile(user_with_filled_values, new OsuRuleset().RulesetInfo)); AddAssert("Section is visible", () => section.Alpha == 1); AddAssert("Array length is the same", () => user_with_filled_values.MonthlyPlayCounts.Length == getChartValuesLength()); } @@ -94,7 +95,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestMissingValues() { - AddStep("Load user", () => user.Value = new UserProfile(user_with_missing_values)); + AddStep("Load user", () => user.Value = new UserProfile(user_with_missing_values, new OsuRuleset().RulesetInfo)); AddAssert("Section is visible", () => section.Alpha == 1); AddAssert("Array length is 7", () => getChartValuesLength() == 7); } diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs index 4caab98f63..6458f54183 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs @@ -9,6 +9,7 @@ using osu.Framework.Testing; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Profile; +using osu.Game.Rulesets.Osu; using osu.Game.Users; namespace osu.Game.Tests.Visual.Online @@ -29,7 +30,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestBasic() { - AddStep("Show example user", () => header.UserProfile.Value = new UserProfile(TestSceneUserProfileOverlay.TEST_USER)); + AddStep("Show example user", () => header.UserProfile.Value = new UserProfile(TestSceneUserProfileOverlay.TEST_USER, new OsuRuleset().RulesetInfo)); } [Test] @@ -41,7 +42,7 @@ namespace osu.Game.Tests.Visual.Online Username = "IAmOnline", LastVisit = DateTimeOffset.Now, IsOnline = true, - })); + }, new OsuRuleset().RulesetInfo)); AddStep("Show offline user", () => header.UserProfile.Value = new UserProfile(new APIUser { @@ -49,7 +50,7 @@ namespace osu.Game.Tests.Visual.Online Username = "IAmOffline", LastVisit = DateTimeOffset.Now.AddDays(-10), IsOnline = false, - })); + }, new OsuRuleset().RulesetInfo)); } [Test] @@ -70,7 +71,7 @@ namespace osu.Game.Tests.Visual.Online Data = Enumerable.Range(2345, 45).Concat(Enumerable.Range(2109, 40)).ToArray() }, } - })); + }, new OsuRuleset().RulesetInfo)); AddStep("Show unranked user", () => header.UserProfile.Value = new UserProfile(new APIUser { @@ -86,7 +87,7 @@ namespace osu.Game.Tests.Visual.Online Data = Enumerable.Range(2345, 85).ToArray() }, } - })); + }, new OsuRuleset().RulesetInfo)); } } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs b/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs index 184b969279..ab53551ea1 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs @@ -12,6 +12,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Profile; using osu.Game.Overlays.Profile.Sections; +using osu.Game.Rulesets.Osu; namespace osu.Game.Tests.Visual.Online { @@ -45,7 +46,7 @@ namespace osu.Game.Tests.Visual.Online } }); - AddStep("Show cookiezi", () => ranks.UserProfile.Value = new UserProfile(new APIUser { Id = 124493 })); + AddStep("Show cookiezi", () => ranks.UserProfile.Value = new UserProfile(new APIUser { Id = 124493 }, new OsuRuleset().RulesetInfo)); } } } diff --git a/osu.Game/Overlays/Profile/UserProfile.cs b/osu.Game/Overlays/Profile/UserProfile.cs index 12a469ddf9..60fc5a0492 100644 --- a/osu.Game/Overlays/Profile/UserProfile.cs +++ b/osu.Game/Overlays/Profile/UserProfile.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Online.API.Requests.Responses; +using osu.Game.Rulesets; namespace osu.Game.Overlays.Profile { @@ -15,11 +16,15 @@ namespace osu.Game.Overlays.Profile /// public APIUser User { get; } - // TODO: add ruleset + /// + /// The ruleset that the user profile is being shown with. + /// + public RulesetInfo Ruleset { get; } - public UserProfile(APIUser user) + public UserProfile(APIUser user, RulesetInfo ruleset) { User = user; + Ruleset = ruleset; } } } diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 5ec92efdbb..2625d85636 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -15,6 +16,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Profile; using osu.Game.Overlays.Profile.Sections; +using osu.Game.Rulesets; using osu.Game.Users; using osuTK; using osuTK.Graphics; @@ -29,6 +31,9 @@ namespace osu.Game.Overlays private ProfileSectionsContainer? sectionsContainer; private ProfileSectionTabControl? tabs; + [Resolved] + private RulesetStore rulesets { get; set; } = null!; + public const float CONTENT_X_MARGIN = 70; public UserProfileOverlay() @@ -40,7 +45,7 @@ namespace osu.Game.Overlays protected override Color4 BackgroundColour => ColourProvider.Background6; - public void ShowUser(IUser user) + public void ShowUser(IUser user, IRulesetInfo? ruleset = null) { if (user.OnlineID == APIUser.SYSTEM_USER_ID) return; @@ -117,15 +122,17 @@ namespace osu.Game.Overlays sectionsContainer.ScrollToTop(); userReq = user.OnlineID > 1 ? new GetUserRequest(user.OnlineID) : new GetUserRequest(user.Username); - userReq.Success += userLoadComplete; + userReq.Success += u => userLoadComplete(u, ruleset); API.Queue(userReq); } - private void userLoadComplete(APIUser user) + private void userLoadComplete(APIUser user, IRulesetInfo? ruleset) { Debug.Assert(sections != null && sectionsContainer != null && tabs != null); - var userProfile = new UserProfile(user); + var actualRuleset = rulesets.GetRuleset(ruleset?.ShortName ?? user.PlayMode).AsNonNull(); + + var userProfile = new UserProfile(user, actualRuleset); Header.UserProfile.Value = userProfile; if (user.ProfileOrder != null) From 7683ab68b034796e1dad3f3a5d63eef71bca450c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 18:03:44 +0100 Subject: [PATCH 2/5] Use `UserProfile` in profile ruleset selector --- .../Online/TestSceneProfileRulesetSelector.cs | 26 +++++++++---------- .../Components/ProfileRulesetSelector.cs | 12 ++++++--- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs index a4d8238fa3..a176557d92 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs @@ -11,6 +11,7 @@ using osu.Framework.Bindables; using osu.Game.Overlays; using osu.Framework.Allocation; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays.Profile; namespace osu.Game.Tests.Visual.Online { @@ -21,26 +22,25 @@ namespace osu.Game.Tests.Visual.Online public TestSceneProfileRulesetSelector() { - ProfileRulesetSelector selector; - var user = new Bindable(); + var userProfile = new Bindable(); - Child = selector = new ProfileRulesetSelector + Child = new ProfileRulesetSelector { Anchor = Anchor.Centre, Origin = Anchor.Centre, - User = { BindTarget = user } + UserProfile = { BindTarget = userProfile } }; + AddStep("User on osu ruleset", () => userProfile.Value = new UserProfile(new APIUser { Id = 0, PlayMode = "osu" }, new OsuRuleset().RulesetInfo)); + AddStep("User on taiko ruleset", () => userProfile.Value = new UserProfile(new APIUser { Id = 1, PlayMode = "osu" }, new TaikoRuleset().RulesetInfo)); + AddStep("User on catch ruleset", () => userProfile.Value = new UserProfile(new APIUser { Id = 2, PlayMode = "osu" }, new CatchRuleset().RulesetInfo)); + AddStep("User on mania ruleset", () => userProfile.Value = new UserProfile(new APIUser { Id = 3, PlayMode = "osu" }, new ManiaRuleset().RulesetInfo)); - AddStep("set osu! as default", () => selector.SetDefaultRuleset(new OsuRuleset().RulesetInfo)); - AddStep("set taiko as default", () => selector.SetDefaultRuleset(new TaikoRuleset().RulesetInfo)); - AddStep("set catch as default", () => selector.SetDefaultRuleset(new CatchRuleset().RulesetInfo)); - AddStep("set mania as default", () => selector.SetDefaultRuleset(new ManiaRuleset().RulesetInfo)); + AddStep("User with osu as default", () => userProfile.Value = new UserProfile(new APIUser { Id = 0, PlayMode = "osu" }, new OsuRuleset().RulesetInfo)); + AddStep("User with taiko as default", () => userProfile.Value = new UserProfile(new APIUser { Id = 1, PlayMode = "taiko" }, new OsuRuleset().RulesetInfo)); + AddStep("User with catch as default", () => userProfile.Value = new UserProfile(new APIUser { Id = 2, PlayMode = "fruits" }, new OsuRuleset().RulesetInfo)); + AddStep("User with mania as default", () => userProfile.Value = new UserProfile(new APIUser { Id = 3, PlayMode = "mania" }, new OsuRuleset().RulesetInfo)); - AddStep("User with osu as default", () => user.Value = new APIUser { Id = 0, PlayMode = "osu" }); - AddStep("User with taiko as default", () => user.Value = new APIUser { Id = 1, PlayMode = "taiko" }); - AddStep("User with catch as default", () => user.Value = new APIUser { Id = 2, PlayMode = "fruits" }); - AddStep("User with mania as default", () => user.Value = new APIUser { Id = 3, PlayMode = "mania" }); - AddStep("null user", () => user.Value = null); + AddStep("null user", () => userProfile.Value = null); } } } diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs index 684ce9088e..fff6ead528 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs @@ -4,19 +4,25 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.UserInterface; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; namespace osu.Game.Overlays.Profile.Header.Components { public partial class ProfileRulesetSelector : OverlayRulesetSelector { - public readonly Bindable User = new Bindable(); + public readonly Bindable UserProfile = new Bindable(); protected override void LoadComplete() { base.LoadComplete(); - User.BindValueChanged(u => SetDefaultRuleset(Rulesets.GetRuleset(u.NewValue?.PlayMode ?? "osu").AsNonNull()), true); + + UserProfile.BindValueChanged(userProfile => updateState(userProfile.NewValue), true); + } + + private void updateState(UserProfile? userProfile) + { + Current.Value = userProfile?.Ruleset; + SetDefaultRuleset(Rulesets.GetRuleset(userProfile?.User.PlayMode ?? @"osu").AsNonNull()); } public void SetDefaultRuleset(RulesetInfo ruleset) From a2e726502f8c549361f4fcbfba5cebe9a2e5db4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 18:44:03 +0100 Subject: [PATCH 3/5] Add ruleset selector to profile overlay --- .../Visual/Online/TestSceneUserProfileOverlay.cs | 1 + .../Profile/Header/Components/ProfileRulesetSelector.cs | 4 +++- osu.Game/Overlays/Profile/ProfileHeader.cs | 8 ++++++++ osu.Game/Overlays/TabControlOverlayHeader.cs | 8 ++++---- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index 446e13a8a3..393fcd6d70 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -98,6 +98,7 @@ namespace osu.Game.Tests.Visual.Online Title = "osu!volunteer", Colour = "ff0000", Achievements = Array.Empty(), + PlayMode = "osu" }; } } diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs index fff6ead528..cdd0ed0b0a 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs @@ -1,9 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.UserInterface; +using osu.Game.Extensions; using osu.Game.Rulesets; namespace osu.Game.Overlays.Profile.Header.Components @@ -21,7 +23,7 @@ namespace osu.Game.Overlays.Profile.Header.Components private void updateState(UserProfile? userProfile) { - Current.Value = userProfile?.Ruleset; + Current.Value = Items.SingleOrDefault(ruleset => userProfile?.Ruleset.MatchesOnlineID(ruleset) == true); SetDefaultRuleset(Rulesets.GetRuleset(userProfile?.User.PlayMode ?? @"osu").AsNonNull()); } diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 447e9148e8..059469230c 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; using osu.Game.Overlays.Profile.Header; +using osu.Game.Overlays.Profile.Header.Components; using osu.Game.Resources.Localisation.Web; using osu.Game.Users; @@ -35,6 +36,13 @@ namespace osu.Game.Overlays.Profile // todo: pending implementation. // TabControl.AddItem(LayoutStrings.HeaderUsersModding); + TabControlContainer.Add(new ProfileRulesetSelector + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + UserProfile = { BindTarget = UserProfile } + }); + // Haphazardly guaranteed by OverlayHeader constructor (see CreateBackground / CreateContent). Debug.Assert(centreHeaderContainer != null); Debug.Assert(detailHeaderContainer != null); diff --git a/osu.Game/Overlays/TabControlOverlayHeader.cs b/osu.Game/Overlays/TabControlOverlayHeader.cs index cad94eba71..8613bac40c 100644 --- a/osu.Game/Overlays/TabControlOverlayHeader.cs +++ b/osu.Game/Overlays/TabControlOverlayHeader.cs @@ -23,10 +23,10 @@ namespace osu.Game.Overlays /// The type of item to be represented by tabs. public abstract partial class TabControlOverlayHeader : OverlayHeader, IHasCurrentValue { - protected OsuTabControl TabControl; + protected OsuTabControl TabControl { get; } + protected Container TabControlContainer { get; } private readonly Box controlBackground; - private readonly Container tabControlContainer; private readonly BindableWithCurrent current = new BindableWithCurrent(); public Bindable Current @@ -41,7 +41,7 @@ namespace osu.Game.Overlays set { base.ContentSidePadding = value; - tabControlContainer.Padding = new MarginPadding { Horizontal = value }; + TabControlContainer.Padding = new MarginPadding { Horizontal = value }; } } @@ -57,7 +57,7 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.Both, }, - tabControlContainer = new Container + TabControlContainer = new Container { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, From c759b743dc2c27bea5686ace7a9ebb34e045073f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 19:12:50 +0100 Subject: [PATCH 4/5] Add support for switching rulesets on profile overlay --- .../Profile/Header/Components/ProfileRulesetSelector.cs | 9 +++++++++ .../Sections/Beatmaps/PaginatedBeatmapContainer.cs | 4 ++-- .../Historical/PaginatedMostPlayedBeatmapContainer.cs | 4 ++-- .../Sections/Kudosu/PaginatedKudosuHistoryContainer.cs | 5 ++--- .../Profile/Sections/PaginatedProfileSubsection.cs | 6 +++--- .../Profile/Sections/Ranks/PaginatedScoreContainer.cs | 4 ++-- .../Sections/Recent/PaginatedRecentActivityContainer.cs | 5 ++--- osu.Game/Overlays/UserProfileOverlay.cs | 5 +++-- 8 files changed, 25 insertions(+), 17 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs index cdd0ed0b0a..2214112577 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.UserInterface; @@ -12,6 +13,9 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class ProfileRulesetSelector : OverlayRulesetSelector { + [Resolved] + private UserProfileOverlay? profileOverlay { get; set; } + public readonly Bindable UserProfile = new Bindable(); protected override void LoadComplete() @@ -19,6 +23,11 @@ namespace osu.Game.Overlays.Profile.Header.Components base.LoadComplete(); UserProfile.BindValueChanged(userProfile => updateState(userProfile.NewValue), true); + Current.BindValueChanged(ruleset => + { + if (UserProfile.Value != null && !ruleset.NewValue.Equals(UserProfile.Value.Ruleset)) + profileOverlay?.ShowUser(UserProfile.Value.User, ruleset.NewValue); + }); } private void updateState(UserProfile? userProfile) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 3b1f26ee7d..be7a3039f1 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -64,8 +64,8 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps } } - protected override APIRequest> CreateRequest(APIUser user, PaginationParameters pagination) => - new GetUserBeatmapsRequest(user.Id, type, pagination); + protected override APIRequest> CreateRequest(UserProfile userProfile, PaginationParameters pagination) => + new GetUserBeatmapsRequest(userProfile.User.Id, type, pagination); protected override Drawable? CreateDrawableItem(APIBeatmapSet model) => model.OnlineID > 0 ? new BeatmapCardNormal(model) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs index 5851262229..3d1458ddf5 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs @@ -29,8 +29,8 @@ namespace osu.Game.Overlays.Profile.Sections.Historical protected override int GetCount(APIUser user) => user.BeatmapPlayCountsCount; - protected override APIRequest> CreateRequest(APIUser user, PaginationParameters pagination) => - new GetUserMostPlayedBeatmapsRequest(user.Id, pagination); + protected override APIRequest> CreateRequest(UserProfile userProfile, PaginationParameters pagination) => + new GetUserMostPlayedBeatmapsRequest(userProfile.User.Id, pagination); protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap mostPlayed) => new DrawableMostPlayedBeatmap(mostPlayed); diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs index 6addd86894..f65b334a9d 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs @@ -8,7 +8,6 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API; using System.Collections.Generic; using osu.Game.Resources.Localisation.Web; -using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Profile.Sections.Kudosu { @@ -19,8 +18,8 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu { } - protected override APIRequest> CreateRequest(APIUser user, PaginationParameters pagination) - => new GetUserKudosuHistoryRequest(user.Id, pagination); + protected override APIRequest> CreateRequest(UserProfile userProfile, PaginationParameters pagination) + => new GetUserKudosuHistoryRequest(userProfile.User.Id, pagination); protected override Drawable CreateDrawableItem(APIKudosuHistory item) => new DrawableKudosuHistoryItem(item); } diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs index d77844fd56..654cc9ff7b 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs @@ -109,14 +109,14 @@ namespace osu.Game.Overlays.Profile.Sections private void showMore() { - if (UserProfile.Value?.User == null) + if (UserProfile.Value == null) return; loadCancellation = new CancellationTokenSource(); CurrentPage = CurrentPage?.TakeNext(ItemsPerPage) ?? new PaginationParameters(InitialItemsCount); - retrievalRequest = CreateRequest(UserProfile.Value.User, CurrentPage.Value); + retrievalRequest = CreateRequest(UserProfile.Value, CurrentPage.Value); retrievalRequest.Success += items => UpdateItems(items, loadCancellation); api.Queue(retrievalRequest); @@ -154,7 +154,7 @@ namespace osu.Game.Overlays.Profile.Sections { } - protected abstract APIRequest> CreateRequest(APIUser user, PaginationParameters pagination); + protected abstract APIRequest> CreateRequest(UserProfile userProfile, PaginationParameters pagination); protected abstract Drawable? CreateDrawableItem(TModel model); diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index cdd1738c8e..aba63cc25d 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -60,8 +60,8 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks base.OnItemsReceived(items); } - protected override APIRequest> CreateRequest(APIUser user, PaginationParameters pagination) => - new GetUserScoresRequest(user.Id, type, pagination); + protected override APIRequest> CreateRequest(UserProfile userProfile, PaginationParameters pagination) => + new GetUserScoresRequest(userProfile.User.Id, type, pagination, userProfile.Ruleset); private int drawableItemIndex; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index c08ea58b5a..74247572ed 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -10,7 +10,6 @@ using System.Collections.Generic; using osuTK; using osu.Framework.Allocation; using osu.Game.Resources.Localisation.Web; -using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Profile.Sections.Recent { @@ -27,8 +26,8 @@ namespace osu.Game.Overlays.Profile.Sections.Recent ItemsContainer.Spacing = new Vector2(0, 8); } - protected override APIRequest> CreateRequest(APIUser user, PaginationParameters pagination) => - new GetUserRecentActivitiesRequest(user.Id, pagination); + protected override APIRequest> CreateRequest(UserProfile userProfile, PaginationParameters pagination) => + new GetUserRecentActivitiesRequest(userProfile.User.Id, pagination); protected override Drawable CreateDrawableItem(APIRecentActivity model) => new DrawableRecentActivity(model); } diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 2625d85636..185119c631 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; +using osu.Game.Extensions; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -52,7 +53,7 @@ namespace osu.Game.Overlays Show(); - if (user.OnlineID == Header?.UserProfile.Value?.User.Id) + if (user.OnlineID == Header.UserProfile.Value?.User.Id && ruleset?.MatchesOnlineID(Header.UserProfile.Value?.Ruleset) == true) return; if (sectionsContainer != null) @@ -121,7 +122,7 @@ namespace osu.Game.Overlays sectionsContainer.ScrollToTop(); - userReq = user.OnlineID > 1 ? new GetUserRequest(user.OnlineID) : new GetUserRequest(user.Username); + userReq = user.OnlineID > 1 ? new GetUserRequest(user.OnlineID, ruleset) : new GetUserRequest(user.Username, ruleset); userReq.Success += u => userLoadComplete(u, ruleset); API.Queue(userReq); } From a124c967dfd96a671640b24734f9e9c10d574f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 30 Dec 2022 20:13:23 +0100 Subject: [PATCH 5/5] Add proper offline & loading state handling to user profile overlay --- .../Online/TestSceneUserProfileOverlay.cs | 25 +++++++++++++++++++ osu.Game/Overlays/UserProfileOverlay.cs | 18 +++++++++++++ 2 files changed, 43 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index 393fcd6d70..d3d9dcb990 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -51,6 +51,31 @@ namespace osu.Game.Tests.Visual.Online }); AddStep("show user", () => profile.ShowUser(new APIUser { Id = 1 })); AddToggleStep("toggle visibility", visible => profile.State.Value = visible ? Visibility.Visible : Visibility.Hidden); + AddStep("log out", () => dummyAPI.Logout()); + AddStep("log back in", () => dummyAPI.Login("username", "password")); + } + + [Test] + public void TestLoading() + { + GetUserRequest pendingRequest = null!; + + AddStep("set up request handling", () => + { + dummyAPI.HandleRequest = req => + { + if (req is GetUserRequest getUserRequest) + { + pendingRequest = getUserRequest; + return true; + } + + return false; + }; + }); + AddStep("show user", () => profile.ShowUser(new APIUser { Id = 1 })); + AddWaitStep("wait some", 3); + AddStep("complete request", () => pendingRequest.TriggerSuccess(TEST_USER)); } public static readonly APIUser TEST_USER = new APIUser diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 185119c631..155833e0c6 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -13,6 +13,8 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Extensions; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Profile; @@ -26,6 +28,11 @@ namespace osu.Game.Overlays { public partial class UserProfileOverlay : FullscreenOverlay { + protected override Container Content => onlineViewContainer; + + private readonly OnlineViewContainer onlineViewContainer; + private readonly LoadingLayer loadingLayer; + private ProfileSection? lastSection; private ProfileSection[]? sections; private GetUserRequest? userReq; @@ -40,6 +47,14 @@ namespace osu.Game.Overlays public UserProfileOverlay() : base(OverlayColourScheme.Pink) { + base.Content.AddRange(new Drawable[] + { + onlineViewContainer = new OnlineViewContainer($"Sign in to view the {Header.Title.Title}") + { + RelativeSizeAxes = Axes.Both + }, + loadingLayer = new LoadingLayer(true) + }); } protected override ProfileHeader CreateHeader() => new ProfileHeader(); @@ -125,6 +140,7 @@ namespace osu.Game.Overlays userReq = user.OnlineID > 1 ? new GetUserRequest(user.OnlineID, ruleset) : new GetUserRequest(user.Username, ruleset); userReq.Success += u => userLoadComplete(u, ruleset); API.Queue(userReq); + loadingLayer.Show(); } private void userLoadComplete(APIUser user, IRulesetInfo? ruleset) @@ -151,6 +167,8 @@ namespace osu.Game.Overlays } } } + + loadingLayer.Hide(); } private partial class ProfileSectionTabControl : OverlayTabControl