From 9d8e7e895442c29df40a3ebf2fb0df5cf020bbb1 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 14 Nov 2020 04:46:26 +0300 Subject: [PATCH 01/34] ProfileLineChart layout implementation --- .../Online/TestSceneProfileLineChart.cs | 39 +++++++++++ .../Sections/Historical/ProfileLineChart.cs | 64 +++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs create mode 100644 osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs b/osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs new file mode 100644 index 0000000000..34359baab5 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Overlays.Profile.Sections.Historical; +using osu.Framework.Graphics; +using static osu.Game.Users.User; +using System; +using osu.Game.Overlays; +using osu.Framework.Allocation; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneProfileLineChart : OsuTestScene + { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); + + public TestSceneProfileLineChart() + { + var values = new[] + { + new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 1000 }, + new UserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 20 }, + new UserHistoryCount { Date = new DateTime(2010, 7, 1), Count = 20000 }, + new UserHistoryCount { Date = new DateTime(2010, 8, 1), Count = 30 }, + new UserHistoryCount { Date = new DateTime(2010, 9, 1), Count = 50 }, + new UserHistoryCount { Date = new DateTime(2010, 10, 1), Count = 2000 }, + new UserHistoryCount { Date = new DateTime(2010, 11, 1), Count = 2100 } + }; + + Add(new ProfileLineChart + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Values = values + }); + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs new file mode 100644 index 0000000000..10a03aa012 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -0,0 +1,64 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; +using JetBrains.Annotations; +using static osu.Game.Users.User; + +namespace osu.Game.Overlays.Profile.Sections.Historical +{ + public class ProfileLineChart : CompositeDrawable + { + private UserHistoryCount[] values; + + [CanBeNull] + public UserHistoryCount[] Values + { + get => values; + set + { + values = value; + graph.Values = values; + } + } + + private readonly UserHistoryGraph graph; + + public ProfileLineChart() + { + RelativeSizeAxes = Axes.X; + Height = 250; + InternalChild = new GridContainer + { + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension() + }, + RowDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] + { + Empty(), + graph = new UserHistoryGraph + { + RelativeSizeAxes = Axes.Both + } + }, + new Drawable[] + { + Empty(), + Empty() + } + } + }; + } + } +} From d98c59f2a4b399da80b5c511f062c60c6d5d536e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 14 Nov 2020 06:38:02 +0300 Subject: [PATCH 02/34] Implement horizontal ticks creation --- .../Sections/Historical/ProfileLineChart.cs | 126 +++++++++++++++++- 1 file changed, 123 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index 10a03aa012..a02f869f51 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -5,6 +5,13 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using JetBrains.Annotations; using static osu.Game.Users.User; +using System; +using System.Linq; +using osu.Game.Graphics.Sprites; +using osu.Framework.Utils; +using osu.Framework.Allocation; +using osu.Game.Graphics; +using osu.Framework.Graphics.Shapes; namespace osu.Game.Overlays.Profile.Sections.Historical { @@ -20,10 +27,14 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { values = value; graph.Values = values; + + createRowTicks(); } } private readonly UserHistoryGraph graph; + private readonly Container rowTicksContainer; + private readonly Container rowLinesContainer; public ProfileLineChart() { @@ -46,10 +57,25 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { new Drawable[] { - Empty(), - graph = new UserHistoryGraph + rowTicksContainer = new Container { - RelativeSizeAxes = Axes.Both + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + rowLinesContainer = new Container + { + RelativeSizeAxes = Axes.Both + }, + graph = new UserHistoryGraph + { + RelativeSizeAxes = Axes.Both + } + } } }, new Drawable[] @@ -60,5 +86,99 @@ namespace osu.Game.Overlays.Profile.Sections.Historical } }; } + + private void createRowTicks() + { + rowTicksContainer.Clear(); + rowLinesContainer.Clear(); + + var min = values.Select(v => v.Count).Min(); + var max = values.Select(v => v.Count).Max(); + + var niceRange = niceNumber(max - min, false); + var niceTick = niceNumber(niceRange / (6 - 1), true); + var axisStart = Math.Floor(min / niceTick) * niceTick; + var axisEnd = Math.Ceiling(max / niceTick) * niceTick; + + var rollingRow = axisStart; + + while (rollingRow <= axisEnd) + { + var y = -Interpolation.ValueAt(rollingRow, 0, 1f, min, max); + + rowTicksContainer.Add(new TickText + { + Anchor = Anchor.BottomRight, + Origin = Anchor.CentreRight, + RelativePositionAxes = Axes.Y, + Text = rollingRow.ToString("N0"), + Y = y + }); + + rowLinesContainer.Add(new TickLine + { + Anchor = Anchor.BottomRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.X, + RelativePositionAxes = Axes.Y, + Height = 1, + Y = y + }); + + rollingRow += niceTick; + } + } + + private double niceNumber(double value, bool round) + { + var exponent = (int)Math.Floor(Math.Log10(value)); + var fraction = value / Math.Pow(10, exponent); + + double niceFraction; + + if (round) + { + if (fraction < 1.5) + niceFraction = 1.0; + else if (fraction < 3) + niceFraction = 2.0; + else if (fraction < 7) + niceFraction = 5.0; + else + niceFraction = 10.0; + } + else + { + if (fraction <= 1.0) + niceFraction = 1.0; + else if (fraction <= 2.0) + niceFraction = 2.0; + else if (fraction <= 5.0) + niceFraction = 5.0; + else + niceFraction = 10.0; + } + + return niceFraction * Math.Pow(10, exponent); + } + + private class TickText : OsuSpriteText + { + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Colour = colourProvider.Foreground1; + Font = OsuFont.GetFont(size: 12); + } + } + + private class TickLine : Box + { + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Colour = colourProvider.Background6; + } + } } } From 00e974794076c241779694f6ec988a8ccf204044 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 14 Nov 2020 06:44:29 +0300 Subject: [PATCH 03/34] Test scene visual improvements --- .../Online/TestSceneProfileLineChart.cs | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs b/osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs index 34359baab5..0be835c07d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs @@ -7,6 +7,8 @@ using static osu.Game.Users.User; using System; using osu.Game.Overlays; using osu.Framework.Allocation; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Containers; namespace osu.Game.Tests.Visual.Online { @@ -28,11 +30,25 @@ namespace osu.Game.Tests.Visual.Online new UserHistoryCount { Date = new DateTime(2010, 11, 1), Count = 2100 } }; - Add(new ProfileLineChart + AddRange(new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Values = values + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background4 + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Padding = new MarginPadding { Horizontal = 50 }, + Child = new ProfileLineChart + { + Values = values + } + } }); } } From 01f28a35c3269316e5c380d14c8c41c3a65eff6b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 14 Nov 2020 07:28:01 +0300 Subject: [PATCH 04/34] Implement vertical ticks creation --- .../Sections/Historical/ProfileLineChart.cs | 70 +++++++++++++++++-- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index a02f869f51..2908b50a6e 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -29,12 +29,15 @@ namespace osu.Game.Overlays.Profile.Sections.Historical graph.Values = values; createRowTicks(); + createColumnTicks(); } } private readonly UserHistoryGraph graph; private readonly Container rowTicksContainer; + private readonly Container columnTicksContainer; private readonly Container rowLinesContainer; + private readonly Container columnLinesContainer; public ProfileLineChart() { @@ -67,9 +70,20 @@ namespace osu.Game.Overlays.Profile.Sections.Historical RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - rowLinesContainer = new Container + new Container { - RelativeSizeAxes = Axes.Both + RelativeSizeAxes = Axes.Both, + Children = new[] + { + rowLinesContainer = new Container + { + RelativeSizeAxes = Axes.Both + }, + columnLinesContainer = new Container + { + RelativeSizeAxes = Axes.Both + } + } }, graph = new UserHistoryGraph { @@ -81,7 +95,12 @@ namespace osu.Game.Overlays.Profile.Sections.Historical new Drawable[] { Empty(), - Empty() + columnTicksContainer = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Top = 10 } + } } } }; @@ -104,7 +123,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical while (rollingRow <= axisEnd) { - var y = -Interpolation.ValueAt(rollingRow, 0, 1f, min, max); + var y = -Interpolation.ValueAt(rollingRow, 0, 1f, axisStart, axisEnd); rowTicksContainer.Add(new TickText { @@ -129,9 +148,50 @@ namespace osu.Game.Overlays.Profile.Sections.Historical } } + private void createColumnTicks() + { + columnTicksContainer.Clear(); + columnLinesContainer.Clear(); + + var min = values.Select(v => v.Date).Min().Ticks; + var max = values.Select(v => v.Date).Max().Ticks; + + var niceRange = niceNumber(max - min, false); + var niceTick = niceNumber(niceRange / (Math.Min(values.Length, 15) - 1), true); + var axisStart = Math.Floor(min / niceTick) * niceTick; + var axisEnd = Math.Ceiling(max / niceTick) * niceTick; + + var rollingRow = axisStart; + + while (rollingRow <= axisEnd) + { + var x = Interpolation.ValueAt(rollingRow, 0, 1f, axisStart, axisEnd); + + columnTicksContainer.Add(new TickText + { + Origin = Anchor.CentreLeft, + RelativePositionAxes = Axes.X, + Text = new DateTime((long)rollingRow).ToString("MMM yyyy"), + Rotation = 45, + X = x + }); + + columnLinesContainer.Add(new TickLine + { + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Y, + RelativePositionAxes = Axes.X, + Width = 1, + X = x + }); + + rollingRow += niceTick; + } + } + private double niceNumber(double value, bool round) { - var exponent = (int)Math.Floor(Math.Log10(value)); + var exponent = Math.Floor(Math.Log10(value)); var fraction = value / Math.Pow(10, exponent); double niceFraction; From ae4a2e74faab435156cfebe6f6da131b5b83896b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 14 Nov 2020 18:21:10 +0300 Subject: [PATCH 05/34] Implement ProfileSubsection --- ...cs => TestSceneProfileSubsectionHeader.cs} | 6 +- .../Profile/Sections/PaginatedContainer.cs | 57 +++----------- .../Profile/Sections/ProfileSubsection.cs | 78 +++++++++++++++++++ ...erHeader.cs => ProfileSubsectionHeader.cs} | 4 +- 4 files changed, 95 insertions(+), 50 deletions(-) rename osu.Game.Tests/Visual/UserInterface/{TestScenePaginatedContainerHeader.cs => TestSceneProfileSubsectionHeader.cs} (95%) create mode 100644 osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs 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..7b66c3f51e 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.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 : FillFlowContainer + public abstract class PaginatedContainer : 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 = new Bindable(); protected FillFlowContainer ItemsContainer; - protected RulesetStore Rulesets; private APIRequest> retrievalRequest; private CancellationTokenSource loadCancellation; - private readonly string missingText; private ShowMoreButton moreButton; - private OsuSpriteText missing; - private PaginatedContainerHeader header; - - private readonly string headerText; - private readonly CounterVisibilityState counterVisibilityState; protected PaginatedContainer(Bindable 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 PaginatedContainerHeader(headerText, counterVisibilityState) - { - Alpha = string.IsNullOrEmpty(headerText) ? 0 : 1 - }, ItemsContainer = new FillFlowContainer { AutoSizeAxes = Axes.Y, @@ -76,21 +56,10 @@ namespace osu.Game.Overlays.Profile.Sections 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 e) + protected override void OnUserChanged(ValueChangedEvent 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 items) { } diff --git a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs new file mode 100644 index 0000000000..9583759693 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs @@ -0,0 +1,78 @@ +// Copyright (c) ppy Pty Ltd . 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 = new Bindable(); + + 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, 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 Drawable[] + { + 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 e) + { + } + + protected void SetCount(int value) => header.Current.Value = value; + } +} 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 + public class ProfileSubsectionHeader : CompositeDrawable, IHasCurrentValue { private readonly BindableWithCurrent current = new BindableWithCurrent(); @@ -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 af174aa653206d3ae3dbb42368b2c4ff5285a488 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 14 Nov 2020 18:48:47 +0300 Subject: [PATCH 06/34] Implement chart subsections --- .../Historical/ChartProfileSubsection.cs | 51 +++++++++++++++++++ .../Historical/PlayHistorySubsection.cs | 19 +++++++ .../Sections/Historical/ProfileLineChart.cs | 4 +- .../Sections/Historical/ReplaysSubsection.cs | 19 +++++++ .../Profile/Sections/HistoricalSection.cs | 2 + 5 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs create mode 100644 osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs create mode 100644 osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs new file mode 100644 index 0000000000..24083c9a79 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs @@ -0,0 +1,51 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Users; +using static osu.Game.Users.User; + +namespace osu.Game.Overlays.Profile.Sections.Historical +{ + public abstract class ChartProfileSubsection : ProfileSubsection + { + private ProfileLineChart chart; + + protected ChartProfileSubsection(Bindable user, string headerText) + : base(user, headerText) + { + + } + + protected override Drawable CreateContent() => new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding + { + Top = 10, + Left = 20, + Right = 40 + }, + Child = chart = new ProfileLineChart() + }; + + protected override void OnUserChanged(ValueChangedEvent e) + { + var values = GetValues(e.NewValue); + + if (values?.Length > 1) + { + chart.Values = values; + Show(); + return; + } + + Hide(); + } + + protected abstract UserHistoryCount[] GetValues(User user); + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs new file mode 100644 index 0000000000..3e35f80b49 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Users; +using static osu.Game.Users.User; + +namespace osu.Game.Overlays.Profile.Sections.Historical +{ + public class PlayHistorySubsection : ChartProfileSubsection + { + public PlayHistorySubsection(Bindable user) + : base(user, "Play History") + { + } + + protected override UserHistoryCount[] GetValues(User user) => user.MonthlyPlaycounts; + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index 2908b50a6e..55fa6c5400 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -130,7 +130,9 @@ namespace osu.Game.Overlays.Profile.Sections.Historical Anchor = Anchor.BottomRight, Origin = Anchor.CentreRight, RelativePositionAxes = Axes.Y, + Margin = new MarginPadding { Right = 3 }, Text = rollingRow.ToString("N0"), + Font = OsuFont.GetFont(size: 12), Y = y }); @@ -172,6 +174,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical Origin = Anchor.CentreLeft, RelativePositionAxes = Axes.X, Text = new DateTime((long)rollingRow).ToString("MMM yyyy"), + Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold), Rotation = 45, X = x }); @@ -228,7 +231,6 @@ namespace osu.Game.Overlays.Profile.Sections.Historical private void load(OverlayColourProvider colourProvider) { Colour = colourProvider.Foreground1; - Font = OsuFont.GetFont(size: 12); } } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs new file mode 100644 index 0000000000..f6abd1c4fc --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Users; +using static osu.Game.Users.User; + +namespace osu.Game.Overlays.Profile.Sections.Historical +{ + public class ReplaysSubsection : ChartProfileSubsection + { + public ReplaysSubsection(Bindable user) + : base(user, "Replays Watched History") + { + } + + protected override UserHistoryCount[] GetValues(User user) => user.ReplaysWatchedCounts; + } +} diff --git a/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs b/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs index bfc47bd88c..6e2b9873cf 100644 --- a/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs +++ b/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs @@ -18,8 +18,10 @@ namespace osu.Game.Overlays.Profile.Sections { Children = new Drawable[] { + new PlayHistorySubsection(User), new PaginatedMostPlayedBeatmapContainer(User), new PaginatedScoreContainer(ScoreType.Recent, User, "Recent Plays (24h)", CounterVisibilityState.VisibleWhenZero), + new ReplaysSubsection(User) }; } } From 02168c6c2fb7f31907c5d02797fbc1508075dd87 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 14 Nov 2020 19:17:01 +0300 Subject: [PATCH 07/34] Implement dates with zero count fill --- .../Historical/ChartProfileSubsection.cs | 28 ++++++++++++++++++- .../Sections/Historical/ProfileLineChart.cs | 2 +- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs index 24083c9a79..38224dd177 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -38,7 +39,32 @@ namespace osu.Game.Overlays.Profile.Sections.Historical if (values?.Length > 1) { - chart.Values = values; + // Fill dates with 0 count + + var newValues = new List { values[0] }; + var newLast = values[0]; + + for (int i = 1; i < values.Length; i++) + { + while (hasMissingDates(newLast, values[i])) + { + newValues.Add(newLast = new UserHistoryCount + { + Count = 0, + Date = newLast.Date.AddMonths(1) + }); + } + + newValues.Add(newLast = values[i]); + } + + static bool hasMissingDates(UserHistoryCount prev, UserHistoryCount current) + { + var possibleCurrent = prev.Date.AddMonths(1); + return possibleCurrent != current.Date; + } + + chart.Values = newValues.ToArray(); Show(); return; } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index 55fa6c5400..7cd529a726 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { private UserHistoryCount[] values; - [CanBeNull] + [NotNull] public UserHistoryCount[] Values { get => values; From 5354bf1fa593bcbfb1d6cafac3e4143af035e45e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 14 Nov 2020 20:07:52 +0300 Subject: [PATCH 08/34] Ticks distribution improvements --- .../Sections/Historical/ProfileLineChart.cs | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index 7cd529a726..fe4677037b 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -116,14 +116,12 @@ namespace osu.Game.Overlays.Profile.Sections.Historical var niceRange = niceNumber(max - min, false); var niceTick = niceNumber(niceRange / (6 - 1), true); - var axisStart = Math.Floor(min / niceTick) * niceTick; - var axisEnd = Math.Ceiling(max / niceTick) * niceTick; - var rollingRow = axisStart; + double rollingRow = min; - while (rollingRow <= axisEnd) + while (rollingRow <= max) { - var y = -Interpolation.ValueAt(rollingRow, 0, 1f, axisStart, axisEnd); + var y = -Interpolation.ValueAt(rollingRow, 0, 1f, min, max); rowTicksContainer.Add(new TickText { @@ -155,25 +153,23 @@ namespace osu.Game.Overlays.Profile.Sections.Historical columnTicksContainer.Clear(); columnLinesContainer.Clear(); - var min = values.Select(v => v.Date).Min().Ticks; - var max = values.Select(v => v.Date).Max().Ticks; + var min = values.Select(v => v.Date).Min().ToOADate(); + var max = values.Select(v => v.Date).Max().ToOADate(); var niceRange = niceNumber(max - min, false); var niceTick = niceNumber(niceRange / (Math.Min(values.Length, 15) - 1), true); - var axisStart = Math.Floor(min / niceTick) * niceTick; - var axisEnd = Math.Ceiling(max / niceTick) * niceTick; - var rollingRow = axisStart; + double rollingRow = min; - while (rollingRow <= axisEnd) + while (rollingRow <= max) { - var x = Interpolation.ValueAt(rollingRow, 0, 1f, axisStart, axisEnd); + var x = Interpolation.ValueAt(rollingRow, 0, 1f, min, max); columnTicksContainer.Add(new TickText { Origin = Anchor.CentreLeft, RelativePositionAxes = Axes.X, - Text = new DateTime((long)rollingRow).ToString("MMM yyyy"), + Text = DateTime.FromOADate(rollingRow).ToString("MMM yyyy"), Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold), Rotation = 45, X = x From a94546f905ca8ca42e9b4386c148bf362bf612a4 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 14 Nov 2020 20:17:32 +0300 Subject: [PATCH 09/34] CI fixes --- .../Profile/Sections/Historical/ChartProfileSubsection.cs | 1 - .../Overlays/Profile/Sections/Historical/ProfileLineChart.cs | 2 +- osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs index 38224dd177..4445cdce51 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs @@ -17,7 +17,6 @@ namespace osu.Game.Overlays.Profile.Sections.Historical protected ChartProfileSubsection(Bindable user, string headerText) : base(user, headerText) { - } protected override Drawable CreateContent() => new Container diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index fe4677037b..b7983fd356 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -92,7 +92,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical } } }, - new Drawable[] + new[] { Empty(), columnTicksContainer = new Container diff --git a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs index 9583759693..751b35e342 100644 --- a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs @@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Profile.Sections AutoSizeAxes = Axes.Y; Direction = FillDirection.Vertical; - Children = new Drawable[] + Children = new[] { header = new ProfileSubsectionHeader(headerText, counterVisibilityState) { From fe9d17fc568cf757991573fb55d12f36875ed908 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 14 Nov 2020 20:31:03 +0300 Subject: [PATCH 10/34] Fix CodeFactor issues --- osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs | 2 +- .../Overlays/Profile/Sections/Historical/ProfileLineChart.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs b/osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs index 0be835c07d..3d342b0d76 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs @@ -3,12 +3,12 @@ using osu.Game.Overlays.Profile.Sections.Historical; using osu.Framework.Graphics; -using static osu.Game.Users.User; using System; using osu.Game.Overlays; using osu.Framework.Allocation; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Containers; +using static osu.Game.Users.User; namespace osu.Game.Tests.Visual.Online { diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index b7983fd356..5a9c42d7e0 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -4,7 +4,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using JetBrains.Annotations; -using static osu.Game.Users.User; using System; using System.Linq; using osu.Game.Graphics.Sprites; @@ -12,6 +11,7 @@ using osu.Framework.Utils; using osu.Framework.Allocation; using osu.Game.Graphics; using osu.Framework.Graphics.Shapes; +using static osu.Game.Users.User; namespace osu.Game.Overlays.Profile.Sections.Historical { From a52c98b55cc0be3e190610a9214cca09eb8288a0 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 14 Nov 2020 21:20:37 +0300 Subject: [PATCH 11/34] Fix broken test scene --- .../Profile/Sections/Historical/PlayHistorySubsection.cs | 2 +- .../Overlays/Profile/Sections/Historical/ReplaysSubsection.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs index 3e35f80b49..2f15886c3a 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs @@ -14,6 +14,6 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { } - protected override UserHistoryCount[] GetValues(User user) => user.MonthlyPlaycounts; + protected override UserHistoryCount[] GetValues(User user) => user?.MonthlyPlaycounts; } } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs index f6abd1c4fc..e594e8d020 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs @@ -14,6 +14,6 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { } - protected override UserHistoryCount[] GetValues(User user) => user.ReplaysWatchedCounts; + protected override UserHistoryCount[] GetValues(User user) => user?.ReplaysWatchedCounts; } } From d4b56aac8403565e2c5f5629c0abe550f76500ad Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 22 Nov 2020 02:17:54 +0300 Subject: [PATCH 12/34] Add missing whitespace --- osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs index 75c3ee8290..51e5622f68 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs @@ -28,6 +28,7 @@ namespace osu.Game.Overlays.Profile.Sections protected int VisiblePages; protected int ItemsPerPage; + protected FillFlowContainer ItemsContainer { get; private set; } private APIRequest> retrievalRequest; From 3cb1d0466734b0b2c07554f14a4c6f7e59f242c9 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 22 Nov 2020 02:25:12 +0300 Subject: [PATCH 13/34] Move dates fill into it's own method --- .../Historical/ChartProfileSubsection.cs | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs index 9413d241fa..783ecec190 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs @@ -44,32 +44,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical if (values?.Length > 1) { - // Fill dates with 0 count - - var newValues = new List { values[0] }; - var newLast = values[0]; - - for (int i = 1; i < values.Length; i++) - { - while (hasMissingDates(newLast, values[i])) - { - newValues.Add(newLast = new UserHistoryCount - { - Count = 0, - Date = newLast.Date.AddMonths(1) - }); - } - - newValues.Add(newLast = values[i]); - } - - static bool hasMissingDates(UserHistoryCount prev, UserHistoryCount current) - { - var possibleCurrent = prev.Date.AddMonths(1); - return possibleCurrent != current.Date; - } - - chart.Values = newValues.ToArray(); + chart.Values = fillZeroValues(values); Show(); return; } @@ -77,6 +52,34 @@ namespace osu.Game.Overlays.Profile.Sections.Historical Hide(); } + private UserHistoryCount[] fillZeroValues(UserHistoryCount[] values) + { + var newValues = new List { values[0] }; + var newLast = values[0]; + + for (int i = 1; i < values.Length; i++) + { + while (hasMissingDates(newLast, values[i])) + { + newValues.Add(newLast = new UserHistoryCount + { + Count = 0, + Date = newLast.Date.AddMonths(1) + }); + } + + newValues.Add(newLast = values[i]); + } + + return newValues.ToArray(); + + static bool hasMissingDates(UserHistoryCount prev, UserHistoryCount current) + { + var possibleCurrent = prev.Date.AddMonths(1); + return possibleCurrent != current.Date; + } + } + protected abstract UserHistoryCount[] GetValues(User user); } } From 453f0ba675de81682ba13a72225e9ad0211b5e2e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 22 Nov 2020 02:34:29 +0300 Subject: [PATCH 14/34] Make tick lines thicker --- .../Profile/Sections/Historical/ProfileLineChart.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index 5a9c42d7e0..c658ac1aa7 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -12,6 +12,7 @@ using osu.Framework.Allocation; using osu.Game.Graphics; using osu.Framework.Graphics.Shapes; using static osu.Game.Users.User; +using osuTK; namespace osu.Game.Overlays.Profile.Sections.Historical { @@ -140,7 +141,8 @@ namespace osu.Game.Overlays.Profile.Sections.Historical Origin = Anchor.CentreRight, RelativeSizeAxes = Axes.X, RelativePositionAxes = Axes.Y, - Height = 1, + Height = 0.1f, + EdgeSmoothness = Vector2.One, Y = y }); @@ -180,7 +182,8 @@ namespace osu.Game.Overlays.Profile.Sections.Historical Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.Y, RelativePositionAxes = Axes.X, - Width = 1, + Width = 0.1f, + EdgeSmoothness = Vector2.One, X = x }); From 6e581902cdd49c05b513518df1b4f84bfc5b71b2 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 22 Nov 2020 03:11:38 +0300 Subject: [PATCH 15/34] Simplify column ticks creation --- .../Sections/Historical/ProfileLineChart.cs | 109 ++++++++++-------- 1 file changed, 58 insertions(+), 51 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index c658ac1aa7..31c14d3b19 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -123,28 +123,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical while (rollingRow <= max) { var y = -Interpolation.ValueAt(rollingRow, 0, 1f, min, max); - - rowTicksContainer.Add(new TickText - { - Anchor = Anchor.BottomRight, - Origin = Anchor.CentreRight, - RelativePositionAxes = Axes.Y, - Margin = new MarginPadding { Right = 3 }, - Text = rollingRow.ToString("N0"), - Font = OsuFont.GetFont(size: 12), - Y = y - }); - - rowLinesContainer.Add(new TickLine - { - Anchor = Anchor.BottomRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.X, - RelativePositionAxes = Axes.Y, - Height = 0.1f, - EdgeSmoothness = Vector2.One, - Y = y - }); + addRowTick(y, (long)rollingRow); rollingRow += niceTick; } @@ -155,42 +134,70 @@ namespace osu.Game.Overlays.Profile.Sections.Historical columnTicksContainer.Clear(); columnLinesContainer.Clear(); - var min = values.Select(v => v.Date).Min().ToOADate(); - var max = values.Select(v => v.Date).Max().ToOADate(); + var totalMonths = values.Length - 1; - var niceRange = niceNumber(max - min, false); - var niceTick = niceNumber(niceRange / (Math.Min(values.Length, 15) - 1), true); + int monthsPerTick = 1; - double rollingRow = min; + if (totalMonths >= 45) + monthsPerTick = 3; + else if (totalMonths >= 20) + monthsPerTick = 2; - while (rollingRow <= max) + for (int i = 0; i < totalMonths; i += monthsPerTick) { - var x = Interpolation.ValueAt(rollingRow, 0, 1f, min, max); - - columnTicksContainer.Add(new TickText - { - Origin = Anchor.CentreLeft, - RelativePositionAxes = Axes.X, - Text = DateTime.FromOADate(rollingRow).ToString("MMM yyyy"), - Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold), - Rotation = 45, - X = x - }); - - columnLinesContainer.Add(new TickLine - { - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.Y, - RelativePositionAxes = Axes.X, - Width = 0.1f, - EdgeSmoothness = Vector2.One, - X = x - }); - - rollingRow += niceTick; + var x = (float)i / totalMonths; + addColumnTick(x, values[i].Date); } } + private void addRowTick(float y, long value) + { + rowTicksContainer.Add(new TickText + { + Anchor = Anchor.BottomRight, + Origin = Anchor.CentreRight, + RelativePositionAxes = Axes.Y, + Margin = new MarginPadding { Right = 3 }, + Text = value.ToString("N0"), + Font = OsuFont.GetFont(size: 12), + Y = y + }); + + rowLinesContainer.Add(new TickLine + { + Anchor = Anchor.BottomRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.X, + RelativePositionAxes = Axes.Y, + Height = 0.1f, + EdgeSmoothness = Vector2.One, + Y = y + }); + } + + private void addColumnTick(float x, DateTime value) + { + columnTicksContainer.Add(new TickText + { + Origin = Anchor.CentreLeft, + RelativePositionAxes = Axes.X, + Text = value.ToString("MMM yyyy"), + Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold), + Rotation = 45, + X = x + }); + + columnLinesContainer.Add(new TickLine + { + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Y, + RelativePositionAxes = Axes.X, + Width = 0.1f, + EdgeSmoothness = Vector2.One, + X = x + }); + } + private double niceNumber(double value, bool round) { var exponent = Math.Floor(Math.Log10(value)); From e6c116f0ab35b181e1d353a0640ec1cd1bcb23c5 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 22 Nov 2020 03:49:00 +0300 Subject: [PATCH 16/34] Rework horizontal ticks creation --- .../Sections/Historical/ProfileLineChart.cs | 73 ++++++++++--------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index 31c14d3b19..770da21657 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -115,17 +115,19 @@ namespace osu.Game.Overlays.Profile.Sections.Historical var min = values.Select(v => v.Count).Min(); var max = values.Select(v => v.Count).Max(); - var niceRange = niceNumber(max - min, false); - var niceTick = niceNumber(niceRange / (6 - 1), true); + var tick = getTick(getRange(max - min), 6); - double rollingRow = min; + double rollingRow = 0; while (rollingRow <= max) { - var y = -Interpolation.ValueAt(rollingRow, 0, 1f, min, max); - addRowTick(y, (long)rollingRow); + if (rollingRow >= min) + { + var y = -Interpolation.ValueAt(rollingRow, 0, 1f, min, max); + addRowTick(y, (long)rollingRow); + } - rollingRow += niceTick; + rollingRow += tick; } } @@ -138,10 +140,8 @@ namespace osu.Game.Overlays.Profile.Sections.Historical int monthsPerTick = 1; - if (totalMonths >= 45) - monthsPerTick = 3; - else if (totalMonths >= 20) - monthsPerTick = 2; + if (totalMonths > 20) + monthsPerTick = totalMonths / 10; for (int i = 0; i < totalMonths; i += monthsPerTick) { @@ -198,37 +198,44 @@ namespace osu.Game.Overlays.Profile.Sections.Historical }); } - private double niceNumber(double value, bool round) + private long getRange(double initialRange) { + var exponent = Math.Floor(Math.Log10(initialRange)); + var fraction = initialRange / Math.Pow(10, exponent); + + double niceFraction; + + if (fraction <= 1.0) + niceFraction = 1.0; + else if (fraction <= 2.0) + niceFraction = 2.0; + else if (fraction <= 5.0) + niceFraction = 5.0; + else + niceFraction = 10.0; + + return (long)(niceFraction * Math.Pow(10, exponent)); + } + + private long getTick(long range, int maxTicksCount) + { + var value = range / (maxTicksCount - 1); + var exponent = Math.Floor(Math.Log10(value)); var fraction = value / Math.Pow(10, exponent); double niceFraction; - if (round) - { - if (fraction < 1.5) - niceFraction = 1.0; - else if (fraction < 3) - niceFraction = 2.0; - else if (fraction < 7) - niceFraction = 5.0; - else - niceFraction = 10.0; - } + if (fraction < 1.5) + niceFraction = 1.0; + else if (fraction < 3) + niceFraction = 2.0; + else if (fraction < 7) + niceFraction = 5.0; else - { - if (fraction <= 1.0) - niceFraction = 1.0; - else if (fraction <= 2.0) - niceFraction = 2.0; - else if (fraction <= 5.0) - niceFraction = 5.0; - else - niceFraction = 10.0; - } + niceFraction = 10.0; - return niceFraction * Math.Pow(10, exponent); + return (long)(niceFraction * Math.Pow(10, exponent)); } private class TickText : OsuSpriteText From f07f8089d69062f44077349945a7680a2ea20c21 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 22 Nov 2020 03:58:56 +0300 Subject: [PATCH 17/34] Adjust monthsPerTick value --- .../Profile/Sections/Historical/ProfileLineChart.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index 770da21657..932005a52f 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -140,8 +140,12 @@ namespace osu.Game.Overlays.Profile.Sections.Historical int monthsPerTick = 1; - if (totalMonths > 20) - monthsPerTick = totalMonths / 10; + if (totalMonths > 80) + monthsPerTick = 12; + else if (totalMonths >= 45) + monthsPerTick = 3; + else if (totalMonths > 20) + monthsPerTick = 2; for (int i = 0; i < totalMonths; i += monthsPerTick) { From 48871329471daf2a5c531460f5490250492529cb Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 22 Nov 2020 04:28:17 +0300 Subject: [PATCH 18/34] Adjustments for edge cases support --- .../Sections/Historical/ProfileLineChart.cs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index 932005a52f..688930d76a 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -117,6 +117,8 @@ namespace osu.Game.Overlays.Profile.Sections.Historical var tick = getTick(getRange(max - min), 6); + bool tickIsDecimal = tick < 1.0; + double rollingRow = 0; while (rollingRow <= max) @@ -124,7 +126,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical if (rollingRow >= min) { var y = -Interpolation.ValueAt(rollingRow, 0, 1f, min, max); - addRowTick(y, (long)rollingRow); + addRowTick(y, rollingRow, tickIsDecimal); } rollingRow += tick; @@ -136,7 +138,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical columnTicksContainer.Clear(); columnLinesContainer.Clear(); - var totalMonths = values.Length - 1; + var totalMonths = values.Length; int monthsPerTick = 1; @@ -149,12 +151,12 @@ namespace osu.Game.Overlays.Profile.Sections.Historical for (int i = 0; i < totalMonths; i += monthsPerTick) { - var x = (float)i / totalMonths; + var x = (float)i / (totalMonths - 1); addColumnTick(x, values[i].Date); } } - private void addRowTick(float y, long value) + private void addRowTick(float y, double value, bool tickIsDecimal) { rowTicksContainer.Add(new TickText { @@ -162,7 +164,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical Origin = Anchor.CentreRight, RelativePositionAxes = Axes.Y, Margin = new MarginPadding { Right = 3 }, - Text = value.ToString("N0"), + Text = tickIsDecimal ? value.ToString("F1") : value.ToString("N0"), Font = OsuFont.GetFont(size: 12), Y = y }); @@ -202,7 +204,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical }); } - private long getRange(double initialRange) + private double getRange(double initialRange) { var exponent = Math.Floor(Math.Log10(initialRange)); var fraction = initialRange / Math.Pow(10, exponent); @@ -218,10 +220,10 @@ namespace osu.Game.Overlays.Profile.Sections.Historical else niceFraction = 10.0; - return (long)(niceFraction * Math.Pow(10, exponent)); + return niceFraction * Math.Pow(10, exponent); } - private long getTick(long range, int maxTicksCount) + private double getTick(double range, int maxTicksCount) { var value = range / (maxTicksCount - 1); @@ -239,7 +241,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical else niceFraction = 10.0; - return (long)(niceFraction * Math.Pow(10, exponent)); + return niceFraction * Math.Pow(10, exponent); } private class TickText : OsuSpriteText From b745fb681a8bfba02e01317f684fa1a3a8b699f0 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 22 Nov 2020 04:40:55 +0300 Subject: [PATCH 19/34] Fix incorrect static using placement --- .../Overlays/Profile/Sections/Historical/ProfileLineChart.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index 688930d76a..1ce14fa245 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -11,8 +11,8 @@ using osu.Framework.Utils; using osu.Framework.Allocation; using osu.Game.Graphics; using osu.Framework.Graphics.Shapes; -using static osu.Game.Users.User; using osuTK; +using static osu.Game.Users.User; namespace osu.Game.Overlays.Profile.Sections.Historical { From 3ed78688012d711fd374f5350b742625cda6f192 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Nov 2020 13:49:14 +0900 Subject: [PATCH 20/34] Scroll editor setup screen to file selector on display Previously the file selector would potentially display off-screen, making for confusing UX. Closes #10942. --- osu.Game/Graphics/Containers/SectionsContainer.cs | 2 ++ .../Edit/Setup/FileChooserLabelledTextBox.cs | 13 ++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index f32f8e0c67..81968de304 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using JetBrains.Annotations; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -14,6 +15,7 @@ namespace osu.Game.Graphics.Containers /// /// A container that can scroll to each section inside it. /// + [Cached] public class SectionsContainer : Container where T : Drawable { diff --git a/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs b/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs index b802b3405a..5de6842b50 100644 --- a/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs +++ b/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs @@ -3,10 +3,12 @@ using System; using System.IO; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; @@ -21,6 +23,9 @@ namespace osu.Game.Screens.Edit.Setup private readonly IBindable currentFile = new Bindable(); + [Resolved] + private SectionsContainer sectionsContainer { get; set; } + public FileChooserLabelledTextBox() { currentFile.BindValueChanged(onFileSelected); @@ -47,14 +52,16 @@ namespace osu.Game.Screens.Edit.Setup public void DisplayFileChooser() { - Target.Child = new FileSelector(validFileExtensions: ResourcesSection.AudioExtensions) + FileSelector fileSelector; + + Target.Child = fileSelector = new FileSelector(validFileExtensions: ResourcesSection.AudioExtensions) { RelativeSizeAxes = Axes.X, Height = 400, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, CurrentFile = { BindTarget = currentFile } }; + + sectionsContainer?.ScrollTo(fileSelector); } internal class FileChooserOsuTextBox : OsuTextBox From 1b33d3003924daed2d2995a4889725728fce4d46 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 23 Nov 2020 08:52:29 +0300 Subject: [PATCH 21/34] Simplify horizontal ticks creation --- .../Sections/Historical/ProfileLineChart.cs | 37 +++++-------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index 1ce14fa245..7dbcb9ba16 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -115,9 +115,11 @@ namespace osu.Game.Overlays.Profile.Sections.Historical var min = values.Select(v => v.Count).Min(); var max = values.Select(v => v.Count).Max(); - var tick = getTick(getRange(max - min), 6); + var tick = getTick(max - min, 6); - bool tickIsDecimal = tick < 1.0; + // Prevent infinite loop in case if tick is zero + if (tick == 0) + tick = 1; double rollingRow = 0; @@ -126,7 +128,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical if (rollingRow >= min) { var y = -Interpolation.ValueAt(rollingRow, 0, 1f, min, max); - addRowTick(y, rollingRow, tickIsDecimal); + addRowTick(y, rollingRow); } rollingRow += tick; @@ -156,7 +158,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical } } - private void addRowTick(float y, double value, bool tickIsDecimal) + private void addRowTick(float y, double value) { rowTicksContainer.Add(new TickText { @@ -164,7 +166,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical Origin = Anchor.CentreRight, RelativePositionAxes = Axes.Y, Margin = new MarginPadding { Right = 3 }, - Text = tickIsDecimal ? value.ToString("F1") : value.ToString("N0"), + Text = value.ToString("N0"), Font = OsuFont.GetFont(size: 12), Y = y }); @@ -204,28 +206,9 @@ namespace osu.Game.Overlays.Profile.Sections.Historical }); } - private double getRange(double initialRange) + private long getTick(long range, int maxTicksCount) { - var exponent = Math.Floor(Math.Log10(initialRange)); - var fraction = initialRange / Math.Pow(10, exponent); - - double niceFraction; - - if (fraction <= 1.0) - niceFraction = 1.0; - else if (fraction <= 2.0) - niceFraction = 2.0; - else if (fraction <= 5.0) - niceFraction = 5.0; - else - niceFraction = 10.0; - - return niceFraction * Math.Pow(10, exponent); - } - - private double getTick(double range, int maxTicksCount) - { - var value = range / (maxTicksCount - 1); + var value = (float)range / (maxTicksCount - 1); var exponent = Math.Floor(Math.Log10(value)); var fraction = value / Math.Pow(10, exponent); @@ -241,7 +224,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical else niceFraction = 10.0; - return niceFraction * Math.Pow(10, exponent); + return (long)(niceFraction * Math.Pow(10, exponent)); } private class TickText : OsuSpriteText From 3c0ee7de9b12f17924e1b94e3bdc9d58f9e6850d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 23 Nov 2020 09:51:50 +0300 Subject: [PATCH 22/34] Add proper tests --- .../Online/TestSceneChartProfileSubsection.cs | 145 ++++++++++++++++++ .../Online/TestSceneProfileLineChart.cs | 55 ------- 2 files changed, 145 insertions(+), 55 deletions(-) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneChartProfileSubsection.cs delete mode 100644 osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneChartProfileSubsection.cs b/osu.Game.Tests/Visual/Online/TestSceneChartProfileSubsection.cs new file mode 100644 index 0000000000..4983dfba12 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneChartProfileSubsection.cs @@ -0,0 +1,145 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Overlays.Profile.Sections.Historical; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Users; +using NUnit.Framework; +using osu.Game.Overlays; +using osu.Framework.Allocation; +using System; +using System.Linq; +using osu.Framework.Testing; +using osu.Framework.Graphics.Shapes; +using static osu.Game.Users.User; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneChartProfileSubsection : OsuTestScene + { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Red); + + private readonly Bindable user = new Bindable(); + private readonly PlayHistorySubsection section; + + public TestSceneChartProfileSubsection() + { + AddRange(new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background4 + }, + section = new PlayHistorySubsection(user) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + } + }); + } + + [Test] + public void TestNullValues() + { + AddStep("Load user", () => user.Value = user_with_null_values); + AddAssert("Section is hidden", () => section.Alpha == 0); + } + + [Test] + public void TestEmptyValues() + { + AddStep("Load user", () => user.Value = user_with_empty_values); + AddAssert("Section is hidden", () => section.Alpha == 0); + } + + [Test] + public void TestOveValue() + { + AddStep("Load user", () => user.Value = user_with_one_value); + AddAssert("Section is hidden", () => section.Alpha == 0); + } + + [Test] + public void TestTwoValues() + { + AddStep("Load user", () => user.Value = user_with_two_values); + AddAssert("Section is visible", () => section.Alpha == 1); + } + + [Test] + public void TestFilledValues() + { + AddStep("Load user", () => user.Value = user_with_filled_values); + AddAssert("Section is visible", () => section.Alpha == 1); + AddAssert("Array length is the same", () => user_with_filled_values.MonthlyPlaycounts.Length == getChartValuesLength()); + } + + [Test] + public void TestMissingValues() + { + AddStep("Load user", () => user.Value = user_with_missing_values); + AddAssert("Section is visible", () => section.Alpha == 1); + AddAssert("Array length is 7", () => getChartValuesLength() == 7); + } + + private int getChartValuesLength() => this.ChildrenOfType().Single().Values.Length; + + private static readonly User user_with_null_values = new User + { + Id = 1 + }; + + private static readonly User user_with_empty_values = new User + { + Id = 2, + MonthlyPlaycounts = Array.Empty() + }; + + private static readonly User user_with_one_value = new User + { + Id = 3, + MonthlyPlaycounts = new[] + { + new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 100 } + } + }; + + private static readonly User user_with_two_values = new User + { + Id = 4, + MonthlyPlaycounts = new[] + { + new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 1 }, + new UserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 2 } + } + }; + + private static readonly User user_with_filled_values = new User + { + Id = 5, + MonthlyPlaycounts = new[] + { + new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 1000 }, + new UserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 20 }, + new UserHistoryCount { Date = new DateTime(2010, 7, 1), Count = 20000 }, + new UserHistoryCount { Date = new DateTime(2010, 8, 1), Count = 30 }, + new UserHistoryCount { Date = new DateTime(2010, 9, 1), Count = 50 }, + new UserHistoryCount { Date = new DateTime(2010, 10, 1), Count = 2000 }, + new UserHistoryCount { Date = new DateTime(2010, 11, 1), Count = 2100 } + } + }; + + private static readonly User user_with_missing_values = new User + { + Id = 6, + MonthlyPlaycounts = new[] + { + new UserHistoryCount { Date = new DateTime(2020, 1, 1), Count = 100 }, + new UserHistoryCount { Date = new DateTime(2020, 7, 1), Count = 200 } + } + }; + } +} diff --git a/osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs b/osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs deleted file mode 100644 index 3d342b0d76..0000000000 --- a/osu.Game.Tests/Visual/Online/TestSceneProfileLineChart.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Overlays.Profile.Sections.Historical; -using osu.Framework.Graphics; -using System; -using osu.Game.Overlays; -using osu.Framework.Allocation; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Containers; -using static osu.Game.Users.User; - -namespace osu.Game.Tests.Visual.Online -{ - public class TestSceneProfileLineChart : OsuTestScene - { - [Cached] - private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); - - public TestSceneProfileLineChart() - { - var values = new[] - { - new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 1000 }, - new UserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 20 }, - new UserHistoryCount { Date = new DateTime(2010, 7, 1), Count = 20000 }, - new UserHistoryCount { Date = new DateTime(2010, 8, 1), Count = 30 }, - new UserHistoryCount { Date = new DateTime(2010, 9, 1), Count = 50 }, - new UserHistoryCount { Date = new DateTime(2010, 10, 1), Count = 2000 }, - new UserHistoryCount { Date = new DateTime(2010, 11, 1), Count = 2100 } - }; - - AddRange(new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background4 - }, - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Padding = new MarginPadding { Horizontal = 50 }, - Child = new ProfileLineChart - { - Values = values - } - } - }); - } - } -} From 087ea9c9a5366c3848a56ea479259065913929d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 23 Nov 2020 20:51:38 +0100 Subject: [PATCH 23/34] Fix typo in test name --- osu.Game.Tests/Visual/Online/TestSceneChartProfileSubsection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChartProfileSubsection.cs b/osu.Game.Tests/Visual/Online/TestSceneChartProfileSubsection.cs index 4983dfba12..0c8ee5e0c5 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChartProfileSubsection.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChartProfileSubsection.cs @@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual.Online } [Test] - public void TestOveValue() + public void TestOneValue() { AddStep("Load user", () => user.Value = user_with_one_value); AddAssert("Section is hidden", () => section.Alpha == 0); From 20f1775ddb11ff2e88c22475788b5784892f0621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 23 Nov 2020 20:59:04 +0100 Subject: [PATCH 24/34] Rename test scene to match tested class --- ...ProfileSubsection.cs => TestScenePlayHistorySubsection.cs} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename osu.Game.Tests/Visual/Online/{TestSceneChartProfileSubsection.cs => TestScenePlayHistorySubsection.cs} (97%) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChartProfileSubsection.cs b/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs similarity index 97% rename from osu.Game.Tests/Visual/Online/TestSceneChartProfileSubsection.cs rename to osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs index 0c8ee5e0c5..c9dbc9dc24 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChartProfileSubsection.cs +++ b/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs @@ -16,7 +16,7 @@ using static osu.Game.Users.User; namespace osu.Game.Tests.Visual.Online { - public class TestSceneChartProfileSubsection : OsuTestScene + public class TestScenePlayHistorySubsection : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Red); @@ -24,7 +24,7 @@ namespace osu.Game.Tests.Visual.Online private readonly Bindable user = new Bindable(); private readonly PlayHistorySubsection section; - public TestSceneChartProfileSubsection() + public TestScenePlayHistorySubsection() { AddRange(new Drawable[] { From e9ffeb8b5d1471e59e91cce116e316e54ffe3db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 23 Nov 2020 21:09:42 +0100 Subject: [PATCH 25/34] Make missing date check more robust --- .../Profile/Sections/Historical/ChartProfileSubsection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs index 783ecec190..3fd334005f 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs @@ -76,7 +76,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical static bool hasMissingDates(UserHistoryCount prev, UserHistoryCount current) { var possibleCurrent = prev.Date.AddMonths(1); - return possibleCurrent != current.Date; + return possibleCurrent < current.Date; } } From bb5aa9a9c914d2fa0bd57431dfa7d737b00831ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 23 Nov 2020 21:24:37 +0100 Subject: [PATCH 26/34] Guard against empty values early --- .../Profile/Sections/Historical/ProfileLineChart.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index 7dbcb9ba16..af2ef5a75c 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -26,8 +26,10 @@ namespace osu.Game.Overlays.Profile.Sections.Historical get => values; set { - values = value; - graph.Values = values; + if (value.Length == 0) + throw new ArgumentException("At least one value expected!", nameof(value)); + + graph.Values = values = value; createRowTicks(); createColumnTicks(); From 7b0d3dfe0cee8696f7251465ba63a7755d161ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 23 Nov 2020 21:38:04 +0100 Subject: [PATCH 27/34] Refactor tick calculation code for readability --- .../Sections/Historical/ProfileLineChart.cs | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index af2ef5a75c..ecc85fb48d 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -117,7 +117,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical var min = values.Select(v => v.Count).Min(); var max = values.Select(v => v.Count).Max(); - var tick = getTick(max - min, 6); + var tick = getTickInterval(max - min, 6); // Prevent infinite loop in case if tick is zero if (tick == 0) @@ -208,25 +208,32 @@ namespace osu.Game.Overlays.Profile.Sections.Historical }); } - private long getTick(long range, int maxTicksCount) + private long getTickInterval(long range, int maxTicksCount) { - var value = (float)range / (maxTicksCount - 1); + // this interval is what would be achieved if the interval was divided perfectly evenly into maxTicksCount ticks. + // can contain ugly fractional parts. + var exactTickInterval = (float)range / (maxTicksCount - 1); - var exponent = Math.Floor(Math.Log10(value)); - var fraction = value / Math.Pow(10, exponent); + // the ideal ticks start with a 1, 2 or 5, and are multipliers of powers of 10. + // first off, use log10 to calculate the number of digits in the "exact" interval. + var numberOfDigits = Math.Floor(Math.Log10(exactTickInterval)); + var tickBase = Math.Pow(10, numberOfDigits); + // then see how the exact tick relates to the power of 10. + var exactTickMultiplier = exactTickInterval / tickBase; - double niceFraction; + double tickMultiplier; - if (fraction < 1.5) - niceFraction = 1.0; - else if (fraction < 3) - niceFraction = 2.0; - else if (fraction < 7) - niceFraction = 5.0; + // round up the fraction to start with a 1, 2 or 5. closest match wins. + if (exactTickMultiplier < 1.5) + tickMultiplier = 1.0; + else if (exactTickMultiplier < 3) + tickMultiplier = 2.0; + else if (exactTickMultiplier < 7) + tickMultiplier = 5.0; else - niceFraction = 10.0; + tickMultiplier = 10.0; - return (long)(niceFraction * Math.Pow(10, exponent)); + return Math.Max((long)(tickMultiplier * tickBase), 1); } private class TickText : OsuSpriteText From 8347ecf494f6824d1fe0ee36b6094e434cc31196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 23 Nov 2020 21:52:47 +0100 Subject: [PATCH 28/34] Simplify row tick creation code --- .../Sections/Historical/ProfileLineChart.cs | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index ecc85fb48d..c1eb0811fb 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -117,23 +117,15 @@ namespace osu.Game.Overlays.Profile.Sections.Historical var min = values.Select(v => v.Count).Min(); var max = values.Select(v => v.Count).Max(); - var tick = getTickInterval(max - min, 6); + var tickInterval = getTickInterval(max - min, 6); - // Prevent infinite loop in case if tick is zero - if (tick == 0) - tick = 1; - - double rollingRow = 0; - - while (rollingRow <= max) + for (long currentTick = 0; currentTick <= max; currentTick += tickInterval) { - if (rollingRow >= min) - { - var y = -Interpolation.ValueAt(rollingRow, 0, 1f, min, max); - addRowTick(y, rollingRow); - } + if (currentTick < min) + continue; - rollingRow += tick; + float y = -Interpolation.ValueAt(currentTick, 0, 1f, min, max); + addRowTick(y, currentTick); } } From 5701b32bae6c6d7dd5e4f7d5cf450415d2d5cc40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 23 Nov 2020 22:12:32 +0100 Subject: [PATCH 29/34] Handle constant graphs better --- .../Online/TestScenePlayHistorySubsection.cs | 40 ++++++++++++++++++- osu.Game/Graphics/UserInterface/LineGraph.cs | 6 ++- .../Sections/Historical/ProfileLineChart.cs | 12 +++++- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs b/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs index c9dbc9dc24..cf5ecf5bf2 100644 --- a/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs +++ b/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs @@ -69,6 +69,20 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Section is visible", () => section.Alpha == 1); } + [Test] + public void TestConstantValues() + { + AddStep("Load user", () => user.Value = user_with_constant_values); + AddAssert("Section is visible", () => section.Alpha == 1); + } + + [Test] + public void TestConstantZeroValues() + { + AddStep("Load user", () => user.Value = user_with_zero_values); + AddAssert("Section is visible", () => section.Alpha == 1); + } + [Test] public void TestFilledValues() { @@ -117,10 +131,32 @@ namespace osu.Game.Tests.Visual.Online } }; - private static readonly User user_with_filled_values = new User + private static readonly User user_with_constant_values = new User { Id = 5, MonthlyPlaycounts = new[] + { + new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 5 }, + new UserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 5 }, + new UserHistoryCount { Date = new DateTime(2010, 7, 1), Count = 5 } + } + }; + + private static readonly User user_with_zero_values = new User + { + Id = 6, + MonthlyPlaycounts = new[] + { + new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 0 }, + new UserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 0 }, + new UserHistoryCount { Date = new DateTime(2010, 7, 1), Count = 0 } + } + }; + + private static readonly User user_with_filled_values = new User + { + Id = 7, + MonthlyPlaycounts = new[] { new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 1000 }, new UserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 20 }, @@ -134,7 +170,7 @@ namespace osu.Game.Tests.Visual.Online private static readonly User user_with_missing_values = new User { - Id = 6, + Id = 8, MonthlyPlaycounts = new[] { new UserHistoryCount { Date = new DateTime(2020, 1, 1), Count = 100 }, diff --git a/osu.Game/Graphics/UserInterface/LineGraph.cs b/osu.Game/Graphics/UserInterface/LineGraph.cs index 42b523fc5c..70db26c817 100644 --- a/osu.Game/Graphics/UserInterface/LineGraph.cs +++ b/osu.Game/Graphics/UserInterface/LineGraph.cs @@ -119,7 +119,11 @@ namespace osu.Game.Graphics.UserInterface protected float GetYPosition(float value) { - if (ActualMaxValue == ActualMinValue) return 0; + if (ActualMaxValue == ActualMinValue) + // show line at top if the only value on the graph is positive, + // and at bottom if the only value on the graph is zero or negative. + // just kind of makes most sense intuitively. + return value > 1 ? 0 : 1; return (ActualMaxValue - value) / (ActualMaxValue - ActualMinValue); } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index c1eb0811fb..989871745d 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -124,8 +124,16 @@ namespace osu.Game.Overlays.Profile.Sections.Historical if (currentTick < min) continue; - float y = -Interpolation.ValueAt(currentTick, 0, 1f, min, max); - addRowTick(y, currentTick); + float y; + // special-case the min == max case to match LineGraph. + // lerp isn't really well-defined over a zero interval anyway. + if (min == max) + y = currentTick > 1 ? 1 : 0; + else + y = Interpolation.ValueAt(currentTick, 0, 1f, min, max); + + // y axis is inverted in graph-like coordinates. + addRowTick(-y, currentTick); } } From 44ca67c534ab40635f632e8b4fb6b2b1e124f4bf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Nov 2020 13:10:11 +0900 Subject: [PATCH 30/34] Simplify fill logic and add xmldoc --- .../Historical/ChartProfileSubsection.cs | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs index 3fd334005f..885b12ca6d 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -52,32 +53,30 @@ namespace osu.Game.Overlays.Profile.Sections.Historical Hide(); } - private UserHistoryCount[] fillZeroValues(UserHistoryCount[] values) + /// + /// Add entries for any missing months (filled with zero values). + /// + private UserHistoryCount[] fillZeroValues(UserHistoryCount[] historyEntries) { - var newValues = new List { values[0] }; - var newLast = values[0]; + var filledHistoryEntries = new List(); - for (int i = 1; i < values.Length; i++) + foreach (var entry in historyEntries) { - while (hasMissingDates(newLast, values[i])) + var lastFilled = filledHistoryEntries.LastOrDefault(); + + while (lastFilled?.Date.AddMonths(1) < entry.Date) { - newValues.Add(newLast = new UserHistoryCount + filledHistoryEntries.Add(lastFilled = new UserHistoryCount { Count = 0, - Date = newLast.Date.AddMonths(1) + Date = lastFilled.Date.AddMonths(1) }); } - newValues.Add(newLast = values[i]); + filledHistoryEntries.Add(entry); } - return newValues.ToArray(); - - static bool hasMissingDates(UserHistoryCount prev, UserHistoryCount current) - { - var possibleCurrent = prev.Date.AddMonths(1); - return possibleCurrent < current.Date; - } + return filledHistoryEntries.ToArray(); } protected abstract UserHistoryCount[] GetValues(User user); From 82640418ba1e140d7d4d4d109a15a29e155fe24f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Nov 2020 13:12:04 +0900 Subject: [PATCH 31/34] Invert hide logic for readability --- .../Profile/Sections/Historical/ChartProfileSubsection.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs index 885b12ca6d..b82773155d 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs @@ -43,14 +43,14 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { var values = GetValues(e.NewValue); - if (values?.Length > 1) + if (values == null || values.Length <= 1) { - chart.Values = fillZeroValues(values); - Show(); + Hide(); return; } - Hide(); + chart.Values = fillZeroValues(values); + Show(); } /// From e36b1051c18ba0fc4d2210cea84b269c4547e2b3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Nov 2020 13:15:59 +0900 Subject: [PATCH 32/34] Add spacing between inline comments --- .../Overlays/Profile/Sections/Historical/ProfileLineChart.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index 989871745d..f02aa36b6c 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -125,6 +125,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical continue; float y; + // special-case the min == max case to match LineGraph. // lerp isn't really well-defined over a zero interval anyway. if (min == max) @@ -218,6 +219,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical // first off, use log10 to calculate the number of digits in the "exact" interval. var numberOfDigits = Math.Floor(Math.Log10(exactTickInterval)); var tickBase = Math.Pow(10, numberOfDigits); + // then see how the exact tick relates to the power of 10. var exactTickMultiplier = exactTickInterval / tickBase; From bd1dad5477f46c041b176d6644714e5f7f126291 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Nov 2020 15:54:27 +0900 Subject: [PATCH 33/34] Remove null allowance for now --- osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs b/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs index 5de6842b50..6e2737256a 100644 --- a/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs +++ b/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs @@ -61,7 +61,7 @@ namespace osu.Game.Screens.Edit.Setup CurrentFile = { BindTarget = currentFile } }; - sectionsContainer?.ScrollTo(fileSelector); + sectionsContainer.ScrollTo(fileSelector); } internal class FileChooserOsuTextBox : OsuTextBox From b9c1f782fa00b52beb0b29772ec9767d45b3e2db Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 24 Nov 2020 17:03:26 +0900 Subject: [PATCH 34/34] Remove type parameter from DrawableCatchHitObject --- .../Objects/Drawables/DrawableBananaShower.cs | 2 +- .../Drawables/DrawableCatchHitObject.cs | 19 +++---------------- .../Objects/Drawables/DrawableDroplet.cs | 4 ++-- .../Objects/Drawables/DrawableFruit.cs | 4 ++-- .../Objects/Drawables/DrawableJuiceStream.cs | 2 +- 5 files changed, 9 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs index 4ce80aceb8..2215e1d983 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public class DrawableBananaShower : DrawableCatchHitObject + public class DrawableBananaShower : DrawableCatchHitObject { private readonly Func> createDrawableRepresentation; private readonly Container bananaContainer; diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs index 7922510a49..07f1f79243 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs @@ -13,12 +13,11 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public abstract class PalpableDrawableCatchHitObject : DrawableCatchHitObject - where TObject : PalpableCatchHitObject + public abstract class PalpableDrawableCatchHitObject : DrawableCatchHitObject { protected Container ScaleContainer { get; private set; } - protected PalpableDrawableCatchHitObject(TObject hitObject) + protected PalpableDrawableCatchHitObject(CatchHitObject hitObject) : base(hitObject) { Origin = Anchor.Centre; @@ -46,19 +45,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables comboColours[(HitObject.IndexInBeatmap + 1) % comboColours.Count]; } - public abstract class DrawableCatchHitObject : DrawableCatchHitObject - where TObject : CatchHitObject - { - public new TObject HitObject; - - protected DrawableCatchHitObject(TObject hitObject) - : base(hitObject) - { - HitObject = hitObject; - Anchor = Anchor.BottomLeft; - } - } - public abstract class DrawableCatchHitObject : DrawableHitObject { protected override double InitialLifetimeOffset => HitObject.TimePreempt; @@ -73,6 +59,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables : base(hitObject) { X = hitObject.X; + Anchor = Anchor.BottomLeft; } public Func CheckPosition; diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs index 688240fd86..9db64eba6e 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs @@ -8,11 +8,11 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public class DrawableDroplet : PalpableDrawableCatchHitObject + public class DrawableDroplet : PalpableDrawableCatchHitObject { public override bool StaysOnPlate => false; - public DrawableDroplet(Droplet h) + public DrawableDroplet(CatchHitObject h) : base(h) { } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs index c1c34e4157..f87c8866b1 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs @@ -8,9 +8,9 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public class DrawableFruit : PalpableDrawableCatchHitObject + public class DrawableFruit : PalpableDrawableCatchHitObject { - public DrawableFruit(Fruit h) + public DrawableFruit(CatchHitObject h) : base(h) { } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs index 7bc016d94f..af4a269404 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public class DrawableJuiceStream : DrawableCatchHitObject + public class DrawableJuiceStream : DrawableCatchHitObject { private readonly Func> createDrawableRepresentation; private readonly Container dropletContainer;