diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index 9f03d947b9..286971bc90 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -40,24 +40,19 @@ namespace osu.Game.Tests.Visual.Online typeof(PreviewButton), typeof(SuccessRate), typeof(BeatmapAvailability), + typeof(BeatmapRulesetSelector), + typeof(BeatmapRulesetTabItem), }; protected override bool UseOnlineAPI => true; - private RulesetInfo taikoRuleset; - private RulesetInfo maniaRuleset; - public TestSceneBeatmapSetOverlay() { Add(overlay = new TestBeatmapSetOverlay()); } - [BackgroundDependencyLoader] - private void load(RulesetStore rulesets) - { - taikoRuleset = rulesets.GetRuleset(1); - maniaRuleset = rulesets.GetRuleset(3); - } + [Resolved] + private RulesetStore rulesets { get; set; } [Test] public void TestLoading() @@ -111,7 +106,7 @@ namespace osu.Game.Tests.Visual.Online StarDifficulty = 9.99, Version = @"TEST", Length = 456000, - Ruleset = maniaRuleset, + Ruleset = rulesets.GetRuleset(3), BaseDifficulty = new BeatmapDifficulty { CircleSize = 1, @@ -189,7 +184,7 @@ namespace osu.Game.Tests.Visual.Online StarDifficulty = 5.67, Version = @"ANOTHER TEST", Length = 123000, - Ruleset = taikoRuleset, + Ruleset = rulesets.GetRuleset(1), BaseDifficulty = new BeatmapDifficulty { CircleSize = 9, @@ -217,6 +212,54 @@ namespace osu.Game.Tests.Visual.Online downloadAssert(false); } + [Test] + public void TestMultipleRulesets() + { + AddStep("show multiple rulesets beatmap", () => + { + var beatmaps = new List(); + + foreach (var ruleset in rulesets.AvailableRulesets.Skip(1)) + { + beatmaps.Add(new BeatmapInfo + { + Version = ruleset.Name, + Ruleset = ruleset, + BaseDifficulty = new BeatmapDifficulty(), + OnlineInfo = new BeatmapOnlineInfo(), + Metrics = new BeatmapMetrics + { + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), + }, + }); + } + + overlay.ShowBeatmapSet(new BeatmapSetInfo + { + Metadata = new BeatmapMetadata + { + Title = @"multiple rulesets beatmap", + Artist = @"none", + Author = new User + { + Username = "BanchoBot", + Id = 3, + } + }, + OnlineInfo = new BeatmapSetOnlineInfo + { + Covers = new BeatmapSetOnlineCovers(), + }, + Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }, + Beatmaps = beatmaps + }); + }); + + AddAssert("shown beatmaps of current ruleset", () => overlay.Header.Picker.Difficulties.All(b => b.Beatmap.Ruleset.Equals(overlay.Header.RulesetSelector.Current.Value))); + AddAssert("left-most beatmap selected", () => overlay.Header.Picker.Difficulties.First().State == BeatmapPicker.DifficultySelectorState.Selected); + } + [Test] public void TestHide() { @@ -281,12 +324,12 @@ namespace osu.Game.Tests.Visual.Online private void downloadAssert(bool shown) { - AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.DownloadButtonsVisible == shown); + AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.Header.DownloadButtonsVisible == shown); } private class TestBeatmapSetOverlay : BeatmapSetOverlay { - public bool DownloadButtonsVisible => Header.DownloadButtonsVisible; + public new Header Header => base.Header; } } } diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 28947b6f22..bf2a92cd4f 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -17,6 +17,7 @@ using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -27,10 +28,11 @@ namespace osu.Game.Overlays.BeatmapSet private const float tile_icon_padding = 7; private const float tile_spacing = 2; - private readonly DifficultiesContainer difficulties; private readonly OsuSpriteText version, starRating; private readonly Statistic plays, favourites; + public readonly DifficultiesContainer Difficulties; + public readonly Bindable Beatmap = new Bindable(); private BeatmapSetInfo beatmapSet; @@ -43,38 +45,10 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmapSet) return; beatmapSet = value; - updateDisplay(); } } - private void updateDisplay() - { - difficulties.Clear(); - - if (BeatmapSet != null) - { - difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.OrderBy(beatmap => beatmap.StarDifficulty).Select(b => new DifficultySelectorButton(b) - { - State = DifficultySelectorState.NotSelected, - OnHovered = beatmap => - { - showBeatmap(beatmap); - starRating.Text = beatmap.StarDifficulty.ToString("Star Difficulty 0.##"); - starRating.FadeIn(100); - }, - OnClicked = beatmap => { Beatmap.Value = beatmap; }, - }); - } - - starRating.FadeOut(100); - Beatmap.Value = BeatmapSet?.Beatmaps.FirstOrDefault(); - plays.Value = BeatmapSet?.OnlineInfo.PlayCount ?? 0; - favourites.Value = BeatmapSet?.OnlineInfo.FavouriteCount ?? 0; - - updateDifficultyButtons(); - } - public BeatmapPicker() { RelativeSizeAxes = Axes.X; @@ -89,7 +63,7 @@ namespace osu.Game.Overlays.BeatmapSet Direction = FillDirection.Vertical, Children = new Drawable[] { - difficulties = new DifficultiesContainer + Difficulties = new DifficultiesContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -147,6 +121,9 @@ namespace osu.Game.Overlays.BeatmapSet }; } + [Resolved] + private IBindable ruleset { get; set; } + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -158,10 +135,39 @@ namespace osu.Game.Overlays.BeatmapSet { base.LoadComplete(); + ruleset.ValueChanged += r => updateDisplay(); + // done here so everything can bind in intialization and get the first trigger Beatmap.TriggerChange(); } + private void updateDisplay() + { + Difficulties.Clear(); + + if (BeatmapSet != null) + { + Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.Where(b => b.Ruleset.Equals(ruleset.Value)).OrderBy(b => b.StarDifficulty).Select(b => new DifficultySelectorButton(b) + { + State = DifficultySelectorState.NotSelected, + OnHovered = beatmap => + { + showBeatmap(beatmap); + starRating.Text = beatmap.StarDifficulty.ToString("Star Difficulty 0.##"); + starRating.FadeIn(100); + }, + OnClicked = beatmap => { Beatmap.Value = beatmap; }, + }); + } + + starRating.FadeOut(100); + Beatmap.Value = Difficulties.FirstOrDefault()?.Beatmap; + plays.Value = BeatmapSet?.OnlineInfo.PlayCount ?? 0; + favourites.Value = BeatmapSet?.OnlineInfo.FavouriteCount ?? 0; + + updateDifficultyButtons(); + } + private void showBeatmap(BeatmapInfo beatmap) { version.Text = beatmap?.Version; @@ -169,10 +175,10 @@ namespace osu.Game.Overlays.BeatmapSet private void updateDifficultyButtons() { - difficulties.Children.ToList().ForEach(diff => diff.State = diff.Beatmap == Beatmap.Value ? DifficultySelectorState.Selected : DifficultySelectorState.NotSelected); + Difficulties.Children.ToList().ForEach(diff => diff.State = diff.Beatmap == Beatmap.Value ? DifficultySelectorState.Selected : DifficultySelectorState.NotSelected); } - private class DifficultiesContainer : FillFlowContainer + public class DifficultiesContainer : FillFlowContainer { public Action OnLostHover; @@ -183,7 +189,7 @@ namespace osu.Game.Overlays.BeatmapSet } } - private class DifficultySelectorButton : OsuClickableContainer, IStateful + public class DifficultySelectorButton : OsuClickableContainer, IStateful { private const float transition_duration = 100; private const float size = 52; @@ -320,7 +326,7 @@ namespace osu.Game.Overlays.BeatmapSet } } - private enum DifficultySelectorState + public enum DifficultySelectorState { Selected, NotSelected, diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs index 3fecfbdaaf..cdea49afe7 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs @@ -120,7 +120,7 @@ namespace osu.Game.Overlays.BeatmapSet { var isHoveredOrActive = IsHovered || Active.Value; - bar.ResizeHeightTo(isHoveredOrActive ? 4 : 1, 200, Easing.OutQuint); + bar.ResizeHeightTo(isHoveredOrActive ? 4 : 0, 200, Easing.OutQuint); name.Colour = isHoveredOrActive ? colour.GrayE : colour.GrayC; name.Font = name.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Regular); diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index 260a989628..7b42e7e459 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -3,6 +3,7 @@ using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -16,6 +17,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online; using osu.Game.Overlays.BeatmapSet.Buttons; using osu.Game.Overlays.Direct; +using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -39,6 +41,7 @@ namespace osu.Game.Overlays.BeatmapSet public bool DownloadButtonsVisible => downloadButtonsContainer.Any(); + public readonly BeatmapRulesetSelector RulesetSelector; public readonly BeatmapPicker Picker; private readonly FavouriteButton favouriteButton; @@ -47,6 +50,9 @@ namespace osu.Game.Overlays.BeatmapSet private readonly LoadingAnimation loading; + [Cached(typeof(IBindable))] + private readonly Bindable ruleset = new Bindable(); + public Header() { ExternalLinkButton externalLink; @@ -69,12 +75,18 @@ namespace osu.Game.Overlays.BeatmapSet { RelativeSizeAxes = Axes.X, Height = tabs_height, - Children = new[] + Children = new Drawable[] { tabsBg = new Box { RelativeSizeAxes = Axes.Both, }, + RulesetSelector = new BeatmapRulesetSelector + { + Current = ruleset, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + } }, }, new Container @@ -223,7 +235,7 @@ namespace osu.Game.Overlays.BeatmapSet BeatmapSet.BindValueChanged(setInfo => { - Picker.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = setInfo.NewValue; + Picker.BeatmapSet = RulesetSelector.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = setInfo.NewValue; cover.BeatmapSet = setInfo.NewValue; if (setInfo.NewValue == null)