diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs index 990e0a166b..dea1e710b5 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs @@ -5,9 +5,11 @@ using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Overlays; using osu.Game.Overlays.BeatmapSet; using osu.Game.Screens.Select.Details; @@ -22,6 +24,9 @@ namespace osu.Game.Tests.Visual.Online private RatingsExposingDetails details; + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + [SetUp] public void Setup() => Schedule(() => { @@ -55,8 +60,12 @@ namespace osu.Game.Tests.Visual.Online { Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(), Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(), - } + }, } + }, + OnlineInfo = new BeatmapSetOnlineInfo + { + Status = BeatmapSetOnlineStatus.Ranked } }; } diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs index 2b572c1f6c..03003daf81 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs @@ -5,11 +5,13 @@ using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Overlays; using osu.Game.Overlays.BeatmapSet; using osu.Game.Screens.Select.Details; using osuTK; @@ -26,6 +28,9 @@ namespace osu.Game.Tests.Visual.Online private GraphExposingSuccessRate successRate; + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + [SetUp] public void Setup() => Schedule(() => { diff --git a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs index cc3b2ac68b..f9a7bc99c3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs @@ -7,11 +7,16 @@ using System.Collections.Generic; using osu.Framework.Graphics; using osu.Framework.Bindables; using osu.Game.Screens.Select.Leaderboards; +using osu.Framework.Allocation; +using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Online { public class TestSceneLeaderboardScopeSelector : OsuTestScene { + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + public override IReadOnlyList RequiredTypes => new[] { typeof(LeaderboardScopeSelector), diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsHeader.cs index 898e461bde..1e711b3cd7 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankingsHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsHeader.cs @@ -34,25 +34,7 @@ namespace osu.Game.Tests.Visual.Online { Current = { BindTarget = scope }, Country = { BindTarget = countryBindable }, - Ruleset = { BindTarget = ruleset }, - Spotlights = new[] - { - new Spotlight - { - Id = 1, - Text = "Spotlight 1" - }, - new Spotlight - { - Id = 2, - Text = "Spotlight 2" - }, - new Spotlight - { - Id = 3, - Text = "Spotlight 3" - } - } + Ruleset = { BindTarget = ruleset } }); var country = new Country diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs index e46c8a4a71..f27ab1e775 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs @@ -35,6 +35,12 @@ namespace osu.Game.Tests.Visual.Online Add(selector = new SpotlightSelector()); } + [Test] + public void TestVisibility() + { + AddStep("Toggle Visibility", selector.ToggleVisibility); + } + [Test] public void TestLocalSpotlights() { diff --git a/osu.Game.Tests/Visual/Online/TestSceneSpotlightsLayout.cs b/osu.Game.Tests/Visual/Online/TestSceneSpotlightsLayout.cs new file mode 100644 index 0000000000..d025a8d7c2 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneSpotlightsLayout.cs @@ -0,0 +1,55 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Overlays; +using osu.Game.Overlays.Rankings; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Catch; +using osu.Game.Rulesets.Mania; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Taiko; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneSpotlightsLayout : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(SpotlightsLayout), + typeof(SpotlightSelector), + }; + + protected override bool UseOnlineAPI => true; + + [Cached] + private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Green); + + public TestSceneSpotlightsLayout() + { + var ruleset = new Bindable(new OsuRuleset().RulesetInfo); + + Add(new BasicScrollContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Width = 0.8f, + Child = new SpotlightsLayout + { + Ruleset = { BindTarget = ruleset } + } + }); + + AddStep("Osu ruleset", () => ruleset.Value = new OsuRuleset().RulesetInfo); + AddStep("Mania ruleset", () => ruleset.Value = new ManiaRuleset().RulesetInfo); + AddStep("Taiko ruleset", () => ruleset.Value = new TaikoRuleset().RulesetInfo); + AddStep("Catch ruleset", () => ruleset.Value = new CatchRuleset().RulesetInfo); + } + } +} diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 80192b9ebc..9474c08c5a 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -17,6 +17,7 @@ using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -426,6 +427,44 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("start not requested", () => !startRequested); } + [TestCase(false)] + [TestCase(true)] + public void TestExternalBeatmapChangeWhileFiltered(bool differentRuleset) + { + createSongSelect(); + addManyTestMaps(); + + changeRuleset(0); + + AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null); + + AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = "nonono"); + + AddUntilStep("dummy selected", () => Beatmap.Value is DummyWorkingBeatmap); + + AddUntilStep("has no selection", () => songSelect.Carousel.SelectedBeatmap == null); + + BeatmapInfo target = null; + + AddStep("select beatmap externally", () => + { + target = manager.GetAllUsableBeatmapSets().Where(b => b.Beatmaps.Any(bi => bi.RulesetID == (differentRuleset ? 1 : 0))) + .ElementAt(5).Beatmaps.First(); + + Beatmap.Value = manager.GetWorkingBeatmap(target); + }); + + AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null); + + AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmap?.OnlineBeatmapID == target.OnlineBeatmapID); + AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID); + + AddStep("reset filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = string.Empty); + + AddAssert("game still correct", () => Beatmap.Value?.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID); + AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmap.OnlineBeatmapID == target.OnlineBeatmapID); + } + [Test] public void TestAutoplayViaCtrlEnter() { @@ -468,6 +507,7 @@ namespace osu.Game.Tests.Visual.SongSelect private void importForRuleset(int id) => manager.Import(createTestBeatmapSet(getImportId(), rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())).Wait(); private static int importId; + private int getImportId() => ++importId; private void checkMusicPlaying(bool playing) => @@ -551,6 +591,8 @@ namespace osu.Game.Tests.Visual.SongSelect public new Bindable Ruleset => base.Ruleset; + public new FilterControl FilterControl => base.FilterControl; + public WorkingBeatmap CurrentBeatmap => Beatmap.Value; public WorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap; public new BeatmapCarousel Carousel => base.Carousel; diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs index 351e5df17a..f6e03d40ff 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs @@ -13,6 +13,7 @@ namespace osu.Game.Beatmaps.Drawables public class BeatmapSetOnlineStatusPill : CircularContainer { private readonly OsuSpriteText statusText; + private readonly Box background; private BeatmapSetOnlineStatus status; @@ -43,6 +44,12 @@ namespace osu.Game.Beatmaps.Drawables set => statusText.Padding = value; } + public Color4 BackgroundColour + { + get => background.Colour; + set => background.Colour = value; + } + public BeatmapSetOnlineStatusPill() { AutoSizeAxes = Axes.Both; @@ -50,7 +57,7 @@ namespace osu.Game.Beatmaps.Drawables Children = new Drawable[] { - new Box + background = new Box { RelativeSizeAxes = Axes.Both, Colour = Color4.Black, diff --git a/osu.Game/Graphics/UserInterface/GradientLineTabControl.cs b/osu.Game/Graphics/UserInterface/GradientLineTabControl.cs index baca57ea89..1d67c4e033 100644 --- a/osu.Game/Graphics/UserInterface/GradientLineTabControl.cs +++ b/osu.Game/Graphics/UserInterface/GradientLineTabControl.cs @@ -49,14 +49,7 @@ namespace osu.Game.Graphics.UserInterface public GradientLine() { RelativeSizeAxes = Axes.X; - Size = new Vector2(0.8f, 1.5f); - - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(mode: GridSizeMode.Relative, size: 0.4f), - new Dimension(), - }; + Size = new Vector2(0.8f, 1f); Content = new[] { @@ -65,16 +58,12 @@ namespace osu.Game.Graphics.UserInterface new Box { RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(Color4.Transparent, Color4.White) + Colour = ColourInfo.GradientHorizontal(Color4.Transparent, Colour) }, new Box { RelativeSizeAxes = Axes.Both, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(Color4.White, Color4.Transparent) + Colour = ColourInfo.GradientHorizontal(Colour, Color4.Transparent) }, } }; diff --git a/osu.Game/Online/API/Requests/Responses/APISpotlight.cs b/osu.Game/Online/API/Requests/Responses/APISpotlight.cs index 3a002e57b2..4f63ebe3df 100644 --- a/osu.Game/Online/API/Requests/Responses/APISpotlight.cs +++ b/osu.Game/Online/API/Requests/Responses/APISpotlight.cs @@ -26,6 +26,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"end_date")] public DateTimeOffset EndDate; + [JsonProperty(@"participant_count")] + public int? Participants; + public override string ToString() => Name; } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index ff3dee55af..79616ef97c 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -446,7 +446,7 @@ namespace osu.Game /// /// The action to perform once we are in the correct state. /// An optional collection of valid screen types. If any of these screens are already current we can perform the action immediately, else the first valid parent will be made current before performing the action. is used if not specified. - protected void PerformFromScreen(Action action, IEnumerable validScreens = null) + public void PerformFromScreen(Action action, IEnumerable validScreens = null) { performFromMainMenuTask?.Cancel(); diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs index e0360c6312..53003b0488 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs @@ -150,7 +150,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons }, new OsuSpriteText { - Text = BeatmapSet.Value.OnlineInfo.HasVideo && noVideo ? "without Video" : string.Empty, + Text = getVideoSuffixText(), Font = OsuFont.GetFont(size: 11, weight: FontWeight.Bold) }, }; @@ -163,5 +163,13 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons private void userChanged(ValueChangedEvent e) => button.Enabled.Value = !(e.NewValue is GuestUser); private void enabledChanged(ValueChangedEvent e) => this.FadeColour(e.NewValue ? Color4.White : Color4.Gray, 200, Easing.OutQuint); + + private string getVideoSuffixText() + { + if (!BeatmapSet.Value.OnlineInfo.HasVideo) + return string.Empty; + + return noVideo ? "without Video" : "with Video"; + } } } diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs index 8c884e0950..7eae05e4a9 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -14,7 +13,6 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Overlays.Direct; using osuTK; -using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapSet.Buttons { @@ -22,7 +20,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons { private const float transition_duration = 500; - private readonly Box bg, progress; + private readonly Box background, progress; private readonly PlayButton playButton; private PreviewTrack preview => playButton.Preview; @@ -40,10 +38,10 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons Children = new Drawable[] { - bg = new Box + background = new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4.Black.Opacity(0.25f), + Alpha = 0.5f }, new Container { @@ -71,9 +69,10 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, OverlayColourProvider colourProvider) { progress.Colour = colours.Yellow; + background.Colour = colourProvider.Background6; } protected override void Update() @@ -91,13 +90,13 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons protected override bool OnHover(HoverEvent e) { - bg.FadeColour(Color4.Black.Opacity(0.5f), 100); + background.FadeTo(0.75f, 80); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - bg.FadeColour(Color4.Black.Opacity(0.25f), 100); + background.FadeTo(0.5f, 80); base.OnHoverLost(e); } } diff --git a/osu.Game/Overlays/BeatmapSet/Details.cs b/osu.Game/Overlays/BeatmapSet/Details.cs index d76f6a43db..488e181fa2 100644 --- a/osu.Game/Overlays/BeatmapSet/Details.cs +++ b/osu.Game/Overlays/BeatmapSet/Details.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -10,7 +9,6 @@ using osu.Game.Beatmaps; using osu.Game.Overlays.BeatmapSet.Buttons; using osu.Game.Screens.Select.Details; using osuTK; -using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapSet { @@ -21,6 +19,7 @@ namespace osu.Game.Overlays.BeatmapSet private readonly PreviewButton preview; private readonly BasicStats basic; private readonly AdvancedStats advanced; + private readonly DetailBox ratingBox; private BeatmapSetInfo beatmapSet; @@ -54,6 +53,7 @@ namespace osu.Game.Overlays.BeatmapSet private void updateDisplay() { Ratings.Metrics = BeatmapSet?.Metrics; + ratingBox.Alpha = BeatmapSet?.OnlineInfo?.Status > 0 ? 1 : 0; } public Details() @@ -86,7 +86,7 @@ namespace osu.Game.Overlays.BeatmapSet Margin = new MarginPadding { Vertical = 7.5f }, }, }, - new DetailBox + ratingBox = new DetailBox { Child = Ratings = new UserRatings { @@ -107,6 +107,8 @@ namespace osu.Game.Overlays.BeatmapSet private class DetailBox : Container { private readonly Container content; + private readonly Box background; + protected override Container Content => content; public DetailBox() @@ -116,10 +118,10 @@ namespace osu.Game.Overlays.BeatmapSet InternalChildren = new Drawable[] { - new Box + background = new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4.Black.Opacity(0.5f), + Alpha = 0.5f }, content = new Container { @@ -129,6 +131,12 @@ namespace osu.Game.Overlays.BeatmapSet }, }; } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + background.Colour = colourProvider.Background6; + } } } } diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index 7c5c5a9d55..29f09a1ad8 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System.Linq; @@ -30,6 +30,7 @@ namespace osu.Game.Overlays.BeatmapSet private const float buttons_spacing = 5; private readonly UpdateableBeatmapSetCover cover; + private readonly Box coverGradient; private readonly OsuSpriteText title, artist; private readonly AuthorInfo author; private readonly FillFlowContainer downloadButtonsContainer; @@ -93,10 +94,9 @@ namespace osu.Game.Overlays.BeatmapSet RelativeSizeAxes = Axes.Both, Masking = true, }, - new Box + coverGradient = new Box { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.3f), Color4.Black.Opacity(0.8f)), + RelativeSizeAxes = Axes.Both }, }, }, @@ -106,8 +106,7 @@ namespace osu.Game.Overlays.BeatmapSet AutoSizeAxes = Axes.Y, Padding = new MarginPadding { - Top = 20, - Bottom = 30, + Vertical = BeatmapSetOverlay.Y_PADDING, Left = BeatmapSetOverlay.X_PADDING, Right = BeatmapSetOverlay.X_PADDING + BeatmapSetOverlay.RIGHT_WIDTH, }, @@ -130,11 +129,12 @@ namespace osu.Game.Overlays.BeatmapSet { Direction = FillDirection.Horizontal, AutoSizeAxes = Axes.Both, + Margin = new MarginPadding { Top = 15 }, Children = new Drawable[] { title = new OsuSpriteText { - Font = OsuFont.GetFont(size: 37, weight: FontWeight.Bold, italics: true) + Font = OsuFont.GetFont(size: 30, weight: FontWeight.SemiBold, italics: true) }, externalLink = new ExternalLinkButton { @@ -144,7 +144,7 @@ namespace osu.Game.Overlays.BeatmapSet }, } }, - artist = new OsuSpriteText { Font = OsuFont.GetFont(size: 25, weight: FontWeight.SemiBold, italics: true) }, + artist = new OsuSpriteText { Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, italics: true) }, new Container { RelativeSizeAxes = Axes.X, @@ -187,7 +187,7 @@ namespace osu.Game.Overlays.BeatmapSet Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Top = BeatmapSetOverlay.TOP_PADDING, Right = BeatmapSetOverlay.X_PADDING }, + Margin = new MarginPadding { Top = BeatmapSetOverlay.Y_PADDING, Right = BeatmapSetOverlay.X_PADDING }, Direction = FillDirection.Vertical, Spacing = new Vector2(10), Children = new Drawable[] @@ -197,7 +197,7 @@ namespace osu.Game.Overlays.BeatmapSet Anchor = Anchor.TopRight, Origin = Anchor.TopRight, TextSize = 14, - TextPadding = new MarginPadding { Horizontal = 25, Vertical = 8 } + TextPadding = new MarginPadding { Horizontal = 35, Vertical = 10 } }, Details = new Details(), }, @@ -215,8 +215,11 @@ namespace osu.Game.Overlays.BeatmapSet } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OverlayColourProvider colourProvider) { + coverGradient.Colour = ColourInfo.GradientVertical(colourProvider.Background6.Opacity(0.3f), colourProvider.Background6.Opacity(0.8f)); + onlineStatusPill.BackgroundColour = colourProvider.Background6; + State.BindValueChanged(_ => updateDownloadButtons()); BeatmapSet.BindValueChanged(setInfo => diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index d7392b31e1..85e871baca 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -38,6 +38,8 @@ namespace osu.Game.Overlays.BeatmapSet public Info() { MetadataSection source, tags, genre, language; + OsuSpriteText unrankedPlaceholder; + RelativeSizeAxes = Axes.X; Height = 220; Masking = true; @@ -110,6 +112,14 @@ namespace osu.Game.Overlays.BeatmapSet RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Top = 20, Horizontal = 15 }, }, + unrankedPlaceholder = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + Text = "Unranked beatmap", + Font = OsuFont.GetFont(size: 12) + }, }, }, }, @@ -122,6 +132,9 @@ namespace osu.Game.Overlays.BeatmapSet tags.Text = b.NewValue?.Metadata.Tags ?? string.Empty; genre.Text = b.NewValue?.OnlineInfo?.Genre?.Name ?? string.Empty; language.Text = b.NewValue?.OnlineInfo?.Language?.Name ?? string.Empty; + var setHasLeaderboard = b.NewValue?.OnlineInfo?.Status > 0; + successRate.Alpha = setHasLeaderboard ? 1 : 0; + unrankedPlaceholder.Alpha = setHasLeaderboard ? 0 : 1; }; } diff --git a/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs b/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs index e2a725ec46..20a3b09db4 100644 --- a/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs @@ -26,10 +26,10 @@ namespace osu.Game.Overlays.BeatmapSet } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OverlayColourProvider colourProvider) { - AccentColour = colours.Blue; - LineColour = Color4.Gray; + AccentColour = colourProvider.Highlight1; + LineColour = colourProvider.Background1; } private class ScopeSelectorTabItem : PageTabItem diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index 758140a12d..43a45bd2fc 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -77,9 +77,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores new TableColumn("rank", Anchor.CentreRight, new Dimension(GridSizeMode.AutoSize)), new TableColumn("", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 70)), // grade new TableColumn("score", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)), - new TableColumn("accuracy", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)), + new TableColumn("accuracy", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 60, maxSize: 70)), new TableColumn("player", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 150)), - new TableColumn("max combo", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 90)) + new TableColumn("max combo", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 110)) }; foreach (var statistic in score.SortedStatistics) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTableRowBackground.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTableRowBackground.cs index 14ea3e6b38..83271efe09 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTableRowBackground.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTableRowBackground.cs @@ -30,7 +30,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores RelativeSizeAxes = Axes.X; Height = 25; - CornerRadius = 3; + CornerRadius = 5; Masking = true; InternalChildren = new Drawable[] diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 0a3b5d9457..8560232209 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -164,7 +164,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { RelativeSizeAxes = Axes.Both, Masking = true, - CornerRadius = 10, + CornerRadius = 5, Child = loading = new DimmedLoadingLayer(iconScale: 0.8f) { Alpha = 0, diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs index 6c9f0b0321..a7066c4827 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs @@ -118,26 +118,42 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { AutoSizeAxes = Axes.Both; - InternalChild = new FillFlowContainer + InternalChild = new GridContainer { AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 1), - Children = new[] + ColumnDimensions = new[] { - text = new OsuSpriteText + new Dimension(GridSizeMode.AutoSize, minSize: minWidth ?? 0) + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, 4), + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] { - Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold), - Text = title.ToUpper() + text = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold), + Text = title.ToUpper() + } }, - separator = new Box + new Drawable[] { - RelativeSizeAxes = minWidth == null ? Axes.X : Axes.None, - Width = minWidth ?? 1f, - Height = 2, - Margin = new MarginPadding { Top = 2 } + separator = new Box + { + Anchor = Anchor.CentreLeft, + RelativeSizeAxes = Axes.X, + Height = 2 + } }, - content + new[] + { + content + } } }; } diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs index 72a7efd777..8a368aa535 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs @@ -96,13 +96,14 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold) + Font = OsuFont.GetFont(size: 10) }, flag = new UpdateableFlag { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Size = new Vector2(19, 13), + Margin = new MarginPadding { Top = 3 }, // makes spacing look more even ShowPlaceholderOnNull = false, }, } diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index 1dcc847760..15216b6e69 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -42,7 +42,7 @@ namespace osu.Game.Overlays.BeatmapSet int playCount = beatmap?.OnlineInfo?.PlayCount ?? 0; var rate = playCount != 0 ? (float)passCount / playCount : 0; - successPercent.Text = rate.ToString("0%"); + successPercent.Text = rate.ToString("0.#%"); successRate.Length = rate; percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic); @@ -105,10 +105,10 @@ namespace osu.Game.Overlays.BeatmapSet } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, OverlayColourProvider colourProvider) { successRate.AccentColour = colours.Green; - successRate.BackgroundColour = colours.GrayD; + successRate.BackgroundColour = colourProvider.Background6; updateDisplay(); } diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index f747cfff16..7624351e41 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -21,7 +21,7 @@ namespace osu.Game.Overlays public class BeatmapSetOverlay : FullscreenOverlay { public const float X_PADDING = 40; - public const float TOP_PADDING = 25; + public const float Y_PADDING = 25; public const float RIGHT_WIDTH = 275; protected readonly Header Header; diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index 94afe4e5a5..2674b3a81e 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -6,25 +6,14 @@ using osu.Framework.Bindables; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; using osu.Game.Users; -using System.Collections.Generic; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Allocation; namespace osu.Game.Overlays.Rankings { public class RankingsOverlayHeader : TabControlOverlayHeader { public readonly Bindable Ruleset = new Bindable(); - public readonly Bindable Spotlight = new Bindable(); public readonly Bindable Country = new Bindable(); - public IEnumerable Spotlights - { - get => spotlightsContainer.Spotlights; - set => spotlightsContainer.Spotlights = value; - } - protected override ScreenTitle CreateTitle() => new RankingsTitle { Scope = { BindTarget = Current } @@ -35,35 +24,11 @@ namespace osu.Game.Overlays.Rankings Current = Ruleset }; - private SpotlightsContainer spotlightsContainer; - - protected override Drawable CreateContent() => new FillFlowContainer + protected override Drawable CreateContent() => new CountryFilter { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new CountryFilter - { - Current = Country - }, - spotlightsContainer = new SpotlightsContainer - { - Spotlight = { BindTarget = Spotlight } - } - } + Current = Country }; - protected override void LoadComplete() - { - Current.BindValueChanged(onCurrentChanged, true); - base.LoadComplete(); - } - - private void onCurrentChanged(ValueChangedEvent scope) => - spotlightsContainer.FadeTo(scope.NewValue == RankingsScope.Spotlights ? 1 : 0, 200, Easing.OutQuint); - private class RankingsTitle : ScreenTitle { public readonly Bindable Scope = new Bindable(); @@ -81,48 +46,6 @@ namespace osu.Game.Overlays.Rankings protected override Drawable CreateIcon() => new ScreenTitleTextureIcon(@"Icons/rankings"); } - - private class SpotlightsContainer : CompositeDrawable - { - public readonly Bindable Spotlight = new Bindable(); - - public IEnumerable Spotlights - { - get => dropdown.Items; - set => dropdown.Items = value; - } - - private readonly OsuDropdown dropdown; - private readonly Box background; - - public SpotlightsContainer() - { - Height = 100; - RelativeSizeAxes = Axes.X; - InternalChildren = new Drawable[] - { - background = new Box - { - RelativeSizeAxes = Axes.Both, - }, - dropdown = new OsuDropdown - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - Width = 0.8f, - Current = Spotlight, - Y = 20, - } - }; - } - - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) - { - background.Colour = colourProvider.Dark3; - } - } } public enum RankingsScope diff --git a/osu.Game/Overlays/Rankings/Spotlight.cs b/osu.Game/Overlays/Rankings/Spotlight.cs deleted file mode 100644 index e956b4f449..0000000000 --- a/osu.Game/Overlays/Rankings/Spotlight.cs +++ /dev/null @@ -1,18 +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 Newtonsoft.Json; - -namespace osu.Game.Overlays.Rankings -{ - public class Spotlight - { - [JsonProperty("id")] - public int Id; - - [JsonProperty("text")] - public string Text; - - public override string ToString() => Text; - } -} diff --git a/osu.Game/Overlays/Rankings/SpotlightSelector.cs b/osu.Game/Overlays/Rankings/SpotlightSelector.cs index e34c01113e..f019b50ae8 100644 --- a/osu.Game/Overlays/Rankings/SpotlightSelector.cs +++ b/osu.Game/Overlays/Rankings/SpotlightSelector.cs @@ -14,11 +14,14 @@ using osuTK; using System; using System.Collections.Generic; using osu.Framework.Graphics.UserInterface; +using osu.Game.Online.API.Requests; namespace osu.Game.Overlays.Rankings { - public class SpotlightSelector : CompositeDrawable, IHasCurrentValue + public class SpotlightSelector : VisibilityContainer, IHasCurrentValue { + private const int duration = 300; + private readonly Box background; private readonly SpotlightsDropdown dropdown; @@ -36,50 +39,60 @@ namespace osu.Game.Overlays.Rankings set => dropdown.Items = value; } + protected override bool StartHidden => true; + private readonly InfoColumn startDateColumn; private readonly InfoColumn endDateColumn; + private readonly InfoColumn mapCountColumn; + private readonly InfoColumn participantsColumn; + private readonly Container content; public SpotlightSelector() { RelativeSizeAxes = Axes.X; Height = 100; - - InternalChildren = new Drawable[] + Add(content = new Container { - background = new Box + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, - Children = new Drawable[] + background = new Box { - dropdown = new SpotlightsDropdown + RelativeSizeAxes = Axes.Both, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, + Children = new Drawable[] { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - Current = Current, - Depth = -float.MaxValue - }, - new FillFlowContainer - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(15, 0), - Children = new Drawable[] + dropdown = new SpotlightsDropdown { - startDateColumn = new InfoColumn(@"Start Date"), - endDateColumn = new InfoColumn(@"End Date"), + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + Current = Current, + Depth = -float.MaxValue + }, + new FillFlowContainer + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(15, 0), + Children = new Drawable[] + { + startDateColumn = new InfoColumn(@"Start Date"), + endDateColumn = new InfoColumn(@"End Date"), + mapCountColumn = new InfoColumn(@"Map Count"), + participantsColumn = new InfoColumn(@"Participants") + } } } } - }, - }; + } + }); } [BackgroundDependencyLoader] @@ -88,18 +101,17 @@ namespace osu.Game.Overlays.Rankings background.Colour = colourProvider.Dark3; } - protected override void LoadComplete() + public void ShowInfo(GetSpotlightRankingsResponse response) { - base.LoadComplete(); - - Current.BindValueChanged(onCurrentChanged); + startDateColumn.Value = dateToString(response.Spotlight.StartDate); + endDateColumn.Value = dateToString(response.Spotlight.EndDate); + mapCountColumn.Value = response.BeatmapSets.Count.ToString(); + participantsColumn.Value = response.Spotlight.Participants?.ToString("N0"); } - private void onCurrentChanged(ValueChangedEvent spotlight) - { - startDateColumn.Value = dateToString(spotlight.NewValue.StartDate); - endDateColumn.Value = dateToString(spotlight.NewValue.EndDate); - } + protected override void PopIn() => content.FadeIn(duration, Easing.OutQuint); + + protected override void PopOut() => content.FadeOut(duration, Easing.OutQuint); private string dateToString(DateTimeOffset date) => date.ToString("yyyy-MM-dd"); diff --git a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs new file mode 100644 index 0000000000..33811cc982 --- /dev/null +++ b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs @@ -0,0 +1,161 @@ +// 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; +using osu.Framework.Bindables; +using osu.Game.Rulesets; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; +using osuTK; +using osu.Framework.Allocation; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Overlays.Rankings.Tables; +using System.Linq; +using osu.Game.Overlays.Direct; +using System.Threading; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays.Rankings +{ + public class SpotlightsLayout : CompositeDrawable + { + public readonly Bindable Ruleset = new Bindable(); + + private readonly Bindable selectedSpotlight = new Bindable(); + + [Resolved] + private IAPIProvider api { get; set; } + + [Resolved] + private RulesetStore rulesets { get; set; } + + private CancellationTokenSource cancellationToken; + private GetSpotlightRankingsRequest getRankingsRequest; + private GetSpotlightsRequest spotlightsRequest; + + private SpotlightSelector selector; + private Container content; + private DimmedLoadingLayer loading; + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + InternalChild = new ReverseChildIDFillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + selector = new SpotlightSelector + { + Current = selectedSpotlight, + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + content = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding { Vertical = 10 } + }, + loading = new DimmedLoadingLayer() + } + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + selector.Show(); + + selectedSpotlight.BindValueChanged(onSpotlightChanged); + Ruleset.BindValueChanged(onRulesetChanged); + + getSpotlights(); + } + + private void getSpotlights() + { + spotlightsRequest = new GetSpotlightsRequest(); + spotlightsRequest.Success += response => selector.Spotlights = response.Spotlights; + api.Queue(spotlightsRequest); + } + + private void onRulesetChanged(ValueChangedEvent ruleset) + { + if (!selector.Spotlights.Any()) + return; + + selectedSpotlight.TriggerChange(); + } + + private void onSpotlightChanged(ValueChangedEvent spotlight) + { + loading.Show(); + + cancellationToken?.Cancel(); + getRankingsRequest?.Cancel(); + + getRankingsRequest = new GetSpotlightRankingsRequest(Ruleset.Value, spotlight.NewValue.Id); + getRankingsRequest.Success += onSuccess; + api.Queue(getRankingsRequest); + } + + private void onSuccess(GetSpotlightRankingsResponse response) + { + LoadComponentAsync(createContent(response), loaded => + { + selector.ShowInfo(response); + + content.Clear(); + content.Add(loaded); + + loading.Hide(); + }, (cancellationToken = new CancellationTokenSource()).Token); + } + + private Drawable createContent(GetSpotlightRankingsResponse response) => new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Children = new Drawable[] + { + new ScoresTable(1, response.Users), + new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Spacing = new Vector2(10), + Children = response.BeatmapSets.Select(b => new DirectGridPanel(b.ToBeatmapSet(rulesets)) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }).ToList() + } + } + }; + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + spotlightsRequest?.Cancel(); + getRankingsRequest?.Cancel(); + cancellationToken?.Cancel(); + } + } +} diff --git a/osu.Game/Overlays/RankingsOverlay.cs b/osu.Game/Overlays/RankingsOverlay.cs index 84470d9caa..f3215d07fa 100644 --- a/osu.Game/Overlays/RankingsOverlay.cs +++ b/osu.Game/Overlays/RankingsOverlay.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays private readonly Bindable ruleset = new Bindable(); private readonly BasicScrollContainer scrollFlow; - private readonly Container tableContainer; + private readonly Container contentContainer; private readonly DimmedLoadingLayer loading; private readonly Box background; @@ -69,13 +69,13 @@ namespace osu.Game.Overlays AutoSizeAxes = Axes.Y, Children = new Drawable[] { - tableContainer = new Container + contentContainer = new Container { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, - Margin = new MarginPadding { Vertical = 10 } + Margin = new MarginPadding { Bottom = 10 } }, loading = new DimmedLoadingLayer(), } @@ -112,7 +112,13 @@ namespace osu.Game.Overlays Scheduler.AddOnce(loadNewContent); }, true); - ruleset.BindValueChanged(_ => Scheduler.AddOnce(loadNewContent), true); + ruleset.BindValueChanged(_ => + { + if (Scope.Value == RankingsScope.Spotlights) + return; + + Scheduler.AddOnce(loadNewContent); + }, true); base.LoadComplete(); } @@ -134,17 +140,26 @@ namespace osu.Game.Overlays cancellationToken?.Cancel(); lastRequest?.Cancel(); + if (Scope.Value == RankingsScope.Spotlights) + { + loadContent(new SpotlightsLayout + { + Ruleset = { BindTarget = ruleset } + }); + return; + } + var request = createScopedRequest(); lastRequest = request; if (request == null) { - loadTable(null); + loadContent(null); return; } - request.Success += () => loadTable(createTableFromResponse(request)); - request.Failure += _ => loadTable(null); + request.Success += () => loadContent(createTableFromResponse(request)); + request.Failure += _ => loadContent(null); api.Queue(request); } @@ -189,21 +204,21 @@ namespace osu.Game.Overlays return null; } - private void loadTable(Drawable table) + private void loadContent(Drawable content) { scrollFlow.ScrollToStart(); - if (table == null) + if (content == null) { - tableContainer.Clear(); + contentContainer.Clear(); loading.Hide(); return; } - LoadComponentAsync(table, t => + LoadComponentAsync(content, loaded => { loading.Hide(); - tableContainer.Child = table; + contentContainer.Child = loaded; }, (cancellationToken = new CancellationTokenSource()).Token); } } diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index cb5ceefb0f..c70fbb67a4 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -141,12 +141,15 @@ namespace osu.Game.Screens.Menu preloadSongSelect(); } + [Resolved] + private OsuGame game { get; set; } + private void confirmAndExit() { if (exitConfirmed) return; exitConfirmed = true; - this.Exit(); + game.PerformFromScreen(menu => menu.Exit()); } private void preloadSongSelect() diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 592e26adc2..7f36a23a86 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -229,6 +229,17 @@ namespace osu.Game.Screens.Select if (item != null) { select(item); + + // if we got here and the set is filtered, it means we were bypassing filters. + // in this case, reapplying the filter is necessary to ensure the panel is in the correct place + // (since it is forcefully being included in the carousel). + if (set.Filtered.Value) + { + Debug.Assert(bypassFilters); + + applyActiveCriteria(false, true); + } + return true; } } diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 301d0d4dae..8e323c66e2 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -62,7 +62,7 @@ namespace osu.Game.Screens.Select.Carousel /// /// All beatmaps which are not filtered and valid for display. /// - protected IEnumerable ValidBeatmaps => Beatmaps.Where(b => !b.Filtered.Value).Select(b => b.Beatmap); + protected IEnumerable ValidBeatmaps => Beatmaps.Where(b => !b.Filtered.Value || b.State.Value == CarouselItemState.Selected).Select(b => b.Beatmap); private int compareUsingAggregateMax(CarouselBeatmapSet other, Func func) { diff --git a/osu.Game/Screens/Select/Carousel/CarouselItem.cs b/osu.Game/Screens/Select/Carousel/CarouselItem.cs index 79c1a4cb6b..1108b72bd2 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselItem.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselItem.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.Select.Carousel /// /// This item is not in a hidden state. /// - public bool Visible => State.Value != CarouselItemState.Collapsed && !Filtered.Value; + public bool Visible => State.Value == CarouselItemState.Selected || (State.Value != CarouselItemState.Collapsed && !Filtered.Value); public virtual List Drawables { diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 5037081b5e..0da260d752 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -376,16 +376,22 @@ namespace osu.Game.Screens.Select private void workingBeatmapChanged(ValueChangedEvent e) { - if (e.NewValue is DummyWorkingBeatmap) return; + if (e.NewValue is DummyWorkingBeatmap || !this.IsCurrentScreen()) return; - if (this.IsCurrentScreen() && !Carousel.SelectBeatmap(e.NewValue?.BeatmapInfo, false)) + if (!Carousel.SelectBeatmap(e.NewValue.BeatmapInfo, false)) { - // If selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch - if (e.NewValue?.BeatmapInfo?.Ruleset != null && !e.NewValue.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) + // A selection may not have been possible with filters applied. + + // There was possibly a ruleset mismatch. This is a case we can help things along by updating the game-wide ruleset to match. + if (e.NewValue.BeatmapInfo.Ruleset != null && !e.NewValue.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) { Ruleset.Value = e.NewValue.BeatmapInfo.Ruleset; - Carousel.SelectBeatmap(e.NewValue.BeatmapInfo); + transferRulesetValue(); } + + // Even if a ruleset mismatch was not the cause (ie. a text filter is applied), + // we still want to forcefully show the new beatmap, bypassing filters. + Carousel.SelectBeatmap(e.NewValue.BeatmapInfo); } }