From c4cb1440ab0a02701f3501b04aa73ef3e8e3cdc3 Mon Sep 17 00:00:00 2001
From: Andrei Zavatski <megaman9919@gmail.com>
Date: Sat, 21 Nov 2020 02:59:01 +0300
Subject: [PATCH 1/5] Rename PaginatedContainerHeader to
 ProfileSubsectionHeader

---
 ...ntainerHeader.cs => TestSceneProfileSubsectionHeader.cs} | 6 +++---
 osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs    | 4 ++--
 ...ginatedContainerHeader.cs => ProfileSubsectionHeader.cs} | 4 ++--
 3 files changed, 7 insertions(+), 7 deletions(-)
 rename osu.Game.Tests/Visual/UserInterface/{TestScenePaginatedContainerHeader.cs => TestSceneProfileSubsectionHeader.cs} (95%)
 rename osu.Game/Overlays/Profile/Sections/{PaginatedContainerHeader.cs => ProfileSubsectionHeader.cs} (95%)

diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePaginatedContainerHeader.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneProfileSubsectionHeader.cs
similarity index 95%
rename from osu.Game.Tests/Visual/UserInterface/TestScenePaginatedContainerHeader.cs
rename to osu.Game.Tests/Visual/UserInterface/TestSceneProfileSubsectionHeader.cs
index 2e9f919cfd..cd226662d7 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestScenePaginatedContainerHeader.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneProfileSubsectionHeader.cs
@@ -11,12 +11,12 @@ using osu.Framework.Allocation;
 
 namespace osu.Game.Tests.Visual.UserInterface
 {
-    public class TestScenePaginatedContainerHeader : OsuTestScene
+    public class TestSceneProfileSubsectionHeader : OsuTestScene
     {
         [Cached]
         private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink);
 
-        private PaginatedContainerHeader header;
+        private ProfileSubsectionHeader header;
 
         [Test]
         public void TestHiddenCounter()
@@ -69,7 +69,7 @@ namespace osu.Game.Tests.Visual.UserInterface
         private void createHeader(string text, CounterVisibilityState state, int initialValue = 0)
         {
             Clear();
-            Add(header = new PaginatedContainerHeader(text, state)
+            Add(header = new ProfileSubsectionHeader(text, state)
             {
                 Anchor = Anchor.Centre,
                 Origin = Anchor.Centre,
diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs
index c1107ce907..5bcd7d34c2 100644
--- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs
@@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Profile.Sections
         private readonly string missingText;
         private ShowMoreButton moreButton;
         private OsuSpriteText missing;
-        private PaginatedContainerHeader header;
+        private ProfileSubsectionHeader header;
 
         private readonly string headerText;
         private readonly CounterVisibilityState counterVisibilityState;
@@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Profile.Sections
 
             Children = new Drawable[]
             {
-                header = new PaginatedContainerHeader(headerText, counterVisibilityState)
+                header = new ProfileSubsectionHeader(headerText, counterVisibilityState)
                 {
                     Alpha = string.IsNullOrEmpty(headerText) ? 0 : 1
                 },
diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainerHeader.cs b/osu.Game/Overlays/Profile/Sections/ProfileSubsectionHeader.cs
similarity index 95%
rename from osu.Game/Overlays/Profile/Sections/PaginatedContainerHeader.cs
rename to osu.Game/Overlays/Profile/Sections/ProfileSubsectionHeader.cs
index 8c617e5fbd..5858cebe89 100644
--- a/osu.Game/Overlays/Profile/Sections/PaginatedContainerHeader.cs
+++ b/osu.Game/Overlays/Profile/Sections/ProfileSubsectionHeader.cs
@@ -14,7 +14,7 @@ using osu.Game.Graphics;
 
 namespace osu.Game.Overlays.Profile.Sections
 {
-    public class PaginatedContainerHeader : CompositeDrawable, IHasCurrentValue<int>
+    public class ProfileSubsectionHeader : CompositeDrawable, IHasCurrentValue<int>
     {
         private readonly BindableWithCurrent<int> current = new BindableWithCurrent<int>();
 
@@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Profile.Sections
 
         private CounterPill counterPill;
 
-        public PaginatedContainerHeader(string text, CounterVisibilityState counterState)
+        public ProfileSubsectionHeader(string text, CounterVisibilityState counterState)
         {
             this.text = text;
             this.counterState = counterState;

From 718ba9253bce4351e2dc07aaa495c943b70b9803 Mon Sep 17 00:00:00 2001
From: Andrei Zavatski <megaman9919@gmail.com>
Date: Sat, 21 Nov 2020 03:18:24 +0300
Subject: [PATCH 2/5] Implement ProfileSubsection component

---
 .../Beatmaps/PaginatedBeatmapContainer.cs     |  2 +-
 .../PaginatedMostPlayedBeatmapContainer.cs    |  2 +-
 .../Kudosu/PaginatedKudosuHistoryContainer.cs |  2 +-
 ...ainer.cs => PaginatedProfileSubsection.cs} | 66 ++++------------
 .../Profile/Sections/ProfileSubsection.cs     | 78 +++++++++++++++++++
 .../Sections/Ranks/PaginatedScoreContainer.cs |  2 +-
 .../PaginatedRecentActivityContainer.cs       |  2 +-
 7 files changed, 100 insertions(+), 54 deletions(-)
 rename osu.Game/Overlays/Profile/Sections/{PaginatedContainer.cs => PaginatedProfileSubsection.cs} (61%)
 create mode 100644 osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs

diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
index 4b7de8de90..780d7ea986 100644
--- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
@@ -14,7 +14,7 @@ using osuTK;
 
 namespace osu.Game.Overlays.Profile.Sections.Beatmaps
 {
-    public class PaginatedBeatmapContainer : PaginatedContainer<APIBeatmapSet>
+    public class PaginatedBeatmapContainer : PaginatedProfileSubsection<APIBeatmapSet>
     {
         private const float panel_padding = 10f;
         private readonly BeatmapSetType type;
diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
index 556f3139dd..e5bb1f8008 100644
--- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
@@ -13,7 +13,7 @@ using osu.Game.Users;
 
 namespace osu.Game.Overlays.Profile.Sections.Historical
 {
-    public class PaginatedMostPlayedBeatmapContainer : PaginatedContainer<APIUserMostPlayedBeatmap>
+    public class PaginatedMostPlayedBeatmapContainer : PaginatedProfileSubsection<APIUserMostPlayedBeatmap>
     {
         public PaginatedMostPlayedBeatmapContainer(Bindable<User> user)
             : base(user, "Most Played Beatmaps", "No records. :(", CounterVisibilityState.AlwaysVisible)
diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs
index 1b8bd23eb4..008d89d881 100644
--- a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs
@@ -11,7 +11,7 @@ using System.Collections.Generic;
 
 namespace osu.Game.Overlays.Profile.Sections.Kudosu
 {
-    public class PaginatedKudosuHistoryContainer : PaginatedContainer<APIKudosuHistory>
+    public class PaginatedKudosuHistoryContainer : PaginatedProfileSubsection<APIKudosuHistory>
     {
         public PaginatedKudosuHistoryContainer(Bindable<User> user)
             : base(user, missingText: "This user hasn't received any kudosu!")
diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs
similarity index 61%
rename from osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs
rename to osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs
index 5bcd7d34c2..1f897d704a 100644
--- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs
@@ -6,10 +6,7 @@ using osu.Framework.Allocation;
 using osu.Framework.Bindables;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
-using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
 using osu.Game.Online.API;
-using osu.Game.Rulesets;
 using osu.Game.Users;
 using System.Collections.Generic;
 using System.Linq;
@@ -18,7 +15,7 @@ using osu.Game.Graphics.UserInterface;
 
 namespace osu.Game.Overlays.Profile.Sections
 {
-    public abstract class PaginatedContainer<TModel> : FillFlowContainer
+    public abstract class PaginatedProfileSubsection<TModel> : ProfileSubsection
     {
         [Resolved]
         private IAPIProvider api { get; set; }
@@ -26,42 +23,25 @@ namespace osu.Game.Overlays.Profile.Sections
         protected int VisiblePages;
         protected int ItemsPerPage;
 
-        protected readonly Bindable<User> User = new Bindable<User>();
-        protected FillFlowContainer ItemsContainer;
-        protected RulesetStore Rulesets;
+        protected FillFlowContainer ItemsContainer { get; private set; }
 
         private APIRequest<List<TModel>> retrievalRequest;
         private CancellationTokenSource loadCancellation;
 
-        private readonly string missingText;
         private ShowMoreButton moreButton;
-        private OsuSpriteText missing;
-        private ProfileSubsectionHeader header;
 
-        private readonly string headerText;
-        private readonly CounterVisibilityState counterVisibilityState;
-
-        protected PaginatedContainer(Bindable<User> user, string headerText = "", string missingText = "", CounterVisibilityState counterVisibilityState = CounterVisibilityState.AlwaysHidden)
+        protected PaginatedProfileSubsection(Bindable<User> user, string headerText = "", string missingText = "", CounterVisibilityState counterVisibilityState = CounterVisibilityState.AlwaysHidden)
+            : base(user, headerText, missingText, counterVisibilityState)
         {
-            this.headerText = headerText;
-            this.missingText = missingText;
-            this.counterVisibilityState = counterVisibilityState;
-            User.BindTo(user);
         }
 
-        [BackgroundDependencyLoader]
-        private void load(RulesetStore rulesets)
+        protected override Drawable CreateContent() => new FillFlowContainer
         {
-            RelativeSizeAxes = Axes.X;
-            AutoSizeAxes = Axes.Y;
-            Direction = FillDirection.Vertical;
-
+            RelativeSizeAxes = Axes.X,
+            AutoSizeAxes = Axes.Y,
+            Direction = FillDirection.Vertical,
             Children = new Drawable[]
             {
-                header = new ProfileSubsectionHeader(headerText, counterVisibilityState)
-                {
-                    Alpha = string.IsNullOrEmpty(headerText) ? 0 : 1
-                },
                 ItemsContainer = new FillFlowContainer
                 {
                     AutoSizeAxes = Axes.Y,
@@ -75,22 +55,11 @@ namespace osu.Game.Overlays.Profile.Sections
                     Alpha = 0,
                     Margin = new MarginPadding { Top = 10 },
                     Action = showMore,
-                },
-                missing = new OsuSpriteText
-                {
-                    Font = OsuFont.GetFont(size: 15),
-                    Text = missingText,
-                    Alpha = 0,
-                },
-            };
+                }
+            }
+        };
 
-            Rulesets = rulesets;
-
-            User.ValueChanged += onUserChanged;
-            User.TriggerChange();
-        }
-
-        private void onUserChanged(ValueChangedEvent<User> e)
+        protected override void OnUserChanged(ValueChangedEvent<User> e)
         {
             loadCancellation?.Cancel();
             retrievalRequest?.Cancel();
@@ -124,15 +93,15 @@ namespace osu.Game.Overlays.Profile.Sections
                 moreButton.Hide();
                 moreButton.IsLoading = false;
 
-                if (!string.IsNullOrEmpty(missing.Text))
-                    missing.Show();
+                if (!string.IsNullOrEmpty(Missing.Text))
+                    Missing.Show();
 
                 return;
             }
 
             LoadComponentsAsync(items.Select(CreateDrawableItem).Where(d => d != null), drawables =>
             {
-                missing.Hide();
+                Missing.Hide();
                 moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0);
                 moreButton.IsLoading = false;
 
@@ -142,8 +111,6 @@ namespace osu.Game.Overlays.Profile.Sections
 
         protected virtual int GetCount(User user) => 0;
 
-        protected void SetCount(int value) => header.Current.Value = value;
-
         protected virtual void OnItemsReceived(List<TModel> items)
         {
         }
@@ -154,8 +121,9 @@ namespace osu.Game.Overlays.Profile.Sections
 
         protected override void Dispose(bool isDisposing)
         {
-            base.Dispose(isDisposing);
             retrievalRequest?.Cancel();
+            loadCancellation?.Cancel();
+            base.Dispose(isDisposing);
         }
     }
 }
diff --git a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs
new file mode 100644
index 0000000000..751b35e342
--- /dev/null
+++ b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs
@@ -0,0 +1,78 @@
+// 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.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Rulesets;
+using osu.Game.Users;
+using JetBrains.Annotations;
+
+namespace osu.Game.Overlays.Profile.Sections
+{
+    public abstract class ProfileSubsection : FillFlowContainer
+    {
+        protected readonly Bindable<User> User = new Bindable<User>();
+
+        protected RulesetStore Rulesets { get; private set; }
+
+        protected OsuSpriteText Missing { get; private set; }
+
+        private readonly string headerText;
+        private readonly string missingText;
+        private readonly CounterVisibilityState counterVisibilityState;
+
+        private ProfileSubsectionHeader header;
+
+        protected ProfileSubsection(Bindable<User> user, string headerText = "", string missingText = "", CounterVisibilityState counterVisibilityState = CounterVisibilityState.AlwaysHidden)
+        {
+            this.headerText = headerText;
+            this.missingText = missingText;
+            this.counterVisibilityState = counterVisibilityState;
+            User.BindTo(user);
+        }
+
+        [BackgroundDependencyLoader]
+        private void load(RulesetStore rulesets)
+        {
+            RelativeSizeAxes = Axes.X;
+            AutoSizeAxes = Axes.Y;
+            Direction = FillDirection.Vertical;
+
+            Children = new[]
+            {
+                header = new ProfileSubsectionHeader(headerText, counterVisibilityState)
+                {
+                    Alpha = string.IsNullOrEmpty(headerText) ? 0 : 1
+                },
+                CreateContent(),
+                Missing = new OsuSpriteText
+                {
+                    Font = OsuFont.GetFont(size: 15),
+                    Text = missingText,
+                    Alpha = 0,
+                },
+            };
+
+            Rulesets = rulesets;
+        }
+
+        protected override void LoadComplete()
+        {
+            base.LoadComplete();
+            User.BindValueChanged(OnUserChanged, true);
+        }
+
+        [NotNull]
+        protected abstract Drawable CreateContent();
+
+        protected virtual void OnUserChanged(ValueChangedEvent<User> e)
+        {
+        }
+
+        protected void SetCount(int value) => header.Current.Value = value;
+    }
+}
diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs
index 1ce3079d52..53f6d375ca 100644
--- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs
@@ -14,7 +14,7 @@ using osu.Framework.Allocation;
 
 namespace osu.Game.Overlays.Profile.Sections.Ranks
 {
-    public class PaginatedScoreContainer : PaginatedContainer<APILegacyScoreInfo>
+    public class PaginatedScoreContainer : PaginatedProfileSubsection<APILegacyScoreInfo>
     {
         private readonly ScoreType type;
 
diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs
index 08f39c6272..d7101a8147 100644
--- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs
@@ -13,7 +13,7 @@ using osu.Framework.Allocation;
 
 namespace osu.Game.Overlays.Profile.Sections.Recent
 {
-    public class PaginatedRecentActivityContainer : PaginatedContainer<APIRecentActivity>
+    public class PaginatedRecentActivityContainer : PaginatedProfileSubsection<APIRecentActivity>
     {
         public PaginatedRecentActivityContainer(Bindable<User> user)
             : base(user, missingText: "This user hasn't done anything notable recently!")

From 11c3ccfcaa4a4a2adb130e3bbbcda97a0ead8c78 Mon Sep 17 00:00:00 2001
From: Andrei Zavatski <megaman9919@gmail.com>
Date: Sat, 21 Nov 2020 22:49:56 +0300
Subject: [PATCH 3/5] Move rulesets property to PaginatedProfileSubsection

---
 .../Profile/Sections/PaginatedProfileSubsection.cs         | 4 ++++
 osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs    | 7 +------
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs
index 1f897d704a..3e6b20bf14 100644
--- a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs
+++ b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs
@@ -12,6 +12,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Threading;
 using osu.Game.Graphics.UserInterface;
+using osu.Game.Rulesets;
 
 namespace osu.Game.Overlays.Profile.Sections
 {
@@ -20,6 +21,9 @@ namespace osu.Game.Overlays.Profile.Sections
         [Resolved]
         private IAPIProvider api { get; set; }
 
+        [Resolved]
+        protected RulesetStore Rulesets { get; private set; }
+
         protected int VisiblePages;
         protected int ItemsPerPage;
 
diff --git a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs
index 751b35e342..6f68804827 100644
--- a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs
+++ b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs
@@ -7,7 +7,6 @@ using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
 using osu.Game.Graphics;
 using osu.Game.Graphics.Sprites;
-using osu.Game.Rulesets;
 using osu.Game.Users;
 using JetBrains.Annotations;
 
@@ -17,8 +16,6 @@ namespace osu.Game.Overlays.Profile.Sections
     {
         protected readonly Bindable<User> User = new Bindable<User>();
 
-        protected RulesetStore Rulesets { get; private set; }
-
         protected OsuSpriteText Missing { get; private set; }
 
         private readonly string headerText;
@@ -36,7 +33,7 @@ namespace osu.Game.Overlays.Profile.Sections
         }
 
         [BackgroundDependencyLoader]
-        private void load(RulesetStore rulesets)
+        private void load()
         {
             RelativeSizeAxes = Axes.X;
             AutoSizeAxes = Axes.Y;
@@ -56,8 +53,6 @@ namespace osu.Game.Overlays.Profile.Sections
                     Alpha = 0,
                 },
             };
-
-            Rulesets = rulesets;
         }
 
         protected override void LoadComplete()

From dbfc839df379c65b09279704036347384ce6ef90 Mon Sep 17 00:00:00 2001
From: Andrei Zavatski <megaman9919@gmail.com>
Date: Sat, 21 Nov 2020 23:03:54 +0300
Subject: [PATCH 4/5] Move missing text to PaginatedProfileSubsection

---
 .../Sections/PaginatedProfileSubsection.cs    | 19 +++++++++++++++----
 .../Profile/Sections/ProfileSubsection.cs     | 16 ++--------------
 2 files changed, 17 insertions(+), 18 deletions(-)

diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs
index 3e6b20bf14..b5ae949105 100644
--- a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs
+++ b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs
@@ -13,6 +13,8 @@ using System.Linq;
 using System.Threading;
 using osu.Game.Graphics.UserInterface;
 using osu.Game.Rulesets;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics;
 
 namespace osu.Game.Overlays.Profile.Sections
 {
@@ -33,10 +35,13 @@ namespace osu.Game.Overlays.Profile.Sections
         private CancellationTokenSource loadCancellation;
 
         private ShowMoreButton moreButton;
+        private OsuSpriteText missing;
+        private readonly string missingText;
 
         protected PaginatedProfileSubsection(Bindable<User> user, string headerText = "", string missingText = "", CounterVisibilityState counterVisibilityState = CounterVisibilityState.AlwaysHidden)
-            : base(user, headerText, missingText, counterVisibilityState)
+            : base(user, headerText, counterVisibilityState)
         {
+            this.missingText = missingText;
         }
 
         protected override Drawable CreateContent() => new FillFlowContainer
@@ -59,6 +64,12 @@ namespace osu.Game.Overlays.Profile.Sections
                     Alpha = 0,
                     Margin = new MarginPadding { Top = 10 },
                     Action = showMore,
+                },
+                missing = new OsuSpriteText
+                {
+                    Font = OsuFont.GetFont(size: 15),
+                    Text = missingText,
+                    Alpha = 0,
                 }
             }
         };
@@ -97,15 +108,15 @@ namespace osu.Game.Overlays.Profile.Sections
                 moreButton.Hide();
                 moreButton.IsLoading = false;
 
-                if (!string.IsNullOrEmpty(Missing.Text))
-                    Missing.Show();
+                if (!string.IsNullOrEmpty(missingText))
+                    missing.Show();
 
                 return;
             }
 
             LoadComponentsAsync(items.Select(CreateDrawableItem).Where(d => d != null), drawables =>
             {
-                Missing.Hide();
+                missing.Hide();
                 moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0);
                 moreButton.IsLoading = false;
 
diff --git a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs
index 6f68804827..0743823113 100644
--- a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs
+++ b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs
@@ -5,8 +5,6 @@ using osu.Framework.Allocation;
 using osu.Framework.Bindables;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
-using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
 using osu.Game.Users;
 using JetBrains.Annotations;
 
@@ -16,18 +14,14 @@ namespace osu.Game.Overlays.Profile.Sections
     {
         protected readonly Bindable<User> User = new Bindable<User>();
 
-        protected OsuSpriteText Missing { get; private set; }
-
         private readonly string headerText;
-        private readonly string missingText;
         private readonly CounterVisibilityState counterVisibilityState;
 
         private ProfileSubsectionHeader header;
 
-        protected ProfileSubsection(Bindable<User> user, string headerText = "", string missingText = "", CounterVisibilityState counterVisibilityState = CounterVisibilityState.AlwaysHidden)
+        protected ProfileSubsection(Bindable<User> user, string headerText = "", CounterVisibilityState counterVisibilityState = CounterVisibilityState.AlwaysHidden)
         {
             this.headerText = headerText;
-            this.missingText = missingText;
             this.counterVisibilityState = counterVisibilityState;
             User.BindTo(user);
         }
@@ -45,13 +39,7 @@ namespace osu.Game.Overlays.Profile.Sections
                 {
                     Alpha = string.IsNullOrEmpty(headerText) ? 0 : 1
                 },
-                CreateContent(),
-                Missing = new OsuSpriteText
-                {
-                    Font = OsuFont.GetFont(size: 15),
-                    Text = missingText,
-                    Alpha = 0,
-                },
+                CreateContent()
             };
         }
 

From fe4c6220418b1f8560f6e6bcdc9c8994e9912efd Mon Sep 17 00:00:00 2001
From: Andrei Zavatski <megaman9919@gmail.com>
Date: Sat, 21 Nov 2020 23:13:46 +0300
Subject: [PATCH 5/5] Make OnUserChanged private

---
 .../Profile/Sections/PaginatedProfileSubsection.cs     |  8 +++++++-
 .../Overlays/Profile/Sections/ProfileSubsection.cs     | 10 ----------
 2 files changed, 7 insertions(+), 11 deletions(-)

diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs
index b5ae949105..51e5622f68 100644
--- a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs
+++ b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs
@@ -74,7 +74,13 @@ namespace osu.Game.Overlays.Profile.Sections
             }
         };
 
-        protected override void OnUserChanged(ValueChangedEvent<User> e)
+        protected override void LoadComplete()
+        {
+            base.LoadComplete();
+            User.BindValueChanged(onUserChanged, true);
+        }
+
+        private void onUserChanged(ValueChangedEvent<User> e)
         {
             loadCancellation?.Cancel();
             retrievalRequest?.Cancel();
diff --git a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs
index 0743823113..3e331f85e9 100644
--- a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs
+++ b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs
@@ -43,19 +43,9 @@ namespace osu.Game.Overlays.Profile.Sections
             };
         }
 
-        protected override void LoadComplete()
-        {
-            base.LoadComplete();
-            User.BindValueChanged(OnUserChanged, true);
-        }
-
         [NotNull]
         protected abstract Drawable CreateContent();
 
-        protected virtual void OnUserChanged(ValueChangedEvent<User> e)
-        {
-        }
-
         protected void SetCount(int value) => header.Current.Value = value;
     }
 }