From c372f9b8f538cec50a085003b4d2758224fa79fc Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 2 Mar 2026 22:37:19 -0800 Subject: [PATCH 01/15] Standardise display order of playcount / favourites --- .../Drawables/Cards/BeatmapCardExtra.cs | 18 +++++++++--------- .../Drawables/Cards/BeatmapCardNormal.cs | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs index 222acbc039..4c4a063708 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs @@ -296,20 +296,20 @@ namespace osu.Game.Beatmaps.Drawables.Cards return original; } - statisticsContainer.Content[0][0] = withMargin(new FavouritesStatistic(BeatmapSet) - { - Current = FavouriteState, - }); - - statisticsContainer.Content[1][0] = withMargin(new PlayCountStatistic(BeatmapSet)); - var hypesStatistic = HypesStatistic.CreateFor(BeatmapSet); if (hypesStatistic != null) - statisticsContainer.Content[0][1] = withMargin(hypesStatistic); + statisticsContainer.Content[0][0] = withMargin(hypesStatistic); var nominationsStatistic = NominationsStatistic.CreateFor(BeatmapSet); if (nominationsStatistic != null) - statisticsContainer.Content[1][1] = withMargin(nominationsStatistic); + statisticsContainer.Content[1][0] = withMargin(nominationsStatistic); + + statisticsContainer.Content[0][1] = withMargin(new PlayCountStatistic(BeatmapSet)); + + statisticsContainer.Content[1][1] = withMargin(new FavouritesStatistic(BeatmapSet) + { + Current = FavouriteState, + }); var dateStatistic = BeatmapCardDateStatistic.CreateFor(BeatmapSet); if (dateStatistic != null) diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs index ac9ee94f56..6974cf81ea 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs @@ -278,8 +278,8 @@ namespace osu.Game.Beatmaps.Drawables.Cards if (nominationsStatistic != null) yield return nominationsStatistic; - yield return new FavouritesStatistic(BeatmapSet) { Current = FavouriteState }; yield return new PlayCountStatistic(BeatmapSet); + yield return new FavouritesStatistic(BeatmapSet) { Current = FavouriteState }; var dateStatistic = BeatmapCardDateStatistic.CreateFor(BeatmapSet); if (dateStatistic != null) From b831bcbcd469459323a3400a17f0aa32c590e8d4 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 2 Mar 2026 22:40:16 -0800 Subject: [PATCH 02/15] Change beatmap card play count and date icon to solid to match web --- .../Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs | 2 +- .../Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs index 861ec9f027..cb4c548556 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs @@ -17,7 +17,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Statistics { this.dateTime = dateTime; - Icon = FontAwesome.Regular.CheckCircle; + Icon = FontAwesome.Solid.CheckCircle; Text = dateTime.ToLocalisedMediumDate(); } diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs index 4ce37b8659..8b6e238625 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs @@ -15,7 +15,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Statistics { public PlayCountStatistic(IBeatmapSetOnlineInfo onlineInfo) { - Icon = FontAwesome.Regular.PlayCircle; + Icon = FontAwesome.Solid.PlayCircle; Text = onlineInfo.PlayCount.ToMetric(decimals: 1); TooltipText = BeatmapsStrings.PanelPlaycount(onlineInfo.PlayCount.ToLocalisableString(@"N0")); } From 7dfbab212eab1a48bcaf0ba17f2c664e24041815 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 2 Mar 2026 22:42:41 -0800 Subject: [PATCH 03/15] Add nominations statistic to beatmap info overlay See https://github.com/ppy/osu-web/blob/2198adfa68bf24709c3b0cc2e6d838e86be5b1d1/resources/js/beatmapsets-show/header.tsx#L116-L123. --- .../Visual/Online/TestSceneBeatmapSetOverlay.cs | 4 ++++ osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index b164c530cb..227e15ccf7 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -72,6 +72,10 @@ namespace osu.Game.Tests.Visual.Online Preview = @"https://b.ppy.sh/preview/12345.mp3", PlayCount = 123, FavouriteCount = 456, + NominationStatus = new BeatmapSetNominationStatus + { + Current = 2, + }, Submitted = DateTime.Now, Ranked = DateTime.Now, BPM = 111, diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index f2630caa83..94aa639274 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Extensions; using osu.Game.Graphics; @@ -32,7 +33,7 @@ namespace osu.Game.Overlays.BeatmapSet private const float tile_spacing = 2; private readonly LinkFlowContainer infoContainer; - private readonly Statistic plays, favourites; + private readonly Statistic nominations, plays, favourites; public readonly DifficultiesContainer Difficulties; @@ -107,6 +108,7 @@ namespace osu.Game.Overlays.BeatmapSet Margin = new MarginPadding { Top = 5 }, Children = new[] { + nominations = new Statistic(FontAwesome.Solid.ThumbsUp), plays = new Statistic(FontAwesome.Solid.PlayCircle), favourites = new Statistic(FontAwesome.Solid.Heart), }, @@ -176,6 +178,14 @@ namespace osu.Game.Overlays.BeatmapSet // Else just choose the first available difficulty for now. Beatmap.Value ??= Difficulties.FirstOrDefault()?.Beatmap; + if (beatmapSet?.Status == BeatmapOnlineStatus.Pending && beatmapSet.NominationStatus != null) + { + nominations.Show(); + nominations.Value = beatmapSet.NominationStatus.Current; + } + else + nominations.Hide(); + plays.Value = BeatmapSet?.PlayCount ?? 0; favourites.Value = BeatmapSet?.FavouriteCount ?? 0; From 564b6ebd0c5bf35e830f13dd20dfd65f1e68882f Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 2 Mar 2026 22:53:09 -0800 Subject: [PATCH 04/15] Add tooltips to beatmap info overlay statistics --- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 94aa639274..59b0547d4e 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -9,6 +9,7 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; @@ -108,8 +109,14 @@ namespace osu.Game.Overlays.BeatmapSet Margin = new MarginPadding { Top = 5 }, Children = new[] { - nominations = new Statistic(FontAwesome.Solid.ThumbsUp), - plays = new Statistic(FontAwesome.Solid.PlayCircle), + nominations = new Statistic(FontAwesome.Solid.ThumbsUp) + { + TooltipText = BeatmapsetsStrings.ShowStatsNominations, + }, + plays = new Statistic(FontAwesome.Solid.PlayCircle) + { + TooltipText = BeatmapsetsStrings.ShowStatsPlaycount, + }, favourites = new Statistic(FontAwesome.Solid.Heart), }, }, @@ -188,6 +195,7 @@ namespace osu.Game.Overlays.BeatmapSet plays.Value = BeatmapSet?.PlayCount ?? 0; favourites.Value = BeatmapSet?.FavouriteCount ?? 0; + favourites.TooltipText = BeatmapSet?.FavouriteCount > 0 ? BeatmapsetsStrings.ShowStatsFavourites : BeatmapsetsStrings.ShowStatsNoFavourites; updateDifficultyButtons(); } @@ -377,7 +385,7 @@ namespace osu.Game.Overlays.BeatmapSet } } - private partial class Statistic : FillFlowContainer + private partial class Statistic : FillFlowContainer, IHasTooltip { private readonly OsuSpriteText text; @@ -417,6 +425,8 @@ namespace osu.Game.Overlays.BeatmapSet }, }; } + + public LocalisableString TooltipText { get; set; } } public enum DifficultySelectorState From 521a40d86025d71b927c16913dd26e035419b278 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 02:19:52 +0900 Subject: [PATCH 05/15] Remove now unused footer buttons From a7e62863969d382836fd1ae9a48d25a4cce10ae4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 16:44:48 +0900 Subject: [PATCH 06/15] Fix a few remaining references to old song select From f20d1827758973c9709610ca95cbe8c2b7fe8da5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 18:52:58 +0900 Subject: [PATCH 07/15] Update filter matching tests to be independent of old song select classes --- .../BenchmarkCarouselFilter.cs | 6 +++--- .../NonVisual/Filtering/FilterMatchingTest.cs | 20 +++++++++++++++++++ .../Filtering/FilterQueryParserTest.cs | 3 +-- .../SelectV2/BeatmapCarouselFilterMatching.cs | 4 ++-- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/osu.Game.Benchmarks/BenchmarkCarouselFilter.cs b/osu.Game.Benchmarks/BenchmarkCarouselFilter.cs index 8f7027da17..ecd76872d1 100644 --- a/osu.Game.Benchmarks/BenchmarkCarouselFilter.cs +++ b/osu.Game.Benchmarks/BenchmarkCarouselFilter.cs @@ -5,7 +5,7 @@ using BenchmarkDotNet.Attributes; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Carousel; +using osu.Game.Tests.NonVisual.Filtering; namespace osu.Game.Benchmarks { @@ -42,7 +42,7 @@ namespace osu.Game.Benchmarks Status = BeatmapOnlineStatus.Loved }; - private CarouselBeatmap carouselBeatmap = null!; + private FilterMatchingTest.CarouselBeatmap carouselBeatmap = null!; private FilterCriteria criteria1 = null!; private FilterCriteria criteria2 = null!; private FilterCriteria criteria3 = null!; @@ -55,7 +55,7 @@ namespace osu.Game.Benchmarks var beatmap = getExampleBeatmap(); beatmap.OnlineID = 20201010; beatmap.BeatmapSet = new BeatmapSetInfo { OnlineID = 1535 }; - carouselBeatmap = new CarouselBeatmap(beatmap); + carouselBeatmap = new FilterMatchingTest.CarouselBeatmap(beatmap); criteria1 = new FilterCriteria(); criteria2 = new FilterCriteria { diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs index 12aab055ad..7dcb8621bf 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs @@ -588,6 +588,26 @@ namespace osu.Game.Tests.NonVisual.Filtering Assert.That(visibleBeatmaps, Is.EqualTo(expectedBeatmapIndexes)); } + // This is a temporary class that emulates what these tests originally used from song select v1. + // If anyone ever ends up tidying up these test, here's a starting point: + // https://gist.github.com/peppy/67fda38f6483fd1dd01ef845ed5bf932 + public class CarouselBeatmap + { + public readonly BeatmapInfo BeatmapInfo; + + public BindableBool Filtered = new BindableBool(); + + public CarouselBeatmap(BeatmapInfo beatmapInfo) + { + BeatmapInfo = beatmapInfo; + } + + public void Filter(FilterCriteria criteria) + { + Filtered.Value = !BeatmapCarouselFilterMatching.CheckCriteriaMatch(BeatmapInfo, criteria); + } + } + private class CustomCriteria : IRulesetFilterCriteria { private readonly bool match; diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 87e439534b..6a87cc1207 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -10,7 +10,6 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Filter; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Carousel; using osu.Game.Screens.Select.Filter; namespace osu.Game.Tests.NonVisual.Filtering @@ -509,7 +508,7 @@ namespace osu.Game.Tests.NonVisual.Filtering ("Another One", "diff ]with [[ brackets]]]"), ("Diff in title", "a"), ("a", "Diff in diff"), - }).Select(info => new CarouselBeatmap(new BeatmapInfo + }).Select(info => new FilterMatchingTest.CarouselBeatmap(new BeatmapInfo { Metadata = new BeatmapMetadata { diff --git a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs b/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs index 31e6c790f2..80f7f058f7 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs @@ -42,7 +42,7 @@ namespace osu.Game.Screens.SelectV2 if (beatmap.Hidden) continue; - if (!checkCriteriaMatch(beatmap, criteria)) + if (!CheckCriteriaMatch(beatmap, criteria)) continue; countMatching++; @@ -52,7 +52,7 @@ namespace osu.Game.Screens.SelectV2 BeatmapItemsCount = countMatching; } - private static bool checkCriteriaMatch(BeatmapInfo beatmap, FilterCriteria criteria) + public static bool CheckCriteriaMatch(BeatmapInfo beatmap, FilterCriteria criteria) { bool match = criteria.Ruleset == null || beatmap.AllowGameplayWithRuleset(criteria.Ruleset!, criteria.AllowConvertedBeatmaps); From ce542b03db2dade2aa153ba545f52c8b56b6f685 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 17:58:46 +0900 Subject: [PATCH 08/15] Move components only used by beatmap set overlay local to namespace --- .../TestSceneAdvancedStats.cs | 4 +-- .../Online/TestSceneBeatmapSetOverlay.cs | 1 - .../TestSceneBeatmapSetOverlayDetails.cs | 1 - .../TestSceneBeatmapSetOverlaySuccessRate.cs | 1 - .../BeatmapSet}/AdvancedStats.cs | 32 +++++++++---------- osu.Game/Overlays/BeatmapSet/Details.cs | 1 - .../BeatmapSet}/FailRetryGraph.cs | 6 ++-- osu.Game/Overlays/BeatmapSet/SuccessRate.cs | 1 - .../BeatmapSet}/UserRatings.cs | 2 +- 9 files changed, 22 insertions(+), 27 deletions(-) rename osu.Game.Tests/Visual/{SongSelect => Online}/TestSceneAdvancedStats.cs (99%) rename osu.Game/{Screens/Select/Details => Overlays/BeatmapSet}/AdvancedStats.cs (99%) rename osu.Game/{Screens/Select/Details => Overlays/BeatmapSet}/FailRetryGraph.cs (98%) rename osu.Game/{Screens/Select/Details => Overlays/BeatmapSet}/UserRatings.cs (99%) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs b/osu.Game.Tests/Visual/Online/TestSceneAdvancedStats.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs rename to osu.Game.Tests/Visual/Online/TestSceneAdvancedStats.cs index 3afc8cd1a4..2ceb8ff0be 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneAdvancedStats.cs @@ -12,15 +12,15 @@ using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Localisation; +using osu.Game.Overlays.BeatmapSet; using osu.Game.Rulesets; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.Select.Details; using osuTK.Graphics; -namespace osu.Game.Tests.Visual.SongSelect +namespace osu.Game.Tests.Visual.Online { [System.ComponentModel.Description("Advanced beatmap statistics display")] public partial class TestSceneAdvancedStats : OsuTestScene diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index b164c530cb..13d668e58c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -22,7 +22,6 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.BeatmapSet.Scores; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.Select.Details; using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Online diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs index 69c9faa9d3..89be688cf2 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs @@ -12,7 +12,6 @@ using osu.Game.Beatmaps; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapSet; -using osu.Game.Screens.Select.Details; namespace osu.Game.Tests.Visual.Online { diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs index 59c96ec719..7f88f1ebd1 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs @@ -16,7 +16,6 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapSet; -using osu.Game.Screens.Select.Details; using osuTK; using osuTK.Graphics; diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Overlays/BeatmapSet/AdvancedStats.cs similarity index 99% rename from osu.Game/Screens/Select/Details/AdvancedStats.cs rename to osu.Game/Overlays/BeatmapSet/AdvancedStats.cs index 2d105ae382..ae2b421edc 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Overlays/BeatmapSet/AdvancedStats.cs @@ -4,36 +4,36 @@ #nullable disable using System; -using osuTK.Graphics; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Beatmaps; -using osu.Framework.Bindables; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using osu.Game.Rulesets.Mods; -using System.Threading; -using System.Threading.Tasks; -using JetBrains.Annotations; -using osu.Framework.Extensions; using osu.Framework.Localisation; using osu.Framework.Threading; using osu.Framework.Utils; +using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.Mods; using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; -using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; using osu.Game.Utils; +using osuTK.Graphics; -namespace osu.Game.Screens.Select.Details +namespace osu.Game.Overlays.BeatmapSet { public partial class AdvancedStats : Container { diff --git a/osu.Game/Overlays/BeatmapSet/Details.cs b/osu.Game/Overlays/BeatmapSet/Details.cs index 7d69cb7329..50c5d5e4c5 100644 --- a/osu.Game/Overlays/BeatmapSet/Details.cs +++ b/osu.Game/Overlays/BeatmapSet/Details.cs @@ -11,7 +11,6 @@ using osu.Game.Beatmaps; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.BeatmapSet.Buttons; using osu.Game.Rulesets; -using osu.Game.Screens.Select.Details; using osuTK; namespace osu.Game.Overlays.BeatmapSet diff --git a/osu.Game/Screens/Select/Details/FailRetryGraph.cs b/osu.Game/Overlays/BeatmapSet/FailRetryGraph.cs similarity index 98% rename from osu.Game/Screens/Select/Details/FailRetryGraph.cs rename to osu.Game/Overlays/BeatmapSet/FailRetryGraph.cs index 9891ef6463..697c879a35 100644 --- a/osu.Game/Screens/Select/Details/FailRetryGraph.cs +++ b/osu.Game/Overlays/BeatmapSet/FailRetryGraph.cs @@ -4,15 +4,15 @@ #nullable disable using System; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; -using System.Linq; -using osu.Game.Beatmaps; -namespace osu.Game.Screens.Select.Details +namespace osu.Game.Overlays.BeatmapSet { public partial class FailRetryGraph : Container { diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index 48732ac586..28190580da 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -14,7 +14,6 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; -using osu.Game.Screens.Select.Details; namespace osu.Game.Overlays.BeatmapSet { diff --git a/osu.Game/Screens/Select/Details/UserRatings.cs b/osu.Game/Overlays/BeatmapSet/UserRatings.cs similarity index 99% rename from osu.Game/Screens/Select/Details/UserRatings.cs rename to osu.Game/Overlays/BeatmapSet/UserRatings.cs index 3664a89394..3f65c055f8 100644 --- a/osu.Game/Screens/Select/Details/UserRatings.cs +++ b/osu.Game/Overlays/BeatmapSet/UserRatings.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Resources.Localisation.Web; -namespace osu.Game.Screens.Select.Details +namespace osu.Game.Overlays.BeatmapSet { public partial class UserRatings : Container { From 54a1417dd87732301b4c8355705950a8950c0134 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 18:15:51 +0900 Subject: [PATCH 09/15] Move leaderboards classes to gameplay namespace for now --- ...stSceneDrawableGameplayLeaderboardScore.cs | 2 +- .../Gameplay/TestSceneGameplayLeaderboard.cs | 2 +- .../TestSceneHUDOverlayRulesetLayouts.cs | 2 +- .../TestSceneSkinEditorMultipleSkins.cs | 2 +- .../Gameplay/TestSceneSkinnableHUDOverlay.cs | 2 +- ...estSceneSoloGameplayLeaderboardProvider.cs | 2 +- ...MultiplayerGameplayLeaderboardTestScene.cs | 2 +- .../TestSceneMultiSpectatorLeaderboard.cs | 2 +- ...TestSceneMultiplayerGameplayLeaderboard.cs | 2 +- ...ceneMultiplayerGameplayLeaderboardTeams.cs | 2 +- .../TestSceneMultiplayerPositionDisplay.cs | 2 +- .../Navigation/TestSceneScreenNavigation.cs | 2 +- .../TestSceneLeaderboardScopeSelector.cs | 2 +- .../Ranking/TestSceneSoloResultsScreen.cs | 2 +- .../TestSceneBeatmapLeaderboardWedge.cs | 2 +- .../SongSelectV2/TestSceneSongSelect.cs | 2 +- osu.Game/Configuration/OsuConfigManager.cs | 2 +- osu.Game/Extensions/ModelExtensions.cs | 2 +- .../Online/API/Requests/GetScoresRequest.cs | 2 +- .../Online/Leaderboards/LeaderboardManager.cs | 2 +- .../Leaderboards/LeaderboardSortMode.cs | 2 +- osu.Game/OsuGame.cs | 2 +- .../BeatmapSet/LeaderboardScopeSelector.cs | 2 +- .../BeatmapSet/Scores/NoScoresPlaceholder.cs | 2 +- .../BeatmapSet/Scores/ScoresContainer.cs | 2 +- osu.Game/Scoring/ScoreInfoExtensions.cs | 2 +- .../Screens/Edit/GameplayTest/EditorPlayer.cs | 2 +- .../Multiplayer/MultiplayerPlayer.cs | 2 +- .../Multiplayer/MultiplayerPositionDisplay.cs | 2 +- .../Spectate/MultiSpectatorPlayer.cs | 2 +- .../Spectate/MultiSpectatorScreen.cs | 2 +- .../OnlinePlay/Playlists/PlaylistsPlayer.cs | 2 +- .../Play/HUD/DrawableGameplayLeaderboard.cs | 2 +- .../HUD/DrawableGameplayLeaderboardScore.cs | 2 +- .../Leaderboards/BeatmapLeaderboardScope.cs | 2 +- .../Leaderboards/GameplayLeaderboardScore.cs | 3 +- .../IGameplayLeaderboardProvider.cs | 2 +- .../MultiSpectatorLeaderboardProvider.cs | 2 +- .../MultiplayerLeaderboardProvider.cs | 2 +- .../PlaylistsGameplayLeaderboardProvider.cs | 3 +- .../SoloGameplayLeaderboardProvider.cs | 3 +- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- osu.Game/Screens/Play/ReplayPlayer.cs | 2 +- osu.Game/Screens/Play/SoloPlayer.cs | 2 +- osu.Game/Screens/Play/SoloSpectatorPlayer.cs | 2 +- osu.Game/Screens/Ranking/SoloResultsScreen.cs | 2 +- .../Select/Leaderboards/BeatmapLeaderboard.cs | 138 ------------------ .../SelectV2/BeatmapDetailsArea.Header.cs | 3 +- .../SelectV2/BeatmapLeaderboardWedge.cs | 2 +- 49 files changed, 49 insertions(+), 189 deletions(-) rename osu.Game/{Screens/Select => Online}/Leaderboards/LeaderboardSortMode.cs (95%) rename osu.Game/Screens/{Select => Play}/Leaderboards/BeatmapLeaderboardScope.cs (95%) rename osu.Game/Screens/{Select => Play}/Leaderboards/GameplayLeaderboardScore.cs (98%) rename osu.Game/Screens/{Select => Play}/Leaderboards/IGameplayLeaderboardProvider.cs (94%) rename osu.Game/Screens/{Select => Play}/Leaderboards/MultiSpectatorLeaderboardProvider.cs (95%) rename osu.Game/Screens/{Select => Play}/Leaderboards/MultiplayerLeaderboardProvider.cs (99%) rename osu.Game/Screens/{Select => Play}/Leaderboards/PlaylistsGameplayLeaderboardProvider.cs (98%) rename osu.Game/Screens/{Select => Play}/Leaderboards/SoloGameplayLeaderboardProvider.cs (98%) delete mode 100644 osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableGameplayLeaderboardScore.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableGameplayLeaderboardScore.cs index 1363ef12a9..e17f1349b3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableGameplayLeaderboardScore.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableGameplayLeaderboardScore.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Online.API.Requests.Responses; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osuTK.Graphics; namespace osu.Game.Tests.Visual.Gameplay diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 45e14053e0..764a8569e6 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -21,7 +21,7 @@ using osu.Game.Rulesets.Osu; using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Tests.Gameplay; using osuTK.Graphics; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlayRulesetLayouts.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlayRulesetLayouts.cs index e67c2d9f09..131b901d6f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlayRulesetLayouts.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlayRulesetLayouts.cs @@ -25,7 +25,7 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Scoring; using osu.Game.Screens.Play; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Skinning; using osu.Game.Tests.Gameplay; using osu.Game.Tests.Visual.Spectator; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs index 76daffbbad..824e4f6a1c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs @@ -15,7 +15,7 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Edit; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Tests.Gameplay; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs index 6e4f3af70a..e42e8f994e 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs @@ -21,7 +21,7 @@ using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Skinning; using osu.Game.Tests.Gameplay; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboardProvider.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboardProvider.cs index 7e728a84ca..e45c4607f9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboardProvider.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboardProvider.cs @@ -10,7 +10,7 @@ using osu.Game.Online.Leaderboards; using osu.Game.Rulesets.Osu; using osu.Game.Scoring; using osu.Game.Screens.Play; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Tests.Gameplay; namespace osu.Game.Tests.Visual.Gameplay diff --git a/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs index 955737578a..801a748105 100644 --- a/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs @@ -21,7 +21,7 @@ using osu.Game.Online.Spectator; using osu.Game.Replays.Legacy; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs index c39708352e..68a2fec0ea 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs @@ -10,7 +10,7 @@ using osu.Framework.Timing; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs index 53e265decb..3cf95b3304 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs @@ -9,7 +9,7 @@ using osu.Game.Online.API; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs index 6141820cb7..6e5add006a 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs @@ -7,7 +7,7 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPositionDisplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPositionDisplay.cs index 9123f63f56..05430cae33 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPositionDisplay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPositionDisplay.cs @@ -12,7 +12,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Osu; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.Play; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Tests.Gameplay; namespace osu.Game.Tests.Visual.Multiplayer diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index b720772cac..1062f32efb 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -48,9 +48,9 @@ using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Screens.SelectV2; using osu.Game.Tests.Beatmaps.IO; using osu.Game.Tests.Resources; diff --git a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs index 4c67f778a2..e4e79e6459 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs @@ -4,9 +4,9 @@ using osu.Game.Overlays.BeatmapSet; using osu.Framework.Graphics; using osu.Framework.Bindables; -using osu.Game.Screens.Select.Leaderboards; using osu.Framework.Allocation; using osu.Game.Overlays; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Tests.Visual.Online { diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs b/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs index e75c831a7f..266adf1ee8 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs @@ -19,8 +19,8 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Leaderboards; using osu.Game.Rulesets; using osu.Game.Scoring; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Ranking diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs index 1c3a5e4bab..4609bd8936 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs @@ -25,7 +25,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; using osu.Game.Users; diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs index f47eafc937..2434924393 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs @@ -20,9 +20,9 @@ using osu.Game.Rulesets.Osu.Mods; using osu.Game.Scoring; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; using osuTK.Input; diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 97bc53388d..ab6a687cb6 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -14,6 +14,7 @@ using osu.Game.Beatmaps.Drawables.Cards; using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.Localisation; +using osu.Game.Online.Leaderboards; using osu.Game.Overlays; using osu.Game.Overlays.Dashboard.Friends; using osu.Game.Overlays.Mods.Input; @@ -22,7 +23,6 @@ using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Skinning; using osu.Game.Users; diff --git a/osu.Game/Extensions/ModelExtensions.cs b/osu.Game/Extensions/ModelExtensions.cs index 7c9d929999..3b17ee104f 100644 --- a/osu.Game/Extensions/ModelExtensions.cs +++ b/osu.Game/Extensions/ModelExtensions.cs @@ -8,7 +8,7 @@ using osu.Game.IO; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Users; namespace osu.Game.Extensions diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index 87fb54a5a9..eb0c82e790 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -4,7 +4,6 @@ using System; using osu.Game.Beatmaps; using osu.Game.Rulesets; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mods; using System.Collections.Generic; @@ -12,6 +11,7 @@ using System.Globalization; using System.Linq; using osu.Framework.IO.Network; using osu.Game.Extensions; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Online.API.Requests { diff --git a/osu.Game/Online/Leaderboards/LeaderboardManager.cs b/osu.Game/Online/Leaderboards/LeaderboardManager.cs index de53acc3f6..d4a258a307 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardManager.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardManager.cs @@ -18,7 +18,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using Realms; namespace osu.Game.Online.Leaderboards diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardSortMode.cs b/osu.Game/Online/Leaderboards/LeaderboardSortMode.cs similarity index 95% rename from osu.Game/Screens/Select/Leaderboards/LeaderboardSortMode.cs rename to osu.Game/Online/Leaderboards/LeaderboardSortMode.cs index d5fb2f3c54..2f2418763d 100644 --- a/osu.Game/Screens/Select/Leaderboards/LeaderboardSortMode.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardSortMode.cs @@ -4,7 +4,7 @@ using osu.Framework.Localisation; using osu.Game.Localisation; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Online.Leaderboards { public enum LeaderboardSortMode { diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b671360d77..0785ecaeaf 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -69,8 +69,8 @@ using osu.Game.Screens.OnlinePlay.Matchmaking.Queue; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Screens.SelectV2; using osu.Game.Seasonal; using osu.Game.Skinning; diff --git a/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs b/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs index 12fbc4c790..ed00f4b0e2 100644 --- a/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs @@ -1,13 +1,13 @@ // 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.Screens.Select.Leaderboards; using osu.Game.Graphics.UserInterface; using osu.Framework.Allocation; using osuTK.Graphics; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Graphics; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Overlays.BeatmapSet { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs b/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs index b161ee49c6..a3e406ac8d 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs @@ -3,10 +3,10 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Screens.Select.Leaderboards; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Overlays.BeatmapSet.Scores { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index cc06383274..63729319db 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -19,7 +19,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osuTK; using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; diff --git a/osu.Game/Scoring/ScoreInfoExtensions.cs b/osu.Game/Scoring/ScoreInfoExtensions.cs index 2eec0399d6..fc367554e7 100644 --- a/osu.Game/Scoring/ScoreInfoExtensions.cs +++ b/osu.Game/Scoring/ScoreInfoExtensions.cs @@ -7,8 +7,8 @@ using System.Linq; using osu.Game.Beatmaps; using osu.Game.Models; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Leaderboards; using osu.Game.Rulesets.Scoring; -using osu.Game.Screens.Select.Leaderboards; using Realms; namespace osu.Game.Scoring diff --git a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs index 2c9b97114d..32762135e5 100644 --- a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs +++ b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs @@ -18,8 +18,8 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Scoring; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Users; namespace osu.Game.Screens.Edit.GameplayTest diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 4cc6f3469d..d7cbd02918 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -17,8 +17,8 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Scoring; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Users; using osuTK; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPositionDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPositionDisplay.cs index a2b9db5a06..f2cbc41d16 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPositionDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPositionDisplay.cs @@ -18,7 +18,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Screens.Play; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osuTK; using osuTK.Graphics; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index e557c6821b..070cda327a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -8,8 +8,8 @@ using osu.Framework.Audio; using osu.Game.Beatmaps; using osu.Game.Scoring; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index f0b0709ab2..ad7966587e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -17,7 +17,7 @@ using osu.Game.Online.Rooms; using osu.Game.Online.Spectator; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Spectate; using osu.Game.Users; using osuTK; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs index 69a1e3b763..ecd45370fc 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs @@ -12,8 +12,8 @@ using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Scoring; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Users; namespace osu.Game.Screens.OnlinePlay.Playlists diff --git a/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboard.cs index ddb926ebf1..cd3ee73018 100644 --- a/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboard.cs @@ -12,7 +12,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Localisation.SkinComponents; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Skinning; using osuTK; using osuTK.Graphics; diff --git a/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs index ef27d027c2..f7220e98ac 100644 --- a/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/DrawableGameplayLeaderboardScore.cs @@ -16,7 +16,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.API; using osu.Game.Rulesets.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Users; using osu.Game.Users.Drawables; using osu.Game.Utils; diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs b/osu.Game/Screens/Play/Leaderboards/BeatmapLeaderboardScope.cs similarity index 95% rename from osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs rename to osu.Game/Screens/Play/Leaderboards/BeatmapLeaderboardScope.cs index 497e456881..555a2a72c5 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs +++ b/osu.Game/Screens/Play/Leaderboards/BeatmapLeaderboardScope.cs @@ -4,7 +4,7 @@ using osu.Framework.Localisation; using osu.Game.Localisation; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Screens.Play.Leaderboards { public enum BeatmapLeaderboardScope { diff --git a/osu.Game/Screens/Select/Leaderboards/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/Leaderboards/GameplayLeaderboardScore.cs similarity index 98% rename from osu.Game/Screens/Select/Leaderboards/GameplayLeaderboardScore.cs rename to osu.Game/Screens/Play/Leaderboards/GameplayLeaderboardScore.cs index dfe95b8ccd..eb65306ae4 100644 --- a/osu.Game/Screens/Select/Leaderboards/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/Leaderboards/GameplayLeaderboardScore.cs @@ -9,10 +9,9 @@ using osu.Game.Online.Spectator; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Scoring.Legacy; -using osu.Game.Screens.Play; using osu.Game.Users; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Screens.Play.Leaderboards { /// /// Represents a score shown on a gameplay leaderboard. diff --git a/osu.Game/Screens/Select/Leaderboards/IGameplayLeaderboardProvider.cs b/osu.Game/Screens/Play/Leaderboards/IGameplayLeaderboardProvider.cs similarity index 94% rename from osu.Game/Screens/Select/Leaderboards/IGameplayLeaderboardProvider.cs rename to osu.Game/Screens/Play/Leaderboards/IGameplayLeaderboardProvider.cs index 9c4875477c..350569f46f 100644 --- a/osu.Game/Screens/Select/Leaderboards/IGameplayLeaderboardProvider.cs +++ b/osu.Game/Screens/Play/Leaderboards/IGameplayLeaderboardProvider.cs @@ -3,7 +3,7 @@ using osu.Framework.Bindables; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Screens.Play.Leaderboards { /// /// Provides a leaderboard to show during gameplay. diff --git a/osu.Game/Screens/Select/Leaderboards/MultiSpectatorLeaderboardProvider.cs b/osu.Game/Screens/Play/Leaderboards/MultiSpectatorLeaderboardProvider.cs similarity index 95% rename from osu.Game/Screens/Select/Leaderboards/MultiSpectatorLeaderboardProvider.cs rename to osu.Game/Screens/Play/Leaderboards/MultiSpectatorLeaderboardProvider.cs index 19ae12a6ca..a6f75e6ca1 100644 --- a/osu.Game/Screens/Select/Leaderboards/MultiSpectatorLeaderboardProvider.cs +++ b/osu.Game/Screens/Play/Leaderboards/MultiSpectatorLeaderboardProvider.cs @@ -5,7 +5,7 @@ using System; using osu.Framework.Timing; using osu.Game.Online.Multiplayer; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Screens.Play.Leaderboards { public partial class MultiSpectatorLeaderboardProvider : MultiplayerLeaderboardProvider { diff --git a/osu.Game/Screens/Select/Leaderboards/MultiplayerLeaderboardProvider.cs b/osu.Game/Screens/Play/Leaderboards/MultiplayerLeaderboardProvider.cs similarity index 99% rename from osu.Game/Screens/Select/Leaderboards/MultiplayerLeaderboardProvider.cs rename to osu.Game/Screens/Play/Leaderboards/MultiplayerLeaderboardProvider.cs index 08af8926df..01bc56c1b5 100644 --- a/osu.Game/Screens/Select/Leaderboards/MultiplayerLeaderboardProvider.cs +++ b/osu.Game/Screens/Play/Leaderboards/MultiplayerLeaderboardProvider.cs @@ -24,7 +24,7 @@ using osu.Game.Online.Spectator; using osu.Game.Rulesets.Scoring; using osuTK.Graphics; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Screens.Play.Leaderboards { [LongRunningLoad] public partial class MultiplayerLeaderboardProvider : CompositeComponent, IGameplayLeaderboardProvider diff --git a/osu.Game/Screens/Select/Leaderboards/PlaylistsGameplayLeaderboardProvider.cs b/osu.Game/Screens/Play/Leaderboards/PlaylistsGameplayLeaderboardProvider.cs similarity index 98% rename from osu.Game/Screens/Select/Leaderboards/PlaylistsGameplayLeaderboardProvider.cs rename to osu.Game/Screens/Play/Leaderboards/PlaylistsGameplayLeaderboardProvider.cs index ea0a2b68dc..7efbfe23a8 100644 --- a/osu.Game/Screens/Select/Leaderboards/PlaylistsGameplayLeaderboardProvider.cs +++ b/osu.Game/Screens/Play/Leaderboards/PlaylistsGameplayLeaderboardProvider.cs @@ -9,9 +9,8 @@ using osu.Framework.Caching; using osu.Framework.Graphics; using osu.Game.Online.API; using osu.Game.Online.Rooms; -using osu.Game.Screens.Play; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Screens.Play.Leaderboards { [LongRunningLoad] public partial class PlaylistsGameplayLeaderboardProvider : Component, IGameplayLeaderboardProvider diff --git a/osu.Game/Screens/Select/Leaderboards/SoloGameplayLeaderboardProvider.cs b/osu.Game/Screens/Play/Leaderboards/SoloGameplayLeaderboardProvider.cs similarity index 98% rename from osu.Game/Screens/Select/Leaderboards/SoloGameplayLeaderboardProvider.cs rename to osu.Game/Screens/Play/Leaderboards/SoloGameplayLeaderboardProvider.cs index fd4ad142a4..62d1220c50 100644 --- a/osu.Game/Screens/Select/Leaderboards/SoloGameplayLeaderboardProvider.cs +++ b/osu.Game/Screens/Play/Leaderboards/SoloGameplayLeaderboardProvider.cs @@ -9,9 +9,8 @@ using osu.Framework.Caching; using osu.Framework.Graphics; using osu.Game.Online.Leaderboards; using osu.Game.Scoring; -using osu.Game.Screens.Play; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Screens.Play.Leaderboards { public partial class SoloGameplayLeaderboardProvider : Component, IGameplayLeaderboardProvider { diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index df535169b3..d082ce6a57 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -34,8 +34,8 @@ using osu.Game.Performance; using osu.Game.Screens.Footer; using osu.Game.Screens.Menu; using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Play.PlayerSettings; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Skinning; using osu.Game.Users; using osu.Game.Utils; diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index b9a6de54b4..cd769d7615 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -15,9 +15,9 @@ using osu.Game.Configuration; using osu.Game.Input.Bindings; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Skinning; using osu.Game.Users; diff --git a/osu.Game/Screens/Play/SoloPlayer.cs b/osu.Game/Screens/Play/SoloPlayer.cs index 1e9222e40a..ee891dd816 100644 --- a/osu.Game/Screens/Play/SoloPlayer.cs +++ b/osu.Game/Screens/Play/SoloPlayer.cs @@ -13,7 +13,7 @@ using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Online.Solo; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Screens.Play { diff --git a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs index d635fa9fe9..c0950929ba 100644 --- a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs @@ -6,7 +6,7 @@ using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Screens; using osu.Game.Online.Spectator; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Users; namespace osu.Game.Screens.Play diff --git a/osu.Game/Screens/Ranking/SoloResultsScreen.cs b/osu.Game/Screens/Ranking/SoloResultsScreen.cs index 5e0095611c..1ed6f70f23 100644 --- a/osu.Game/Screens/Ranking/SoloResultsScreen.cs +++ b/osu.Game/Screens/Ranking/SoloResultsScreen.cs @@ -12,7 +12,7 @@ using osu.Game.Extensions; using osu.Game.Online.API; using osu.Game.Online.Leaderboards; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; namespace osu.Game.Screens.Ranking { diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs deleted file mode 100644 index ddb7814d12..0000000000 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ /dev/null @@ -1,138 +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 System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Game.Beatmaps; -using osu.Game.Online.API; -using osu.Game.Online.Leaderboards; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Scoring; - -namespace osu.Game.Screens.Select.Leaderboards -{ - public partial class BeatmapLeaderboard : Leaderboard - { - public Action? ScoreSelected; - - private BeatmapInfo? beatmapInfo; - - public BeatmapInfo? BeatmapInfo - { - get => beatmapInfo; - set - { - if (beatmapInfo == null && value == null) - return; - - if (beatmapInfo?.Equals(value) == true) - return; - - beatmapInfo = value; - - // Refetch is scheduled, which can cause scores to be outdated if the leaderboard is not currently updating. - // As scores are potentially used by other components, clear them eagerly to ensure a more correct state. - SetScores(null); - - RefetchScores(); - } - } - - private bool filterMods; - - /// - /// Whether to apply the game's currently selected mods as a filter when retrieving scores. - /// - public bool FilterMods - { - get => filterMods; - set - { - if (value == filterMods) - return; - - filterMods = value; - - RefetchScores(); - } - } - - private readonly IBindable fetchedScores = new Bindable(); - - [Resolved] - private IBindable ruleset { get; set; } = null!; - - [Resolved] - private IBindable> mods { get; set; } = null!; - - [Resolved] - private LeaderboardManager leaderboardManager { get; set; } = null!; - - [BackgroundDependencyLoader] - private void load() - { - ruleset.ValueChanged += _ => RefetchScores(); - mods.ValueChanged += _ => - { - if (filterMods) - RefetchScores(); - }; - } - - private bool initialFetchComplete; - - protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local; - - protected override APIRequest? FetchScores(CancellationToken cancellationToken) - { - var fetchBeatmapInfo = BeatmapInfo; - var fetchRuleset = ruleset.Value ?? fetchBeatmapInfo?.Ruleset; - - // Without this check, an initial fetch will be performed and clear global cache. - if (fetchBeatmapInfo == null) - return null; - - // For now, we forcefully refresh to keep things simple. - // In the future, removing this requirement may be deemed useful, but will need ample testing of edge case scenarios - // (like returning from gameplay after setting a new score, returning to song select after main menu). - leaderboardManager.FetchWithCriteria(new LeaderboardCriteria(fetchBeatmapInfo, fetchRuleset, Scope, filterMods ? mods.Value.Where(m => m.UserPlayable).ToArray() : null), forceRefresh: true); - - if (!initialFetchComplete) - { - // only bind this after the first fetch to avoid reading stale scores. - fetchedScores.BindTo(leaderboardManager.Scores); - fetchedScores.BindValueChanged(_ => updateScores(), true); - initialFetchComplete = true; - } - - return null; - } - - private void updateScores() - { - var scores = fetchedScores.Value; - - if (scores == null) return; - - if (scores.FailState == null) - Schedule(() => SetScores(scores.TopScores, scores.UserScore)); - else - Schedule(() => SetErrorState((LeaderboardState)scores.FailState)); - } - - protected override LeaderboardScore CreateDrawableScore(ScoreInfo model, int index) => new LeaderboardScore(model, index, IsOnlineScope, Scope != BeatmapLeaderboardScope.Friend) - { - Action = () => ScoreSelected?.Invoke(model) - }; - - protected override LeaderboardScore CreateDrawableTopScore(ScoreInfo model) => new LeaderboardScore(model, model.Position, false, Scope != BeatmapLeaderboardScope.Friend) - { - Action = () => ScoreSelected?.Invoke(model) - }; - } -} diff --git a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs b/osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs index f4a223985d..5b3f27ce64 100644 --- a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs +++ b/osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs @@ -12,8 +12,9 @@ using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; +using osu.Game.Online.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Leaderboards; using osuTK; namespace osu.Game.Screens.SelectV2 diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs b/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs index 3c91185c21..18b1bc2e27 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs +++ b/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs @@ -33,7 +33,7 @@ using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Play.Leaderboards; using osuTK; using osuTK.Graphics; From 1a8d2855d4add4f8d86660d7fe890e1be94fcd6b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 19:08:44 +0900 Subject: [PATCH 10/15] Remove all song select v1 files This contains no code changes (that would need review), only file deletion and extraction where required in a few odd cases. --- .../TestSceneBeatmapMetadataDisplay.cs | 2 +- .../TestSceneUserTopScoreContainer.cs | 6 +- .../TestSceneMatchBeatmapDetailArea.cs | 52 - .../SongSelect/TestSceneBeatmapCarousel.cs | 1467 ----------------- .../SongSelect/TestSceneBeatmapDetails.cs | 162 -- .../SongSelect/TestSceneBeatmapInfoWedge.cs | 305 ---- .../TestSceneBeatmapOptionsOverlay.cs | 31 - .../SongSelect/TestSceneFilterControl.cs | 24 - .../SongSelect/TestSceneSongSelectFooter.cs | 109 -- .../SongSelect/TestSceneTopLocalRank.cs | 224 --- .../TestSceneUpdateBeatmapSetButton.cs | 262 --- .../TestSceneCollectionDropdown.cs | 2 +- .../TestSceneFooterButtonMods.cs | 99 -- .../Graphics/UserInterface/TwoLayerButton.cs | 23 +- .../Overlays/Settings/Sections/SkinSection.cs | 23 +- .../BeatmapDetailAreaPlaylistTabItem.cs | 12 - .../Components/MatchBeatmapDetailArea.cs | 110 -- osu.Game/Screens/Select/BeatmapCarousel.cs | 1280 -------------- osu.Game/Screens/Select/BeatmapDetailArea.cs | 108 -- .../Select/BeatmapDetailAreaDetailTabItem.cs | 10 - .../BeatmapDetailAreaLeaderboardTabItem.cs | 22 - .../Select/BeatmapDetailAreaTabControl.cs | 108 -- .../Select/BeatmapDetailAreaTabItem.cs | 37 - osu.Game/Screens/Select/BeatmapDetails.cs | 278 ---- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 517 ------ .../Select/BeatmapInfoWedgeBackground.cs | 65 - .../Select/Carousel/CarouselBeatmap.cs | 161 -- .../Select/Carousel/CarouselBeatmapSet.cs | 184 --- .../Screens/Select/Carousel/CarouselGroup.cs | 140 -- .../Carousel/CarouselGroupEagerSelect.cs | 159 -- .../Screens/Select/Carousel/CarouselHeader.cs | 168 -- .../Screens/Select/Carousel/CarouselItem.cs | 66 - .../Carousel/DrawableCarouselBeatmap.cs | 321 ---- .../Carousel/DrawableCarouselBeatmapSet.cs | 356 ---- .../Select/Carousel/DrawableCarouselItem.cs | 177 -- .../Carousel/FilterableDifficultyIcon.cs | 35 - .../Select/Carousel/GroupedDifficultyIcon.cs | 60 - .../Select/Carousel/SetPanelBackground.cs | 92 -- .../Select/Carousel/SetPanelContent.cs | 117 -- .../Screens/Select/Carousel/TopLocalRank.cs | 86 - .../Select/Carousel/UpdateBeatmapSetButton.cs | 178 -- osu.Game/Screens/Select/FilterControl.cs | 309 ---- osu.Game/Screens/Select/Footer.cs | 124 -- osu.Game/Screens/Select/FooterButton.cs | 234 --- osu.Game/Screens/Select/FooterButtonMods.cs | 143 -- .../Screens/Select/FooterButtonOptions.cs | 22 - osu.Game/Screens/Select/FooterButtonRandom.cs | 169 -- .../Screens/Select/NoResultsPlaceholder.cs | 155 -- .../Select/Options/BeatmapOptionsButton.cs | 159 -- .../Select/Options/BeatmapOptionsOverlay.cs | 137 -- .../Screens/Select/PlayBeatmapDetailArea.cs | 150 -- osu.Game/Screens/Select/SkinDeleteDialog.cs | 30 - osu.Game/Screens/Select/SongSelect.cs | 1184 ------------- osu.Game/Screens/Select/WedgeBackground.cs | 39 - .../SelectV2/LeftSideInteractionContainer.cs | 60 + osu.Game/Screens/SelectV2/SongSelect.cs | 4 +- 56 files changed, 101 insertions(+), 10456 deletions(-) rename osu.Game.Tests/Visual/{SongSelect => Gameplay}/TestSceneBeatmapMetadataDisplay.cs (99%) rename osu.Game.Tests/Visual/{SongSelect => Gameplay}/TestSceneUserTopScoreContainer.cs (98%) delete mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs rename osu.Game.Tests/Visual/{SongSelect => UserInterface}/TestSceneCollectionDropdown.cs (99%) delete mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Components/BeatmapDetailAreaPlaylistTabItem.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs delete mode 100644 osu.Game/Screens/Select/BeatmapCarousel.cs delete mode 100644 osu.Game/Screens/Select/BeatmapDetailArea.cs delete mode 100644 osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs delete mode 100644 osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs delete mode 100644 osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs delete mode 100644 osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs delete mode 100644 osu.Game/Screens/Select/BeatmapDetails.cs delete mode 100644 osu.Game/Screens/Select/BeatmapInfoWedge.cs delete mode 100644 osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs delete mode 100644 osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs delete mode 100644 osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs delete mode 100644 osu.Game/Screens/Select/Carousel/CarouselGroup.cs delete mode 100644 osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs delete mode 100644 osu.Game/Screens/Select/Carousel/CarouselHeader.cs delete mode 100644 osu.Game/Screens/Select/Carousel/CarouselItem.cs delete mode 100644 osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs delete mode 100644 osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs delete mode 100644 osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs delete mode 100644 osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs delete mode 100644 osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs delete mode 100644 osu.Game/Screens/Select/Carousel/SetPanelBackground.cs delete mode 100644 osu.Game/Screens/Select/Carousel/SetPanelContent.cs delete mode 100644 osu.Game/Screens/Select/Carousel/TopLocalRank.cs delete mode 100644 osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs delete mode 100644 osu.Game/Screens/Select/FilterControl.cs delete mode 100644 osu.Game/Screens/Select/Footer.cs delete mode 100644 osu.Game/Screens/Select/FooterButton.cs delete mode 100644 osu.Game/Screens/Select/FooterButtonMods.cs delete mode 100644 osu.Game/Screens/Select/FooterButtonOptions.cs delete mode 100644 osu.Game/Screens/Select/FooterButtonRandom.cs delete mode 100644 osu.Game/Screens/Select/NoResultsPlaceholder.cs delete mode 100644 osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs delete mode 100644 osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs delete mode 100644 osu.Game/Screens/Select/PlayBeatmapDetailArea.cs delete mode 100644 osu.Game/Screens/Select/SkinDeleteDialog.cs delete mode 100644 osu.Game/Screens/Select/SongSelect.cs delete mode 100644 osu.Game/Screens/Select/WedgeBackground.cs create mode 100644 osu.Game/Screens/SelectV2/LeftSideInteractionContainer.cs diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapMetadataDisplay.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs rename to osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapMetadataDisplay.cs index a9829fbf0c..63a0198ef5 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapMetadataDisplay.cs @@ -19,7 +19,7 @@ using osu.Game.Screens.Menu; using osu.Game.Screens.Play; using osuTK; -namespace osu.Game.Tests.Visual.SongSelect +namespace osu.Game.Tests.Visual.Gameplay { public partial class TestSceneBeatmapMetadataDisplay : OsuTestScene { diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneUserTopScoreContainer.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs rename to osu.Game.Tests/Visual/Gameplay/TestSceneUserTopScoreContainer.cs index 30f1803795..8edf83631a 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneUserTopScoreContainer.cs @@ -6,16 +6,16 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Online.API.Requests.Responses; -using osuTK.Graphics; using osu.Game.Online.Leaderboards; using osu.Game.Overlays; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; -using osu.Game.Scoring; using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Scoring; using osu.Game.Users; +using osuTK.Graphics; -namespace osu.Game.Tests.Visual.SongSelect +namespace osu.Game.Tests.Visual.Gameplay { public partial class TestSceneUserTopScoreContainer : OsuTestScene { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs deleted file mode 100644 index e372d63fde..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs +++ /dev/null @@ -1,52 +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 System.Linq; -using osu.Framework.Graphics; -using osu.Game.Online.API; -using osu.Game.Online.Rooms; -using osu.Game.Rulesets.Osu; -using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.OnlinePlay.Components; -using osu.Game.Tests.Beatmaps; -using osu.Game.Tests.Visual.OnlinePlay; -using osuTK; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - public partial class TestSceneMatchBeatmapDetailArea : OnlinePlayTestScene - { - private Room room = null!; - - public override void SetUpSteps() - { - base.SetUpSteps(); - - AddStep("create area", () => - { - Child = new MatchBeatmapDetailArea(room = new Room()) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(500), - CreateNewItem = createNewItem - }; - }); - } - - private void createNewItem() - { - room.Playlist = room.Playlist.Append(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo) - { - ID = room.Playlist.Count, - RulesetID = new OsuRuleset().RulesetInfo.OnlineID, - RequiredMods = new[] - { - new APIMod(new OsuModHardRock()), - new APIMod(new OsuModDoubleTime()), - new APIMod(new OsuModAutoplay()) - } - }).ToArray(); - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs deleted file mode 100644 index 11e754c868..0000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ /dev/null @@ -1,1467 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Collections.Generic; -using System.Linq; -using JetBrains.Annotations; -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Testing; -using osu.Framework.Utils; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Database; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Catch; -using osu.Game.Rulesets.Osu; -using osu.Game.Rulesets.Taiko; -using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Carousel; -using osu.Game.Screens.Select.Filter; -using osu.Game.Tests.Beatmaps; -using osu.Game.Tests.Resources; -using osuTK.Input; - -namespace osu.Game.Tests.Visual.SongSelect -{ - [TestFixture] - public partial class TestSceneBeatmapCarousel : OsuManualInputManagerTestScene - { - private TestBeatmapCarousel carousel; - private RulesetStore rulesets; - - private readonly Stack selectedSets = new Stack(); - private readonly HashSet eagerSelectedIDs = new HashSet(); - - private BeatmapInfo currentSelection => carousel.SelectedBeatmapInfo; - - private const int set_count = 5; - private const int diff_count = 3; - - [Cached(typeof(BeatmapStore))] - private TestBeatmapStore beatmaps = new TestBeatmapStore(); - - [BackgroundDependencyLoader] - private void load(RulesetStore rulesets) - { - this.rulesets = rulesets; - } - - [Test] - public void TestExternalRulesetChange() - { - createCarousel(new List()); - - AddStep("filter to ruleset 0", () => carousel.FilterImmediately(new FilterCriteria - { - Ruleset = rulesets.AvailableRulesets.ElementAt(0), - AllowConvertedBeatmaps = true, - })); - - AddStep("add mixed ruleset beatmapset", () => - { - var testMixed = TestResources.CreateTestBeatmapSetInfo(3); - - for (int i = 0; i <= 2; i++) - { - testMixed.Beatmaps[i].Ruleset = rulesets.AvailableRulesets.ElementAt(i); - } - - carousel.UpdateBeatmapSet(testMixed); - }); - - AddUntilStep("wait for filtered difficulties", () => - { - var visibleBeatmapPanels = carousel.Items.OfType().Where(p => p.IsPresent).ToArray(); - - return visibleBeatmapPanels.Length == 1 - && visibleBeatmapPanels.Count(p => ((CarouselBeatmap)p.Item)!.BeatmapInfo.Ruleset.OnlineID == 0) == 1; - }); - - AddStep("filter to ruleset 1", () => carousel.FilterImmediately(new FilterCriteria - { - Ruleset = rulesets.AvailableRulesets.ElementAt(1), - AllowConvertedBeatmaps = true, - })); - - AddUntilStep("wait for filtered difficulties", () => - { - var visibleBeatmapPanels = carousel.Items.OfType().Where(p => p.IsPresent).ToArray(); - - return visibleBeatmapPanels.Length == 2 - && visibleBeatmapPanels.Count(p => ((CarouselBeatmap)p.Item)!.BeatmapInfo.Ruleset.OnlineID == 0) == 1 - && visibleBeatmapPanels.Count(p => ((CarouselBeatmap)p.Item)!.BeatmapInfo.Ruleset.OnlineID == 1) == 1; - }); - - AddStep("filter to ruleset 2", () => carousel.FilterImmediately(new FilterCriteria - { - Ruleset = rulesets.AvailableRulesets.ElementAt(2), - AllowConvertedBeatmaps = true, - })); - - AddUntilStep("wait for filtered difficulties", () => - { - var visibleBeatmapPanels = carousel.Items.OfType().Where(p => p.IsPresent).ToArray(); - - return visibleBeatmapPanels.Length == 2 - && visibleBeatmapPanels.Count(p => ((CarouselBeatmap)p.Item!).BeatmapInfo.Ruleset.OnlineID == 0) == 1 - && visibleBeatmapPanels.Count(p => ((CarouselBeatmap)p.Item!).BeatmapInfo.Ruleset.OnlineID == 2) == 1; - }); - } - - [Test] - public void TestScrollPositionMaintainedOnAdd() - { - loadBeatmaps(setCount: 1); - - for (int i = 0; i < 10; i++) - { - AddRepeatStep("Add some sets", () => carousel.UpdateBeatmapSet(TestResources.CreateTestBeatmapSetInfo()), 4); - - checkSelectionIsCentered(); - } - } - - [Test] - public void TestDeletion() - { - loadBeatmaps(setCount: 5, randomDifficulties: true); - - AddStep("remove first set", () => carousel.RemoveBeatmapSet(carousel.Items.Select(item => item.Item).OfType().First().BeatmapSet)); - AddUntilStep("4 beatmap sets visible", () => this.ChildrenOfType().Count(set => set.Alpha > 0) == 4); - } - - [Test] - public void TestScrollPositionMaintainedOnDelete() - { - loadBeatmaps(setCount: 50); - - for (int i = 0; i < 10; i++) - { - AddRepeatStep("Remove some sets", () => - carousel.RemoveBeatmapSet(carousel.Items.Select(item => item.Item) - .OfType() - .OrderBy(item => item.GetHashCode()) - .First(item => item.State.Value != CarouselItemState.Selected && item.Visible).BeatmapSet), 4); - - checkSelectionIsCentered(); - } - } - - [Test] - public void TestManyPanels() - { - loadBeatmaps(setCount: 5000, randomDifficulties: true); - } - - [Test] - public void TestKeyRepeat() - { - loadBeatmaps(); - advanceSelection(false); - - AddStep("press down arrow", () => InputManager.PressKey(Key.Down)); - - BeatmapInfo selection = null; - - checkSelectionIterating(true); - - AddStep("press up arrow", () => InputManager.PressKey(Key.Up)); - - checkSelectionIterating(true); - - AddStep("release down arrow", () => InputManager.ReleaseKey(Key.Down)); - - checkSelectionIterating(true); - - AddStep("release up arrow", () => InputManager.ReleaseKey(Key.Up)); - - checkSelectionIterating(false); - - void checkSelectionIterating(bool isIterating) - { - for (int i = 0; i < 3; i++) - { - AddStep("store selection", () => selection = carousel.SelectedBeatmapInfo); - if (isIterating) - AddUntilStep("selection changed", () => !carousel.SelectedBeatmapInfo?.Equals(selection) == true); - else - AddUntilStep("selection not changed", () => carousel.SelectedBeatmapInfo?.Equals(selection) == true); - } - } - } - - [Test] - public void TestRecommendedSelection() - { - loadBeatmaps(carouselAdjust: carousel => carousel.GetRecommendedBeatmap = beatmaps => beatmaps.LastOrDefault()); - - AddStep("select last", () => carousel.SelectBeatmap(carousel.BeatmapSets.Last().Beatmaps.Last())); - - // check recommended was selected - advanceSelection(direction: 1, diff: false); - waitForSelection(1, 3); - - // change away from recommended - advanceSelection(direction: -1, diff: true); - waitForSelection(1, 2); - - // next set, check recommended - advanceSelection(direction: 1, diff: false); - waitForSelection(2, 3); - - // next set, check recommended - advanceSelection(direction: 1, diff: false); - waitForSelection(3, 3); - - // go back to first set and ensure user selection was retained - advanceSelection(direction: -1, diff: false); - advanceSelection(direction: -1, diff: false); - waitForSelection(1, 2); - } - - /// - /// Test keyboard traversal - /// - [Test] - public void TestTraversal() - { - loadBeatmaps(); - - AddStep("select first", () => carousel.SelectBeatmap(carousel.BeatmapSets.First().Beatmaps.First())); - waitForSelection(1, 1); - - advanceSelection(direction: 1, diff: true); - waitForSelection(1, 2); - - advanceSelection(direction: -1, diff: false); - waitForSelection(set_count, 1); - - advanceSelection(direction: -1, diff: true); - waitForSelection(set_count - 1, 3); - - advanceSelection(diff: false); - advanceSelection(diff: false); - waitForSelection(1, 2); - - advanceSelection(direction: -1, diff: true); - advanceSelection(direction: -1, diff: true); - waitForSelection(set_count, 3); - } - - [TestCase(true)] - [TestCase(false)] - public void TestTraversalBeyondVisible(bool forwards) - { - var sets = new List(); - - const int total_set_count = 200; - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - for (int i = 0; i < total_set_count; i++) - sets.Add(TestResources.CreateTestBeatmapSetInfo()); - }); - - loadBeatmaps(sets); - - for (int i = 1; i < total_set_count; i += i) - selectNextAndAssert(i); - - void selectNextAndAssert(int amount) - { - setSelected(forwards ? 1 : total_set_count, 1); - - AddStep($"{(forwards ? "Next" : "Previous")} beatmap {amount} times", () => - { - for (int i = 0; i < amount; i++) - { - carousel.SelectNext(forwards ? 1 : -1); - } - }); - - waitForSelection(forwards ? amount + 1 : total_set_count - amount); - } - } - - [Test] - public void TestTraversalBeyondVisibleDifficulties() - { - var sets = new List(); - - const int total_set_count = 20; - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - for (int i = 0; i < total_set_count; i++) - sets.Add(TestResources.CreateTestBeatmapSetInfo(3)); - }); - - loadBeatmaps(sets); - - // Selects next set once, difficulty index doesn't change - selectNextAndAssert(3, true, 2, 1); - - // Selects next set 16 times (50 \ 3 == 16), difficulty index changes twice (50 % 3 == 2) - selectNextAndAssert(50, true, 17, 3); - - // Travels around the carousel thrice (200 \ 60 == 3) - // continues to select 20 times (200 \ 60 == 20) - // selects next set 6 times (20 \ 3 == 6) - // difficulty index changes twice (20 % 3 == 2) - selectNextAndAssert(200, true, 7, 3); - - // All same but in reverse - selectNextAndAssert(3, false, 19, 3); - selectNextAndAssert(50, false, 4, 1); - selectNextAndAssert(200, false, 14, 1); - - void selectNextAndAssert(int amount, bool forwards, int expectedSet, int expectedDiff) - { - // Select very first or very last difficulty - setSelected(forwards ? 1 : 20, forwards ? 1 : 3); - - AddStep($"{(forwards ? "Next" : "Previous")} difficulty {amount} times", () => - { - for (int i = 0; i < amount; i++) - carousel.SelectNext(forwards ? 1 : -1, false); - }); - - waitForSelection(expectedSet, expectedDiff); - } - } - - /// - /// Test filtering - /// - [Test] - public void TestFiltering() - { - loadBeatmaps(); - - // basic filtering - setSelected(1, 1); - - AddStep("Filter", () => carousel.FilterImmediately(new FilterCriteria { SearchText = carousel.BeatmapSets.ElementAt(2).Metadata.Title })); - checkVisibleItemCount(diff: false, count: 1); - checkVisibleItemCount(diff: true, count: 3); - waitForSelection(3, 1); - - advanceSelection(diff: true, count: 4); - waitForSelection(3, 2); - - AddStep("Un-filter (debounce)", () => carousel.Filter(new FilterCriteria())); - AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask); - checkVisibleItemCount(diff: false, count: set_count); - checkVisibleItemCount(diff: true, count: 3); - - // test filtering some difficulties (and keeping current beatmap set selected). - - setSelected(1, 2); - AddStep("Filter some difficulties", () => carousel.FilterImmediately(new FilterCriteria { SearchText = "Normal" })); - waitForSelection(1, 1); - - AddStep("Un-filter", () => carousel.FilterImmediately(new FilterCriteria())); - waitForSelection(1, 1); - - AddStep("Filter all", () => carousel.FilterImmediately(new FilterCriteria { SearchText = "Dingo" })); - - checkVisibleItemCount(false, 0); - checkVisibleItemCount(true, 0); - AddAssert("Selection is null", () => currentSelection == null); - - advanceSelection(true); - AddAssert("Selection is null", () => currentSelection == null); - - advanceSelection(false); - AddAssert("Selection is null", () => currentSelection == null); - - AddStep("Un-filter", () => carousel.FilterImmediately(new FilterCriteria())); - - AddAssert("Selection is non-null", () => currentSelection != null); - - setSelected(1, 3); - } - - [Test] - public void TestFilterRange() - { - string searchText = null; - - loadBeatmaps(); - - // buffer the selection - setSelected(3, 2); - - AddStep("get search text", () => searchText = carousel.SelectedBeatmapSet!.Metadata.Title); - - setSelected(1, 3); - - AddStep("Apply a range filter", () => carousel.FilterImmediately(new FilterCriteria - { - SearchText = searchText, - StarDifficulty = new FilterCriteria.OptionalRange - { - Min = 2, - Max = 5.5, - IsLowerInclusive = true - } - })); - - // should reselect the buffered selection. - waitForSelection(3, 2); - } - - /// - /// Test random non-repeating algorithm - /// - [Test] - public void TestRandom() - { - loadBeatmaps(); - - setSelected(1, 1); - - nextRandom(); - ensureRandomDidntRepeat(); - nextRandom(); - ensureRandomDidntRepeat(); - nextRandom(); - ensureRandomDidntRepeat(); - - prevRandom(); - ensureRandomFetchSuccess(); - prevRandom(); - ensureRandomFetchSuccess(); - - nextRandom(); - ensureRandomDidntRepeat(); - nextRandom(); - ensureRandomDidntRepeat(); - - nextRandom(); - AddAssert("ensure repeat", () => selectedSets.Contains(carousel.SelectedBeatmapSet)); - - AddStep("Add set with 100 difficulties", () => carousel.UpdateBeatmapSet(TestResources.CreateTestBeatmapSetInfo(100, rulesets.AvailableRulesets.ToArray()))); - AddStep("Filter Extra", () => carousel.FilterImmediately(new FilterCriteria { SearchText = "Extra 10" })); - checkInvisibleDifficultiesUnselectable(); - checkInvisibleDifficultiesUnselectable(); - checkInvisibleDifficultiesUnselectable(); - checkInvisibleDifficultiesUnselectable(); - checkInvisibleDifficultiesUnselectable(); - AddStep("Un-filter", () => carousel.FilterImmediately(new FilterCriteria())); - } - - [Test] - public void TestRewind() - { - const int local_set_count = 3; - const int random_select_count = local_set_count * 3; - loadBeatmaps(setCount: local_set_count); - - for (int i = 0; i < random_select_count; i++) - nextRandom(); - - for (int i = 0; i < random_select_count; i++) - { - prevRandom(); - AddAssert("correct random last selected", () => selectedSets.Peek(), () => Is.EqualTo(carousel.SelectedBeatmapSet)); - } - } - - [Test] - public void TestRewindToDeletedBeatmap() - { - loadBeatmaps(); - - var firstAdded = TestResources.CreateTestBeatmapSetInfo(); - - AddStep("add new set", () => carousel.UpdateBeatmapSet(firstAdded)); - AddStep("select set", () => carousel.SelectBeatmap(firstAdded.Beatmaps.First())); - - nextRandom(); - - AddStep("delete set", () => carousel.RemoveBeatmapSet(firstAdded)); - - prevRandom(); - - AddAssert("deleted set not selected", () => carousel.SelectedBeatmapSet?.Equals(firstAdded) == false); - } - - /// - /// Test adding and removing beatmap sets - /// - [Test] - public void TestAddRemove() - { - loadBeatmaps(); - - var firstAdded = TestResources.CreateTestBeatmapSetInfo(); - var secondAdded = TestResources.CreateTestBeatmapSetInfo(); - - AddStep("Add new set", () => carousel.UpdateBeatmapSet(firstAdded)); - AddStep("Add new set", () => carousel.UpdateBeatmapSet(secondAdded)); - - checkVisibleItemCount(false, set_count + 2); - - AddStep("Remove set", () => carousel.RemoveBeatmapSet(firstAdded)); - - checkVisibleItemCount(false, set_count + 1); - - setSelected(set_count + 1, 1); - - AddStep("Remove set", () => carousel.RemoveBeatmapSet(secondAdded)); - - checkVisibleItemCount(false, set_count); - - waitForSelection(set_count); - } - - [Test] - public void TestDifficultiesSplitOutOnLoad() - { - loadBeatmaps(new List { TestResources.CreateTestBeatmapSetInfo(diff_count) }, () => new FilterCriteria - { - Sort = SortMode.Difficulty, - }); - - checkVisibleItemCount(false, 3); - } - - [Test] - public void TestAddRemoveDifficultySort() - { - const int local_set_count = 2; - const int local_diff_count = 2; - - loadBeatmaps(setCount: local_set_count, diffCount: local_diff_count); - - AddStep("Sort by difficulty", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Difficulty })); - - checkVisibleItemCount(false, local_set_count * local_diff_count); - - var firstAdded = TestResources.CreateTestBeatmapSetInfo(local_diff_count); - firstAdded.Status = BeatmapOnlineStatus.Loved; - - AddStep("Add new set", () => carousel.UpdateBeatmapSet(firstAdded)); - - checkVisibleItemCount(false, (local_set_count + 1) * local_diff_count); - - AddStep("Remove set", () => carousel.RemoveBeatmapSet(firstAdded)); - - checkVisibleItemCount(false, (local_set_count) * local_diff_count); - - setSelected(local_set_count, 1); - - waitForSelection(local_set_count); - } - - [Test] - public void TestSelectionEnteringFromEmptyRuleset() - { - var sets = new List(); - - AddStep("Create beatmaps for taiko only", () => - { - sets.Clear(); - - var rulesetBeatmapSet = TestResources.CreateTestBeatmapSetInfo(1); - var taikoRuleset = rulesets.AvailableRulesets.ElementAt(1); - rulesetBeatmapSet.Beatmaps.ForEach(b => b.Ruleset = taikoRuleset); - - sets.Add(rulesetBeatmapSet); - }); - - loadBeatmaps(sets, () => new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) }); - - AddStep("Set non-empty mode filter", () => - carousel.FilterImmediately(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(1) })); - - AddAssert("Something is selected", () => carousel.SelectedBeatmapInfo != null); - } - - [Test] - public void TestSortingDateSubmitted() - { - var sets = new List(); - const string zzz_string = "zzzzz"; - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < 10; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(5); - - // A total of 6 sets have date submitted (4 don't) - // A total of 5 sets have artist string (3 of which also have date submitted) - - if (i >= 2 && i < 8) // i = 2, 3, 4, 5, 6, 7 have submitted date - set.DateSubmitted = DateTimeOffset.Now.AddMinutes(i); - if (i < 5) // i = 0, 1, 2, 3, 4 have matching string - set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_string); - - set.Beatmaps.ForEach(b => b.Metadata.Title = $"submitted: {set.DateSubmitted}"); - - sets.Add(set); - } - }); - - loadBeatmaps(sets); - - AddStep("Sort by date submitted", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.DateSubmitted })); - checkVisibleItemCount(diff: false, count: 10); - checkVisibleItemCount(diff: true, count: 5); - - AddAssert("missing date are at end", - () => carousel.Items.OfType().Reverse().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted == null).Count(), () => Is.EqualTo(4)); - AddAssert("rest are at start", () => carousel.Items.OfType().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted != null).Count(), - () => Is.EqualTo(6)); - - AddStep("Sort by date submitted and string", () => carousel.FilterImmediately(new FilterCriteria - { - Sort = SortMode.DateSubmitted, - SearchText = zzz_string - })); - checkVisibleItemCount(diff: false, count: 5); - checkVisibleItemCount(diff: true, count: 5); - - AddAssert("missing date are at end", - () => carousel.Items.OfType().Reverse().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted == null).Count(), () => Is.EqualTo(2)); - AddAssert("rest are at start", () => carousel.Items.OfType().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted != null).Count(), - () => Is.EqualTo(3)); - } - - [Test] - public void TestSorting() - { - var sets = new List(); - - const string zzz_lowercase = "zzzzz"; - const string zzz_uppercase = "ZZZZZ"; - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < 20; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(); - - if (i == 4) - set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_uppercase); - - if (i == 8) - set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_lowercase); - - if (i == 12) - set.Beatmaps.ForEach(b => b.Metadata.Author.Username = zzz_uppercase); - - if (i == 16) - set.Beatmaps.ForEach(b => b.Metadata.Author.Username = zzz_lowercase); - - sets.Add(set); - } - }); - - loadBeatmaps(sets); - - AddStep("Sort by author", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Author })); - AddAssert($"Check {zzz_uppercase} is last", () => carousel.BeatmapSets.Last().Metadata.Author.Username == zzz_uppercase); - AddAssert($"Check {zzz_lowercase} is second last", () => carousel.BeatmapSets.SkipLast(1).Last().Metadata.Author.Username == zzz_lowercase); - AddStep("Sort by artist", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Artist })); - AddAssert($"Check {zzz_uppercase} is last", () => carousel.BeatmapSets.Last().Metadata.Artist == zzz_uppercase); - AddAssert($"Check {zzz_lowercase} is second last", () => carousel.BeatmapSets.SkipLast(1).Last().Metadata.Artist == zzz_lowercase); - } - - [Test] - public void TestSortByArtistUsesTitleAsTiebreaker() - { - var sets = new List(); - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < 20; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(); - - if (i == 4) - { - set.Beatmaps.ForEach(b => - { - b.Metadata.Artist = "ZZZ"; - b.Metadata.Title = "AAA"; - }); - } - - if (i == 8) - { - set.Beatmaps.ForEach(b => - { - b.Metadata.Artist = "ZZZ"; - b.Metadata.Title = "ZZZ"; - }); - } - - sets.Add(set); - } - }); - - loadBeatmaps(sets); - - AddStep("Sort by artist", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Artist })); - AddAssert("Check last item", () => - { - var lastItem = carousel.BeatmapSets.Last(); - return lastItem.Metadata.Artist == "ZZZ" && lastItem.Metadata.Title == "ZZZ"; - }); - AddAssert("Check second last item", () => - { - var secondLastItem = carousel.BeatmapSets.SkipLast(1).Last(); - return secondLastItem.Metadata.Artist == "ZZZ" && secondLastItem.Metadata.Title == "AAA"; - }); - } - - /// - /// Ensures stability is maintained on different sort modes for items with equal properties. - /// - [Test] - public void TestSortingStabilityDateAdded() - { - var sets = new List(); - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < 10; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(); - - set.DateAdded = DateTimeOffset.FromUnixTimeSeconds(i); - - // only need to set the first as they are a shared reference. - var beatmap = set.Beatmaps.First(); - - beatmap.Metadata.Artist = "a"; - beatmap.Metadata.Title = "b"; - - sets.Add(set); - } - }); - - loadBeatmaps(sets); - - AddStep("Sort by title", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Title })); - AddAssert("Items remain in descending added order", () => carousel.BeatmapSets.Select(s => s.DateAdded), () => Is.Ordered.Descending); - - AddStep("Sort by artist", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Artist })); - AddAssert("Items remain in descending added order", () => carousel.BeatmapSets.Select(s => s.DateAdded), () => Is.Ordered.Descending); - } - - /// - /// Ensures stability is maintained on different sort modes while a new item is added to the carousel. - /// - [Test] - public void TestSortingStabilityWithRemovedAndReaddedItem() - { - List sets = new List(); - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < 3; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(diff_count); - - // only need to set the first as they are a shared reference. - var beatmap = set.Beatmaps.First(); - - beatmap.Metadata.Artist = "same artist"; - beatmap.Metadata.Title = "same title"; - - // testing the case where DateAdded happens to equal (quite rare). - set.DateAdded = DateTimeOffset.UnixEpoch; - - sets.Add(set); - } - }); - - Guid[] originalOrder = null!; - - loadBeatmaps(sets); - - AddStep("Sort by artist", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Artist })); - - AddAssert("Items in descending added order", () => carousel.BeatmapSets.Select(s => s.DateAdded), () => Is.Ordered.Descending); - AddStep("Save order", () => originalOrder = carousel.BeatmapSets.Select(s => s.ID).ToArray()); - - AddStep("Remove item", () => carousel.RemoveBeatmapSet(sets[1])); - AddStep("Re-add item", () => carousel.UpdateBeatmapSet(sets[1])); - - AddAssert("Order didn't change", () => carousel.BeatmapSets.Select(s => s.ID), () => Is.EqualTo(originalOrder)); - - AddStep("Sort by title", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Title })); - AddAssert("Order didn't change", () => carousel.BeatmapSets.Select(s => s.ID), () => Is.EqualTo(originalOrder)); - } - - /// - /// Ensures stability is maintained on different sort modes while a new item is added to the carousel. - /// - [Test] - public void TestSortingStabilityWithNewItems() - { - List sets = new List(); - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < 3; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(diff_count); - - // only need to set the first as they are a shared reference. - var beatmap = set.Beatmaps.First(); - - beatmap.Metadata.Artist = "same artist"; - beatmap.Metadata.Title = "same title"; - - // testing the case where DateAdded happens to equal (quite rare). - set.DateAdded = DateTimeOffset.UnixEpoch; - - sets.Add(set); - } - }); - - Guid[] originalOrder = null!; - - loadBeatmaps(sets); - - AddStep("Sort by artist", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Artist })); - - AddAssert("Items in descending added order", () => carousel.BeatmapSets.Select(s => s.DateAdded), () => Is.Ordered.Descending); - AddStep("Save order", () => originalOrder = carousel.BeatmapSets.Select(s => s.ID).ToArray()); - - AddStep("Add new item", () => - { - var set = TestResources.CreateTestBeatmapSetInfo(); - - // only need to set the first as they are a shared reference. - var beatmap = set.Beatmaps.First(); - - beatmap.Metadata.Artist = "same artist"; - beatmap.Metadata.Title = "same title"; - - set.DateAdded = DateTimeOffset.FromUnixTimeSeconds(1); - - carousel.UpdateBeatmapSet(set); - - // add set to expected ordering - originalOrder = originalOrder.Prepend(set.ID).ToArray(); - }); - - AddAssert("Order didn't change", () => carousel.BeatmapSets.Select(s => s.ID), () => Is.EqualTo(originalOrder)); - - AddStep("Sort by title", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Title })); - AddAssert("Order didn't change", () => carousel.BeatmapSets.Select(s => s.ID), () => Is.EqualTo(originalOrder)); - } - - [Test] - public void TestSortingWithDifficultyFiltered() - { - const int local_diff_count = 3; - const int local_set_count = 2; - - List sets = new List(); - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < local_set_count; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(local_diff_count); - set.Beatmaps[0].StarRating = 3 - i; - set.Beatmaps[1].StarRating = 6 + i; - sets.Add(set); - } - }); - - loadBeatmaps(sets); - - AddStep("Sort by difficulty", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Difficulty })); - - checkVisibleItemCount(false, local_set_count * local_diff_count); - checkVisibleItemCount(true, 1); - - AddStep("Filter to normal", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Difficulty, SearchText = "Normal" })); - checkVisibleItemCount(false, local_set_count); - checkVisibleItemCount(true, 1); - - AddUntilStep("Check all visible sets have one normal", () => - { - return carousel.Items.OfType() - .Where(p => p.IsPresent) - .Count(p => ((CarouselBeatmapSet)p.Item)!.Beatmaps.Single().BeatmapInfo.DifficultyName.StartsWith("Normal", StringComparison.Ordinal)) == local_set_count; - }); - - AddStep("Filter to insane", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Difficulty, SearchText = "Insane" })); - checkVisibleItemCount(false, local_set_count); - checkVisibleItemCount(true, 1); - - AddUntilStep("Check all visible sets have one insane", () => - { - return carousel.Items.OfType() - .Where(p => p.IsPresent) - .Count(p => ((CarouselBeatmapSet)p.Item)!.Beatmaps.Single().BeatmapInfo.DifficultyName.StartsWith("Insane", StringComparison.Ordinal)) == local_set_count; - }); - } - - [Test] - public void TestRemoveAll() - { - loadBeatmaps(); - - setSelected(2, 1); - AddAssert("Selection is non-null", () => currentSelection != null); - - AddStep("Remove selected", () => carousel.RemoveBeatmapSet(carousel.SelectedBeatmapSet!)); - waitForSelection(2); - - AddStep("Remove first", () => carousel.RemoveBeatmapSet(carousel.BeatmapSets.First())); - AddStep("Remove first", () => carousel.RemoveBeatmapSet(carousel.BeatmapSets.First())); - waitForSelection(1); - - AddUntilStep("Remove all", () => - { - if (!carousel.BeatmapSets.Any()) return true; - - carousel.RemoveBeatmapSet(carousel.BeatmapSets.Last()); - return false; - }); - - checkNoSelection(); - } - - [Test] - public void TestEmptyTraversal() - { - loadBeatmaps(new List()); - - advanceSelection(direction: 1, diff: false); - checkNoSelection(); - - advanceSelection(direction: 1, diff: true); - checkNoSelection(); - - advanceSelection(direction: -1, diff: false); - checkNoSelection(); - - advanceSelection(direction: -1, diff: true); - checkNoSelection(); - } - - [Test] - public void TestHiding() - { - BeatmapSetInfo hidingSet = null; - List hiddenList = new List(); - - AddStep("create hidden set", () => - { - hidingSet = TestResources.CreateTestBeatmapSetInfo(diff_count); - hidingSet.Beatmaps[1].Hidden = true; - - hiddenList.Clear(); - hiddenList.Add(hidingSet); - }); - - loadBeatmaps(hiddenList); - - setSelected(1, 1); - - checkVisibleItemCount(true, 2); - advanceSelection(true); - waitForSelection(1, 3); - - setHidden(3); - waitForSelection(1, 1); - - setHidden(2, false); - advanceSelection(true); - waitForSelection(1, 2); - - setHidden(1); - waitForSelection(1, 2); - - setHidden(2); - checkNoSelection(); - - void setHidden(int diff, bool hidden = true) - { - AddStep((hidden ? "" : "un") + $"hide diff {diff}", () => - { - hidingSet.Beatmaps[diff - 1].Hidden = hidden; - carousel.UpdateBeatmapSet(hidingSet); - }); - } - } - - [Test] - public void TestSelectingFilteredRuleset() - { - BeatmapSetInfo testMixed = null; - - createCarousel(new List()); - - AddStep("add mixed ruleset beatmapset", () => - { - testMixed = TestResources.CreateTestBeatmapSetInfo(diff_count); - - for (int i = 0; i <= 2; i++) - { - testMixed.Beatmaps[i].Ruleset = rulesets.AvailableRulesets.ElementAt(i); - } - - carousel.UpdateBeatmapSet(testMixed); - }); - AddStep("filter to ruleset 0", () => - carousel.FilterImmediately(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) })); - AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testMixed.Beatmaps[1], false)); - AddAssert("unfiltered beatmap not selected", () => carousel.SelectedBeatmapInfo?.Ruleset.OnlineID == 0); - - AddStep("remove mixed set", () => - { - carousel.RemoveBeatmapSet(testMixed); - testMixed = null; - }); - BeatmapSetInfo testSingle = null; - AddStep("add single ruleset beatmapset", () => - { - testSingle = TestResources.CreateTestBeatmapSetInfo(diff_count); - testSingle.Beatmaps.ForEach(b => - { - b.Ruleset = rulesets.AvailableRulesets.ElementAt(1); - }); - - carousel.UpdateBeatmapSet(testSingle); - }); - AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testSingle.Beatmaps[0], false)); - checkNoSelection(); - AddStep("remove single ruleset set", () => carousel.RemoveBeatmapSet(testSingle)); - } - - [Test] - public void TestCarouselRemembersSelection() - { - List manySets = new List(); - - AddStep("Populuate beatmap sets", () => - { - manySets.Clear(); - - for (int i = 1; i <= 50; i++) - manySets.Add(TestResources.CreateTestBeatmapSetInfo(diff_count)); - }); - - loadBeatmaps(manySets); - - advanceSelection(direction: 1, diff: false); - - for (int i = 0; i < 5; i++) - { - AddStep("Toggle non-matching filter", () => - { - carousel.FilterImmediately(new FilterCriteria { SearchText = Guid.NewGuid().ToString() }); - }); - - AddStep("Restore no filter", () => - { - carousel.FilterImmediately(new FilterCriteria()); - eagerSelectedIDs.Add(carousel.SelectedBeatmapSet!.ID); - }); - } - - // always returns to same selection as long as it's available. - AddAssert("Selection was remembered", () => eagerSelectedIDs.Count == 1); - } - - [Test] - public void TestCarouselRemembersSelectionDifficultySort() - { - List manySets = new List(); - - AddStep("Populate beatmap sets", () => - { - manySets.Clear(); - - for (int i = 1; i <= 50; i++) - manySets.Add(TestResources.CreateTestBeatmapSetInfo(diff_count)); - }); - - loadBeatmaps(manySets); - - AddStep("Sort by difficulty", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Difficulty })); - - advanceSelection(direction: 1, diff: false); - - for (int i = 0; i < 5; i++) - { - AddStep("Toggle non-matching filter", () => - { - carousel.FilterImmediately(new FilterCriteria { SearchText = Guid.NewGuid().ToString() }); - }); - - AddStep("Restore no filter", () => - { - carousel.FilterImmediately(new FilterCriteria()); - eagerSelectedIDs.Add(carousel.SelectedBeatmapSet!.ID); - }); - } - - // always returns to same selection as long as it's available. - AddAssert("Selection was remembered", () => eagerSelectedIDs.Count == 1); - } - - [Test] - public void TestCarouselRetainsSelectionFromDifficultySort() - { - List manySets = new List(); - - AddStep("Populate beatmap sets", () => - { - manySets.Clear(); - - for (int i = 1; i <= 50; i++) - manySets.Add(TestResources.CreateTestBeatmapSetInfo(diff_count)); - }); - - loadBeatmaps(manySets); - - BeatmapInfo chosenBeatmap = null!; - AddStep("select given beatmap", () => carousel.SelectBeatmap(chosenBeatmap = manySets[20].Beatmaps[0])); - AddUntilStep("selection changed", () => carousel.SelectedBeatmapInfo, () => Is.EqualTo(chosenBeatmap)); - - AddStep("sort by difficulty", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Difficulty })); - AddAssert("selection retained", () => carousel.SelectedBeatmapInfo, () => Is.EqualTo(chosenBeatmap)); - - AddStep("sort by title", () => carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Title })); - AddAssert("selection retained", () => carousel.SelectedBeatmapInfo, () => Is.EqualTo(chosenBeatmap)); - } - - [Test] - public void TestFilteringByUserStarDifficulty() - { - BeatmapSetInfo set = null; - - loadBeatmaps(new List()); - - AddStep("add mixed difficulty set", () => - { - set = TestResources.CreateTestBeatmapSetInfo(1); - set.Beatmaps.Clear(); - - for (int i = 1; i <= 15; i++) - { - set.Beatmaps.Add(new BeatmapInfo(new OsuRuleset().RulesetInfo, new BeatmapDifficulty(), new BeatmapMetadata()) - { - DifficultyName = $"Stars: {i}", - StarRating = i, - }); - } - - carousel.UpdateBeatmapSet(set); - }); - - AddStep("select added set", () => carousel.SelectBeatmap(set.Beatmaps[0], false)); - - AddStep("filter [5..]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Min = 5 } })); - AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask); - checkVisibleItemCount(true, 11); - - AddStep("filter to [0..7]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Max = 7 } })); - AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask); - checkVisibleItemCount(true, 7); - - AddStep("filter to [5..7]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Min = 5, Max = 7 } })); - AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask); - checkVisibleItemCount(true, 3); - - AddStep("filter [2..2]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Min = 2, Max = 2 } })); - AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask); - checkVisibleItemCount(true, 1); - - AddStep("filter to [0..]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Min = 0 } })); - AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask); - checkVisibleItemCount(true, 15); - } - - [Test] - public void TestCarouselSelectsNextWhenPreviousIsFiltered() - { - List sets = new List(); - - // 10 sets that go osu! -> taiko -> catch -> osu! -> ... - for (int i = 0; i < 10; i++) - sets.Add(TestResources.CreateTestBeatmapSetInfo(5, new[] { getRuleset(i) })); - - // Sort mode is important to keep the ruleset order - loadBeatmaps(sets, () => new FilterCriteria { Sort = SortMode.Title }); - setSelected(1, 1); - - for (int i = 1; i < 10; i++) - { - var rulesetInfo = getRuleset(i % 3); - - AddStep($"Set ruleset to {rulesetInfo.ShortName}", () => - { - carousel.FilterImmediately(new FilterCriteria { Ruleset = rulesetInfo, Sort = SortMode.Title }); - }); - waitForSelection(i + 1, 1); - } - - static RulesetInfo getRuleset(int index) - { - switch (index % 3) - { - default: - return new OsuRuleset().RulesetInfo; - - case 1: - return new TaikoRuleset().RulesetInfo; - - case 2: - return new CatchRuleset().RulesetInfo; - } - } - } - - [Test] - public void TestCarouselSelectsBackwardsWhenDistanceIsShorter() - { - List sets = new List(); - - // 10 sets that go taiko, osu!, osu!, osu!, taiko, osu!, osu!, osu!, ... - for (int i = 0; i < 10; i++) - sets.Add(TestResources.CreateTestBeatmapSetInfo(5, new[] { getRuleset(i) })); - - // Sort mode is important to keep the ruleset order - loadBeatmaps(sets, () => new FilterCriteria { Sort = SortMode.Title }); - - for (int i = 2; i < 10; i += 4) - { - setSelected(i, 1); - AddStep("Set ruleset to taiko", () => - { - carousel.FilterImmediately(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(1), Sort = SortMode.Title }); - }); - waitForSelection(i - 1, 1); - AddStep("Remove ruleset filter", () => - { - carousel.FilterImmediately(new FilterCriteria { Sort = SortMode.Title }); - }); - } - - static RulesetInfo getRuleset(int index) - { - switch (index % 4) - { - case 0: - return new TaikoRuleset().RulesetInfo; - - default: - return new OsuRuleset().RulesetInfo; - } - } - } - - private void loadBeatmaps(List beatmapSets = null, Func initialCriteria = null, Action carouselAdjust = null, - int? setCount = null, int? diffCount = null, bool randomDifficulties = false) - { - bool changed = false; - - if (beatmapSets == null) - { - beatmapSets = new List(); - var statuses = Enum.GetValues() - .Except(new[] { BeatmapOnlineStatus.None }) // make sure a badge is always shown. - .ToArray(); - - for (int i = 1; i <= (setCount ?? set_count); i++) - { - var set = randomDifficulties - ? TestResources.CreateTestBeatmapSetInfo() - : TestResources.CreateTestBeatmapSetInfo(diffCount ?? diff_count); - set.Status = statuses[RNG.Next(statuses.Length)]; - - beatmapSets.Add(set); - } - } - - createCarousel(beatmapSets, initialCriteria, c => - { - carousel.BeatmapSetsChanged = () => changed = true; - carouselAdjust?.Invoke(c); - }); - - AddUntilStep("Wait for load", () => changed); - } - - private void createCarousel(List beatmapSets, [CanBeNull] Func initialCriteria = null, Action carouselAdjust = null, Container target = null) - { - AddStep("Create carousel", () => - { - selectedSets.Clear(); - eagerSelectedIDs.Clear(); - - carousel = new TestBeatmapCarousel(initialCriteria?.Invoke() ?? new FilterCriteria()) - { - RelativeSizeAxes = Axes.Both, - }; - - carouselAdjust?.Invoke(carousel); - - beatmaps.BeatmapSets.Clear(); - beatmaps.BeatmapSets.AddRange(beatmapSets); - - (target ?? this).Child = carousel; - }); - } - - private void ensureRandomFetchSuccess() => - AddAssert("ensure prev random fetch worked", () => selectedSets.Peek().Equals(carousel.SelectedBeatmapSet)); - - private void waitForSelection(int set, int? diff = null) => - AddUntilStep($"selected is set{set}{(diff.HasValue ? $" diff{diff.Value}" : "")}", () => - { - if (diff != null) - return carousel.SelectedBeatmapInfo?.Equals(carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Skip(diff.Value - 1).First()) == true; - - return carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Contains(carousel.SelectedBeatmapInfo); - }); - - private void setSelected(int set, int diff) => - AddStep($"select set{set} diff{diff}", () => - carousel.SelectBeatmap(carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Skip(diff - 1).First())); - - private void advanceSelection(bool diff, int direction = 1, int count = 1) - { - if (count == 1) - { - AddStep($"select {(direction > 0 ? "next" : "prev")} {(diff ? "diff" : "set")}", () => - carousel.SelectNext(direction, !diff)); - } - else - { - AddRepeatStep($"select {(direction > 0 ? "next" : "prev")} {(diff ? "diff" : "set")}", () => - carousel.SelectNext(direction, !diff), count); - } - } - - private void checkVisibleItemCount(bool diff, int count) - { - // until step required as we are querying against alive items, which are loaded asynchronously inside DrawableCarouselBeatmapSet. - AddUntilStep($"{count} {(diff ? "diffs" : "sets")} visible", () => - carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible), () => Is.EqualTo(count)); - } - - private void checkSelectionIsCentered() - { - AddAssert("Selected panel is centered", () => - { - return Precision.AlmostEquals( - carousel.ScreenSpaceDrawQuad.Centre, - carousel.Items - .First(i => i.Item?.State.Value == CarouselItemState.Selected) - .ScreenSpaceDrawQuad.Centre, 100); - }); - } - - private void checkNoSelection() => AddAssert("Selection is null", () => currentSelection == null); - - private void nextRandom() => - AddStep("select random next", () => - { - carousel.RandomAlgorithm.Value = RandomSelectAlgorithm.RandomPermutation; - - if (!selectedSets.Any() && carousel.SelectedBeatmapInfo != null) - selectedSets.Push(carousel.SelectedBeatmapSet); - - carousel.SelectNextRandom(); - selectedSets.Push(carousel.SelectedBeatmapSet); - }); - - private void ensureRandomDidntRepeat() => - AddAssert("ensure no repeats", () => selectedSets.Distinct().Count() == selectedSets.Count); - - private void prevRandom() => AddStep("select random last", () => - { - carousel.SelectPreviousRandom(); - selectedSets.Pop(); - }); - - private bool selectedBeatmapVisible() - { - var currentlySelected = carousel.Items.FirstOrDefault(s => s.Item is CarouselBeatmap && s.Item.State.Value == CarouselItemState.Selected); - if (currentlySelected == null) - return true; - - return currentlySelected.Item!.Visible; - } - - private void checkInvisibleDifficultiesUnselectable() - { - nextRandom(); - AddAssert("Selection is visible", selectedBeatmapVisible); - } - - private partial class TestBeatmapCarousel : BeatmapCarousel - { - public TestBeatmapCarousel(FilterCriteria criteria) - : base(criteria) - { - } - - public bool PendingFilterTask => PendingFilter != null; - - public IEnumerable Items - { - get - { - foreach (var item in Scroll.Children.OrderBy(c => c.Y)) - { - if (item.Item?.Visible != true) - continue; - - yield return item; - - if (item is DrawableCarouselBeatmapSet set) - { - foreach (var difficulty in set.DrawableBeatmaps) - yield return difficulty; - } - } - } - } - - public void FilterImmediately(FilterCriteria newCriteria) - { - Filter(newCriteria); - FlushPendingFilterOperations(); - } - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs deleted file mode 100644 index 20cc1e544e..0000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.Linq; -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Game.Beatmaps; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Screens.Select; - -namespace osu.Game.Tests.Visual.SongSelect -{ - [System.ComponentModel.Description("PlaySongSelect beatmap details")] - public partial class TestSceneBeatmapDetails : OsuTestScene - { - private BeatmapDetails details; - - private DummyAPIAccess api => (DummyAPIAccess)API; - - [SetUp] - public void Setup() => Schedule(() => - { - Child = details = new BeatmapDetails - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(150), - }; - }); - - [Test] - public void TestAllMetrics() - { - AddStep("all metrics", () => details.BeatmapInfo = new APIBeatmap - { - BeatmapSet = new APIBeatmapSet - { - Source = "osu!", - Tags = "this beatmap has all the metrics", - Ratings = Enumerable.Range(0, 11).ToArray(), - }, - DifficultyName = "All Metrics", - CircleSize = 7, - DrainRate = 1, - OverallDifficulty = 5.7f, - ApproachRate = 3.5f, - StarRating = 5.3f, - FailTimes = new APIFailTimes - { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), - }, - }); - } - - [Test] - public void TestAllMetricsExceptSource() - { - AddStep("all except source", () => details.BeatmapInfo = new APIBeatmap - { - BeatmapSet = new APIBeatmapSet - { - Tags = "this beatmap has all the metrics", - Ratings = Enumerable.Range(0, 11).ToArray(), - }, - DifficultyName = "All Metrics", - CircleSize = 7, - DrainRate = 1, - OverallDifficulty = 5.7f, - ApproachRate = 3.5f, - StarRating = 5.3f, - FailTimes = new APIFailTimes - { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), - }, - }); - } - - [Test] - public void TestOnlyRatings() - { - AddStep("ratings", () => details.BeatmapInfo = new APIBeatmap - { - BeatmapSet = new APIBeatmapSet - { - Ratings = Enumerable.Range(0, 11).ToArray(), - Source = "osu!", - Tags = "this beatmap has ratings metrics but not retries or fails", - }, - DifficultyName = "Only Ratings", - CircleSize = 6, - DrainRate = 9, - OverallDifficulty = 6, - ApproachRate = 6, - StarRating = 4.8f, - }); - } - - [Test] - public void TestOnlyFailsAndRetries() - { - AddStep("fails retries", () => details.BeatmapInfo = new APIBeatmap - { - DifficultyName = "Only Retries and Fails", - BeatmapSet = new APIBeatmapSet - { - Source = "osu!", - Tags = "this beatmap has retries and fails but no ratings", - }, - CircleSize = 3.7f, - DrainRate = 6, - OverallDifficulty = 6, - ApproachRate = 7, - StarRating = 2.91f, - FailTimes = new APIFailTimes - { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), - }, - }); - } - - [Test] - public void TestNoMetrics() - { - AddStep("no metrics", () => details.BeatmapInfo = new APIBeatmap - { - DifficultyName = "No Metrics", - BeatmapSet = new APIBeatmapSet - { - Source = "osu!", - Tags = "this beatmap has no metrics", - }, - CircleSize = 5, - DrainRate = 5, - OverallDifficulty = 5.5f, - ApproachRate = 6.5f, - StarRating = 1.97f, - }); - } - - [Test] - public void TestNullBeatmap() - { - AddStep("null beatmap", () => details.BeatmapInfo = null); - } - - [Test] - public void TestOnlineMetrics() - { - AddStep("online ratings/retries/fails", () => details.BeatmapInfo = new APIBeatmap - { - OnlineID = 162, - }); - AddStep("set online", () => api.SetState(APIState.Online)); - AddStep("set offline", () => api.SetState(APIState.Offline)); - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs deleted file mode 100644 index 0e0f3c554a..0000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs +++ /dev/null @@ -1,305 +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 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.UserInterface; -using osu.Framework.Testing; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Extensions; -using osu.Game.Graphics.Sprites; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Catch; -using osu.Game.Rulesets.Mania; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Legacy; -using osu.Game.Rulesets.Osu; -using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Rulesets.Taiko; -using osu.Game.Screens.Select; -using osuTK; - -namespace osu.Game.Tests.Visual.SongSelect -{ - [TestFixture] - public partial class TestSceneBeatmapInfoWedge : OsuTestScene - { - [Resolved] - private RulesetStore rulesets { get; set; } = null!; - - private TestBeatmapInfoWedge infoWedge = null!; - private readonly List beatmaps = new List(); - - protected override void LoadComplete() - { - base.LoadComplete(); - - Add(infoWedge = new TestBeatmapInfoWedge - { - Size = new Vector2(0.5f, 245), - RelativeSizeAxes = Axes.X, - Margin = new MarginPadding { Top = 20 } - }); - - AddStep("show", () => infoWedge.Show()); - - selectBeatmap(Beatmap.Value.Beatmap); - - AddWaitStep("wait for select", 3); - - AddStep("hide", () => { infoWedge.Hide(); }); - - AddWaitStep("wait for hide", 3); - - AddStep("show", () => { infoWedge.Show(); }); - - AddSliderStep("change star difficulty", 0, 11.9, 5.55, v => - { - foreach (var hasCurrentValue in infoWedge.Info.ChildrenOfType>()) - hasCurrentValue.Current.Value = new StarDifficulty(v, 0); - }); - - foreach (var rulesetInfo in rulesets.AvailableRulesets) - { - var instance = rulesetInfo.CreateInstance(); - var testBeatmap = CreateTestBeatmap(rulesetInfo); - - beatmaps.Add(testBeatmap); - - setRuleset(rulesetInfo); - - selectBeatmap(testBeatmap); - - testBeatmapLabels(instance); - - switch (instance) - { - case OsuRuleset: - testInfoLabels(5); - break; - - case TaikoRuleset: - testInfoLabels(5); - break; - - case CatchRuleset: - testInfoLabels(5); - break; - - case ManiaRuleset: - testInfoLabels(4); - break; - - default: - testInfoLabels(2); - break; - } - } - } - - private void testBeatmapLabels(Ruleset ruleset) - { - AddAssert("check version", () => infoWedge.Info.VersionLabel.Current.Value == $"{ruleset.ShortName}Version"); - AddAssert("check title", () => infoWedge.Info.TitleLabel.Current.Value == $"{ruleset.ShortName}Title"); - AddAssert("check artist", () => infoWedge.Info.ArtistLabel.Current.Value == $"{ruleset.ShortName}Artist"); - AddAssert("check author", () => infoWedge.Info.MapperContainer.ChildrenOfType().Any(s => s.Current.Value == $"{ruleset.ShortName}Author")); - } - - private void testInfoLabels(int expectedCount) - { - AddAssert("check info labels exists", () => infoWedge.Info.ChildrenOfType().Any()); - AddAssert("check info labels count", () => infoWedge.Info.ChildrenOfType().Count() == expectedCount); - } - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("reset mods", () => SelectedMods.SetDefault()); - } - - [Test] - public void TestTruncation() - { - selectBeatmap(CreateLongMetadata()); - } - - [Test] - public void TestNullBeatmap() - { - selectBeatmap(null); - AddAssert("check empty version", () => string.IsNullOrEmpty(infoWedge.Info.VersionLabel.Current.Value)); - AddAssert("check default title", () => infoWedge.Info.TitleLabel.Current.Value == Beatmap.Default.BeatmapInfo.Metadata.Title); - AddAssert("check default artist", () => infoWedge.Info.ArtistLabel.Current.Value == Beatmap.Default.BeatmapInfo.Metadata.Artist); - AddAssert("check empty author", () => !infoWedge.Info.MapperContainer.ChildrenOfType().Any()); - AddAssert("check no info labels", () => !infoWedge.Info.ChildrenOfType().Any()); - } - - [Test] - public void TestBPMUpdates() - { - const double bpm = 120; - IBeatmap beatmap = CreateTestBeatmap(new OsuRuleset().RulesetInfo); - beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 60 * 1000 / bpm }); - - OsuModDoubleTime doubleTime = null!; - - selectBeatmap(beatmap); - checkDisplayedBPM($"{bpm}"); - - AddStep("select DT", () => SelectedMods.Value = new[] { doubleTime = new OsuModDoubleTime() }); - checkDisplayedBPM($"{bpm * 1.5f}"); - - AddStep("change DT rate", () => doubleTime.SpeedChange.Value = 2); - checkDisplayedBPM($"{bpm * 2}"); - } - - [TestCase(120, 125, null, "120-125 (mostly 120)")] - [TestCase(120, 120.6, null, "120-121 (mostly 120)")] - [TestCase(120, 120.4, null, "120")] - [TestCase(120, 120.6, "DT", "180-181 (mostly 180)")] - [TestCase(120, 120.4, "DT", "180-181 (mostly 180)")] - public void TestVaryingBPM(double commonBpm, double otherBpm, string? mod, string expectedDisplay) - { - IBeatmap beatmap = CreateTestBeatmap(new OsuRuleset().RulesetInfo); - beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 60 * 1000 / commonBpm }); - beatmap.ControlPointInfo.Add(100, new TimingControlPoint { BeatLength = 60 * 1000 / otherBpm }); - beatmap.ControlPointInfo.Add(200, new TimingControlPoint { BeatLength = 60 * 1000 / commonBpm }); - - if (mod != null) - AddStep($"select {mod}", () => SelectedMods.Value = new[] { Ruleset.Value.CreateInstance().CreateModFromAcronym(mod) }); - - selectBeatmap(beatmap); - checkDisplayedBPM(expectedDisplay); - } - - private void checkDisplayedBPM(string target) - { - AddUntilStep($"displayed bpm is {target}", () => - { - var label = infoWedge.DisplayedContent.ChildrenOfType().Single(l => l.Statistic.Name == BeatmapsetsStrings.ShowStatsBpm); - return label.Statistic.Content == target; - }); - } - - [TestCase] - public void TestLengthUpdates() - { - IBeatmap beatmap = CreateTestBeatmap(new OsuRuleset().RulesetInfo); - double drain = beatmap.CalculateDrainLength(); - beatmap.BeatmapInfo.Length = drain; - - OsuModDoubleTime doubleTime = null!; - - selectBeatmap(beatmap); - checkDisplayedLength(drain); - - AddStep("select DT", () => SelectedMods.Value = new[] { doubleTime = new OsuModDoubleTime() }); - checkDisplayedLength(Math.Round(drain / 1.5f)); - - AddStep("change DT rate", () => doubleTime.SpeedChange.Value = 2); - checkDisplayedLength(Math.Round(drain / 2)); - } - - private void checkDisplayedLength(double drain) - { - var displayedLength = drain.ToFormattedDuration(); - - AddUntilStep($"check map drain ({displayedLength})", () => - { - var label = infoWedge.DisplayedContent.ChildrenOfType() - .Single(l => l.Statistic.Name == BeatmapsetsStrings.ShowStatsTotalLength(displayedLength)); - return label.Statistic.Content == displayedLength.ToString(); - }); - } - - private void setRuleset(RulesetInfo rulesetInfo) - { - Container? containerBefore = null; - - AddStep("set ruleset", () => - { - // wedge content is only refreshed if the ruleset changes, so only wait for load in that case. - if (!rulesetInfo.Equals(Ruleset.Value)) - containerBefore = infoWedge.DisplayedContent; - - Ruleset.Value = rulesetInfo; - }); - - AddUntilStep("wait for async load", () => infoWedge.DisplayedContent != containerBefore); - } - - private void selectBeatmap(IBeatmap? b) - { - Container? containerBefore = null; - - AddStep($"select {b?.Metadata.Title ?? "null"} beatmap", () => - { - containerBefore = infoWedge.DisplayedContent; - infoWedge.Beatmap = Beatmap.Value = b == null ? Beatmap.Default : CreateWorkingBeatmap(b); - }); - - AddUntilStep("wait for async load", () => infoWedge.DisplayedContent != containerBefore); - } - - public static IBeatmap CreateTestBeatmap(RulesetInfo ruleset) - { - List objects = new List(); - for (double i = 0; i < 50000; i += 1000) - objects.Add(new TestHitObject { StartTime = i }); - - return new Beatmap - { - BeatmapInfo = new BeatmapInfo - { - Metadata = new BeatmapMetadata - { - Author = { Username = $"{ruleset.ShortName}Author" }, - Artist = $"{ruleset.ShortName}Artist", - Source = $"{ruleset.ShortName}Source", - Title = $"{ruleset.ShortName}Title" - }, - Ruleset = ruleset, - StarRating = 6, - DifficultyName = $"{ruleset.ShortName}Version", - Difficulty = new BeatmapDifficulty() - }, - HitObjects = objects - }; - } - - public static IBeatmap CreateLongMetadata() - { - return new Beatmap - { - BeatmapInfo = new BeatmapInfo - { - Metadata = new BeatmapMetadata - { - Author = { Username = "WWWWWWWWWWWWWWW" }, - Artist = "Verrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Artist", - Source = "Verrrrry long Source", - Title = "Verrrrry long Title" - }, - DifficultyName = "Verrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Version", - Status = BeatmapOnlineStatus.Graveyard, - }, - }; - } - - private partial class TestBeatmapInfoWedge : BeatmapInfoWedge - { - public new Container DisplayedContent => base.DisplayedContent; - - public new WedgeInfoText Info => base.Info; - } - - private class TestHitObject : ConvertHitObject; - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs deleted file mode 100644 index fa4981c137..0000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs +++ /dev/null @@ -1,31 +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 System.ComponentModel; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; -using osu.Game.Screens.Select.Options; - -namespace osu.Game.Tests.Visual.SongSelect -{ - [Description("bottom beatmap details")] - public partial class TestSceneBeatmapOptionsOverlay : OsuTestScene - { - public TestSceneBeatmapOptionsOverlay() - { - var overlay = new BeatmapOptionsOverlay(); - - var colours = new OsuColour(); - - overlay.AddButton(@"Manage", @"collections", FontAwesome.Solid.Book, colours.Green, null); - overlay.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, null); - overlay.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, colours.Purple, null); - overlay.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, null); - overlay.AddButton(@"Edit", @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, null); - - Add(overlay); - - AddStep(@"Toggle", overlay.ToggleVisibility); - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs deleted file mode 100644 index 41e44357d7..0000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs +++ /dev/null @@ -1,24 +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 NUnit.Framework; -using osu.Framework.Graphics; -using osu.Game.Screens.Select; - -namespace osu.Game.Tests.Visual.SongSelect -{ - public partial class TestSceneFilterControl : OsuManualInputManagerTestScene - { - [SetUp] - public void SetUp() => Schedule(() => - { - Child = new FilterControl - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.X, - Height = FilterControl.HEIGHT, - }; - }); - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs deleted file mode 100644 index 646dedc2be..0000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.Linq; -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Framework.Testing; -using osu.Game.Screens.Select; -using osuTK; -using osuTK.Input; - -namespace osu.Game.Tests.Visual.SongSelect -{ - public partial class TestSceneSongSelectFooter : OsuManualInputManagerTestScene - { - private FooterButtonRandom randomButton; - - private bool nextRandomCalled; - private bool previousRandomCalled; - - [SetUp] - public void SetUp() => Schedule(() => - { - nextRandomCalled = false; - previousRandomCalled = false; - - Footer footer; - - Child = footer = new Footer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }; - - footer.AddButton(new FooterButtonMods(), null); - footer.AddButton(randomButton = new FooterButtonRandom - { - NextRandom = () => nextRandomCalled = true, - PreviousRandom = () => previousRandomCalled = true, - }, null); - footer.AddButton(new FooterButtonOptions(), null); - - InputManager.MoveMouseTo(Vector2.Zero); - }); - - [Test] - public void TestState() - { - AddRepeatStep("toggle options state", () => this.ChildrenOfType().Last().Enabled.Toggle(), 20); - } - - [Test] - public void TestFooterRandom() - { - AddStep("press F2", () => InputManager.Key(Key.F2)); - AddAssert("next random invoked", () => nextRandomCalled && !previousRandomCalled); - } - - [Test] - public void TestFooterRandomViaMouse() - { - AddStep("click button", () => - { - InputManager.MoveMouseTo(randomButton); - InputManager.Click(MouseButton.Left); - }); - AddAssert("next random invoked", () => nextRandomCalled && !previousRandomCalled); - } - - [Test] - public void TestFooterRewind() - { - AddStep("press Shift+F2", () => - { - InputManager.PressKey(Key.LShift); - InputManager.PressKey(Key.F2); - InputManager.ReleaseKey(Key.F2); - InputManager.ReleaseKey(Key.LShift); - }); - AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled); - } - - [Test] - public void TestFooterRewindViaShiftMouseLeft() - { - AddStep("shift + click button", () => - { - InputManager.PressKey(Key.LShift); - InputManager.MoveMouseTo(randomButton); - InputManager.Click(MouseButton.Left); - InputManager.ReleaseKey(Key.LShift); - }); - AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled); - } - - [Test] - public void TestFooterRewindViaMouseRight() - { - AddStep("right click button", () => - { - InputManager.MoveMouseTo(randomButton); - InputManager.Click(MouseButton.Right); - }); - AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled); - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs deleted file mode 100644 index cb0845ede8..0000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs +++ /dev/null @@ -1,224 +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 System.Linq; -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Extensions; -using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Graphics; -using osu.Framework.Platform; -using osu.Framework.Testing; -using osu.Game.Beatmaps; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Rulesets; -using osu.Game.Scoring; -using osu.Game.Screens.Select.Carousel; -using osu.Game.Tests.Resources; -using osuTK; - -namespace osu.Game.Tests.Visual.SongSelect -{ - public partial class TestSceneTopLocalRank : OsuTestScene - { - private RulesetStore rulesets = null!; - private BeatmapManager beatmapManager = null!; - private ScoreManager scoreManager = null!; - private TopLocalRank topLocalRank = null!; - - [BackgroundDependencyLoader] - private void load(GameHost host, AudioManager audio) - { - Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); - Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default)); - Dependencies.Cache(scoreManager = new ScoreManager(rulesets, () => beatmapManager, LocalStorage, Realm, API)); - Dependencies.Cache(Realm); - - beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely(); - } - - private BeatmapInfo importedBeatmap => beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First(b => b.Ruleset.ShortName == "osu"); - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("Delete all scores", () => scoreManager.Delete()); - - AddStep("Create local rank", () => - { - Child = topLocalRank = new TopLocalRank(importedBeatmap) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(10), - }; - }); - - AddAssert("No rank displayed initially", () => topLocalRank.DisplayedRank == null); - } - - [Test] - public void TestBasicImportDelete() - { - ScoreInfo testScoreInfo = null!; - - AddStep("Add score for current user", () => - { - testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo.User = API.LocalUser.Value; - testScoreInfo.Rank = ScoreRank.B; - - scoreManager.Import(testScoreInfo); - }); - - AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B); - - AddStep("Delete score", () => scoreManager.Delete(testScoreInfo)); - - AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank == null); - } - - [Test] - public void TestRulesetChange() - { - AddStep("Add score for current user", () => - { - var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo.User = API.LocalUser.Value; - testScoreInfo.Rank = ScoreRank.B; - - scoreManager.Import(testScoreInfo); - }); - - AddUntilStep("Wait for initial display", () => topLocalRank.DisplayedRank == ScoreRank.B); - - AddStep("Change ruleset", () => Ruleset.Value = rulesets.GetRuleset("fruits")); - AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank == null); - - AddStep("Change ruleset back", () => Ruleset.Value = rulesets.GetRuleset("osu")); - AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B); - } - - [Test] - public void TestHigherScoreSet() - { - AddStep("Add score for current user", () => - { - var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo.User = API.LocalUser.Value; - testScoreInfo.Rank = ScoreRank.B; - - scoreManager.Import(testScoreInfo); - }); - - AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B); - - AddStep("Add higher score for current user", () => - { - var testScoreInfo2 = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo2.User = API.LocalUser.Value; - testScoreInfo2.Rank = ScoreRank.X; - testScoreInfo2.TotalScore = 1000000; - testScoreInfo2.Statistics = testScoreInfo2.MaximumStatistics; - - scoreManager.Import(testScoreInfo2); - }); - - AddUntilStep("SS rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.X); - } - - [Test] - public void TestLegacyScore() - { - ScoreInfo testScoreInfo = null!; - - AddStep("Add legacy score for current user", () => - { - testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo.User = API.LocalUser.Value; - testScoreInfo.Rank = ScoreRank.B; - - scoreManager.Import(testScoreInfo); - }); - - AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B); - - AddStep("Add higher-graded score for current user", () => - { - var testScoreInfo2 = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo2.User = API.LocalUser.Value; - testScoreInfo2.Rank = ScoreRank.X; - testScoreInfo2.Statistics = testScoreInfo2.MaximumStatistics; - testScoreInfo2.TotalScore = testScoreInfo.TotalScore + 1; - - scoreManager.Import(testScoreInfo2); - }); - - AddUntilStep("SS rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.X); - } - - [Test] - public void TestGuestScore() - { - AddStep("Add score for guest user", () => - { - var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo.User = new GuestUser(); - testScoreInfo.Rank = ScoreRank.B; - - scoreManager.Import(testScoreInfo); - }); - - AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank, () => Is.EqualTo(ScoreRank.B)); - } - - [Test] - public void TestUnknownUserScore() - { - AddStep("Add score for unknown user", () => - { - var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo.User = new APIUser { Username = "AAA", }; - testScoreInfo.Rank = ScoreRank.S; - - scoreManager.Import(testScoreInfo); - }); - - AddUntilStep("S rank displayed", () => topLocalRank.DisplayedRank, () => Is.EqualTo(ScoreRank.S)); - } - - [Test] - public void TestAnotherUserScore() - { - AddStep("Add score for not-current user", () => - { - var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); - - testScoreInfo.User = new APIUser { Username = "notme", Id = 43, }; - testScoreInfo.Rank = ScoreRank.S; - - scoreManager.Import(testScoreInfo); - }); - - AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank, () => Is.Null); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - if (rulesets.IsNotNull()) - rulesets.Dispose(); - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs deleted file mode 100644 index 2311c360ff..0000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs +++ /dev/null @@ -1,262 +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 System; -using System.Linq; -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Graphics; -using osu.Framework.Testing; -using osu.Game.Beatmaps; -using osu.Game.Database; -using osu.Game.Online.API; -using osu.Game.Overlays; -using osu.Game.Overlays.Dialog; -using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Carousel; -using osu.Game.Screens.Select.Filter; -using osu.Game.Tests.Beatmaps; -using osu.Game.Tests.Online; -using osu.Game.Tests.Resources; -using osuTK.Input; - -namespace osu.Game.Tests.Visual.SongSelect -{ - [TestFixture] - public partial class TestSceneUpdateBeatmapSetButton : OsuManualInputManagerTestScene - { - private BeatmapCarousel carousel = null!; - - private TestScenePlaylistsBeatmapAvailabilityTracker.TestBeatmapModelDownloader beatmapDownloader = null!; - - private BeatmapSetInfo testBeatmapSetInfo = null!; - - [Cached(typeof(BeatmapStore))] - private TestBeatmapStore beatmaps = new TestBeatmapStore(); - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - - var importer = parent.Get(); - - dependencies.CacheAs(beatmapDownloader = new TestScenePlaylistsBeatmapAvailabilityTracker.TestBeatmapModelDownloader(importer, API)); - return dependencies; - } - - private UpdateBeatmapSetButton? getUpdateButton() => carousel.ChildrenOfType().SingleOrDefault(); - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("create carousel", () => Child = createCarousel()); - - AddUntilStep("wait for load", () => carousel.BeatmapSetsLoaded); - - AddAssert("update button not visible", () => getUpdateButton() == null); - } - - [Test] - public void TestDownloadToCompletion() - { - ArchiveDownloadRequest? downloadRequest = null; - - AddStep("update online hash", () => - { - testBeatmapSetInfo.Beatmaps.First().OnlineMD5Hash = "different hash"; - testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now; - - carousel.UpdateBeatmapSet(testBeatmapSetInfo); - }); - - AddUntilStep("only one set visible", () => carousel.ChildrenOfType().Count() == 1); - AddUntilStep("update button visible", () => getUpdateButton() != null); - - AddStep("click button", () => getUpdateButton()?.TriggerClick()); - - AddUntilStep("wait for download started", () => - { - downloadRequest = beatmapDownloader.GetExistingDownload(testBeatmapSetInfo); - return downloadRequest != null; - }); - - AddUntilStep("wait for button disabled", () => getUpdateButton()?.Enabled.Value == false); - - AddUntilStep("progress download to completion", () => - { - if (downloadRequest is TestScenePlaylistsBeatmapAvailabilityTracker.TestDownloadRequest testRequest) - { - testRequest.SetProgress(testRequest.Progress + 0.1f); - - if (testRequest.Progress >= 1) - { - testRequest.TriggerSuccess(); - - // usually this would be done by the import process. - testBeatmapSetInfo.Beatmaps.First().MD5Hash = "different hash"; - testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now; - - // usually this would be done by a realm subscription. - carousel.UpdateBeatmapSet(testBeatmapSetInfo); - return true; - } - } - - return false; - }); - } - - [Test] - public void TestDownloadFailed() - { - ArchiveDownloadRequest? downloadRequest = null; - - AddStep("update online hash", () => - { - testBeatmapSetInfo.Beatmaps.First().OnlineMD5Hash = "different hash"; - testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now; - - carousel.UpdateBeatmapSet(testBeatmapSetInfo); - }); - - AddUntilStep("only one set visible", () => carousel.ChildrenOfType().Count() == 1); - AddUntilStep("update button visible", () => getUpdateButton() != null); - - AddStep("click button", () => getUpdateButton()?.TriggerClick()); - - AddUntilStep("wait for download started", () => - { - downloadRequest = beatmapDownloader.GetExistingDownload(testBeatmapSetInfo); - return downloadRequest != null; - }); - - AddUntilStep("wait for button disabled", () => getUpdateButton()?.Enabled.Value == false); - - AddUntilStep("progress download to failure", () => - { - if (downloadRequest is TestScenePlaylistsBeatmapAvailabilityTracker.TestDownloadRequest testRequest) - { - testRequest.SetProgress(testRequest.Progress + 0.1f); - - if (testRequest.Progress >= 0.5f) - { - testRequest.TriggerFailure(new InvalidOperationException()); - return true; - } - } - - return false; - }); - - AddUntilStep("wait for button enabled", () => getUpdateButton()?.Enabled.Value == true); - } - - [Test] - public void TestUpdateLocalBeatmap() - { - DialogOverlay dialogOverlay = null!; - UpdateBeatmapSetButton? updateButton = null; - - AddStep("create carousel with dialog overlay", () => - { - dialogOverlay = new DialogOverlay(); - - Child = new DependencyProvidingContainer - { - RelativeSizeAxes = Axes.Both, - CachedDependencies = new (Type, object)[] { (typeof(IDialogOverlay), dialogOverlay), }, - Children = new Drawable[] - { - createCarousel(), - dialogOverlay, - }, - }; - }); - - AddStep("setup beatmap state", () => - { - testBeatmapSetInfo.Beatmaps.First().OnlineMD5Hash = "different hash"; - testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now; - testBeatmapSetInfo.Status = BeatmapOnlineStatus.LocallyModified; - - carousel.UpdateBeatmapSet(testBeatmapSetInfo); - }); - - AddUntilStep("wait for update button", () => (updateButton = getUpdateButton()) != null); - AddStep("click button", () => updateButton.AsNonNull().TriggerClick()); - - AddAssert("dialog displayed", () => dialogOverlay.CurrentDialog is UpdateLocalConfirmationDialog); - AddStep("click confirmation", () => - { - InputManager.MoveMouseTo(dialogOverlay.CurrentDialog.ChildrenOfType().First()); - InputManager.PressButton(MouseButton.Left); - }); - - AddUntilStep("update started", () => beatmapDownloader.GetExistingDownload(testBeatmapSetInfo) != null); - AddStep("release mouse button", () => InputManager.ReleaseButton(MouseButton.Left)); - } - - [Test] - public void TestSplitDisplay() - { - ArchiveDownloadRequest? downloadRequest = null; - - AddStep("set difficulty sort mode", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Difficulty })); - AddStep("update online hash", () => - { - testBeatmapSetInfo.Beatmaps.First().OnlineMD5Hash = "different hash"; - testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now; - - carousel.UpdateBeatmapSet(testBeatmapSetInfo); - }); - - AddUntilStep("multiple \"sets\" visible", () => carousel.ChildrenOfType().Count(), () => Is.GreaterThan(1)); - AddUntilStep("update button visible", getUpdateButton, () => Is.Not.Null); - - AddStep("click button", () => getUpdateButton()?.TriggerClick()); - - AddUntilStep("wait for download started", () => - { - downloadRequest = beatmapDownloader.GetExistingDownload(testBeatmapSetInfo); - return downloadRequest != null; - }); - - AddUntilStep("wait for button disabled", () => getUpdateButton()?.Enabled.Value == false); - - AddUntilStep("progress download to completion", () => - { - if (downloadRequest is TestScenePlaylistsBeatmapAvailabilityTracker.TestDownloadRequest testRequest) - { - testRequest.SetProgress(testRequest.Progress + 0.1f); - - if (testRequest.Progress >= 1) - { - testRequest.TriggerSuccess(); - - // usually this would be done by the import process. - testBeatmapSetInfo.Beatmaps.First().MD5Hash = "different hash"; - testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now; - - // usually this would be done by a realm subscription. - carousel.UpdateBeatmapSet(testBeatmapSetInfo); - return true; - } - } - - return false; - }); - } - - private BeatmapCarousel createCarousel() - { - beatmaps.BeatmapSets.Clear(); - beatmaps.BeatmapSets.Add(testBeatmapSetInfo = TestResources.CreateTestBeatmapSetInfo(5)); - - return carousel = new BeatmapCarousel(new FilterCriteria()) - { - RelativeSizeAxes = Axes.Both, - }; - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCollectionDropdown.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs rename to osu.Game.Tests/Visual/UserInterface/TestSceneCollectionDropdown.cs index 8525e33a33..c5a0d7eab8 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCollectionDropdown.cs @@ -25,7 +25,7 @@ using osu.Game.Tests.Resources; using osuTK.Input; using Realms; -namespace osu.Game.Tests.Visual.SongSelect +namespace osu.Game.Tests.Visual.UserInterface { public partial class TestSceneCollectionDropdown : OsuManualInputManagerTestScene { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs deleted file mode 100644 index b79ce6c75f..0000000000 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs +++ /dev/null @@ -1,99 +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 System; -using System.Collections.Generic; -using System.Linq; -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.Select; -using osu.Game.Utils; - -namespace osu.Game.Tests.Visual.UserInterface -{ - public partial class TestSceneFooterButtonMods : OsuTestScene - { - private readonly TestFooterButtonMods footerButtonMods; - - public TestSceneFooterButtonMods() - { - Add(footerButtonMods = new TestFooterButtonMods()); - } - - [Test] - public void TestIncrementMultiplier() - { - var hiddenMod = new Mod[] { new OsuModHidden() }; - AddStep(@"Add Hidden", () => changeMods(hiddenMod)); - AddAssert(@"Check Hidden multiplier", () => assertModsMultiplier(hiddenMod)); - - var hardRockMod = new Mod[] { new OsuModHardRock() }; - AddStep(@"Add HardRock", () => changeMods(hardRockMod)); - AddAssert(@"Check HardRock multiplier", () => assertModsMultiplier(hardRockMod)); - - var doubleTimeMod = new Mod[] { new OsuModDoubleTime() }; - AddStep(@"Add DoubleTime", () => changeMods(doubleTimeMod)); - AddAssert(@"Check DoubleTime multiplier", () => assertModsMultiplier(doubleTimeMod)); - - var multipleIncrementMods = new Mod[] { new OsuModDoubleTime(), new OsuModHidden(), new OsuModHardRock() }; - AddStep(@"Add multiple Mods", () => changeMods(multipleIncrementMods)); - AddAssert(@"Check multiple mod multiplier", () => assertModsMultiplier(multipleIncrementMods)); - } - - [Test] - public void TestDecrementMultiplier() - { - var easyMod = new Mod[] { new OsuModEasy() }; - AddStep(@"Add Easy", () => changeMods(easyMod)); - AddAssert(@"Check Easy multiplier", () => assertModsMultiplier(easyMod)); - - var noFailMod = new Mod[] { new OsuModNoFail() }; - AddStep(@"Add NoFail", () => changeMods(noFailMod)); - AddAssert(@"Check NoFail multiplier", () => assertModsMultiplier(noFailMod)); - - var multipleDecrementMods = new Mod[] { new OsuModEasy(), new OsuModNoFail() }; - AddStep(@"Add Multiple Mods", () => changeMods(multipleDecrementMods)); - AddAssert(@"Check multiple mod multiplier", () => assertModsMultiplier(multipleDecrementMods)); - } - - [Test] - public void TestClearMultiplier() - { - var multipleMods = new Mod[] { new OsuModDoubleTime(), new OsuModFlashlight() }; - AddStep(@"Add mods", () => changeMods(multipleMods)); - AddStep(@"Clear selected mod", () => changeMods(Array.Empty())); - AddAssert(@"Check empty multiplier", () => assertModsMultiplier(Array.Empty())); - } - - [Test] - public void TestUnrankedBadge() - { - AddStep(@"Add unranked mod", () => changeMods(new[] { new OsuModDeflate() })); - AddAssert("Unranked badge shown", () => footerButtonMods.UnrankedBadge.Alpha == 1); - AddStep(@"Clear selected mod", () => changeMods(Array.Empty())); - AddAssert("Unranked badge not shown", () => footerButtonMods.UnrankedBadge.Alpha == 0); - } - - private void changeMods(IReadOnlyList mods) - { - footerButtonMods.Current.Value = mods; - } - - private bool assertModsMultiplier(IEnumerable mods) - { - double multiplier = mods.Aggregate(1.0, (current, mod) => current * mod.ScoreMultiplier); - string expectedValue = multiplier == 1 ? string.Empty : ModUtils.FormatScoreMultiplier(multiplier).ToString(); - - return expectedValue == footerButtonMods.MultiplierText.Current.Value; - } - - private partial class TestFooterButtonMods : FooterButtonMods - { - public new OsuSpriteText MultiplierText => base.MultiplierText; - public new Drawable UnrankedBadge => base.UnrankedBadge; - } - } -} diff --git a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs index 6f61a14b75..3083abc393 100644 --- a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs +++ b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs @@ -1,21 +1,20 @@ // 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 osu.Framework.Audio.Track; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; -using osuTK; -using osuTK.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Framework.Extensions.Color4Extensions; -using osu.Game.Graphics.Containers; -using osu.Game.Beatmaps.ControlPoints; -using osu.Framework.Audio.Track; -using System; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; -using osu.Game.Screens.Select; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface { @@ -31,7 +30,9 @@ namespace osu.Game.Graphics.UserInterface private const float shear_width = 5f; - private static readonly Vector2 shear = new Vector2(shear_width / Footer.HEIGHT, 0); + public const float HEIGHT = 50; + + private static readonly Vector2 shear = new Vector2(shear_width / HEIGHT, 0); public static readonly Vector2 SIZE_EXTENDED = new Vector2(140, 50); public static readonly Vector2 SIZE_RETRACTED = new Vector2(100, 50); diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index e0bc193df6..8d8c73b14e 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -22,8 +22,8 @@ using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; +using osu.Game.Overlays.Dialog; using osu.Game.Overlays.SkinEditor; -using osu.Game.Screens.Select; using osu.Game.Skinning; using osuTK; using Realms; @@ -237,6 +237,27 @@ namespace osu.Game.Overlays.Settings.Sections } } + public partial class SkinDeleteDialog : DeletionDialog + { + private readonly Skin skin; + + public SkinDeleteDialog(Skin skin) + { + this.skin = skin; + BodyText = skin.SkinInfo.Value.Name; + } + + [BackgroundDependencyLoader] + private void load(SkinManager manager) + { + DangerousAction = () => + { + manager.Delete(skin.SkinInfo.Value); + manager.CurrentSkinInfo.SetDefault(); + }; + } + } + public partial class RenameSkinPopover : OsuPopover { [Resolved] diff --git a/osu.Game/Screens/OnlinePlay/Components/BeatmapDetailAreaPlaylistTabItem.cs b/osu.Game/Screens/OnlinePlay/Components/BeatmapDetailAreaPlaylistTabItem.cs deleted file mode 100644 index 41b994ea32..0000000000 --- a/osu.Game/Screens/OnlinePlay/Components/BeatmapDetailAreaPlaylistTabItem.cs +++ /dev/null @@ -1,12 +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.Screens.Select; - -namespace osu.Game.Screens.OnlinePlay.Components -{ - public class BeatmapDetailAreaPlaylistTabItem : BeatmapDetailAreaTabItem - { - public override string Name => "Playlist"; - } -} diff --git a/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs b/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs deleted file mode 100644 index 1f2b2e3fc2..0000000000 --- a/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs +++ /dev/null @@ -1,110 +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 System; -using System.ComponentModel; -using System.Linq; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Graphics.UserInterfaceV2; -using osu.Game.Online.Rooms; -using osu.Game.Screens.OnlinePlay.Playlists; -using osu.Game.Screens.Select; -using osuTK; -using Container = osu.Framework.Graphics.Containers.Container; - -namespace osu.Game.Screens.OnlinePlay.Components -{ - public partial class MatchBeatmapDetailArea : BeatmapDetailArea - { - public Action? CreateNewItem; - - private readonly Room room; - private readonly GridContainer playlistArea; - private readonly DrawableRoomPlaylist playlist; - - public MatchBeatmapDetailArea(Room room) - { - this.room = room; - - Add(playlistArea = new GridContainer - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Vertical = 10 }, - Content = new[] - { - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Bottom = 10 }, - Child = playlist = new PlaylistsRoomSettingsPlaylist - { - RelativeSizeAxes = Axes.Both - } - } - }, - new Drawable[] - { - new RoundedButton - { - Text = "Add new playlist entry", - RelativeSizeAxes = Axes.Both, - Size = Vector2.One, - Action = () => CreateNewItem?.Invoke() - } - }, - }, - RowDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.Absolute, 50), - } - }); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - playlist.Items.BindCollectionChanged((_, __) => room.Playlist = playlist.Items.ToArray()); - - room.PropertyChanged += onRoomPropertyChanged; - updateRoomPlaylist(); - } - - private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == nameof(Room.Playlist)) - updateRoomPlaylist(); - } - - private void updateRoomPlaylist() - => playlist.Items.ReplaceRange(0, playlist.Items.Count, room.Playlist); - - protected override void OnTabChanged(BeatmapDetailAreaTabItem tab, bool selectedMods) - { - base.OnTabChanged(tab, selectedMods); - - switch (tab) - { - case BeatmapDetailAreaPlaylistTabItem: - playlistArea.Show(); - break; - - default: - playlistArea.Hide(); - break; - } - } - - protected override BeatmapDetailAreaTabItem[] CreateTabItems() => base.CreateTabItems().Prepend(new BeatmapDetailAreaPlaylistTabItem()).ToArray(); - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - room.PropertyChanged -= onRoomPropertyChanged; - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs deleted file mode 100644 index dda62e8ba8..0000000000 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ /dev/null @@ -1,1280 +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 System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Bindables; -using osu.Framework.Caching; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Pooling; -using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; -using osu.Framework.Layout; -using osu.Framework.Threading; -using osu.Framework.Utils; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Database; -using osu.Game.Extensions; -using osu.Game.Graphics.Containers; -using osu.Game.Input.Bindings; -using osu.Game.Screens.Select.Carousel; -using osu.Game.Screens.Select.Filter; -using osuTK; -using osuTK.Input; - -namespace osu.Game.Screens.Select -{ - public partial class BeatmapCarousel : CompositeDrawable, IKeyBindingHandler - { - /// - /// Height of the area above the carousel that should be treated as visible due to transparency of elements in front of it. - /// - public float BleedTop { get; set; } - - /// - /// Height of the area below the carousel that should be treated as visible due to transparency of elements in front of it. - /// - public float BleedBottom { get; set; } - - /// - /// Triggered when finish loading, or are subsequently changed. - /// - public Action? BeatmapSetsChanged; - - /// - /// Triggered after filter conditions have finished being applied to the model hierarchy. - /// - public Action? FilterApplied; - - /// - /// The currently selected beatmap. - /// - public BeatmapInfo? SelectedBeatmapInfo => selectedBeatmap?.BeatmapInfo; - - private CarouselBeatmap? selectedBeatmap => selectedBeatmapSet?.Beatmaps.FirstOrDefault(s => s.State.Value == CarouselItemState.Selected); - - /// - /// The total count of non-filtered beatmaps displayed. - /// - public int CountDisplayed => beatmapSets.Where(s => !s.Filtered.Value).Sum(s => s.TotalItemsNotFiltered); - - /// - /// The currently selected beatmap set. - /// - public BeatmapSetInfo? SelectedBeatmapSet => selectedBeatmapSet?.BeatmapSet; - - /// - /// A function to optionally decide on a recommended difficulty from a beatmap set. - /// - public Func, BeatmapInfo?>? GetRecommendedBeatmap; - - private CarouselBeatmapSet? selectedBeatmapSet; - - /// - /// Raised when the is changed. - /// - public Action? SelectionChanged; - - public override bool HandleNonPositionalInput => AllowSelection; - public override bool HandlePositionalInput => AllowSelection; - - public override bool PropagatePositionalInputSubTree => AllowSelection; - public override bool PropagateNonPositionalInputSubTree => AllowSelection; - - private (int first, int last) displayedRange; - - /// - /// Extend the range to retain already loaded pooled drawables. - /// - private const float distance_offscreen_before_unload = 2048; - - /// - /// Extend the range to update positions / retrieve pooled drawables outside of visible range. - /// - private const float distance_offscreen_to_preload = 768; - - /// - /// Whether carousel items have completed asynchronously loaded. - /// - public bool BeatmapSetsLoaded { get; private set; } - - [Cached] - protected readonly CarouselScrollContainer Scroll; - - [Resolved] - private RealmAccess realm { get; set; } = null!; - - private IBindableList? detachedBeatmapSets; - - private readonly NoResultsPlaceholder noResultsPlaceholder; - - private IEnumerable beatmapSets => root.Items.OfType(); - - internal IEnumerable BeatmapSets => beatmapSets.Select(g => g.BeatmapSet); - - private void loadNewRoot() - { - beatmapsSplitOut = activeCriteria.Sort == SortMode.Difficulty; - - // Ensure no changes are made to the list while we are initialising items. - // We'll catch up on changes via subscriptions anyway. - BeatmapSetInfo[] loadableSets = detachedBeatmapSets!.ToArray(); - - if (selectedBeatmapSet != null && !loadableSets.Contains(selectedBeatmapSet.BeatmapSet, EqualityComparer.Default)) - selectedBeatmapSet = null; - - var selectedBeatmapBefore = selectedBeatmap?.BeatmapInfo; - - CarouselRoot newRoot = new CarouselRoot(this); - - if (beatmapsSplitOut) - { - var carouselBeatmapSets = loadableSets.SelectMany(s => s.Beatmaps).Select(b => - { - return createCarouselSet(new BeatmapSetInfo(new[] { b }) - { - ID = b.BeatmapSet!.ID, - OnlineID = b.BeatmapSet!.OnlineID, - Status = b.BeatmapSet!.Status, - }); - }).OfType(); - - newRoot.AddItems(carouselBeatmapSets); - } - else - { - var carouselBeatmapSets = loadableSets.Select(createCarouselSet).OfType(); - - newRoot.AddItems(carouselBeatmapSets); - } - - root = newRoot; - root.Filter(activeCriteria); - - Scroll.Clear(false); - itemsCache.Invalidate(); - ScrollToSelected(); - - // Restore selection - if (selectedBeatmapBefore != null && newRoot.BeatmapSetsByID.TryGetValue(selectedBeatmapBefore.BeatmapSet!.ID, out var newSelectionCandidates)) - { - CarouselBeatmap? found = newSelectionCandidates.SelectMany(s => s.Beatmaps).SingleOrDefault(b => b.BeatmapInfo.ID == selectedBeatmapBefore.ID); - - if (found != null) - found.State.Value = CarouselItemState.Selected; - } - - Schedule(() => - { - invalidateAfterChange(); - BeatmapSetsLoaded = true; - }); - } - - private readonly List visibleItems = new List(); - - private readonly Cached itemsCache = new Cached(); - private PendingScrollOperation pendingScrollOperation = PendingScrollOperation.None; - - public Bindable RandomAlgorithm = new Bindable(); - private readonly List previouslyVisitedRandomSets = new List(); - private readonly List randomSelectedBeatmaps = new List(); - - private CarouselRoot root; - - private readonly DrawablePool setPool = new DrawablePool(100); - - private Sample? spinSample; - private Sample? randomSelectSample; - - private int visibleSetsCount; - - public BeatmapCarousel(FilterCriteria initialCriteria) - { - root = new CarouselRoot(this); - InternalChild = new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - setPool, - Scroll = new CarouselScrollContainer - { - RelativeSizeAxes = Axes.Both, - }, - noResultsPlaceholder = new NoResultsPlaceholder() - } - }; - - activeCriteria = initialCriteria; - } - - [BackgroundDependencyLoader] - private void load(OsuConfigManager config, AudioManager audio, BeatmapStore beatmaps, CancellationToken? cancellationToken) - { - spinSample = audio.Samples.Get("SongSelect/random-spin"); - randomSelectSample = audio.Samples.Get(@"SongSelect/select-random"); - - config.BindWith(OsuSetting.RandomSelectAlgorithm, RandomAlgorithm); - - detachedBeatmapSets = beatmaps.GetBeatmapSets(cancellationToken); - detachedBeatmapSets.BindCollectionChanged(beatmapSetsChanged); - loadNewRoot(); - } - - private readonly HashSet setsRequiringUpdate = new HashSet(); - private readonly HashSet setsRequiringRemoval = new HashSet(); - - private void beatmapSetsChanged(object? beatmaps, NotifyCollectionChangedEventArgs changed) - { - IEnumerable? oldBeatmapSets = changed.OldItems?.Cast(); - HashSet oldBeatmapSetIDs = oldBeatmapSets?.Select(s => s.ID).ToHashSet() ?? []; - - IEnumerable? newBeatmapSets = changed.NewItems?.Cast(); - HashSet newBeatmapSetIDs = newBeatmapSets?.Select(s => s.ID).ToHashSet() ?? []; - - switch (changed.Action) - { - case NotifyCollectionChangedAction.Add: - setsRequiringRemoval.RemoveWhere(s => newBeatmapSetIDs.Contains(s.ID)); - setsRequiringUpdate.AddRange(newBeatmapSets!); - break; - - case NotifyCollectionChangedAction.Remove: - setsRequiringUpdate.RemoveWhere(s => oldBeatmapSetIDs.Contains(s.ID)); - setsRequiringRemoval.AddRange(oldBeatmapSets!); - break; - - case NotifyCollectionChangedAction.Replace: - setsRequiringUpdate.RemoveWhere(s => oldBeatmapSetIDs.Contains(s.ID)); - setsRequiringRemoval.AddRange(oldBeatmapSets!); - - setsRequiringRemoval.RemoveWhere(s => newBeatmapSetIDs.Contains(s.ID)); - setsRequiringUpdate.AddRange(newBeatmapSets!); - break; - - case NotifyCollectionChangedAction.Move: - setsRequiringUpdate.AddRange(newBeatmapSets!); - break; - - case NotifyCollectionChangedAction.Reset: - setsRequiringRemoval.Clear(); - setsRequiringUpdate.Clear(); - loadNewRoot(); - break; - } - - Scheduler.AddOnce(processBeatmapChanges); - } - - // All local operations must be scheduled. - // - // If we don't schedule, beatmaps getting changed while song select is suspended (ie. last played being updated) - // will cause unexpected sounds and operations to occur in the background. - private void processBeatmapChanges() - { - try - { - // To handle the beatmap update flow, attempt to track selection changes across delete-insert transactions. - // When an update occurs, the previous beatmap set is either soft or hard deleted. - // Check if the current selection was potentially deleted by re-querying its validity. - bool selectedSetMarkedDeleted = SelectedBeatmapSet != null && fetchFromID(SelectedBeatmapSet.ID)?.DeletePending != false; - - foreach (var set in setsRequiringRemoval) removeBeatmapSet(set.ID); - - foreach (var set in setsRequiringUpdate) updateBeatmapSet(set); - - if (setsRequiringRemoval.Count > 0 && SelectedBeatmapInfo != null) - { - // If SelectedBeatmapInfo is non-null, the set should also be non-null. - Debug.Assert(SelectedBeatmapSet != null); - - if (selectedSetMarkedDeleted && setsRequiringUpdate.Any()) - { - // If it is no longer valid, make the bold assumption that an updated version will be available in the modified/inserted indices. - // This relies on the full update operation being in a single transaction, so please don't change that. - foreach (var set in setsRequiringUpdate) - { - foreach (var beatmapInfo in set.Beatmaps) - { - if (!((IBeatmapMetadataInfo)beatmapInfo.Metadata).Equals(SelectedBeatmapInfo.Metadata)) continue; - - // Best effort matching. We can't use ID because in the update flow a new version will get its own GUID. - if (beatmapInfo.DifficultyName == SelectedBeatmapInfo.DifficultyName) - { - SelectBeatmap(beatmapInfo); - return; - } - } - } - - // If a direct selection couldn't be made, it's feasible that the difficulty name (or beatmap metadata) changed. - // Let's attempt to follow set-level selection anyway. - SelectBeatmap(setsRequiringUpdate.First().Beatmaps.First()); - } - } - } - finally - { - BeatmapSetsLoaded = true; - invalidateAfterChange(); - } - - setsRequiringRemoval.Clear(); - setsRequiringUpdate.Clear(); - - BeatmapSetInfo? fetchFromID(Guid id) => realm.Realm.Find(id); - } - - public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) => Schedule(() => - { - removeBeatmapSet(beatmapSet.ID); - invalidateAfterChange(); - }); - - private void removeBeatmapSet(Guid beatmapSetID) - { - if (!root.BeatmapSetsByID.TryGetValue(beatmapSetID, out var existingSets)) - return; - - foreach (var set in existingSets) - { - foreach (var beatmap in set.Beatmaps) - randomSelectedBeatmaps.Remove(beatmap); - previouslyVisitedRandomSets.Remove(set); - - root.RemoveItem(set); - } - } - - public void UpdateBeatmapSet(BeatmapSetInfo beatmapSet) => Schedule(() => - { - updateBeatmapSet(beatmapSet); - invalidateAfterChange(); - }); - - private void updateBeatmapSet(BeatmapSetInfo beatmapSet) - { - var newSets = new List(); - - if (beatmapsSplitOut) - { - foreach (var beatmap in beatmapSet.Beatmaps) - { - var newSet = createCarouselSet(new BeatmapSetInfo(new[] { beatmap }) - { - ID = beatmapSet.ID, - OnlineID = beatmapSet.OnlineID, - Status = beatmapSet.Status, - }); - - if (newSet != null) - newSets.Add(newSet); - } - } - else - { - var newSet = createCarouselSet(beatmapSet); - - if (newSet != null) - newSets.Add(newSet); - } - - var removedSets = root.ReplaceItem(beatmapSet, newSets); - - // If we don't remove these here, it may remain in a hidden state until scrolled off screen. - // Doesn't really affect anything during actual user interaction, but makes testing annoying. - foreach (var removedSet in removedSets) - { - var removedDrawable = Scroll.FirstOrDefault(c => c.Item == removedSet); - if (removedDrawable != null) - expirePanelImmediately(removedDrawable); - } - } - - /// - /// Selects a given beatmap on the carousel. - /// - /// The beatmap to select. - /// Whether to select the beatmap even if it is filtered (i.e., not visible on carousel). - /// True if a selection was made, False if it wasn't. - public bool SelectBeatmap(BeatmapInfo? beatmapInfo, bool bypassFilters = true) - { - // ensure that any pending events from BeatmapManager have been run before attempting a selection. - Scheduler.Update(); - - if (beatmapInfo?.Hidden != false) - return false; - - foreach (CarouselBeatmapSet set in beatmapSets) - { - if (!bypassFilters && set.Filtered.Value) - continue; - - var item = set.Beatmaps.FirstOrDefault(p => p.BeatmapInfo.Equals(beatmapInfo)); - - if (item == null) - // The beatmap that needs to be selected doesn't exist in this set - continue; - - if (!bypassFilters && item.Filtered.Value) - return false; - - 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); - } - - return true; - } - - return false; - } - - /// - /// Increment selection in the carousel in a chosen direction. - /// - /// The direction to increment. Negative is backwards. - /// Whether to skip individual difficulties and only increment over full groups. - public void SelectNext(int direction = 1, bool skipDifficulties = true) - { - if (beatmapSets.All(s => s.Filtered.Value)) - return; - - if (skipDifficulties) - selectNextSet(direction, true); - else - selectNextDifficulty(direction); - } - - private void selectNextSet(int direction, bool skipDifficulties) - { - if (selectedBeatmap == null || selectedBeatmapSet == null) - return; - - var unfilteredSets = beatmapSets.Where(s => !s.Filtered.Value).ToList(); - - var nextSet = unfilteredSets[(unfilteredSets.IndexOf(selectedBeatmapSet) + direction + unfilteredSets.Count) % unfilteredSets.Count]; - - if (skipDifficulties) - select(nextSet); - else - select(direction > 0 ? nextSet.Beatmaps.First(b => !b.Filtered.Value) : nextSet.Beatmaps.Last(b => !b.Filtered.Value)); - } - - private void selectNextDifficulty(int direction) - { - if (selectedBeatmap == null || selectedBeatmapSet == null) - return; - - var unfilteredDifficulties = selectedBeatmapSet.Items.Where(s => !s.Filtered.Value).ToList(); - - int index = unfilteredDifficulties.IndexOf(selectedBeatmap); - - if (index + direction < 0 || index + direction >= unfilteredDifficulties.Count) - selectNextSet(direction, false); - else - select(unfilteredDifficulties[index + direction]); - } - - /// - /// Select the next beatmap in the random sequence. - /// - /// True if a selection could be made, else False. - public bool SelectNextRandom() - { - if (!AllowSelection) - return false; - - var visibleSets = beatmapSets.Where(s => !s.Filtered.Value).ToList(); - - visibleSetsCount = visibleSets.Count; - - if (!visibleSets.Any()) - return false; - - if (selectedBeatmap != null && selectedBeatmapSet != null) - { - randomSelectedBeatmaps.Add(selectedBeatmap); - - // when performing a random, we want to add the current set to the previously visited list - // else the user may be "randomised" to the existing selection. - if (previouslyVisitedRandomSets.LastOrDefault() != selectedBeatmapSet) - previouslyVisitedRandomSets.Add(selectedBeatmapSet); - } - - CarouselBeatmapSet set; - - if (RandomAlgorithm.Value == RandomSelectAlgorithm.RandomPermutation) - { - var notYetVisitedSets = visibleSets.Except(previouslyVisitedRandomSets).ToList(); - - if (!notYetVisitedSets.Any()) - { - previouslyVisitedRandomSets.RemoveAll(visibleSets.Contains); - notYetVisitedSets = visibleSets; - } - - set = notYetVisitedSets.ElementAt(RNG.Next(notYetVisitedSets.Count)); - previouslyVisitedRandomSets.Add(set); - } - else - set = visibleSets.ElementAt(RNG.Next(visibleSets.Count)); - - if (selectedBeatmapSet != null) - playSpinSample(distanceBetween(set, selectedBeatmapSet)); - - select(set); - return true; - } - - public void SelectPreviousRandom() - { - while (randomSelectedBeatmaps.Any()) - { - var beatmap = randomSelectedBeatmaps[^1]; - randomSelectedBeatmaps.RemoveAt(randomSelectedBeatmaps.Count - 1); - - if (!beatmap.Filtered.Value && beatmap.BeatmapInfo.BeatmapSet?.DeletePending != true) - { - if (selectedBeatmapSet != null) - { - if (RandomAlgorithm.Value == RandomSelectAlgorithm.RandomPermutation) - previouslyVisitedRandomSets.Remove(selectedBeatmapSet); - - playSpinSample(distanceBetween(beatmap, selectedBeatmapSet)); - } - - select(beatmap); - break; - } - } - } - - private double distanceBetween(CarouselItem item1, CarouselItem item2) => Math.Ceiling(Math.Abs(item1.CarouselYPosition - item2.CarouselYPosition) / DrawableCarouselItem.MAX_HEIGHT); - - private void playSpinSample(double distance) - { - var chan = spinSample?.GetChannel(); - - if (chan != null) - { - chan.Frequency.Value = 1f + Math.Min(1f, distance / visibleSetsCount); - chan.Play(); - } - - randomSelectSample?.Play(); - } - - private void select(CarouselItem? item) - { - if (!AllowSelection) - return; - - if (item == null) return; - - item.State.Value = CarouselItemState.Selected; - } - - private FilterCriteria activeCriteria; - - protected ScheduledDelegate? PendingFilter; - - public bool AllowSelection = true; - - /// - /// Half the height of the visible content. - /// - /// This is different from the height of .displayableContent, since - /// the beatmap carousel bleeds into the and the - /// - /// - private float visibleHalfHeight => (DrawHeight + BleedBottom + BleedTop) / 2; - - /// - /// The position of the lower visible bound with respect to the current scroll position. - /// - private float visibleBottomBound => (float)(Scroll.Current + DrawHeight + BleedBottom); - - /// - /// The position of the upper visible bound with respect to the current scroll position. - /// - private float visibleUpperBound => (float)(Scroll.Current - BleedTop); - - public void FlushPendingFilterOperations() - { - if (!IsLoaded) - return; - - if (PendingFilter?.Completed == false) - { - applyActiveCriteria(false); - Update(); - } - } - - public void Filter(FilterCriteria? newCriteria) - { - if (newCriteria != null) - activeCriteria = newCriteria; - - applyActiveCriteria(true); - } - - private bool beatmapsSplitOut; - - private void applyActiveCriteria(bool debounce) - { - PendingFilter?.Cancel(); - PendingFilter = null; - - if (debounce) - PendingFilter = Scheduler.AddDelayed(perform, 250); - else - { - // if initial load is not yet finished, this will be run inline in loadBeatmapSets to ensure correct order of operation. - if (!BeatmapSetsLoaded) - PendingFilter = Schedule(perform); - else - perform(); - } - - void perform() - { - PendingFilter = null; - - if ((activeCriteria.Sort == SortMode.Difficulty) != beatmapsSplitOut) - { - loadNewRoot(); - return; - } - - root.Filter(activeCriteria); - itemsCache.Invalidate(); - - ScrollToSelected(true); - - FilterApplied?.Invoke(); - } - } - - private void invalidateAfterChange() - { - itemsCache.Invalidate(); - - if (!Scroll.UserScrolling) - ScrollToSelected(true); - - BeatmapSetsChanged?.Invoke(); - } - - private float? scrollTarget; - - /// - /// Scroll to the current . - /// - /// - /// Whether the scroll position should immediately be shifted to the target, delegating animation to visible panels. - /// This should be true for operations like filtering - where panels are changing visibility state - to avoid large jumps in animation. - /// - public void ScrollToSelected(bool immediate = false) => - pendingScrollOperation = immediate ? PendingScrollOperation.Immediate : PendingScrollOperation.Standard; - - #region Button selection logic - - public bool OnPressed(KeyBindingPressEvent e) - { - switch (e.Action) - { - case GlobalAction.SelectNext: - case GlobalAction.ActivateNextSet: - SelectNext(1, e.Action == GlobalAction.ActivateNextSet); - return true; - - case GlobalAction.SelectPrevious: - case GlobalAction.ActivatePreviousSet: - SelectNext(-1, e.Action == GlobalAction.ActivatePreviousSet); - return true; - } - - return false; - } - - public void OnReleased(KeyBindingReleaseEvent e) - { - } - - #endregion - - protected override bool OnInvalidate(Invalidation invalidation, InvalidationSource source) - { - // handles the vertical size of the carousel changing (ie. on window resize when aspect ratio has changed). - if (invalidation.HasFlag(Invalidation.DrawSize)) - itemsCache.Invalidate(); - - return base.OnInvalidate(invalidation, source); - } - - protected override void Update() - { - base.Update(); - - bool revalidateItems = !itemsCache.IsValid; - - // First we iterate over all non-filtered carousel items and populate their - // vertical position data. - if (revalidateItems) - { - updateYPositions(); - - if (visibleItems.Count == 0) - { - noResultsPlaceholder.Filter = activeCriteria; - noResultsPlaceholder.Show(); - } - else - noResultsPlaceholder.Hide(); - } - - // if there is a pending scroll action we apply it without animation and transfer the difference in position to the panels. - // this is intentionally applied before updating the visible range below, to avoid animating new items (sourced from pool) from locations off-screen, as it looks bad. - if (pendingScrollOperation != PendingScrollOperation.None) - updateScrollPosition(); - - // This data is consumed to find the currently displayable range. - // This is the range we want to keep drawables for, and should exceed the visible range slightly to avoid drawable churn. - var newDisplayRange = getDisplayRange(); - - // If the filtered items or visible range has changed, pooling requirements need to be checked. - // This involves fetching new items from the pool, returning no-longer required items. - if (revalidateItems || newDisplayRange != displayedRange) - { - displayedRange = newDisplayRange; - - if (visibleItems.Count > 0) - { - var toDisplay = visibleItems.GetRange(displayedRange.first, displayedRange.last - displayedRange.first + 1); - - foreach (var panel in Scroll) - { - Debug.Assert(panel.Item != null); - - if (toDisplay.Remove(panel.Item)) - { - // panel already displayed. - continue; - } - - // panel loaded as drawable but not required by visible range. - // remove but only if too far off-screen - if (panel.Y + panel.DrawHeight < visibleUpperBound - distance_offscreen_before_unload || panel.Y > visibleBottomBound + distance_offscreen_before_unload) - expirePanelImmediately(panel); - } - - // Add those items within the previously found index range that should be displayed. - foreach (var item in toDisplay) - { - var panel = setPool.Get(); - - panel.Item = item; - panel.Y = item.CarouselYPosition; - - Scroll.Add(panel); - } - } - } - - // Update externally controlled state of currently visible items (e.g. x-offset and opacity). - // This is a per-frame update on all drawable panels. - foreach (DrawableCarouselItem item in Scroll) - { - updateItem(item); - - Debug.Assert(item.Item != null); - - if (item.Item.Visible) - { - bool isSelected = item.Item.State.Value == CarouselItemState.Selected; - - bool hasPassedSelection = item.Item.CarouselYPosition < selectedBeatmapSet?.CarouselYPosition; - - // Cheap way of doing animations when entering / exiting song select. - const double half_time = 50; - const float panel_x_offset_when_inactive = 200; - - if (isSelected || AllowSelection) - { - item.Alpha = (float)Interpolation.DampContinuously(item.Alpha, 1, half_time, Clock.ElapsedFrameTime); - item.X = (float)Interpolation.DampContinuously(item.X, 0, half_time, Clock.ElapsedFrameTime); - } - else - { - item.Alpha = (float)Interpolation.DampContinuously(item.Alpha, 0, half_time, Clock.ElapsedFrameTime); - item.X = (float)Interpolation.DampContinuously(item.X, panel_x_offset_when_inactive, half_time, Clock.ElapsedFrameTime); - } - - Scroll.ChangeChildDepth(item, hasPassedSelection ? -item.Item.CarouselYPosition : item.Item.CarouselYPosition); - } - - if (item is DrawableCarouselBeatmapSet set) - { - for (int i = 0; i < set.DrawableBeatmaps.Count; i++) - updateItem(set.DrawableBeatmaps[i], item); - } - } - } - - private static void expirePanelImmediately(DrawableCarouselItem panel) - { - // may want a fade effect here (could be seen if a huge change happens, like a set with 20 difficulties becomes selected). - panel.ClearTransforms(); - panel.Expire(); - } - - private readonly CarouselBoundsItem carouselBoundsItem = new CarouselBoundsItem(); - - private (int firstIndex, int lastIndex) getDisplayRange() - { - // Find index range of all items that should be on-screen - carouselBoundsItem.CarouselYPosition = visibleUpperBound - distance_offscreen_to_preload; - int firstIndex = visibleItems.BinarySearch(carouselBoundsItem); - if (firstIndex < 0) firstIndex = ~firstIndex; - - carouselBoundsItem.CarouselYPosition = visibleBottomBound + distance_offscreen_to_preload; - int lastIndex = visibleItems.BinarySearch(carouselBoundsItem); - if (lastIndex < 0) lastIndex = ~lastIndex; - - // as we can't be 100% sure on the size of individual carousel drawables, - // always play it safe and extend bounds by one. - firstIndex = Math.Max(0, firstIndex - 1); - lastIndex = Math.Clamp(lastIndex + 1, firstIndex, Math.Max(0, visibleItems.Count - 1)); - - return (firstIndex, lastIndex); - } - - private CarouselBeatmapSet? createCarouselSet(BeatmapSetInfo beatmapSet) - { - // This can be moved to the realm query if required using: - // .Filter("DeletePending == false && Protected == false && ANY Beatmaps.Hidden == false") - // - // As long as we are detaching though, it makes more sense to do it here as adding to the realm query has an overhead - // as seen at https://github.com/realm/realm-dotnet/discussions/2773#discussioncomment-2004275. - if (beatmapSet.Beatmaps.All(b => b.Hidden)) - return null; - - var set = new CarouselBeatmapSet(beatmapSet) - { - GetRecommendedBeatmap = beatmaps => GetRecommendedBeatmap?.Invoke(beatmaps) - }; - - foreach (var c in set.Beatmaps) - { - c.State.ValueChanged += state => - { - if (state.NewValue == CarouselItemState.Selected) - { - selectedBeatmapSet = set; - SelectionChanged?.Invoke(c.BeatmapInfo); - - itemsCache.Invalidate(); - ScrollToSelected(); - } - }; - } - - return set; - } - - /// - /// Computes the target Y positions for every item in the carousel. - /// - /// The Y position of the currently selected item. - private void updateYPositions() - { - visibleItems.Clear(); - - float currentY = visibleHalfHeight; - - scrollTarget = null; - - foreach (CarouselItem item in root.Items) - { - if (item.Filtered.Value) - continue; - - switch (item) - { - case CarouselBeatmapSet set: - { - bool isSelected = item.State.Value == CarouselItemState.Selected; - - float padding = isSelected ? 5 : -5; - - if (isSelected) - // double padding because we want to cancel the negative padding from the last item. - currentY += padding * 2; - - visibleItems.Add(set); - set.CarouselYPosition = currentY; - - if (isSelected) - { - // scroll position at currentY makes the set panel appear at the very top of the carousel's screen space - // move down by half of visible height (height of the carousel's visible extent, including semi-transparent areas) - // then reapply the top semi-transparent area (because carousel's screen space starts below it) - scrollTarget = currentY + DrawableCarouselBeatmapSet.HEIGHT - visibleHalfHeight + BleedTop; - - foreach (var b in set.Beatmaps) - { - if (!b.Visible) - continue; - - if (b.State.Value == CarouselItemState.Selected) - { - scrollTarget += b.TotalHeight / 2; - break; - } - - scrollTarget += b.TotalHeight; - } - } - - currentY += set.TotalHeight + padding; - break; - } - } - } - - currentY += visibleHalfHeight; - - Scroll.ScrollContent.Height = currentY; - - itemsCache.Validate(); - - // update and let external consumers know about selection loss. - if (BeatmapSetsLoaded && AllowSelection) - { - bool selectionLost = selectedBeatmapSet != null && selectedBeatmapSet.State.Value != CarouselItemState.Selected; - - if (selectionLost) - { - selectedBeatmapSet = null; - SelectionChanged?.Invoke(null); - } - } - } - - private bool firstScroll = true; - - private void updateScrollPosition() - { - if (scrollTarget != null) - { - if (firstScroll) - { - // reduce movement when first displaying the carousel. - Scroll.ScrollTo(scrollTarget.Value - 200, false); - firstScroll = false; - } - - switch (pendingScrollOperation) - { - case PendingScrollOperation.Standard: - Scroll.ScrollTo(scrollTarget.Value); - break; - - case PendingScrollOperation.Immediate: - - // in order to simplify animation logic, rather than using the animated version of ScrollTo, - // we take the difference in scroll height and apply to all visible panels. - // this avoids edge cases like when the visible panels is reduced suddenly, causing ScrollContainer - // to enter clamp-special-case mode where it animates completely differently to normal. - float scrollChange = (float)(scrollTarget.Value - Scroll.Current); - Scroll.ScrollTo(scrollTarget.Value, false); - foreach (var i in Scroll) - i.Y += scrollChange; - break; - } - - pendingScrollOperation = PendingScrollOperation.None; - } - } - - /// - /// Computes the x-offset of currently visible items. Makes the carousel appear round. - /// - /// - /// Vertical distance from the center of the carousel container - /// ranging from -1 to 1. - /// - /// Half the height of the carousel container. - private static float offsetX(float dist, float halfHeight) - { - // The radius of the circle the carousel moves on. - const float circle_radius = 3; - float discriminant = MathF.Max(0, circle_radius * circle_radius - dist * dist); - float x = (circle_radius - MathF.Sqrt(discriminant)) * halfHeight; - - return 125 + x; - } - - /// - /// Update an item's x position and multiplicative alpha based on its y position and - /// the current scroll position. - /// - /// The item to be updated. - /// For nested items, the parent of the item to be updated. - private void updateItem(DrawableCarouselItem item, DrawableCarouselItem? parent = null) - { - Vector2 posInScroll = Scroll.ScrollContent.ToLocalSpace(item.Header.ScreenSpaceDrawQuad.Centre); - float itemDrawY = posInScroll.Y - visibleUpperBound; - float dist = Math.Abs(1f - itemDrawY / visibleHalfHeight); - - // adjusting the item's overall X position can cause it to become masked away when - // child items (difficulties) are still visible. - item.Header.X = offsetX(dist, visibleHalfHeight) - (parent?.X ?? 0); - } - - private enum PendingScrollOperation - { - None, - Standard, - Immediate, - } - - /// - /// A carousel item strictly used for binary search purposes. - /// - private class CarouselBoundsItem : CarouselItem - { - public override DrawableCarouselItem CreateDrawableRepresentation() => throw new NotImplementedException(); - } - - private class CarouselRoot : CarouselGroupEagerSelect - { - // May only be null during construction (State.Value set causes PerformSelection to be triggered). - private readonly BeatmapCarousel? carousel; - - public readonly Dictionary> BeatmapSetsByID = new Dictionary>(); - - public CarouselRoot(BeatmapCarousel carousel) - { - // root should always remain selected. if not, PerformSelection will not be called. - State.Value = CarouselItemState.Selected; - State.ValueChanged += _ => State.Value = CarouselItemState.Selected; - - this.carousel = carousel; - } - - public override void AddItem(CarouselItem i) - { - CarouselBeatmapSet set = (CarouselBeatmapSet)i; - if (BeatmapSetsByID.TryGetValue(set.BeatmapSet.ID, out var sets)) - sets.Add(set); - else - BeatmapSetsByID.Add(set.BeatmapSet.ID, new List { set }); - - base.AddItem(i); - } - - /// - /// A special method to handle replace operations (general for updating a beatmap). - /// Avoids event-driven selection flip-flopping during the remove/add process. - /// - /// The beatmap set to be replaced. - /// All new items to replace the removed beatmap set. - /// All removed items, for any further processing. - public IEnumerable ReplaceItem(BeatmapSetInfo oldItem, List newItems) - { - var previousSelection = (LastSelected as CarouselBeatmapSet)?.Beatmaps - .FirstOrDefault(s => s.State.Value == CarouselItemState.Selected) - ?.BeatmapInfo; - - bool wasSelected = previousSelection?.BeatmapSet?.ID == oldItem.ID; - - // Without doing this, the removal of the old beatmap will cause carousel's eager selection - // logic to invoke, causing one unnecessary selection. - DisableSelection = true; - var removedSets = RemoveItemsByID(oldItem.ID); - DisableSelection = false; - - foreach (var set in newItems) - AddItem(set); - - // Check if we can/need to maintain our current selection. - if (wasSelected) - { - CarouselBeatmap? matchingBeatmap = newItems.SelectMany(s => s.Beatmaps) - .FirstOrDefault(b => b.BeatmapInfo.ID == previousSelection?.ID); - - if (matchingBeatmap != null) - matchingBeatmap.State.Value = CarouselItemState.Selected; - } - - return removedSets; - } - - public IEnumerable RemoveItemsByID(Guid beatmapSetID) - { - if (BeatmapSetsByID.TryGetValue(beatmapSetID, out var carouselBeatmapSets)) - { - foreach (var set in carouselBeatmapSets) - RemoveItem(set); - - return carouselBeatmapSets; - } - - return Enumerable.Empty(); - } - - public override void RemoveItem(CarouselItem i) - { - CarouselBeatmapSet set = (CarouselBeatmapSet)i; - BeatmapSetsByID.Remove(set.BeatmapSet.ID); - - base.RemoveItem(i); - } - - protected override void PerformSelection() - { - if (LastSelected == null) - carousel?.SelectNextRandom(); - else - base.PerformSelection(); - } - } - - public partial class CarouselScrollContainer : UserTrackingScrollContainer, IKeyBindingHandler - { - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; - - public CarouselScrollContainer() - { - // size is determined by the carousel itself, due to not all content necessarily being loaded. - ScrollContent.AutoSizeAxes = Axes.None; - - // the scroll container may get pushed off-screen by global screen changes, but we still want panels to display outside of the bounds. - Masking = false; - } - - #region Absolute scrolling - - private bool absoluteScrolling; - - protected override bool IsDragging => base.IsDragging || absoluteScrolling; - - public bool OnPressed(KeyBindingPressEvent e) - { - switch (e.Action) - { - case GlobalAction.AbsoluteScrollSongList: - beginAbsoluteScrolling(e); - return true; - } - - return false; - } - - public void OnReleased(KeyBindingReleaseEvent e) - { - switch (e.Action) - { - case GlobalAction.AbsoluteScrollSongList: - endAbsoluteScrolling(); - break; - } - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - if (e.Button == MouseButton.Right) - { - // To avoid conflicts with context menus, disallow absolute scroll if it looks like things will fall over. - if (GetContainingInputManager()!.HoveredDrawables.OfType().Any()) - return false; - - beginAbsoluteScrolling(e); - } - - return base.OnMouseDown(e); - } - - protected override void OnMouseUp(MouseUpEvent e) - { - if (e.Button == MouseButton.Right) - endAbsoluteScrolling(); - base.OnMouseUp(e); - } - - protected override bool OnMouseMove(MouseMoveEvent e) - { - if (absoluteScrolling) - { - ScrollToAbsolutePosition(e.CurrentState.Mouse.Position); - return true; - } - - return base.OnMouseMove(e); - } - - private void beginAbsoluteScrolling(UIEvent e) - { - ScrollToAbsolutePosition(e.CurrentState.Mouse.Position); - absoluteScrolling = true; - } - - private void endAbsoluteScrolling() => absoluteScrolling = false; - - #endregion - - protected override ScrollbarContainer CreateScrollbar(Direction direction) - { - return new PaddedScrollbar(); - } - - protected partial class PaddedScrollbar : OsuScrollbar - { - public PaddedScrollbar() - : base(Direction.Vertical) - { - } - } - - private const float top_padding = 10; - private const float bottom_padding = 70; - - protected override float ToScrollbarPosition(double scrollPosition) - { - if (Precision.AlmostEquals(0, ScrollableExtent)) - return 0; - - return (float)(top_padding + (ScrollbarMovementExtent - (top_padding + bottom_padding)) * (scrollPosition / ScrollableExtent)); - } - - protected override float FromScrollbarPosition(float scrollbarPosition) - { - if (Precision.AlmostEquals(0, ScrollbarMovementExtent)) - return 0; - - return (float)(ScrollableExtent * ((scrollbarPosition - top_padding) / (ScrollbarMovementExtent - (top_padding + bottom_padding)))); - } - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs deleted file mode 100644 index 595b86924b..0000000000 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; - -namespace osu.Game.Screens.Select -{ - public abstract partial class BeatmapDetailArea : Container - { - private const float details_padding = 10; - - private WorkingBeatmap beatmap; - - public virtual WorkingBeatmap Beatmap - { - get => beatmap; - set - { - beatmap = value; - - Details.BeatmapInfo = value?.BeatmapInfo; - } - } - - public readonly BeatmapDetails Details; - - protected Bindable CurrentTab => tabControl.Current; - - protected Bindable CurrentModsFilter => tabControl.CurrentModsFilter; - - private readonly Container content; - protected override Container Content => content; - - private readonly BeatmapDetailAreaTabControl tabControl; - - protected BeatmapDetailArea() - { - AddRangeInternal(new Drawable[] - { - content = new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = BeatmapDetailAreaTabControl.HEIGHT }, - Child = Details = new BeatmapDetails - { - RelativeSizeAxes = Axes.X, - Alpha = 0, - Margin = new MarginPadding { Top = details_padding }, - } - }, - tabControl = new BeatmapDetailAreaTabControl - { - RelativeSizeAxes = Axes.X, - TabItems = CreateTabItems(), - OnFilter = OnTabChanged, - }, - }); - } - - /// - /// Refreshes the currently-displayed details. - /// - public virtual void Refresh() - { - } - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - Details.Height = Math.Min(DrawHeight - details_padding * 3 - BeatmapDetailAreaTabControl.HEIGHT, 450); - } - - /// - /// Invoked when a new tab is selected. - /// - /// The tab that was selected. - /// Whether the currently-selected mods should be considered. - protected virtual void OnTabChanged(BeatmapDetailAreaTabItem tab, bool selectedMods) - { - switch (tab) - { - case BeatmapDetailAreaDetailTabItem: - Details.Show(); - break; - - default: - Details.Hide(); - break; - } - } - - /// - /// Creates the tabs to be displayed. - /// - /// The tabs. - protected virtual BeatmapDetailAreaTabItem[] CreateTabItems() => new BeatmapDetailAreaTabItem[] - { - new BeatmapDetailAreaDetailTabItem(), - }; - } -} diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs b/osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs deleted file mode 100644 index 4ff2600a72..0000000000 --- a/osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -namespace osu.Game.Screens.Select -{ - public class BeatmapDetailAreaDetailTabItem : BeatmapDetailAreaTabItem - { - public override string Name => "Details"; - } -} diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs b/osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs deleted file mode 100644 index 8dbe5b8bea..0000000000 --- a/osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs +++ /dev/null @@ -1,22 +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 System; - -namespace osu.Game.Screens.Select -{ - public class BeatmapDetailAreaLeaderboardTabItem : BeatmapDetailAreaTabItem - where TScope : Enum - { - public override string Name => Scope.ToString(); - - public override bool FilterableByMods => true; - - public readonly TScope Scope; - - public BeatmapDetailAreaLeaderboardTabItem(TScope scope) - { - Scope = scope; - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs deleted file mode 100644 index f9dab2bb1d..0000000000 --- a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Collections.Generic; -using osuTK.Graphics; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; -using osu.Framework.Graphics.Shapes; - -namespace osu.Game.Screens.Select -{ - public partial class BeatmapDetailAreaTabControl : Container - { - public const float HEIGHT = 24; - - public Bindable Current - { - get => tabs.Current; - set => tabs.Current = value; - } - - public Bindable CurrentModsFilter - { - get => modsCheckbox.Current; - set => modsCheckbox.Current = value; - } - - public Action OnFilter; // passed the selected tab and if mods is checked - - public IReadOnlyList TabItems - { - get => tabs.Items; - set => tabs.Items = value; - } - - private readonly OsuTabControlCheckbox modsCheckbox; - private readonly OsuTabControl tabs; - private readonly Container tabsContainer; - - public BeatmapDetailAreaTabControl() - { - Height = HEIGHT; - - Children = new Drawable[] - { - new Box - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - Height = 1, - Colour = Color4.White.Opacity(0.2f), - }, - tabsContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Child = tabs = new OsuTabControl - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Both, - IsSwitchable = true, - }, - }, - modsCheckbox = new OsuTabControlCheckbox - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Text = @"Selected Mods", - Alpha = 0, - }, - }; - - tabs.Current.ValueChanged += _ => invokeOnFilter(); - modsCheckbox.Current.ValueChanged += _ => invokeOnFilter(); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colour) - { - modsCheckbox.AccentColour = tabs.AccentColour = colour.YellowLight; - } - - private void invokeOnFilter() - { - OnFilter?.Invoke(tabs.Current.Value, modsCheckbox.Current.Value); - - if (tabs.Current.Value.FilterableByMods) - { - modsCheckbox.FadeTo(1, 200, Easing.OutQuint); - tabsContainer.Padding = new MarginPadding { Right = 100 }; - } - else - { - modsCheckbox.FadeTo(0, 200, Easing.OutQuint); - tabsContainer.Padding = new MarginPadding(); - } - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs deleted file mode 100644 index 7b7a93d6ee..0000000000 --- a/osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; - -namespace osu.Game.Screens.Select -{ - public abstract class BeatmapDetailAreaTabItem : IEquatable - { - /// - /// The name of this tab, to be displayed in the tab control. - /// - public abstract string Name { get; } - - /// - /// Whether the contents of this tab can be filtered by the user's currently-selected mods. - /// - public virtual bool FilterableByMods => false; - - public override string ToString() => Name; - - public bool Equals(BeatmapDetailAreaTabItem other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - - return Name == other.Name; - } - - public override int GetHashCode() - { - return Name != null ? Name.GetHashCode() : 0; - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs deleted file mode 100644 index 6a6a4cddf3..0000000000 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ /dev/null @@ -1,278 +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 System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests; -using osu.Game.Overlays.BeatmapSet; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Screens.Select.Details; -using osuTK; - -namespace osu.Game.Screens.Select -{ - public partial class BeatmapDetails : Container - { - private const float spacing = 10; - private const float transition_duration = 250; - - private readonly UserRatings ratingsDisplay; - private readonly MetadataSection description, source, tags; - private readonly Container failRetryContainer; - private readonly FailRetryGraph failRetryGraph; - private readonly LoadingLayer loading; - - [Resolved] - private IAPIProvider api { get; set; } = null!; - - [Resolved] - private SongSelect? songSelect { get; set; } - - private IBeatmapInfo? beatmapInfo; - - private APIFailTimes? failTimes; - - private int[]? ratings; - - public IBeatmapInfo? BeatmapInfo - { - get => beatmapInfo; - set - { - if (value == beatmapInfo) return; - - beatmapInfo = value; - - var onlineInfo = beatmapInfo as IBeatmapOnlineInfo; - var onlineSetInfo = beatmapInfo?.BeatmapSet as IBeatmapSetOnlineInfo; - - failTimes = onlineInfo?.FailTimes; - ratings = onlineSetInfo?.Ratings; - - Scheduler.AddOnce(updateStatistics); - } - } - - public BeatmapDetails() - { - CornerRadius = 10; - Masking = true; - - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Colour4.Black.Opacity(0.3f), - }, - new GridContainer - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = spacing }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension() - }, - Content = new[] - { - new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Width = 0.5f, - Spacing = new Vector2(spacing), - Padding = new MarginPadding { Right = spacing / 2 }, - Children = new[] - { - new DetailBox().WithChild(new OnlineViewContainer(string.Empty) - { - RelativeSizeAxes = Axes.X, - Height = 134, - Padding = new MarginPadding { Horizontal = spacing, Top = spacing }, - Child = ratingsDisplay = new UserRatings - { - RelativeSizeAxes = Axes.Both, - }, - }), - }, - }, - new OsuScrollContainer - { - RelativeSizeAxes = Axes.X, - Height = 250, - Width = 0.5f, - ScrollbarVisible = false, - Padding = new MarginPadding { Left = spacing / 2 }, - Child = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - LayoutDuration = transition_duration, - LayoutEasing = Easing.OutQuad, - Children = new[] - { - description = new MetadataSectionDescription(query => songSelect?.Search(query)), - source = new MetadataSectionSource(query => songSelect?.Search(query)), - tags = new MetadataSectionMapperTags(query => songSelect?.Search(query)), - }, - }, - }, - }, - }, - }, - new Drawable[] - { - failRetryContainer = new OnlineViewContainer("Sign in to view more details") - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new OsuSpriteText - { - Text = BeatmapsetsStrings.ShowInfoPointsOfFailure, - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 14), - }, - failRetryGraph = new FailRetryGraph - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 14 + spacing / 2 }, - }, - }, - }, - } - } - }, - loading = new LoadingLayer(true) - }; - } - - private void updateStatistics() - { - description.Metadata = BeatmapInfo?.DifficultyName ?? string.Empty; - source.Metadata = BeatmapInfo?.Metadata.Source ?? string.Empty; - tags.Metadata = BeatmapInfo?.Metadata.Tags ?? string.Empty; - - // failTimes may have been previously fetched - if (ratings != null && failTimes != null) - { - updateMetrics(); - return; - } - - // for now, let's early abort if an OnlineID is not present (should have been populated at import time). - if (BeatmapInfo == null || BeatmapInfo.OnlineID <= 0 || api.State.Value == APIState.Offline) - { - updateMetrics(); - return; - } - - var requestedBeatmap = BeatmapInfo; - - var lookup = new GetBeatmapRequest(requestedBeatmap); - - lookup.Success += res => - { - Schedule(() => - { - if (beatmapInfo != requestedBeatmap) - // the beatmap has been changed since we started the lookup. - return; - - ratings = res.BeatmapSet?.Ratings; - failTimes = res.FailTimes; - - updateMetrics(); - }); - }; - - lookup.Failure += _ => - { - Schedule(() => - { - if (beatmapInfo != requestedBeatmap) - // the beatmap has been changed since we started the lookup. - return; - - updateMetrics(); - }); - }; - - api.Queue(lookup); - loading.Show(); - } - - private void updateMetrics() - { - bool hasMetrics = (failTimes?.Retries?.Any() ?? false) || (failTimes?.Fails?.Any() ?? false); - - if (ratings?.Any() ?? false) - { - ratingsDisplay.Ratings = ratings; - ratingsDisplay.FadeIn(transition_duration); - } - else - { - // loading or just has no data server-side. - ratingsDisplay.Ratings = new int[10]; - ratingsDisplay.FadeTo(0.25f, transition_duration); - } - - if (hasMetrics) - { - failRetryGraph.FailTimes = failTimes; - failRetryContainer.FadeIn(transition_duration); - } - else - { - failRetryGraph.FailTimes = new APIFailTimes - { - Fails = new int[100], - Retries = new int[100], - }; - } - - loading.Hide(); - } - - private partial class DetailBox : Container - { - private readonly Container content; - protected override Container Content => content; - - public DetailBox() - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - - InternalChildren = new Drawable[] - { - content = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }, - }; - } - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs deleted file mode 100644 index 79564167f4..0000000000 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ /dev/null @@ -1,517 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using osuTK; -using osuTK.Graphics; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Localisation; -using osu.Framework.Logging; -using osu.Game.Configuration; -using osu.Game.Extensions; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.UI; -using osu.Game.Graphics.Containers; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Utils; - -namespace osu.Game.Screens.Select -{ - public partial class BeatmapInfoWedge : VisibilityContainer - { - public const float BORDER_THICKNESS = 2.5f; - private const float shear_width = 36.75f; - - private const float transition_duration = 250; - - private static readonly Vector2 wedged_container_shear = new Vector2(shear_width / SongSelect.WEDGE_HEIGHT, 0); - - [Resolved] - private IBindable ruleset { get; set; } - - protected Container DisplayedContent { get; private set; } - - protected WedgeInfoText Info { get; private set; } - - public BeatmapInfoWedge() - { - Shear = wedged_container_shear; - Masking = true; - BorderColour = new Color4(221, 255, 255, 255); - BorderThickness = BORDER_THICKNESS; - Alpha = 0; - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = new Color4(130, 204, 255, 150), - Radius = 15, - Roundness = 15, - }; - } - - [BackgroundDependencyLoader] - private void load() - { - ruleset.BindValueChanged(_ => updateDisplay()); - } - - private const double animation_duration = 800; - - protected override void PopIn() - { - this.MoveToX(0, animation_duration, Easing.OutQuint); - this.FadeIn(transition_duration); - } - - protected override void PopOut() - { - this.MoveToX(-100, animation_duration, Easing.In); - this.FadeOut(transition_duration * 2, Easing.In); - } - - private WorkingBeatmap beatmap; - - public WorkingBeatmap Beatmap - { - get => beatmap; - set - { - if (beatmap == value) return; - - beatmap = value; - - updateDisplay(); - } - } - - public override bool IsPresent => base.IsPresent || DisplayedContent == null; // Visibility is updated in the LoadComponentAsync callback - - private Container loadingInfo; - - private void updateDisplay() - { - Scheduler.AddOnce(perform); - - void perform() - { - void removeOldInfo() - { - State.Value = beatmap == null ? Visibility.Hidden : Visibility.Visible; - - DisplayedContent?.FadeOut(transition_duration); - DisplayedContent?.Expire(); - DisplayedContent = null; - } - - if (beatmap == null) - { - removeOldInfo(); - return; - } - - LoadComponentAsync(loadingInfo = new Container - { - RelativeSizeAxes = Axes.Both, - Shear = -Shear, - Depth = DisplayedContent?.Depth + 1 ?? 0, - Children = new Drawable[] - { - new BeatmapInfoWedgeBackground(beatmap), - Info = new WedgeInfoText(beatmap, ruleset.Value), - } - }, loaded => - { - // ensure we are the most recent loaded wedge. - if (loaded != loadingInfo) return; - - removeOldInfo(); - Add(DisplayedContent = loaded); - }); - } - } - - public partial class WedgeInfoText : Container - { - public OsuSpriteText VersionLabel { get; private set; } - public OsuSpriteText TitleLabel { get; private set; } - public OsuSpriteText ArtistLabel { get; private set; } - public FillFlowContainer MapperContainer { get; private set; } - - private Container difficultyColourBar; - private StarRatingDisplay starRatingDisplay; - - private ILocalisedBindableString titleBinding; - private ILocalisedBindableString artistBinding; - private FillFlowContainer infoLabelContainer; - private Container bpmLabelContainer; - private Container lengthLabelContainer; - - private readonly WorkingBeatmap working; - private readonly RulesetInfo ruleset; - - [Resolved] - private IBindable> mods { get; set; } - - [Resolved] - private BeatmapDifficultyCache difficultyCache { get; set; } - - [Resolved] - private OsuColour colours { get; set; } - - private ModSettingChangeTracker settingChangeTracker; - - public WedgeInfoText(WorkingBeatmap working, RulesetInfo userRuleset) - { - this.working = working; - ruleset = userRuleset ?? working.BeatmapInfo.Ruleset; - } - - private CancellationTokenSource cancellationSource; - private IBindable starDifficulty; - - [BackgroundDependencyLoader] - private void load(LocalisationManager localisation) - { - var beatmapInfo = working.BeatmapInfo; - var metadata = beatmapInfo.Metadata; - - RelativeSizeAxes = Axes.Both; - - titleBinding = localisation.GetLocalisedBindableString(new RomanisableString(metadata.TitleUnicode, metadata.Title)); - artistBinding = localisation.GetLocalisedBindableString(new RomanisableString(metadata.ArtistUnicode, metadata.Artist)); - - const float top_height = 0.7f; - - Children = new Drawable[] - { - difficultyColourBar = new Container - { - RelativeSizeAxes = Axes.Y, - Width = 20f, - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Width = top_height, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Both, - Alpha = 0.5f, - X = top_height, - Width = 1 - top_height, - } - } - }, - new FillFlowContainer - { - Name = "Topleft-aligned metadata", - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - Direction = FillDirection.Vertical, - Padding = new MarginPadding { Top = 10, Left = 25, Right = shear_width * 2.5f }, - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Children = new Drawable[] - { - VersionLabel = new TruncatingSpriteText - { - Text = beatmapInfo.DifficultyName, - Font = OsuFont.GetFont(size: 24, italics: true), - RelativeSizeAxes = Axes.X, - }, - } - }, - new FillFlowContainer - { - Name = "Topright-aligned metadata", - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Direction = FillDirection.Vertical, - Padding = new MarginPadding { Top = 14, Right = shear_width / 2 }, - AutoSizeAxes = Axes.Both, - Shear = wedged_container_shear, - Spacing = new Vector2(0f, 5f), - Children = new Drawable[] - { - starRatingDisplay = new StarRatingDisplay(default, animated: true) - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Shear = -wedged_container_shear, - Alpha = 0f, - }, - new BeatmapSetOnlineStatusPill - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Shear = -wedged_container_shear, - TextSize = 11, - TextPadding = new MarginPadding { Horizontal = 8, Vertical = 2 }, - Status = beatmapInfo.Status, - Alpha = string.IsNullOrEmpty(beatmapInfo.DifficultyName) ? 0 : 1 - } - } - }, - new FillFlowContainer - { - Name = "Centre-aligned metadata", - Anchor = Anchor.CentreLeft, - Origin = Anchor.TopLeft, - Y = -7, - Direction = FillDirection.Vertical, - Padding = new MarginPadding { Left = 25, Right = shear_width }, - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Children = new Drawable[] - { - TitleLabel = new TruncatingSpriteText - { - Current = { BindTarget = titleBinding }, - Font = OsuFont.GetFont(size: 28, italics: true), - RelativeSizeAxes = Axes.X, - }, - ArtistLabel = new TruncatingSpriteText - { - Current = { BindTarget = artistBinding }, - Font = OsuFont.GetFont(size: 17, italics: true), - RelativeSizeAxes = Axes.X, - }, - MapperContainer = new FillFlowContainer - { - Margin = new MarginPadding { Top = 10 }, - Direction = FillDirection.Horizontal, - AutoSizeAxes = Axes.Both, - Child = getMapper(metadata), - }, - infoLabelContainer = new FillFlowContainer - { - Margin = new MarginPadding { Top = 8 }, - Spacing = new Vector2(20, 0), - AutoSizeAxes = Axes.Both, - } - } - } - }; - - addInfoLabels(); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - starRatingDisplay.DisplayedStars.BindValueChanged(s => - { - difficultyColourBar.Colour = colours.ForStarDifficulty(s.NewValue); - }, true); - - starDifficulty = difficultyCache.GetBindableDifficulty(working.BeatmapInfo, (cancellationSource = new CancellationTokenSource()).Token); - starDifficulty.BindValueChanged(s => - { - starRatingDisplay.Current.Value = s.NewValue; - - // Don't roll the counter on initial display (but still allow it to roll on applying mods etc.) - if (!starRatingDisplay.IsPresent) - starRatingDisplay.FinishTransforms(true); - - starRatingDisplay.FadeIn(transition_duration); - }); - - mods.BindValueChanged(m => - { - settingChangeTracker?.Dispose(); - - refreshBPMAndLengthLabel(); - - settingChangeTracker = new ModSettingChangeTracker(m.NewValue); - settingChangeTracker.SettingChanged += _ => refreshBPMAndLengthLabel(); - }, true); - } - - private void addInfoLabels() - { - if (working.Beatmap?.HitObjects.Any() != true) - return; - - try - { - IBeatmap playableBeatmap; - - try - { - // Try to get the beatmap with the user's ruleset - playableBeatmap = working.GetPlayableBeatmap(ruleset, Array.Empty()); - } - catch (BeatmapInvalidForRulesetException) - { - // Can't be converted to the user's ruleset, so use the beatmap's own ruleset - playableBeatmap = working.GetPlayableBeatmap(working.BeatmapInfo.Ruleset, Array.Empty()); - } - - infoLabelContainer.Children = new Drawable[] - { - lengthLabelContainer = new Container - { - AutoSizeAxes = Axes.Both, - }, - bpmLabelContainer = new Container - { - AutoSizeAxes = Axes.Both, - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Spacing = new Vector2(20, 0), - Children = playableBeatmap.GetStatistics().Select(s => new InfoLabel(s)).ToArray() - } - }; - } - catch (Exception e) - { - Logger.Error(e, "Could not load beatmap successfully!"); - } - } - - private void refreshBPMAndLengthLabel() - { - var beatmap = working.Beatmap; - - if (beatmap == null || bpmLabelContainer == null) - return; - - double rate = ModUtils.CalculateRateWithMods(mods.Value); - - int bpmMax = FormatUtils.RoundBPM(beatmap.ControlPointInfo.BPMMaximum, rate); - int bpmMin = FormatUtils.RoundBPM(beatmap.ControlPointInfo.BPMMinimum, rate); - int mostCommonBPM = FormatUtils.RoundBPM(60000 / beatmap.GetMostCommonBeatLength(), rate); - - string labelText = bpmMin == bpmMax - ? $"{bpmMin}" - : $"{bpmMin}-{bpmMax} (mostly {mostCommonBPM})"; - - bpmLabelContainer.Child = new InfoLabel(new BeatmapStatistic - { - Name = BeatmapsetsStrings.ShowStatsBpm, - CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Bpm), - Content = labelText - }); - - double drainLength = Math.Round(beatmap.CalculateDrainLength() / rate); - double hitLength = Math.Round(beatmap.BeatmapInfo.Length / rate); - - lengthLabelContainer.Child = new InfoLabel(new BeatmapStatistic - { - Name = BeatmapsetsStrings.ShowStatsTotalLength(drainLength.ToFormattedDuration()), - CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Length), - Content = hitLength.ToFormattedDuration().ToString(), - }); - } - - private Drawable getMapper(BeatmapMetadata metadata) - { - if (string.IsNullOrEmpty(metadata.Author.Username)) - return Empty(); - - return new LinkFlowContainer(s => - { - s.Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 15); - }).With(d => - { - d.AutoSizeAxes = Axes.Both; - d.AddText("mapped by "); - d.AddUserLink(metadata.Author); - }); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - settingChangeTracker?.Dispose(); - cancellationSource?.Cancel(); - } - - public partial class InfoLabel : Container, IHasTooltip - { - public LocalisableString TooltipText { get; } - - internal BeatmapStatistic Statistic { get; } - - public InfoLabel(BeatmapStatistic statistic) - { - Statistic = statistic; - TooltipText = statistic.Name; - AutoSizeAxes = Axes.Both; - - Children = new Drawable[] - { - new Container - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Size = new Vector2(20), - Children = new[] - { - new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"441288"), - Icon = FontAwesome.Solid.Square, - Rotation = 45, - }, - new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"f7dd55"), - Icon = FontAwesome.Regular.Circle, - Size = new Vector2(0.7f) - }, - statistic.CreateIcon().With(i => - { - i.Anchor = Anchor.Centre; - i.Origin = Anchor.Centre; - i.RelativeSizeAxes = Axes.Both; - i.Colour = Color4Extensions.FromHex(@"f7dd55"); - i.Size = new Vector2(0.6f); - }), - } - }, - new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Colour = new Color4(255, 221, 85, 255), - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 17), - Margin = new MarginPadding { Left = 30 }, - Text = statistic.Content, - } - }; - } - } - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs b/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs deleted file mode 100644 index 50ec446c4f..0000000000 --- a/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs +++ /dev/null @@ -1,65 +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 osuTK.Graphics; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Drawables; -using osu.Framework.Graphics.Shapes; - -namespace osu.Game.Screens.Select -{ - internal partial class BeatmapInfoWedgeBackground : CompositeDrawable - { - private readonly IWorkingBeatmap beatmap; - - public BeatmapInfoWedgeBackground(IWorkingBeatmap beatmap) - { - this.beatmap = beatmap; - } - - [BackgroundDependencyLoader] - private void load() - { - RelativeSizeAxes = Axes.Both; - - InternalChild = new BufferedContainer(cachedFrameBuffer: true) - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - // We will create the white-to-black gradient by modulating transparency and having - // a black backdrop. This results in an sRGB-space gradient and not linear space, - // transitioning from white to black more perceptually uniformly. - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - // We use a container, such that we can set the colour gradient to go across the - // vertices of the masked container instead of the vertices of the (larger) sprite. - new Container - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(Color4.White, Color4.White.Opacity(0.3f)), - Children = new[] - { - // Zoomed-in and cropped beatmap background - new BeatmapBackgroundSprite(beatmap) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fill, - }, - }, - }, - } - }; - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs deleted file mode 100644 index 39bf4e134b..0000000000 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ /dev/null @@ -1,161 +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 System; -using System.Linq; -using osu.Game.Beatmaps; -using osu.Game.Screens.Select.Filter; -using osu.Game.Utils; - -namespace osu.Game.Screens.Select.Carousel -{ - public class CarouselBeatmap : CarouselItem - { - public override float TotalHeight => DrawableCarouselBeatmap.HEIGHT; - - public readonly BeatmapInfo BeatmapInfo; - - public CarouselBeatmap(BeatmapInfo beatmapInfo) - { - BeatmapInfo = beatmapInfo; - State.Value = CarouselItemState.Collapsed; - } - - public override DrawableCarouselItem CreateDrawableRepresentation() => new DrawableCarouselBeatmap(this); - - public override void Filter(FilterCriteria criteria) - { - base.Filter(criteria); - - Filtered.Value = !checkMatch(criteria); - } - - private bool checkMatch(FilterCriteria criteria) - { - bool match = - criteria.Ruleset == null || - BeatmapInfo.Ruleset.ShortName == criteria.Ruleset.ShortName || - (BeatmapInfo.Ruleset.OnlineID == 0 && criteria.Ruleset.OnlineID != 0 && criteria.AllowConvertedBeatmaps); - - if (BeatmapInfo.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true) - { - // only check ruleset equality or convertability for selected beatmap - return match; - } - - if (!match) return false; - - if (criteria.SearchTerms.Length > 0) - { - match = BeatmapInfo.Match(criteria.SearchTerms); - - // if a match wasn't found via text matching of terms, do a second catch-all check matching against online IDs. - // this should be done after text matching so we can prioritise matching numbers in metadata. - if (!match && criteria.SearchNumber.HasValue) - { - match = (BeatmapInfo.OnlineID == criteria.SearchNumber.Value) || - (BeatmapInfo.BeatmapSet?.OnlineID == criteria.SearchNumber.Value); - } - } - - if (!match) return false; - - match &= !criteria.StarDifficulty.HasFilter || criteria.StarDifficulty.IsInRange(BeatmapInfo.StarRating.FloorToDecimalDigits(2)); - match &= !criteria.ApproachRate.HasFilter || criteria.ApproachRate.IsInRange(BeatmapInfo.Difficulty.ApproachRate); - match &= !criteria.DrainRate.HasFilter || criteria.DrainRate.IsInRange(BeatmapInfo.Difficulty.DrainRate); - match &= !criteria.CircleSize.HasFilter || criteria.CircleSize.IsInRange(BeatmapInfo.Difficulty.CircleSize); - match &= !criteria.OverallDifficulty.HasFilter || criteria.OverallDifficulty.IsInRange(BeatmapInfo.Difficulty.OverallDifficulty); - match &= !criteria.Length.HasFilter || criteria.Length.IsInRange(BeatmapInfo.Length); - match &= !criteria.LastPlayed.HasFilter || criteria.LastPlayed.IsInRange(BeatmapInfo.LastPlayed ?? DateTimeOffset.MinValue); - match &= !criteria.DateRanked.HasFilter || (BeatmapInfo.BeatmapSet?.DateRanked != null && criteria.DateRanked.IsInRange(BeatmapInfo.BeatmapSet.DateRanked.Value)); - match &= !criteria.DateSubmitted.HasFilter || (BeatmapInfo.BeatmapSet?.DateSubmitted != null && criteria.DateSubmitted.IsInRange(BeatmapInfo.BeatmapSet.DateSubmitted.Value)); - match &= !criteria.BPM.HasFilter || criteria.BPM.IsInRange(BeatmapInfo.BPM); - - match &= !criteria.BeatDivisor.HasFilter || criteria.BeatDivisor.IsInRange(BeatmapInfo.BeatDivisor); - match &= !criteria.OnlineStatus.HasFilter || criteria.OnlineStatus.IsInRange(BeatmapInfo.Status); - - if (!match) return false; - - match &= !criteria.Creator.HasFilter || criteria.Creator.Matches(BeatmapInfo.Metadata.Author.Username); - - if (criteria.Artist.HasFilter) - { - if (criteria.Artist.ExcludeTerm) - match &= criteria.Artist.Matches(BeatmapInfo.Metadata.Artist) && criteria.Artist.Matches(BeatmapInfo.Metadata.ArtistUnicode); - else - match &= criteria.Artist.Matches(BeatmapInfo.Metadata.Artist) || criteria.Artist.Matches(BeatmapInfo.Metadata.ArtistUnicode); - } - - if (criteria.Title.HasFilter) - { - if (criteria.Title.ExcludeTerm) - match &= criteria.Title.Matches(BeatmapInfo.Metadata.Title) && criteria.Title.Matches(BeatmapInfo.Metadata.TitleUnicode); - else - match &= criteria.Title.Matches(BeatmapInfo.Metadata.Title) || criteria.Title.Matches(BeatmapInfo.Metadata.TitleUnicode); - } - - match &= !criteria.DifficultyName.HasFilter || criteria.DifficultyName.Matches(BeatmapInfo.DifficultyName); - match &= !criteria.Source.HasFilter || criteria.Source.Matches(BeatmapInfo.Metadata.Source); - - if (criteria.UserTags.Any()) - { - foreach (var tagFilter in criteria.UserTags) - { - if (tagFilter.ExcludeTerm) - { - // if `ExcludeTerm` is true, `Matches()` will return true if a user tag *doesn't match* the excluded term. - // thus, every user tag must pass this filter. - foreach (string tag in BeatmapInfo.Metadata.UserTags) - match &= tagFilter.Matches(tag); - } - else - { - // if `ExcludeTerm` is false, `Matches()` will return true if a user tag *matches* the expected term. - // the expected behaviour is that a beatmap should be displayed if at least one of the user tags passes the filter. - bool anyTagMatched = false; - - foreach (string tag in BeatmapInfo.Metadata.UserTags) - anyTagMatched |= tagFilter.Matches(tag); - - match &= anyTagMatched; - } - } - } - - match &= !criteria.UserStarDifficulty.HasFilter || criteria.UserStarDifficulty.IsInRange(BeatmapInfo.StarRating); - - if (!match) return false; - - match &= criteria.CollectionBeatmapMD5Hashes?.Contains(BeatmapInfo.MD5Hash) ?? true; - if (match && criteria.RulesetCriteria != null) - match &= criteria.RulesetCriteria.Matches(BeatmapInfo, criteria); - - if (match && criteria.HasOnlineID == true) - match &= BeatmapInfo.OnlineID >= 0; - - if (match && criteria.BeatmapSetId != null) - match &= criteria.BeatmapSetId == BeatmapInfo.BeatmapSet?.OnlineID; - - return match; - } - - public override int CompareTo(FilterCriteria criteria, CarouselItem other) - { - if (!(other is CarouselBeatmap otherBeatmap)) - return base.CompareTo(criteria, other); - - switch (criteria.Sort) - { - default: - case SortMode.Difficulty: - int ruleset = BeatmapInfo.Ruleset.CompareTo(otherBeatmap.BeatmapInfo.Ruleset); - - if (ruleset != 0) return ruleset; - - return BeatmapInfo.StarRating.CompareTo(otherBeatmap.BeatmapInfo.StarRating); - } - } - - public override string ToString() => BeatmapInfo.ToString(); - } -} diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs deleted file mode 100644 index 7e15699804..0000000000 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ /dev/null @@ -1,184 +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 System; -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Game.Beatmaps; -using osu.Game.Screens.Select.Filter; -using osu.Game.Utils; - -namespace osu.Game.Screens.Select.Carousel -{ - public class CarouselBeatmapSet : CarouselGroupEagerSelect - { - public override float TotalHeight - { - get - { - switch (State.Value) - { - case CarouselItemState.Selected: - return DrawableCarouselBeatmapSet.HEIGHT + Items.Count(c => c.Visible) * DrawableCarouselBeatmap.HEIGHT; - - default: - return DrawableCarouselBeatmapSet.HEIGHT; - } - } - } - - public IEnumerable Beatmaps => Items.OfType(); - - public BeatmapSetInfo BeatmapSet; - - public Func, BeatmapInfo?>? GetRecommendedBeatmap; - - public CarouselBeatmapSet(BeatmapSetInfo beatmapSet) - { - BeatmapSet = beatmapSet ?? throw new ArgumentNullException(nameof(beatmapSet)); - - beatmapSet.Beatmaps - .Where(b => !b.Hidden) - .OrderBy(b => b.Ruleset) - .ThenBy(b => b.StarRating) - .Select(b => new CarouselBeatmap(b)) - .ForEach(AddItem); - } - - public override CarouselItem? GetNextToSelect() - { - if (LastSelected == null || LastSelected.Filtered.Value) - { - if (GetRecommendedBeatmap?.Invoke(Items.OfType().Where(b => !b.Filtered.Value).Select(b => b.BeatmapInfo)) is BeatmapInfo recommended) - return Items.OfType().First(b => b.BeatmapInfo.Equals(recommended)); - } - - return base.GetNextToSelect(); - } - - public override int CompareTo(FilterCriteria criteria, CarouselItem other) - { - if (!(other is CarouselBeatmapSet otherSet)) - return base.CompareTo(criteria, other); - - int comparison; - - switch (criteria.Sort) - { - default: - case SortMode.Artist: - comparison = OrdinalSortByCaseStringComparer.DEFAULT.Compare(BeatmapSet.Metadata.Artist, otherSet.BeatmapSet.Metadata.Artist); - if (comparison == 0) - goto case SortMode.Title; - break; - - case SortMode.Title: - comparison = OrdinalSortByCaseStringComparer.DEFAULT.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title); - break; - - case SortMode.Author: - comparison = OrdinalSortByCaseStringComparer.DEFAULT.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username); - break; - - case SortMode.Source: - comparison = OrdinalSortByCaseStringComparer.DEFAULT.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source); - break; - - case SortMode.DateAdded: - comparison = otherSet.BeatmapSet.DateAdded.CompareTo(BeatmapSet.DateAdded); - break; - - case SortMode.DateRanked: - comparison = Nullable.Compare(otherSet.BeatmapSet.DateRanked, BeatmapSet.DateRanked); - break; - - case SortMode.LastPlayed: - comparison = -compareUsingAggregateMax(otherSet, static b => (b.LastPlayed ?? DateTimeOffset.MinValue).ToUnixTimeSeconds()); - break; - - case SortMode.BPM: - comparison = compareUsingAggregateMax(otherSet, static b => b.BPM); - break; - - case SortMode.Length: - comparison = compareUsingAggregateMax(otherSet, static b => b.Length); - break; - - case SortMode.Difficulty: - comparison = compareUsingAggregateMax(otherSet, static b => b.StarRating); - break; - - case SortMode.DateSubmitted: - comparison = Nullable.Compare(otherSet.BeatmapSet.DateSubmitted, BeatmapSet.DateSubmitted); - break; - } - - if (comparison != 0) return comparison; - - // If the initial sort could not differentiate, attempt to use DateAdded to order sets in a stable fashion. - // The directionality of this matches the current SortMode.DateAdded, but we may want to reconsider if that becomes a user decision (ie. asc / desc). - comparison = otherSet.BeatmapSet.DateAdded.CompareTo(BeatmapSet.DateAdded); - - if (comparison != 0) return comparison; - - // If DateAdded fails to break the tie, fallback to our internal GUID for stability. - // This basically means it's a stable random sort. - return otherSet.BeatmapSet.ID.CompareTo(BeatmapSet.ID); - } - - /// - /// All beatmaps which are not filtered and valid for display. - /// - protected IEnumerable ValidBeatmaps - { - get - { - foreach (var item in Items) // iterating over Items directly to not allocate 2 enumerators - { - if (item is CarouselBeatmap b && (!b.Filtered.Value || b.State.Value == CarouselItemState.Selected)) - yield return b.BeatmapInfo; - } - } - } - - /// - /// Whether there are available beatmaps which are not filtered and valid for display. - /// Cheaper alternative to .Any() - /// - public bool HasValidBeatmaps - { - get - { - foreach (var item in Items) // iterating over Items directly to not allocate 2 enumerators - { - if (item is CarouselBeatmap b && (!b.Filtered.Value || b.State.Value == CarouselItemState.Selected)) - return true; - } - - return false; - } - } - - private int compareUsingAggregateMax(CarouselBeatmapSet other, Func func) - { - bool ourBeatmaps = HasValidBeatmaps; - bool otherBeatmaps = other.HasValidBeatmaps; - - if (!ourBeatmaps && !otherBeatmaps) return 0; - if (!ourBeatmaps) return -1; - if (!otherBeatmaps) return 1; - - return ValidBeatmaps.Max(func).CompareTo(other.ValidBeatmaps.Max(func)); - } - - public override void Filter(FilterCriteria criteria) - { - base.Filter(criteria); - - Filtered.Value = Items.All(i => i.Filtered.Value); - } - - public override string ToString() => BeatmapSet.ToString(); - } -} diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs deleted file mode 100644 index c0fb5fa397..0000000000 --- a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs +++ /dev/null @@ -1,140 +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 System.Collections.Generic; -using osu.Framework.Extensions.ListExtensions; -using osu.Framework.Lists; - -namespace osu.Game.Screens.Select.Carousel -{ - /// - /// A group which ensures only one item is selected. - /// - public abstract class CarouselGroup : CarouselItem - { - protected CarouselGroup(List? items = null) - { - if (items != null) this.items = items; - - State.ValueChanged += state => - { - switch (state.NewValue) - { - case CarouselItemState.Collapsed: - case CarouselItemState.NotSelected: - this.items.ForEach(c => c.State.Value = CarouselItemState.Collapsed); - break; - - case CarouselItemState.Selected: - this.items.ForEach(c => - { - if (c.State.Value == CarouselItemState.Collapsed) c.State.Value = CarouselItemState.NotSelected; - }); - break; - } - }; - } - - public override DrawableCarouselItem? CreateDrawableRepresentation() => null; - - public SlimReadOnlyListWrapper Items => items.AsSlimReadOnly(); - - public int TotalItemsNotFiltered { get; private set; } - - private readonly List items = new List(); - - /// - /// Used to assign a monotonically increasing ID to items as they are added. This member is - /// incremented whenever an item is added. - /// - private ulong currentItemID; - - private Comparer? criteriaComparer; - private FilterCriteria? lastCriteria; - - protected int GetIndexOfItem(CarouselItem lastSelected) => items.IndexOf(lastSelected); - - public virtual void RemoveItem(CarouselItem i) - { - items.Remove(i); - - if (!i.Filtered.Value) - TotalItemsNotFiltered--; - - // it's important we do the deselection after removing, so any further actions based on - // State.ValueChanged make decisions post-removal. - i.State.Value = CarouselItemState.Collapsed; - } - - public virtual void AddItem(CarouselItem i) - { - i.State.ValueChanged += state => ChildItemStateChanged(i, state.NewValue); - i.ItemID = ++currentItemID; - - if (lastCriteria != null) - { - i.Filter(lastCriteria); - - int index = items.BinarySearch(i, criteriaComparer); - if (index < 0) index = ~index; // BinarySearch hacks multiple return values with 2's complement. - - items.Insert(index, i); - } - else - { - // criteria may be null for initial population. the filtering will be applied post-add. - items.Add(i); - } - - if (!i.Filtered.Value) - TotalItemsNotFiltered++; - } - - public override void Filter(FilterCriteria criteria) - { - base.Filter(criteria); - - TotalItemsNotFiltered = 0; - - foreach (var c in items) - { - c.Filter(criteria); - if (!c.Filtered.Value) - TotalItemsNotFiltered++; - } - - // Sorting is expensive, so only perform if it's actually changed. - if (lastCriteria?.RequiresSorting(criteria) != false) - { - criteriaComparer = Comparer.Create((x, y) => - { - int comparison = x.CompareTo(criteria, y); - if (comparison != 0) - return comparison; - - return x.ItemID.CompareTo(y.ItemID); - }); - - items.Sort(criteriaComparer); - } - - lastCriteria = criteria; - } - - protected virtual void ChildItemStateChanged(CarouselItem item, CarouselItemState value) - { - // ensure we are the only item selected - if (value == CarouselItemState.Selected) - { - foreach (var b in items) - { - if (item == b) continue; - - b.State.Value = CarouselItemState.NotSelected; - } - - State.Value = CarouselItemState.Selected; - } - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs deleted file mode 100644 index 8cc1ea258a..0000000000 --- a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs +++ /dev/null @@ -1,159 +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 System; -using System.Collections.Generic; -using System.Linq; - -namespace osu.Game.Screens.Select.Carousel -{ - /// - /// A group which ensures at least one item is selected (if the group itself is selected). - /// - public abstract class CarouselGroupEagerSelect : CarouselGroup - { - protected CarouselGroupEagerSelect() - { - State.ValueChanged += state => - { - if (state.NewValue == CarouselItemState.Selected) - attemptSelection(); - }; - } - - /// - /// The last selected item. - /// - protected CarouselItem? LastSelected { get; private set; } - - /// - /// We need to keep track of the index for cases where the selection is removed but we want to select a new item based on its old location. - /// - private int lastSelectedIndex; - - /// - /// To avoid overhead during filter operations, we don't attempt any selections until after all - /// items have been filtered. This bool will be true during the base - /// operation. - /// - protected bool DisableSelection; - - public override void Filter(FilterCriteria criteria) - { - DisableSelection = true; - base.Filter(criteria); - DisableSelection = false; - - attemptSelection(); - } - - public override void RemoveItem(CarouselItem i) - { - base.RemoveItem(i); - - if (i != LastSelected) - updateSelectedIndex(); - } - - private bool addingItems; - - public void AddItems(IEnumerable items) - { - addingItems = true; - - foreach (var i in items) - AddItem(i); - - addingItems = false; - - attemptSelection(); - } - - public override void AddItem(CarouselItem i) - { - base.AddItem(i); - if (!addingItems) - attemptSelection(); - } - - protected override void ChildItemStateChanged(CarouselItem item, CarouselItemState value) - { - base.ChildItemStateChanged(item, value); - - switch (value) - { - case CarouselItemState.Selected: - updateSelected(item); - break; - - case CarouselItemState.NotSelected: - case CarouselItemState.Collapsed: - attemptSelection(); - break; - } - } - - private void attemptSelection() - { - if (DisableSelection) return; - - // we only perform eager selection if we are a currently selected group. - if (State.Value != CarouselItemState.Selected) return; - - // we only perform eager selection if none of our items are in a selected state already. - if (Items.Any(i => i.State.Value == CarouselItemState.Selected)) return; - - PerformSelection(); - } - - /// - /// Finds the item this group would select next if it attempted selection - /// - /// An unfiltered item nearest to the last selected one or null if all items are filtered - public virtual CarouselItem? GetNextToSelect() - { - if (Items.Count == 0) - return null; - - int forwardsIndex = lastSelectedIndex; - int backwardsIndex = Math.Min(lastSelectedIndex, Items.Count - 1); - - while (true) - { - bool hasBackwards = backwardsIndex >= 0 && backwardsIndex < Items.Count; - bool hasForwards = forwardsIndex < Items.Count; - - if (!hasBackwards && !hasForwards) - return null; - - if (hasForwards && !Items[forwardsIndex].Filtered.Value) - return Items[forwardsIndex]; - - if (hasBackwards && !Items[backwardsIndex].Filtered.Value) - return Items[backwardsIndex]; - - forwardsIndex++; - backwardsIndex--; - } - } - - protected virtual void PerformSelection() - { - CarouselItem? nextToSelect = GetNextToSelect(); - - if (nextToSelect != null) - nextToSelect.State.Value = CarouselItemState.Selected; - else - updateSelected(null); - } - - private void updateSelected(CarouselItem? newSelection) - { - if (newSelection != null) - LastSelected = newSelection; - updateSelectedIndex(); - } - - private void updateSelectedIndex() => lastSelectedIndex = LastSelected == null ? 0 : Math.Max(0, GetIndexOfItem(LastSelected)); - } -} diff --git a/osu.Game/Screens/Select/Carousel/CarouselHeader.cs b/osu.Game/Screens/Select/Carousel/CarouselHeader.cs deleted file mode 100644 index 7e668fcd87..0000000000 --- a/osu.Game/Screens/Select/Carousel/CarouselHeader.cs +++ /dev/null @@ -1,168 +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.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Events; -using osu.Framework.Utils; -using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class CarouselHeader : Container - { - public Container BorderContainer; - - public readonly Bindable State = new Bindable(CarouselItemState.NotSelected); - - private readonly HoverLayer hoverLayer; - - protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both }; - - private const float corner_radius = 10; - private const float border_thickness = 2.5f; - - public CarouselHeader() - { - RelativeSizeAxes = Axes.X; - Height = DrawableCarouselItem.MAX_HEIGHT; - - InternalChild = BorderContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = corner_radius, - BorderColour = new Color4(221, 255, 255, 255), - Children = new Drawable[] - { - Content, - hoverLayer = new HoverLayer(), - new HeaderSounds(), - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - State.BindValueChanged(updateState, true); - } - - private void updateState(ValueChangedEvent state) - { - switch (state.NewValue) - { - case CarouselItemState.Collapsed: - case CarouselItemState.NotSelected: - hoverLayer.InsetForBorder = false; - - BorderContainer.BorderThickness = 0; - BorderContainer.EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(1), - Radius = 10, - Colour = Color4.Black.Opacity(100), - }; - break; - - case CarouselItemState.Selected: - hoverLayer.InsetForBorder = true; - - BorderContainer.BorderThickness = border_thickness; - BorderContainer.EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = new Color4(130, 204, 255, 150), - Radius = 20, - Roundness = 10, - }; - break; - } - } - - public partial class HoverLayer : CompositeDrawable - { - private Box box = null!; - - public HoverLayer() - { - RelativeSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - InternalChild = box = new Box - { - Colour = colours.Blue.Opacity(0.1f), - Alpha = 0, - Blending = BlendingParameters.Additive, - RelativeSizeAxes = Axes.Both, - }; - } - - public bool InsetForBorder - { - set - { - if (value) - { - // apply same border as above to avoid applying additive overlay to it (and blowing out the colour). - Masking = true; - CornerRadius = corner_radius; - BorderThickness = border_thickness; - } - else - { - BorderThickness = 0; - CornerRadius = 0; - Masking = false; - } - } - } - - protected override bool OnHover(HoverEvent e) - { - box.FadeIn(100, Easing.OutQuint); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - box.FadeOut(1000, Easing.OutQuint); - base.OnHoverLost(e); - } - } - - private partial class HeaderSounds : HoverSampleDebounceComponent - { - private Sample? sampleHover; - - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - sampleHover = audio.Samples.Get("UI/default-hover"); - } - - public override void PlayHoverSample() - { - if (sampleHover == null) return; - - sampleHover.Frequency.Value = 0.99 + RNG.NextDouble(0.02); - sampleHover.Play(); - } - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/CarouselItem.cs b/osu.Game/Screens/Select/Carousel/CarouselItem.cs deleted file mode 100644 index 5e425a4a1c..0000000000 --- a/osu.Game/Screens/Select/Carousel/CarouselItem.cs +++ /dev/null @@ -1,66 +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 System; -using osu.Framework.Bindables; - -namespace osu.Game.Screens.Select.Carousel -{ - public abstract class CarouselItem : IComparable - { - public virtual float TotalHeight => 0; - - /// - /// An externally defined value used to determine this item's vertical display offset relative to the carousel. - /// - public float CarouselYPosition; - - public readonly BindableBool Filtered = new BindableBool(); - - public readonly Bindable State = new Bindable(CarouselItemState.NotSelected); - - /// - /// This item is not in a hidden state. - /// - public bool Visible => State.Value != CarouselItemState.Collapsed && !Filtered.Value; - - protected CarouselItem() - { - Filtered.ValueChanged += filtered => - { - if (filtered.NewValue && State.Value == CarouselItemState.Selected) - State.Value = CarouselItemState.NotSelected; - }; - } - - /// - /// Used as a default sort method for s of differing types. - /// - internal ulong ItemID; - - /// - /// Create a fresh drawable version of this item. - /// - public abstract DrawableCarouselItem? CreateDrawableRepresentation(); - - public virtual void Filter(FilterCriteria criteria) - { - } - - public virtual int CompareTo(FilterCriteria criteria, CarouselItem other) => ItemID.CompareTo(other.ItemID); - - public int CompareTo(CarouselItem? other) - { - if (other == null) return 1; - - return CarouselYPosition.CompareTo(other.CarouselYPosition); - } - } - - public enum CarouselItemState - { - Collapsed, - NotSelected, - Selected, - } -} diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs deleted file mode 100644 index a8f5b6dd24..0000000000 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ /dev/null @@ -1,321 +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 System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Extensions.LocalisationExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Collections; -using osu.Game.Database; -using osu.Game.Graphics; -using osu.Game.Graphics.Backgrounds; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; -using osu.Game.Overlays; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osuTK; -using osuTK.Graphics; -using CommonStrings = osu.Game.Localisation.CommonStrings; -using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class DrawableCarouselBeatmap : DrawableCarouselItem, IHasContextMenu - { - public const float CAROUSEL_BEATMAP_SPACING = 5; - - /// - /// The height of a carousel beatmap, including vertical spacing. - /// - public const float HEIGHT = height + CAROUSEL_BEATMAP_SPACING; - - private const float height = MAX_HEIGHT * 0.6f; - - private readonly BeatmapInfo beatmapInfo; - - private Sprite background = null!; - - private MenuItem[]? mainMenuItems; - - private Action? selectRequested; - private Action? hideRequested; - - private Triangles triangles = null!; - - private StarCounter starCounter = null!; - private DifficultyIcon difficultyIcon = null!; - - private OsuSpriteText keyCountText = null!; - - [Resolved] - private BeatmapSetOverlay? beatmapOverlay { get; set; } - - [Resolved] - private BeatmapDifficultyCache difficultyCache { get; set; } = null!; - - [Resolved] - private ManageCollectionsDialog? manageCollectionsDialog { get; set; } - - [Resolved] - private RealmAccess realm { get; set; } = null!; - - [Resolved] - private IBindable ruleset { get; set; } = null!; - - [Resolved] - private IBindable> mods { get; set; } = null!; - - [Resolved] - private IAPIProvider api { get; set; } = null!; - - [Resolved] - private OsuGame? game { get; set; } - - [Resolved] - private BeatmapManager? manager { get; set; } - - private IBindable starDifficultyBindable = null!; - private CancellationTokenSource? starDifficultyCancellationSource; - - public DrawableCarouselBeatmap(CarouselBeatmap panel) - { - beatmapInfo = panel.BeatmapInfo; - Item = panel; - } - - [BackgroundDependencyLoader] - private void load(SongSelect? songSelect) - { - Header.Height = height; - - if (songSelect != null) - { - mainMenuItems = songSelect.CreateForwardNavigationMenuItemsForBeatmap(() => beatmapInfo); - selectRequested = b => songSelect.FinaliseSelection(b); - } - - if (manager != null) - hideRequested = b => manager.Hide(b); - - Header.Children = new Drawable[] - { - background = new Box - { - RelativeSizeAxes = Axes.Both, - }, - triangles = new Triangles - { - TriangleScale = 2, - RelativeSizeAxes = Axes.Both, - ColourLight = Color4Extensions.FromHex(@"3a7285"), - ColourDark = Color4Extensions.FromHex(@"123744") - }, - new FillFlowContainer - { - Padding = new MarginPadding(5), - Direction = FillDirection.Horizontal, - AutoSizeAxes = Axes.Both, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Children = new Drawable[] - { - difficultyIcon = new DifficultyIcon(beatmapInfo) - { - TooltipType = DifficultyIconTooltipType.None, - Scale = new Vector2(1.8f), - }, - new FillFlowContainer - { - Padding = new MarginPadding { Left = 5 }, - Direction = FillDirection.Vertical, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new FillFlowContainer - { - Direction = FillDirection.Horizontal, - Spacing = new Vector2(4, 0), - AutoSizeAxes = Axes.Both, - Children = new[] - { - keyCountText = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 20), - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Alpha = 0, - }, - new OsuSpriteText - { - Text = beatmapInfo.DifficultyName, - Font = OsuFont.GetFont(size: 20), - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft - }, - new OsuSpriteText - { - Text = BeatmapsetsStrings.ShowDetailsMappedBy(beatmapInfo.Metadata.Author.Username), - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft - }, - } - }, - new FillFlowContainer - { - Direction = FillDirection.Horizontal, - Spacing = new Vector2(4, 0), - Scale = new Vector2(0.8f), - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new TopLocalRank(beatmapInfo), - starCounter = new StarCounter() - } - } - } - } - } - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - ruleset.BindValueChanged(_ => updateKeyCount()); - mods.BindValueChanged(_ => updateKeyCount()); - } - - protected override void Selected() - { - base.Selected(); - - MovementContainer.MoveToX(-50, 500, Easing.OutExpo); - - background.Colour = ColourInfo.GradientVertical( - new Color4(20, 43, 51, 255), - new Color4(40, 86, 102, 255)); - - triangles.Colour = Color4.White; - } - - protected override void Deselected() - { - base.Deselected(); - - MovementContainer.MoveToX(0, 500, Easing.OutExpo); - - background.Colour = new Color4(20, 43, 51, 255); - triangles.Colour = OsuColour.Gray(0.5f); - } - - protected override bool OnClick(ClickEvent e) - { - if (Item?.State.Value == CarouselItemState.Selected) - selectRequested?.Invoke(beatmapInfo); - - return base.OnClick(e); - } - - protected override void ApplyState() - { - if (Item?.State.Value != CarouselItemState.Collapsed && Alpha == 0) - starCounter.ReplayAnimation(); - - starDifficultyCancellationSource?.Cancel(); - - // Only compute difficulty when the item is visible. - if (Item?.State.Value != CarouselItemState.Collapsed) - { - // We've potentially cancelled the computation above so a new bindable is required. - starDifficultyBindable = difficultyCache.GetBindableDifficulty(beatmapInfo, (starDifficultyCancellationSource = new CancellationTokenSource()).Token, 200); - starDifficultyBindable.BindValueChanged(d => - { - starCounter.Current = (float)(d.NewValue.Stars); - difficultyIcon.Current.Value = d.NewValue; - }, true); - - updateKeyCount(); - } - - base.ApplyState(); - } - - private void updateKeyCount() - { - if (Item?.State.Value == CarouselItemState.Collapsed) - return; - - if (ruleset.Value.OnlineID == 3) - { - // Account for mania differences locally for now. - // Eventually this should be handled in a more modular way, allowing rulesets to add more information to the panel. - ILegacyRuleset legacyRuleset = (ILegacyRuleset)ruleset.Value.CreateInstance(); - - keyCountText.Alpha = 1; - keyCountText.Text = $"[{legacyRuleset.GetKeyCount(beatmapInfo, mods.Value)}K]"; - } - else - keyCountText.Alpha = 0; - } - - public MenuItem[] ContextMenuItems - { - get - { - List items = new List(); - - if (mainMenuItems != null) - items.AddRange(mainMenuItems); - - if (beatmapInfo.OnlineID > 0 && beatmapOverlay != null) - items.Add(new OsuMenuItem("Details...", MenuItemType.Standard, () => beatmapOverlay.FetchAndShowBeatmap(beatmapInfo.OnlineID))); - - var collectionItems = realm.Realm.All() - .OrderBy(c => c.Name) - .AsEnumerable() - .Select(c => new CollectionToggleMenuItem(c.ToLive(realm), beatmapInfo)).Cast().ToList(); - - if (manageCollectionsDialog != null) - collectionItems.Add(new OsuMenuItem("Manage...", MenuItemType.Standard, manageCollectionsDialog.Show)); - - items.Add(new OsuMenuItem("Collections") { Items = collectionItems }); - - if (beatmapInfo.GetOnlineURL(api, ruleset.Value) is string url) - items.Add(new OsuMenuItem(CommonStrings.CopyLink, MenuItemType.Standard, () => game?.CopyToClipboard(url))); - - if (manager != null) - items.Add(new OsuMenuItem("Mark as played", MenuItemType.Standard, () => manager.MarkPlayed(beatmapInfo))); - - if (hideRequested != null) - items.Add(new OsuMenuItem(WebCommonStrings.ButtonsHide.ToSentence(), MenuItemType.Destructive, () => hideRequested(beatmapInfo))); - - return items.ToArray(); - } - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - starDifficultyCancellationSource?.Cancel(); - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs deleted file mode 100644 index f0e024663d..0000000000 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ /dev/null @@ -1,356 +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 System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Primitives; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Utils; -using osu.Game.Beatmaps; -using osu.Game.Collections; -using osu.Game.Database; -using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; -using osu.Game.Online.API; -using osu.Game.Overlays; -using osu.Game.Rulesets; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class DrawableCarouselBeatmapSet : DrawableCarouselItem, IHasContextMenu - { - public const float HEIGHT = MAX_HEIGHT; - - private Action restoreHiddenRequested = null!; - private Action? viewDetails; - - [Resolved] - private IDialogOverlay? dialogOverlay { get; set; } - - [Resolved] - private ManageCollectionsDialog? manageCollectionsDialog { get; set; } - - [Resolved] - private RealmAccess realm { get; set; } = null!; - - [Resolved] - private IAPIProvider api { get; set; } = null!; - - [Resolved] - private OsuGame? game { get; set; } - - [Resolved] - private IBindable ruleset { get; set; } = null!; - - public IReadOnlyList DrawableBeatmaps => beatmapContainer?.IsLoaded != true ? Array.Empty() : beatmapContainer; - - private Container? beatmapContainer; - - private BeatmapSetInfo beatmapSet = null!; - - private Task? beatmapsLoadTask; - - private MenuItem[]? mainMenuItems; - - private double timeSinceUnpool; - - [Resolved] - private BeatmapManager manager { get; set; } = null!; - - protected override void FreeAfterUse() - { - base.FreeAfterUse(); - - Item = null; - timeSinceUnpool = 0; - - ClearTransforms(); - } - - [BackgroundDependencyLoader] - private void load(BeatmapSetOverlay? beatmapOverlay, SongSelect? songSelect) - { - if (songSelect != null) - mainMenuItems = songSelect.CreateForwardNavigationMenuItemsForBeatmap(() => (((CarouselBeatmapSet)Item!).GetNextToSelect() as CarouselBeatmap)!.BeatmapInfo); - - restoreHiddenRequested = s => - { - foreach (var b in s.Beatmaps) - manager.Restore(b); - }; - - if (beatmapOverlay != null) - viewDetails = beatmapOverlay.FetchAndShowBeatmapSet; - } - - protected override void Update() - { - base.Update(); - - Debug.Assert(Item != null); - - // position updates should not occur if the item is filtered away. - // this avoids panels flying across the screen only to be eventually off-screen or faded out. - if (!Item.Visible) return; - - float targetY = Item.CarouselYPosition; - - if (Precision.AlmostEquals(targetY, Y)) - Y = targetY; - else - // algorithm for this is taken from ScrollContainer. - // while it doesn't necessarily need to match 1:1, as we are emulating scroll in some cases this feels most correct. - Y = (float)Interpolation.Lerp(targetY, Y, Math.Exp(-0.01 * Time.Elapsed)); - - loadContentIfRequired(); - } - - private CancellationTokenSource? loadCancellation; - - protected override void UpdateItem() - { - loadCancellation?.Cancel(); - loadCancellation = null; - - base.UpdateItem(); - - Content.Clear(); - Header.Clear(); - - beatmapContainer = null; - beatmapsLoadTask = null; - - if (Item == null) - return; - - beatmapSet = ((CarouselBeatmapSet)Item).BeatmapSet; - } - - protected override void Deselected() - { - base.Deselected(); - - MovementContainer.MoveToX(0, 500, Easing.OutExpo); - - updateBeatmapYPositions(); - } - - protected override void Selected() - { - base.Selected(); - - MovementContainer.MoveToX(-100, 500, Easing.OutExpo); - - updateBeatmapDifficulties(); - } - - private void updateBeatmapDifficulties() - { - Debug.Assert(Item != null); - - var carouselBeatmapSet = (CarouselBeatmapSet)Item; - - var visibleBeatmaps = carouselBeatmapSet.Items.Where(c => c.Visible).ToArray(); - - // if we are already displaying all the correct beatmaps, only run animation updates. - // note that the displayed beatmaps may change due to the applied filter. - // a future optimisation could add/remove only changed difficulties rather than reinitialise. - if (beatmapContainer != null && visibleBeatmaps.Length == beatmapContainer.Count && visibleBeatmaps.All(b => beatmapContainer.Any(c => c.Item == b))) - { - updateBeatmapYPositions(); - } - else - { - // on selection we show our child beatmaps. - // for now this is a simple drawable construction each selection. - // can be improved in the future. - beatmapContainer = new Container - { - X = 100, - RelativeSizeAxes = Axes.Both, - ChildrenEnumerable = visibleBeatmaps.Select(c => c.CreateDrawableRepresentation()!) - }; - - beatmapsLoadTask = LoadComponentAsync(beatmapContainer, loaded => - { - // make sure the pooled target hasn't changed. - if (beatmapContainer != loaded) - return; - - Content.Child = loaded; - updateBeatmapYPositions(); - }); - } - } - - [Resolved] - private BeatmapCarousel.CarouselScrollContainer scrollContainer { get; set; } = null!; - - private void loadContentIfRequired() - { - Quad containingSsdq = scrollContainer.ScreenSpaceDrawQuad; - - // Using DelayedLoadWrappers would only allow us to load content when on screen, but we want to preload while off-screen - // to provide a better user experience. - - // This is tracking time that this drawable is updating since the last pool. - // This is intended to provide a debounce so very fast scrolls (from one end to the other of the carousel) - // don't cause huge overheads. - // - // We increase the delay based on distance from centre, so the beatmaps the user is currently looking at load first. - float timeUpdatingBeforeLoad = 50 + Math.Abs(containingSsdq.Centre.Y - ScreenSpaceDrawQuad.Centre.Y) / containingSsdq.Height * 100; - - Debug.Assert(Item != null); - - // A load is already in progress if the cancellation token is non-null. - if (loadCancellation != null) - return; - - timeSinceUnpool += Time.Elapsed; - - // We only trigger a load after this set has been in an updating state for a set amount of time. - if (timeSinceUnpool <= timeUpdatingBeforeLoad) - return; - - loadCancellation = new CancellationTokenSource(); - - LoadComponentsAsync(new CompositeDrawable[] - { - // Choice of background image matches BSS implementation (always uses the lowest `beatmap_id` from the set). - new SetPanelBackground(manager.GetWorkingBeatmap(beatmapSet.Beatmaps.MinBy(b => b.OnlineID))) - { - RelativeSizeAxes = Axes.Both, - }, - new SetPanelContent((CarouselBeatmapSet)Item) - { - Depth = float.MinValue, - RelativeSizeAxes = Axes.Both, - } - }, drawables => - { - Header.AddRange(drawables); - drawables.ForEach(d => d.FadeInFromZero(150)); - }, loadCancellation.Token); - } - - private void updateBeatmapYPositions() - { - if (beatmapContainer == null) - return; - - if (beatmapsLoadTask == null || !beatmapsLoadTask.IsCompleted) - return; - - float yPos = DrawableCarouselBeatmap.CAROUSEL_BEATMAP_SPACING; - - bool isSelected = Item?.State.Value == CarouselItemState.Selected; - - foreach (var panel in beatmapContainer) - { - Debug.Assert(panel.Item != null); - - if (isSelected) - { - panel.MoveToY(yPos, 800, Easing.OutQuint); - yPos += panel.Item.TotalHeight; - } - else - panel.MoveToY(0, 800, Easing.OutQuint); - } - } - - public MenuItem[] ContextMenuItems - { - get - { - Debug.Assert(beatmapSet != null); - - List items = new List(); - - if (Item?.State.Value == CarouselItemState.NotSelected) - items.Add(new OsuMenuItem("Expand", MenuItemType.Highlighted, () => Item.State.Value = CarouselItemState.Selected)); - - if (mainMenuItems != null) - items.AddRange(mainMenuItems); - - if (beatmapSet.OnlineID > 0 && viewDetails != null) - items.Add(new OsuMenuItem("Details...", MenuItemType.Standard, () => viewDetails(beatmapSet.OnlineID))); - - var collectionItems = realm.Realm.All() - .OrderBy(c => c.Name) - .AsEnumerable() - .Select(createCollectionMenuItem) - .ToList(); - - if (manageCollectionsDialog != null) - collectionItems.Add(new OsuMenuItem("Manage...", MenuItemType.Standard, manageCollectionsDialog.Show)); - - items.Add(new OsuMenuItem("Collections") { Items = collectionItems }); - - if (beatmapSet.Beatmaps.Any(b => b.Hidden)) - items.Add(new OsuMenuItem("Restore all hidden", MenuItemType.Standard, () => restoreHiddenRequested(beatmapSet))); - - if (beatmapSet.GetOnlineURL(api, ruleset.Value) is string url) - items.Add(new OsuMenuItem(CommonStrings.CopyLink, MenuItemType.Standard, () => game?.CopyToClipboard(url))); - - if (dialogOverlay != null) - items.Add(new OsuMenuItem("Delete...", MenuItemType.Destructive, () => dialogOverlay.Push(new BeatmapDeleteDialog(beatmapSet)))); - return items.ToArray(); - } - } - - private MenuItem createCollectionMenuItem(BeatmapCollection collection) - { - Debug.Assert(beatmapSet != null); - - TernaryState state; - - int countExisting = beatmapSet.Beatmaps.Count(b => collection.BeatmapMD5Hashes.Contains(b.MD5Hash)); - - if (countExisting == beatmapSet.Beatmaps.Count) - state = TernaryState.True; - else if (countExisting > 0) - state = TernaryState.Indeterminate; - else - state = TernaryState.False; - - var liveCollection = collection.ToLive(realm); - - return new TernaryStateToggleMenuItem(collection.Name, MenuItemType.Standard, s => - { - Task.Run(() => liveCollection.PerformWrite(c => - { - foreach (var b in beatmapSet.Beatmaps) - { - switch (s) - { - case TernaryState.True: - if (c.BeatmapMD5Hashes.Contains(b.MD5Hash)) - continue; - - c.BeatmapMD5Hashes.Add(b.MD5Hash); - break; - - case TernaryState.False: - c.BeatmapMD5Hashes.Remove(b.MD5Hash); - break; - } - } - })); - }) - { - State = { Value = state } - }; - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs deleted file mode 100644 index 10921c331e..0000000000 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs +++ /dev/null @@ -1,177 +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 System.Diagnostics; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Pooling; -using osu.Framework.Input.Events; -using osuTK; - -namespace osu.Game.Screens.Select.Carousel -{ - public abstract partial class DrawableCarouselItem : PoolableDrawable - { - public const float MAX_HEIGHT = 80; - - public override bool IsPresent => base.IsPresent || Item?.Visible == true; - - public override bool HandlePositionalInput => Item?.Visible == true; - public override bool PropagatePositionalInputSubTree => Item?.Visible == true; - - public readonly CarouselHeader Header; - - /// - /// Optional content which sits below the header. - /// - protected readonly Container Content; - - protected readonly Container MovementContainer; - - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => - Header.ReceivePositionalInputAt(screenSpacePos); - - private CarouselItem? item; - - public CarouselItem? Item - { - get => item; - set - { - if (item == value) - return; - - if (item != null) - { - item.Filtered.ValueChanged -= onStateChange; - item.State.ValueChanged -= onStateChange; - - Header.State.UnbindFrom(item.State); - - if (item is CarouselGroup group) - { - foreach (var c in group.Items) - c.Filtered.ValueChanged -= onStateChange; - } - } - - item = value; - - if (IsLoaded && !IsDisposed) - UpdateItem(); - } - } - - protected DrawableCarouselItem() - { - RelativeSizeAxes = Axes.X; - - Alpha = 0; - - InternalChildren = new Drawable[] - { - MovementContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - Header = new CarouselHeader(), - Content = new Container - { - RelativeSizeAxes = Axes.Both, - } - } - }, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - UpdateItem(); - } - - protected override void Update() - { - base.Update(); - Content.Y = Header.Height; - } - - protected virtual void UpdateItem() - { - if (Item == null) - return; - - Scheduler.AddOnce(ApplyState); - - Item.Filtered.ValueChanged += onStateChange; - Item.State.ValueChanged += onStateChange; - - Header.State.BindTo(Item.State); - - if (Item is CarouselGroup group) - { - foreach (var c in group.Items) - c.Filtered.ValueChanged += onStateChange; - } - } - - private void onStateChange(ValueChangedEvent obj) => Scheduler.AddOnce(ApplyState); - - private void onStateChange(ValueChangedEvent _) => Scheduler.AddOnce(ApplyState); - - protected virtual void ApplyState() - { - Debug.Assert(Item != null); - - // Use the fact that we know the precise height of the item from the model to avoid the need for AutoSize overhead. - // Additionally, AutoSize doesn't work well due to content starting off-screen and being masked away. - Height = Item.TotalHeight; - - switch (Item.State.Value) - { - case CarouselItemState.NotSelected: - Deselected(); - break; - - case CarouselItemState.Selected: - Selected(); - break; - } - - if (!Item.Visible) - this.FadeOut(100, Easing.OutQuint); - else - this.FadeIn(400, Easing.OutQuint); - } - - protected virtual void Selected() - { - Debug.Assert(Item != null); - } - - protected virtual void Deselected() - { - } - - protected override bool OnClick(ClickEvent e) - { - Debug.Assert(Item != null); - - Item.State.Value = CarouselItemState.Selected; - return true; - } - - protected override bool OnHover(HoverEvent e) => true; - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - // This is important to clean up event subscriptions. - Item = null; - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs b/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs deleted file mode 100644 index cd8e20ad39..0000000000 --- a/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs +++ /dev/null @@ -1,35 +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.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Input.Events; -using osu.Game.Beatmaps.Drawables; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class FilterableDifficultyIcon : DifficultyIcon - { - private readonly BindableBool filtered = new BindableBool(); - - public bool IsFiltered => filtered.Value; - - public readonly CarouselBeatmap Item; - - public FilterableDifficultyIcon(CarouselBeatmap item) - : base(item.BeatmapInfo) - { - filtered.BindTo(item.Filtered); - filtered.ValueChanged += isFiltered => Schedule(() => this.FadeTo(isFiltered.NewValue ? 0.1f : 1, 100)); - filtered.TriggerChange(); - - Item = item; - } - - protected override bool OnClick(ClickEvent e) - { - Item.State.Value = CarouselItemState.Selected; - return true; - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs b/osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs deleted file mode 100644 index 3de44fa032..0000000000 --- a/osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs +++ /dev/null @@ -1,60 +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 System.Collections.Generic; -using System.Linq; -using osu.Framework.Graphics; -using osu.Framework.Input.Events; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Rulesets; -using osuTK.Graphics; - -namespace osu.Game.Screens.Select.Carousel -{ - /// - /// A difficulty icon that contains a counter on the right-side of it. - /// - /// - /// Used in cases when there are too many difficulty icons to show. - /// - public partial class GroupedDifficultyIcon : DifficultyIcon - { - public readonly List Items; - - public GroupedDifficultyIcon(List items, RulesetInfo ruleset) - : base(items.OrderBy(b => b.BeatmapInfo.StarRating).Last().BeatmapInfo, ruleset) - { - Items = items; - - foreach (var item in items) - item.Filtered.BindValueChanged(_ => Scheduler.AddOnce(updateFilteredDisplay)); - - AddInternal(new OsuSpriteText - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Padding = new MarginPadding { Left = Size.X }, - Margin = new MarginPadding { Left = 2, Right = 5 }, - Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold), - Text = items.Count.ToString(), - Colour = Color4.White, - }); - - updateFilteredDisplay(); - } - - protected override bool OnClick(ClickEvent e) - { - Items.First().State.Value = CarouselItemState.Selected; - return true; - } - - private void updateFilteredDisplay() - { - // for now, fade the whole group based on the ratio of hidden items. - this.FadeTo(1 - 0.9f * ((float)Items.Count(i => i.Filtered.Value) / Items.Count), 100); - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs b/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs deleted file mode 100644 index b8729b7174..0000000000 --- a/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs +++ /dev/null @@ -1,92 +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 System; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Game.Beatmaps; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class SetPanelBackground : BufferedContainer - { - public SetPanelBackground(IWorkingBeatmap working) - : base(cachedFrameBuffer: true) - { - RedrawOnScale = false; - - Children = new Drawable[] - { - new PanelBeatmapBackground(working) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fill, - }, - new FillFlowContainer - { - Depth = -1, - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - // This makes the gradient not be perfectly horizontal, but diagonal at a ~40° angle - Shear = new Vector2(0.8f, 0), - Alpha = 0.5f, - Children = new[] - { - // The left half with no gradient applied - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Width = 0.4f, - }, - // Piecewise-linear gradient with 3 segments to make it appear smoother - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(Color4.Black, new Color4(0f, 0f, 0f, 0.9f)), - Width = 0.05f, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(new Color4(0f, 0f, 0f, 0.9f), new Color4(0f, 0f, 0f, 0.1f)), - Width = 0.2f, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(new Color4(0f, 0f, 0f, 0.1f), new Color4(0, 0, 0, 0)), - Width = 0.05f, - }, - } - }, - }; - } - - public partial class PanelBeatmapBackground : Sprite - { - private readonly IWorkingBeatmap working; - - public PanelBeatmapBackground(IWorkingBeatmap working) - { - ArgumentNullException.ThrowIfNull(working); - - this.working = working; - } - - [BackgroundDependencyLoader] - private void load() - { - Texture = working.GetPanelBackground(); - } - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/SetPanelContent.cs b/osu.Game/Screens/Select/Carousel/SetPanelContent.cs deleted file mode 100644 index c3ded16bd2..0000000000 --- a/osu.Game/Screens/Select/Carousel/SetPanelContent.cs +++ /dev/null @@ -1,117 +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 System.Collections.Generic; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Localisation; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osuTK; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class SetPanelContent : CompositeDrawable - { - // Disallow interacting with difficulty icons on a panel until the panel has been selected. - public override bool PropagatePositionalInputSubTree => carouselSet.State.Value == CarouselItemState.Selected; - - private readonly CarouselBeatmapSet carouselSet; - - private FillFlowContainer iconFlow = null!; - - public SetPanelContent(CarouselBeatmapSet carouselSet) - { - this.carouselSet = carouselSet; - - // required to ensure we load as soon as any part of the panel comes on screen - RelativeSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader] - private void load() - { - var beatmapSet = carouselSet.BeatmapSet; - - InternalChild = new FillFlowContainer - { - // required to ensure we load as soon as any part of the panel comes on screen - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Padding = new MarginPadding { Top = 5, Left = 18, Right = 10, Bottom = 10 }, - Children = new Drawable[] - { - new OsuSpriteText - { - Text = new RomanisableString(beatmapSet.Metadata.TitleUnicode, beatmapSet.Metadata.Title), - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 22, italics: true), - Shadow = true, - }, - new OsuSpriteText - { - Text = new RomanisableString(beatmapSet.Metadata.ArtistUnicode, beatmapSet.Metadata.Artist), - Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 17, italics: true), - Shadow = true, - }, - new FillFlowContainer - { - Direction = FillDirection.Horizontal, - AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Top = 5 }, - Spacing = new Vector2(5), - Children = new[] - { - beatmapSet.AllBeatmapsUpToDate - ? Empty() - : new Container - { - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - Children = new Drawable[] - { - new UpdateBeatmapSetButton(beatmapSet), - } - }, - new BeatmapSetOnlineStatusPill - { - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - TextSize = 11, - TextPadding = new MarginPadding { Horizontal = 8, Vertical = 2 }, - Status = beatmapSet.Status - }, - iconFlow = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Spacing = new Vector2(3), - }, - } - } - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - iconFlow.ChildrenEnumerable = getDifficultyIcons(); - } - - private const int maximum_difficulty_icons = 18; - - private IEnumerable getDifficultyIcons() - { - var beatmaps = carouselSet.Beatmaps.ToList(); - - return beatmaps.Count > maximum_difficulty_icons - ? beatmaps.GroupBy(b => b.BeatmapInfo.Ruleset) - .Select(group => new GroupedDifficultyIcon(group.ToList(), group.Last().BeatmapInfo.Ruleset)) - : beatmaps.Select(b => new FilterableDifficultyIcon(b)); - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs deleted file mode 100644 index 6f1f2e8370..0000000000 --- a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs +++ /dev/null @@ -1,86 +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 System; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; -using osu.Game.Database; -using osu.Game.Online.API; -using osu.Game.Online.Leaderboards; -using osu.Game.Rulesets; -using osu.Game.Scoring; -using osuTK; -using Realms; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class TopLocalRank : CompositeDrawable - { - private readonly BeatmapInfo beatmapInfo; - - [Resolved] - private IBindable ruleset { get; set; } = null!; - - [Resolved] - private RealmAccess realm { get; set; } = null!; - - [Resolved] - private IAPIProvider api { get; set; } = null!; - - private IDisposable? scoreSubscription; - - private readonly UpdateableRank updateable; - - public ScoreRank? DisplayedRank => updateable.Rank; - - public TopLocalRank(BeatmapInfo beatmapInfo) - { - this.beatmapInfo = beatmapInfo; - - AutoSizeAxes = Axes.Both; - - InternalChild = updateable = new UpdateableRank - { - Size = new Vector2(40, 20), - Alpha = 0, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - ruleset.BindValueChanged(_ => - { - scoreSubscription?.Dispose(); - scoreSubscription = realm.RegisterForNotifications(r => - r.GetAllLocalScoresForUser(api.LocalUser.Value.Id) - .Filter($@"{nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $0" - + $" && {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $1", beatmapInfo.ID, ruleset.Value.ShortName), - localScoresChanged); - }, true); - - void localScoresChanged(IRealmCollection sender, ChangeSet? changes) - { - // This subscription may fire from changes to linked beatmaps, which we don't care about. - // It's currently not possible for a score to be modified after insertion, so we can safely ignore callbacks with only modifications. - if (changes?.HasCollectionChanges() == false) - return; - - ScoreInfo? topScore = sender.MaxBy(info => (info.TotalScore, -info.Date.UtcDateTime.Ticks)); - updateable.Rank = topScore?.Rank; - updateable.Alpha = topScore != null ? 1 : 0; - } - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - scoreSubscription?.Dispose(); - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs b/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs deleted file mode 100644 index d41870f1d2..0000000000 --- a/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs +++ /dev/null @@ -1,178 +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.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Input.Events; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; -using osu.Game.Overlays; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Select.Carousel -{ - public partial class UpdateBeatmapSetButton : OsuAnimatedButton - { - private readonly BeatmapSetInfo beatmapSetInfo; - private SpriteIcon icon = null!; - private Box progressFill = null!; - - [Resolved] - private BeatmapModelDownloader beatmapDownloader { get; set; } = null!; - - [Resolved] - private IAPIProvider api { get; set; } = null!; - - [Resolved] - private LoginOverlay? loginOverlay { get; set; } - - [Resolved] - private IDialogOverlay? dialogOverlay { get; set; } - - public UpdateBeatmapSetButton(BeatmapSetInfo beatmapSetInfo) - { - this.beatmapSetInfo = beatmapSetInfo; - - AutoSizeAxes = Axes.Both; - - Anchor = Anchor.CentreLeft; - Origin = Anchor.CentreLeft; - } - - private Bindable preferNoVideo = null!; - - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) - { - const float icon_size = 14; - - preferNoVideo = config.GetBindable(OsuSetting.PreferNoVideo); - - Content.Anchor = Anchor.CentreLeft; - Content.Origin = Anchor.CentreLeft; - - Content.AddRange(new Drawable[] - { - progressFill = new Box - { - Colour = Color4.White, - Alpha = 0.2f, - Blending = BlendingParameters.Additive, - RelativeSizeAxes = Axes.Both, - Width = 0, - }, - new FillFlowContainer - { - Padding = new MarginPadding { Horizontal = 5, Vertical = 3 }, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(4), - Children = new Drawable[] - { - new Container - { - Size = new Vector2(icon_size), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Children = new Drawable[] - { - icon = new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Icon = FontAwesome.Solid.SyncAlt, - Size = new Vector2(icon_size), - }, - } - }, - new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.Default.With(weight: FontWeight.Bold), - Text = "Update", - } - } - }, - }); - - Action = updateBeatmap; - } - - private bool updateConfirmed; - - private void updateBeatmap() - { - if (!api.IsLoggedIn) - { - loginOverlay?.Show(); - return; - } - - if (dialogOverlay != null && beatmapSetInfo.Status == BeatmapOnlineStatus.LocallyModified && !updateConfirmed) - { - dialogOverlay.Push(new UpdateLocalConfirmationDialog(() => - { - updateConfirmed = true; - updateBeatmap(); - })); - - return; - } - - updateConfirmed = false; - - beatmapDownloader.DownloadAsUpdate(beatmapSetInfo, preferNoVideo.Value); - attachExistingDownload(); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - icon.Spin(4000, RotationDirection.Clockwise); - } - - private void attachExistingDownload() - { - var download = beatmapDownloader.GetExistingDownload(beatmapSetInfo); - - if (download != null) - { - Enabled.Value = false; - TooltipText = string.Empty; - - download.DownloadProgressed += progress => progressFill.ResizeWidthTo(progress, 100, Easing.OutQuint); - download.Failure += _ => attachExistingDownload(); - } - else - { - Enabled.Value = true; - TooltipText = "Update beatmap with online changes"; - - progressFill.ResizeWidthTo(0, 100, Easing.OutQuint); - } - } - - protected override bool OnHover(HoverEvent e) - { - icon.Spin(400, RotationDirection.Clockwise, icon.Rotation); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - icon.Spin(4000, RotationDirection.Clockwise, icon.Rotation); - base.OnHoverLost(e); - } - } -} diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs deleted file mode 100644 index 4781a3dee7..0000000000 --- a/osu.Game/Screens/Select/FilterControl.cs +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using JetBrains.Annotations; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input; -using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Game.Collections; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Select.Filter; -using osuTK; -using osuTK.Input; - -namespace osu.Game.Screens.Select -{ - public partial class FilterControl : Container - { - public const float HEIGHT = 2 * side_margin + 120; - - private const float side_margin = 10; - - public Action FilterChanged; - - public Bindable CurrentTextSearch => searchTextBox.Current; - - public LocalisableString InformationalText - { - get => searchTextBox.FilterText.Text; - set => searchTextBox.FilterText.Text = value; - } - - private OsuTabControl sortTabs; - private Bindable sortMode; - private Bindable groupMode; - private FilterControlTextBox searchTextBox; - private CollectionDropdown collectionDropdown; - - [CanBeNull] - private FilterCriteria currentCriteria; - - public virtual FilterCriteria CreateCriteria() - { - string query = searchTextBox.Text; - - var criteria = new FilterCriteria - { - Group = groupMode.Value, - Sort = sortMode.Value, - AllowConvertedBeatmaps = showConverted.Value, - Ruleset = ruleset.Value, - Mods = mods.Value, - CollectionBeatmapMD5Hashes = collectionDropdown.Current.Value?.Collection?.PerformRead(c => c.BeatmapMD5Hashes).ToImmutableHashSet() - }; - - if (!minimumStars.IsDefault) - criteria.UserStarDifficulty.Min = minimumStars.Value; - - if (!maximumStars.IsDefault) - criteria.UserStarDifficulty.Max = maximumStars.Value; - - criteria.RulesetCriteria = ruleset.Value.CreateInstance().CreateRulesetFilterCriteria(); - - FilterQueryParser.ApplyQueries(criteria, query); - return criteria; - } - - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => - base.ReceivePositionalInputAt(screenSpacePos) || sortTabs.ReceivePositionalInputAt(screenSpacePos); - - [BackgroundDependencyLoader(permitNulls: true)] - private void load(OsuColour colours, OsuConfigManager config) - { - sortMode = config.GetBindable(OsuSetting.SongSelectSortingMode); - groupMode = config.GetBindable(OsuSetting.SongSelectGroupMode); - - Children = new Drawable[] - { - new Box - { - Colour = OsuColour.Gray(0.05f), - Alpha = 0.96f, - Width = 2, - RelativeSizeAxes = Axes.Both, - }, - new Container - { - Padding = new MarginPadding(side_margin), - RelativeSizeAxes = Axes.Both, - Width = 0.5f, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - // Reverse ChildID so that dropdowns in the top section appear on top of the bottom section. - Child = new ReverseChildIDFillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Spacing = new Vector2(0, 5), - Children = new Drawable[] - { - searchTextBox = new FilterControlTextBox - { - RelativeSizeAxes = Axes.X, - }, - new Box - { - RelativeSizeAxes = Axes.X, - Height = 1, - Colour = OsuColour.Gray(80), - }, - new GridContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.Absolute, OsuTabControl.HORIZONTAL_SPACING), - new Dimension(), - new Dimension(GridSizeMode.Absolute, OsuTabControl.HORIZONTAL_SPACING), - new Dimension(GridSizeMode.AutoSize), - }, - RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, - Content = new[] - { - new[] - { - new OsuSpriteText - { - Text = SortStrings.Default, - Font = OsuFont.GetFont(size: 14), - Margin = new MarginPadding(5), - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - }, - Empty(), - sortTabs = new OsuTabControl - { - RelativeSizeAxes = Axes.X, - Height = 24, - AutoSort = true, - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - AccentColour = colours.GreenLight, - Current = { BindTarget = sortMode } - }, - Empty(), - new OsuTabControlCheckbox - { - Text = "Show converted", - Current = config.GetBindable(OsuSetting.ShowConvertedBeatmaps), - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - }, - } - } - }, - new Container - { - RelativeSizeAxes = Axes.X, - Height = 40, - Children = new Drawable[] - { - new RangeSlider - { - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - Label = "Difficulty range", - LowerBound = config.GetBindable(OsuSetting.DisplayStarsMinimum), - UpperBound = config.GetBindable(OsuSetting.DisplayStarsMaximum), - RelativeSizeAxes = Axes.Both, - Width = 0.48f, - DefaultStringLowerBound = "0", - DefaultStringUpperBound = "∞", - DefaultTooltipUpperBound = UserInterfaceStrings.NoLimit, - TooltipSuffix = "stars" - }, - collectionDropdown = new CollectionDropdown - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - RequestFilter = updateCriteria, - RelativeSizeAxes = Axes.X, - Y = 4, - Width = 0.5f, - } - } - }, - } - } - } - }; - - config.BindWith(OsuSetting.ShowConvertedBeatmaps, showConverted); - showConverted.ValueChanged += _ => updateCriteria(); - - config.BindWith(OsuSetting.DisplayStarsMinimum, minimumStars); - minimumStars.ValueChanged += _ => updateCriteria(); - - config.BindWith(OsuSetting.DisplayStarsMaximum, maximumStars); - maximumStars.ValueChanged += _ => updateCriteria(); - - ruleset.BindValueChanged(_ => updateCriteria()); - mods.BindValueChanged(m => - { - // Mods are updated once by the mod select overlay when song select is entered, - // regardless of if there are any mods or any changes have taken place. - // Updating the criteria here so early triggers a re-ordering of panels on song select, via... some mechanism. - // Todo: Investigate/fix and potentially remove this. - if (m.NewValue.SequenceEqual(m.OldValue)) - return; - - if (currentCriteria?.RulesetCriteria?.FilterMayChangeFromMods(m) == true) - updateCriteria(); - }); - - groupMode.BindValueChanged(_ => updateCriteria()); - sortMode.BindValueChanged(_ => updateCriteria()); - - searchTextBox.Current.ValueChanged += _ => updateCriteria(); - - updateCriteria(); - } - - public void Deactivate() - { - searchTextBox.ReadOnly = true; - searchTextBox.HoldFocus = false; - if (searchTextBox.HasFocus) - GetContainingFocusManager()!.ChangeFocus(searchTextBox); - } - - public void Activate() - { - searchTextBox.ReadOnly = false; - searchTextBox.HoldFocus = true; - } - - [Resolved] - private IBindable ruleset { get; set; } = null!; - - [Resolved] - private IBindable> mods { get; set; } = null!; - - private readonly Bindable showConverted = new Bindable(); - private readonly Bindable minimumStars = new BindableDouble(); - private readonly Bindable maximumStars = new BindableDouble(); - - private void updateCriteria() => FilterChanged?.Invoke(currentCriteria = CreateCriteria()); - - protected override bool OnClick(ClickEvent e) => true; - - protected override bool OnHover(HoverEvent e) => true; - - internal partial class FilterControlTextBox : SeekLimitedSearchTextBox - { - private const float filter_text_size = 12; - - public OsuSpriteText FilterText { get; private set; } - - public FilterControlTextBox() - { - Height += filter_text_size; - TextContainer.Height *= (Height - filter_text_size) / Height; - TextContainer.Margin = new MarginPadding { Bottom = filter_text_size }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - TextContainer.Add(FilterText = new OsuSpriteText - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.TopLeft, - Depth = float.MinValue, - Font = OsuFont.Default.With(size: filter_text_size, weight: FontWeight.SemiBold), - Margin = new MarginPadding { Top = 2, Left = 2 }, - Colour = colours.Yellow - }); - } - - public override bool OnPressed(KeyBindingPressEvent e) - { - // the "cut" platform key binding (shift-delete) conflicts with the beatmap deletion action. - if (e.Action == PlatformAction.Cut && e.ShiftPressed && e.CurrentState.Keyboard.Keys.IsPressed(Key.Delete)) - return false; - - return base.OnPressed(e); - } - } - } -} diff --git a/osu.Game/Screens/Select/Footer.cs b/osu.Game/Screens/Select/Footer.cs deleted file mode 100644 index 1d05f644b7..0000000000 --- a/osu.Game/Screens/Select/Footer.cs +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.Collections.Generic; -using System.Linq; -using osuTK; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Events; -using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; - -namespace osu.Game.Screens.Select -{ - public partial class Footer : Container - { - private readonly Box modeLight; - - public const float HEIGHT = 50; - - public const int TRANSITION_LENGTH = 300; - - private const float padding = 80; - - private readonly FillFlowContainer buttons; - - private readonly List overlays = new List(); - - /// The button to be added. - /// The to be toggled by this button. - public void AddButton(FooterButton button, OverlayContainer overlay) - { - if (overlay != null) - { - overlays.Add(overlay); - button.Action = () => showOverlay(overlay); - } - - button.Hovered = updateModeLight; - button.HoverLost = updateModeLight; - - buttons.Add(button); - } - - private void showOverlay(OverlayContainer overlay) - { - foreach (var o in overlays) - { - if (o == overlay) - o.ToggleVisibility(); - else - o.Hide(); - } - } - - private void updateModeLight() - { - var selectedButton = buttons.FirstOrDefault(b => b.Enabled.Value && b.IsHovered); - - if (selectedButton != null) - { - modeLight.FadeIn(TRANSITION_LENGTH, Easing.OutQuint); - modeLight.FadeColour(selectedButton.SelectedColour, TRANSITION_LENGTH, Easing.OutQuint); - } - else - modeLight.FadeOut(TRANSITION_LENGTH, Easing.OutQuint); - } - - public Footer() - { - RelativeSizeAxes = Axes.X; - Height = HEIGHT; - Anchor = Anchor.BottomCentre; - Origin = Anchor.BottomCentre; - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Size = Vector2.One, - Colour = OsuColour.Gray(0.1f), - Alpha = 0.96f, - }, - modeLight = new Box - { - RelativeSizeAxes = Axes.X, - Height = 3, - Position = new Vector2(0, -3), - Colour = OsuColour.Gray(0.1f), - }, - new FillFlowContainer - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Position = new Vector2(TwoLayerButton.SIZE_EXTENDED.X + padding, 0), - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(padding, 0), - Children = new Drawable[] - { - buttons = new FillFlowContainer - { - Direction = FillDirection.Horizontal, - Spacing = new Vector2(-FooterButton.SHEAR_WIDTH, 0), - AutoSizeAxes = Axes.Both, - } - } - } - }; - - updateModeLight(); - } - - protected override bool OnMouseDown(MouseDownEvent e) => true; - - protected override bool OnClick(ClickEvent e) => true; - - protected override bool OnHover(HoverEvent e) => true; - } -} diff --git a/osu.Game/Screens/Select/FooterButton.cs b/osu.Game/Screens/Select/FooterButton.cs deleted file mode 100644 index dafa0b0c1c..0000000000 --- a/osu.Game/Screens/Select/FooterButton.cs +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Input.Bindings; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Select -{ - public partial class FooterButton : OsuClickableContainer, IKeyBindingHandler - { - public const float SHEAR_WIDTH = 7.5f; - - protected static readonly Vector2 SHEAR = new Vector2(SHEAR_WIDTH / Footer.HEIGHT, 0); - - /// - /// Used to show an initial animation hinting at the enabled state. - /// - protected virtual bool IsActive => false; - - public LocalisableString Text - { - get => SpriteText?.Text ?? default; - set - { - if (SpriteText != null) - SpriteText.Text = value; - } - } - - private Color4 deselectedColour; - - public Color4 DeselectedColour - { - get => deselectedColour; - set - { - deselectedColour = value; - if (light.Colour != SelectedColour) - light.Colour = value; - } - } - - private Color4 selectedColour; - - public Color4 SelectedColour - { - get => selectedColour; - set - { - selectedColour = value; - box.Colour = selectedColour; - } - } - - protected FillFlowContainer ButtonContentContainer; - protected readonly Container TextContainer; - protected readonly SpriteText SpriteText; - private readonly Box box; - private readonly Box light; - - public FooterButton() - { - AutoSizeAxes = Axes.Both; - Shear = SHEAR; - Children = new Drawable[] - { - box = new Box - { - RelativeSizeAxes = Axes.Both, - EdgeSmoothness = new Vector2(2, 0), - Colour = Color4.White, - Alpha = 0, - }, - light = new Box - { - Height = 4, - EdgeSmoothness = new Vector2(2, 0), - RelativeSizeAxes = Axes.X, - }, - new Container - { - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - ButtonContentContainer = new FillFlowContainer - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Direction = FillDirection.Horizontal, - Shear = -SHEAR, - AutoSizeAxes = Axes.X, - Height = 50, - Spacing = new Vector2(15, 0), - Children = new Drawable[] - { - TextContainer = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Child = SpriteText = new OsuSpriteText - { - AlwaysPresent = true, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } - }, - }, - }, - }, - }, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - Enabled.BindValueChanged(_ => updateDisplay(), true); - - if (IsActive) - { - box.ClearTransforms(); - - using (box.BeginDelayedSequence(200)) - { - box.FadeIn(200) - .Then() - .FadeOut(1500, Easing.OutQuint); - } - } - } - - public Action Hovered; - public Action HoverLost; - public GlobalAction? Hotkey; - - private bool mouseDown; - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - float horizontalMargin = (100 - TextContainer.Width) / 2; - ButtonContentContainer.Padding = new MarginPadding - { - Left = horizontalMargin, - // right side margin offset to compensate for shear - Right = horizontalMargin - SHEAR_WIDTH / 2 - }; - } - - protected override bool OnHover(HoverEvent e) - { - Hovered?.Invoke(); - updateDisplay(); - return true; - } - - protected override void OnHoverLost(HoverLostEvent e) - { - HoverLost?.Invoke(); - updateDisplay(); - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - if (!Enabled.Value) - return true; - - mouseDown = true; - updateDisplay(); - return base.OnMouseDown(e); - } - - protected override void OnMouseUp(MouseUpEvent e) - { - mouseDown = false; - updateDisplay(); - base.OnMouseUp(e); - } - - protected override bool OnClick(ClickEvent e) - { - if (!Enabled.Value) - return true; - - box.ClearTransforms(); - box.Alpha = 1; - box.FadeOut(Footer.TRANSITION_LENGTH * 3, Easing.OutQuint); - return base.OnClick(e); - } - - public virtual bool OnPressed(KeyBindingPressEvent e) - { - if (e.Action == Hotkey && !e.Repeat) - { - TriggerClick(); - return true; - } - - return false; - } - - public virtual void OnReleased(KeyBindingReleaseEvent e) { } - - private void updateDisplay() - { - this.FadeTo(Enabled.Value ? 1 : 0.25f, Footer.TRANSITION_LENGTH, Easing.OutQuint); - - light.ScaleTo(Enabled.Value && IsHovered ? new Vector2(1, 2) : new Vector2(1), Footer.TRANSITION_LENGTH, Easing.OutQuint); - light.FadeColour(Enabled.Value && IsHovered ? SelectedColour : DeselectedColour, Footer.TRANSITION_LENGTH, Easing.OutQuint); - - box.FadeTo(Enabled.Value & mouseDown ? 0.3f : 0f, Footer.TRANSITION_LENGTH * 2, Easing.OutQuint); - - if (Enabled.Value && IsHovered) - Hovered?.Invoke(); - else - HoverLost?.Invoke(); - } - } -} diff --git a/osu.Game/Screens/Select/FooterButtonMods.cs b/osu.Game/Screens/Select/FooterButtonMods.cs deleted file mode 100644 index a15d315f1b..0000000000 --- a/osu.Game/Screens/Select/FooterButtonMods.cs +++ /dev/null @@ -1,143 +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.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Game.Screens.Play.HUD; -using osu.Game.Rulesets.Mods; -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Extensions.LocalisationExtensions; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osuTK; -using osuTK.Graphics; -using osu.Game.Input.Bindings; -using osu.Game.Localisation; -using osu.Game.Utils; - -namespace osu.Game.Screens.Select -{ - public partial class FooterButtonMods : FooterButton, IHasCurrentValue> - { - public Bindable> Current - { - get => modDisplay.Current; - set => modDisplay.Current = value; - } - - protected OsuSpriteText MultiplierText { get; private set; } = null!; - protected Container UnrankedBadge { get; private set; } = null!; - - private readonly ModDisplay modDisplay; - - private ModSettingChangeTracker? modSettingChangeTracker; - - private Color4 lowMultiplierColour; - private Color4 highMultiplierColour; - - public FooterButtonMods() - { - // must be created in ctor for correct operation of `Current`. - modDisplay = new ModDisplay - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(0.8f), - ExpansionMode = ExpansionMode.AlwaysContracted, - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - SelectedColour = colours.Yellow; - DeselectedColour = SelectedColour.Opacity(0.5f); - lowMultiplierColour = colours.Green; - highMultiplierColour = colours.Red; - Text = @"mods"; - Hotkey = GlobalAction.ToggleModSelection; - - ButtonContentContainer.AddRange(new Drawable[] - { - modDisplay, - MultiplierText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(weight: FontWeight.Bold), - }, - UnrankedBadge = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Circle - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = colours.Yellow, - RelativeSizeAxes = Axes.Both, - }, - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = colours.Gray2, - Padding = new MarginPadding(5), - UseFullGlyphHeight = false, - Text = ModSelectOverlayStrings.Unranked.ToLower() - } - } - }, - }); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - Current.BindValueChanged(mods => - { - modSettingChangeTracker?.Dispose(); - - updateMultiplierText(); - - if (mods.NewValue != null) - { - modSettingChangeTracker = new ModSettingChangeTracker(mods.NewValue); - modSettingChangeTracker.SettingChanged += _ => updateMultiplierText(); - } - }, true); - } - - private void updateMultiplierText() => Schedule(() => - { - double multiplier = Current.Value?.Aggregate(1.0, (current, mod) => current * mod.ScoreMultiplier) ?? 1; - MultiplierText.Text = multiplier == 1 ? string.Empty : ModUtils.FormatScoreMultiplier(multiplier); - - if (multiplier > 1) - MultiplierText.FadeColour(highMultiplierColour, 200); - else if (multiplier < 1) - MultiplierText.FadeColour(lowMultiplierColour, 200); - else - MultiplierText.FadeColour(Color4.White, 200); - - if (Current.Value?.Count > 0) - modDisplay.FadeIn(); - else - modDisplay.FadeOut(); - - bool anyUnrankedMods = Current.Value?.Any(m => !m.Ranked) == true; - UnrankedBadge.FadeTo(anyUnrankedMods ? 1 : 0); - }); - } -} diff --git a/osu.Game/Screens/Select/FooterButtonOptions.cs b/osu.Game/Screens/Select/FooterButtonOptions.cs deleted file mode 100644 index 532051369b..0000000000 --- a/osu.Game/Screens/Select/FooterButtonOptions.cs +++ /dev/null @@ -1,22 +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.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Game.Graphics; -using osu.Game.Input.Bindings; - -namespace osu.Game.Screens.Select -{ - public partial class FooterButtonOptions : FooterButton - { - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - SelectedColour = colours.Blue; - DeselectedColour = SelectedColour.Opacity(0.5f); - Text = @"options"; - Hotkey = GlobalAction.ToggleBeatmapOptions; - } - } -} diff --git a/osu.Game/Screens/Select/FooterButtonRandom.cs b/osu.Game/Screens/Select/FooterButtonRandom.cs deleted file mode 100644 index 2d5d049133..0000000000 --- a/osu.Game/Screens/Select/FooterButtonRandom.cs +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Input.Events; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Input.Bindings; -using osuTK; -using osuTK.Input; - -namespace osu.Game.Screens.Select -{ - public partial class FooterButtonRandom : FooterButton - { - public Action NextRandom { get; set; } - public Action PreviousRandom { get; set; } - - private Container persistentText; - private OsuSpriteText randomSpriteText; - private OsuSpriteText rewindSpriteText; - private bool rewindSearch; - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - SelectedColour = colours.Green; - DeselectedColour = SelectedColour.Opacity(0.5f); - - TextContainer.Add(persistentText = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AlwaysPresent = true, - AutoSizeAxes = Axes.Both, - Children = new[] - { - randomSpriteText = new OsuSpriteText - { - AlwaysPresent = true, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "random", - }, - rewindSpriteText = new OsuSpriteText - { - AlwaysPresent = true, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "rewind", - Alpha = 0f, - } - } - }); - - Action = () => - { - if (rewindSearch) - { - const double fade_time = 500; - - OsuSpriteText fallingRewind; - - TextContainer.Add(fallingRewind = new OsuSpriteText - { - Alpha = 0, - Text = rewindSpriteText.Text, - AlwaysPresent = true, // make sure the button is sized large enough to always show this - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }); - - fallingRewind.FadeOutFromOne(fade_time, Easing.In); - fallingRewind.MoveTo(Vector2.Zero).MoveTo(new Vector2(0, 10), fade_time, Easing.In); - fallingRewind.Expire(); - - persistentText.FadeInFromZero(fade_time, Easing.In); - - PreviousRandom.Invoke(); - } - else - { - NextRandom.Invoke(); - } - }; - } - - protected override bool OnKeyDown(KeyDownEvent e) - { - updateText(e); - return base.OnKeyDown(e); - } - - protected override void OnKeyUp(KeyUpEvent e) - { - updateText(e); - base.OnKeyUp(e); - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - updateText(e); - return base.OnMouseDown(e); - } - - protected override bool OnClick(ClickEvent e) - { - try - { - // this uses OR to handle rewinding when clicks are triggered by other sources (i.e. right button in OnMouseUp). - rewindSearch |= e.ShiftPressed; - return base.OnClick(e); - } - finally - { - rewindSearch = false; - } - } - - protected override void OnMouseUp(MouseUpEvent e) - { - base.OnMouseUp(e); - - if (e.Button == MouseButton.Right && IsHovered) - { - rewindSearch = true; - TriggerClick(); - } - - updateText(e); - } - - public override bool OnPressed(KeyBindingPressEvent e) - { - rewindSearch = e.Action == GlobalAction.SelectPreviousRandom; - - if (e.Action != GlobalAction.SelectNextRandom && e.Action != GlobalAction.SelectPreviousRandom) - { - return false; - } - - if (!e.Repeat) - TriggerClick(); - return true; - } - - public override void OnReleased(KeyBindingReleaseEvent e) - { - if (e.Action == GlobalAction.SelectPreviousRandom) - { - rewindSearch = false; - } - } - - private void updateText(UIEvent e) - { - bool aboutToRewind = e.ShiftPressed || e.CurrentState.Mouse.IsPressed(MouseButton.Right); - - randomSpriteText.Alpha = aboutToRewind ? 0 : 1; - rewindSpriteText.Alpha = aboutToRewind ? 1 : 0; - } - } -} diff --git a/osu.Game/Screens/Select/NoResultsPlaceholder.cs b/osu.Game/Screens/Select/NoResultsPlaceholder.cs deleted file mode 100644 index 50577d5fea..0000000000 --- a/osu.Game/Screens/Select/NoResultsPlaceholder.cs +++ /dev/null @@ -1,155 +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.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Localisation; -using osu.Game.Online.Chat; -using osu.Game.Overlays; -using osuTK; - -namespace osu.Game.Screens.Select -{ - public partial class NoResultsPlaceholder : VisibilityContainer - { - private FilterCriteria? filter; - - private LinkFlowContainer textFlow = null!; - - [Resolved] - private BeatmapManager beatmaps { get; set; } = null!; - - [Resolved] - private FirstRunSetupOverlay? firstRunSetupOverlay { get; set; } - - [Resolved] - private OsuConfigManager config { get; set; } = null!; - - public FilterCriteria Filter - { - set - { - if (filter == value) - return; - - filter = value; - Scheduler.AddOnce(updateText); - } - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Masking = true; - CornerRadius = 10; - - Width = 400; - AutoSizeAxes = Axes.Y; - - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - - InternalChildren = new Drawable[] - { - new Box - { - Colour = colours.Gray2, - RelativeSizeAxes = Axes.Both, - }, - new SpriteIcon - { - Icon = FontAwesome.Regular.SadTear, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Margin = new MarginPadding(10), - Size = new Vector2(50), - }, - textFlow = new LinkFlowContainer - { - Y = 60, - Padding = new MarginPadding(10), - TextAnchor = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - } - }; - } - - protected override void PopIn() - { - this.FadeIn(600, Easing.OutQuint); - - Scheduler.AddOnce(updateText); - } - - protected override void PopOut() - { - this.FadeOut(200, Easing.OutQuint); - } - - private void updateText() - { - // TODO: Refresh this text when new beatmaps are imported. Right now it won't get up-to-date suggestions. - - // Bounce should play every time the filter criteria is updated. - this.ScaleTo(0.9f) - .ScaleTo(1f, 1000, Easing.OutElastic); - - textFlow.Clear(); - - if (beatmaps.QueryBeatmapSet(s => !s.Protected && !s.DeletePending) == null) - { - textFlow.AddParagraph("No beatmaps found!"); - textFlow.AddParagraph(string.Empty); - - textFlow.AddParagraph("- Consider running the \""); - textFlow.AddLink(FirstRunSetupOverlayStrings.FirstRunSetupTitle, () => firstRunSetupOverlay?.Show()); - textFlow.AddText("\" to download or import some beatmaps!"); - } - else - { - textFlow.AddParagraph("No beatmaps match your filter criteria!"); - textFlow.AddParagraph(string.Empty); - - if (filter?.UserStarDifficulty.HasFilter == true) - { - textFlow.AddParagraph("- Try "); - textFlow.AddLink("removing", () => - { - config.SetValue(OsuSetting.DisplayStarsMinimum, 0.0); - config.SetValue(OsuSetting.DisplayStarsMaximum, 10.1); - }); - - string lowerStar = $"{filter.UserStarDifficulty.Min ?? 0:N1}"; - string upperStar = filter.UserStarDifficulty.Max == null ? "∞" : $"{filter.UserStarDifficulty.Max:N1}"; - - textFlow.AddText($" the {lowerStar} - {upperStar} star difficulty filter."); - } - - // TODO: Add realm queries to hint at which ruleset results are available in (and allow clicking to switch). - // TODO: Make this message more certain by ensuring the osu! beatmaps exist before suggesting. - if (filter?.Ruleset?.OnlineID != 0 && filter?.AllowConvertedBeatmaps == false) - { - textFlow.AddParagraph("- Try "); - textFlow.AddLink("enabling ", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, true)); - textFlow.AddText("automatic conversion!"); - } - } - - if (!string.IsNullOrEmpty(filter?.SearchText)) - { - textFlow.AddParagraph("- Try "); - textFlow.AddLink("searching online", LinkAction.SearchBeatmapSet, filter.SearchText); - textFlow.AddText($" for \"{filter.SearchText}\"."); - } - // TODO: add clickable link to reset criteria. - } - } -} diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs deleted file mode 100644 index 572b2427b1..0000000000 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs +++ /dev/null @@ -1,159 +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.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osuTK; -using osuTK.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; - -namespace osu.Game.Screens.Select.Options -{ - public partial class BeatmapOptionsButton : OsuClickableContainer - { - private const float width = 130; - - private readonly Box background; - private readonly Box flash; - private readonly SpriteIcon iconText; - private readonly OsuSpriteText firstLine; - private readonly OsuSpriteText secondLine; - private readonly Container box; - - public Color4 ButtonColour - { - get => background.Colour; - set => background.Colour = value; - } - - public IconUsage Icon - { - get => iconText.Icon; - set => iconText.Icon = value; - } - - public LocalisableString FirstLineText - { - get => firstLine.Text; - set => firstLine.Text = value; - } - - public LocalisableString SecondLineText - { - get => secondLine.Text; - set => secondLine.Text = value; - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - flash.FadeTo(0.1f, 1000, Easing.OutQuint); - return base.OnMouseDown(e); - } - - protected override void OnMouseUp(MouseUpEvent e) - { - flash.FadeTo(0, 1000, Easing.OutQuint); - base.OnMouseUp(e); - } - - protected override bool OnClick(ClickEvent e) - { - flash.ClearTransforms(); - flash.Alpha = 0.9f; - flash.FadeOut(800, Easing.OutExpo); - - return base.OnClick(e); - } - - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => box.ReceivePositionalInputAt(screenSpacePos); - - public BeatmapOptionsButton() - : base(HoverSampleSet.Button) - { - Width = width; - RelativeSizeAxes = Axes.Y; - - Children = new Drawable[] - { - box = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Shear = OsuGame.SHEAR, - Masking = true, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(0.2f), - Roundness = 5, - Radius = 8, - }, - Children = new Drawable[] - { - background = new Box - { - RelativeSizeAxes = Axes.Both, - EdgeSmoothness = new Vector2(1.5f, 0), - Colour = Color4.Black, - }, - flash = new Box - { - RelativeSizeAxes = Axes.Both, - EdgeSmoothness = new Vector2(1.5f, 0), - Blending = BlendingParameters.Additive, - Colour = Color4.White, - Alpha = 0, - }, - }, - }, - new FillFlowContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - iconText = new SpriteIcon - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Size = new Vector2(30), - Shadow = true, - Icon = FontAwesome.Solid.TimesCircle, - Margin = new MarginPadding - { - Bottom = 5, - }, - }, - firstLine = new OsuSpriteText - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Font = OsuFont.GetFont(weight: FontWeight.Bold), - Text = @"", - }, - secondLine = new OsuSpriteText - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Font = OsuFont.GetFont(weight: FontWeight.Bold), - Text = @"", - }, - }, - }, - }; - } - } -} diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs deleted file mode 100644 index 7b631ebfea..0000000000 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osuTK; -using osuTK.Graphics; -using osuTK.Input; -using osu.Game.Graphics.Containers; -using osu.Framework.Input.Events; -using System.Linq; -using osu.Framework.Localisation; - -namespace osu.Game.Screens.Select.Options -{ - public partial class BeatmapOptionsOverlay : OsuFocusedOverlayContainer - { - private const float transition_duration = 500; - private const float x_position = 0.2f; - private const float x_movement = 0.8f; - - private const float height = 100; - - private readonly Box holder; - private readonly FillFlowContainer buttonsContainer; - - public override bool BlockScreenWideMouse => false; - - protected override string PopInSampleName => "SongSelect/options-pop-in"; - protected override string PopOutSampleName => "SongSelect/options-pop-out"; - - public BeatmapOptionsOverlay() - { - AutoSizeAxes = Axes.Y; - RelativeSizeAxes = Axes.X; - Anchor = Anchor.BottomLeft; - Origin = Anchor.BottomLeft; - - Children = new Drawable[] - { - holder = new Box - { - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Both, - Height = 0.5f, - Scale = new Vector2(1, 0), - Colour = Color4.Black.Opacity(0.5f), - }, - buttonsContainer = new ReverseChildIDFillFlowContainer - { - Height = height, - RelativePositionAxes = Axes.X, - AutoSizeAxes = Axes.X, - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - }, - }; - } - - /// Text in the first line. - /// Text in the second line. - /// Colour of the button. - /// Icon of the button. - /// Binding the button does. - public void AddButton(LocalisableString firstLine, string secondLine, IconUsage icon, Color4 colour, Action action) - { - var button = new BeatmapOptionsButton - { - FirstLineText = firstLine, - SecondLineText = secondLine, - Icon = icon, - ButtonColour = colour, - Action = () => - { - Hide(); - action?.Invoke(); - }, - }; - - buttonsContainer.Add(button); - } - - protected override void PopIn() - { - this.FadeIn(transition_duration, Easing.OutQuint); - - if (buttonsContainer.Position.X == 1 || Alpha == 0) - buttonsContainer.MoveToX(x_position - x_movement); - - holder.ScaleTo(new Vector2(1, 1), transition_duration / 2, Easing.OutQuint); - - buttonsContainer.MoveToX(x_position, transition_duration, Easing.OutQuint); - buttonsContainer.TransformSpacingTo(Vector2.Zero, transition_duration, Easing.OutQuint); - } - - protected override void PopOut() - { - base.PopOut(); - - holder.ScaleTo(new Vector2(1, 0), transition_duration / 2, Easing.InSine); - - buttonsContainer.MoveToX(x_position + x_movement, transition_duration, Easing.InSine); - buttonsContainer.TransformSpacingTo(new Vector2(200f, 0f), transition_duration, Easing.InSine); - - this.FadeOut(transition_duration, Easing.InQuint); - } - - protected override bool OnKeyDown(KeyDownEvent e) - { - // don't absorb control as ToolbarRulesetSelector uses control + number to navigate - if (e.ControlPressed) return false; - - if (!e.Repeat && e.Key >= Key.Number1 && e.Key <= Key.Number9) - { - int requested = e.Key - Key.Number1; - - // go reverse as buttonsContainer is a ReverseChildIDFillFlowContainer - BeatmapOptionsButton found = buttonsContainer.Children.ElementAtOrDefault((buttonsContainer.Children.Count - 1) - requested); - - if (found != null) - { - found.TriggerClick(); - return true; - } - } - - return base.OnKeyDown(e); - } - } -} diff --git a/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs b/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs deleted file mode 100644 index ae318de754..0000000000 --- a/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Screens.Select.Leaderboards; - -namespace osu.Game.Screens.Select -{ - public partial class PlayBeatmapDetailArea : BeatmapDetailArea - { - public readonly BeatmapLeaderboard Leaderboard; - - public override WorkingBeatmap Beatmap - { - get => base.Beatmap; - set - { - base.Beatmap = value; - - Leaderboard.BeatmapInfo = value is DummyWorkingBeatmap ? null : value?.BeatmapInfo; - } - } - - private Bindable selectedTab; - - private Bindable selectedModsFilter; - - public PlayBeatmapDetailArea() - { - Add(Leaderboard = new BeatmapLeaderboard { RelativeSizeAxes = Axes.Both }); - } - - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) - { - selectedTab = config.GetBindable(OsuSetting.BeatmapDetailTab); - selectedModsFilter = config.GetBindable(OsuSetting.BeatmapDetailModsFilter); - - selectedTab.BindValueChanged(tab => CurrentTab.Value = getTabItemFromTabType(tab.NewValue), true); - CurrentTab.BindValueChanged(tab => selectedTab.Value = getTabTypeFromTabItem(tab.NewValue)); - - selectedModsFilter.BindValueChanged(checkbox => CurrentModsFilter.Value = checkbox.NewValue, true); - CurrentModsFilter.BindValueChanged(checkbox => selectedModsFilter.Value = checkbox.NewValue); - } - - public override void Refresh() - { - base.Refresh(); - - Leaderboard.RefetchScores(); - } - - protected override void OnTabChanged(BeatmapDetailAreaTabItem tab, bool selectedMods) - { - base.OnTabChanged(tab, selectedMods); - - Leaderboard.FilterMods = selectedMods; - - switch (tab) - { - case BeatmapDetailAreaLeaderboardTabItem leaderboard: - Leaderboard.Scope = leaderboard.Scope; - Leaderboard.Show(); - break; - - default: - Leaderboard.Hide(); - break; - } - } - - protected override BeatmapDetailAreaTabItem[] CreateTabItems() => base.CreateTabItems().Concat(new BeatmapDetailAreaTabItem[] - { - new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local), - new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Global), - new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Country), - new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Friend), - new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Team), - }).ToArray(); - - private BeatmapDetailAreaTabItem getTabItemFromTabType(BeatmapDetailTab type) - { - switch (type) - { - case BeatmapDetailTab.Details: - return new BeatmapDetailAreaDetailTabItem(); - - case BeatmapDetailTab.Local: - return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local); - - case BeatmapDetailTab.Global: - return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Global); - - case BeatmapDetailTab.Country: - return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Country); - - case BeatmapDetailTab.Friends: - return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Friend); - - case BeatmapDetailTab.Team: - return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Team); - - default: - throw new ArgumentOutOfRangeException(nameof(type)); - } - } - - private BeatmapDetailTab getTabTypeFromTabItem(BeatmapDetailAreaTabItem item) - { - switch (item) - { - case BeatmapDetailAreaDetailTabItem: - return BeatmapDetailTab.Details; - - case BeatmapDetailAreaLeaderboardTabItem leaderboardTab: - switch (leaderboardTab.Scope) - { - case BeatmapLeaderboardScope.Local: - return BeatmapDetailTab.Local; - - case BeatmapLeaderboardScope.Country: - return BeatmapDetailTab.Country; - - case BeatmapLeaderboardScope.Global: - return BeatmapDetailTab.Global; - - case BeatmapLeaderboardScope.Friend: - return BeatmapDetailTab.Friends; - - case BeatmapLeaderboardScope.Team: - return BeatmapDetailTab.Team; - - default: - throw new ArgumentOutOfRangeException(nameof(item)); - } - - default: - throw new ArgumentOutOfRangeException(nameof(item)); - } - } - } -} diff --git a/osu.Game/Screens/Select/SkinDeleteDialog.cs b/osu.Game/Screens/Select/SkinDeleteDialog.cs deleted file mode 100644 index cd14b5b6d2..0000000000 --- a/osu.Game/Screens/Select/SkinDeleteDialog.cs +++ /dev/null @@ -1,30 +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.Framework.Allocation; -using osu.Game.Skinning; -using osu.Game.Overlays.Dialog; - -namespace osu.Game.Screens.Select -{ - public partial class SkinDeleteDialog : DeletionDialog - { - private readonly Skin skin; - - public SkinDeleteDialog(Skin skin) - { - this.skin = skin; - BodyText = skin.SkinInfo.Value.Name; - } - - [BackgroundDependencyLoader] - private void load(SkinManager manager) - { - DangerousAction = () => - { - manager.Delete(skin.SkinInfo.Value); - manager.CurrentSkinInfo.SetDefault(); - }; - } - } -} diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs deleted file mode 100644 index 606d53d884..0000000000 --- a/osu.Game/Screens/Select/SongSelect.cs +++ /dev/null @@ -1,1184 +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 System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Audio.Track; -using osu.Framework.Bindables; -using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input; -using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; -using osu.Framework.Logging; -using osu.Framework.Screens; -using osu.Framework.Threading; -using osu.Game.Beatmaps; -using osu.Game.Collections; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Cursor; -using osu.Game.Graphics.UserInterface; -using osu.Game.Input.Bindings; -using osu.Game.Overlays; -using osu.Game.Overlays.Mods; -using osu.Game.Overlays.Volume; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Backgrounds; -using osu.Game.Screens.Edit; -using osu.Game.Screens.Menu; -using osu.Game.Screens.Play; -using osu.Game.Screens.Select.Details; -using osu.Game.Screens.Select.Options; -using osu.Game.Skinning; -using osu.Game.Utils; -using osuTK; -using osuTK.Graphics; -using osuTK.Input; - -namespace osu.Game.Screens.Select -{ - public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler - { - public static readonly float WEDGE_HEIGHT = 200; - - protected const float BACKGROUND_BLUR = 20; - private const float left_area_padding = 20; - - public FilterControl FilterControl { get; private set; } = null!; - - /// - /// Whether this song select instance should take control of the global track, - /// applying looping and preview offsets. - /// - protected virtual bool ControlGlobalMusic => true; - - protected virtual bool ShowSongSelectFooter => true; - - public override bool? ApplyModTrackAdjustments => true; - - /// - /// Can be null if is false. - /// - protected BeatmapOptionsOverlay BeatmapOptions { get; private set; } = null!; - - /// - /// Can be null if is false. - /// - protected Footer? SongSelectFooter { get; private set; } - - /// - /// Contains any panel which is triggered by a footer button. - /// Helps keep them located beneath the footer itself. - /// - protected Container FooterPanels { get; private set; } = null!; - - /// - /// The that opens the mod select dialog. - /// - protected FooterButton ModsFooterButton { get; private set; } = null!; - - /// - /// Whether entering editor mode should be allowed. - /// - public virtual bool AllowEditing => true; - - public bool BeatmapSetsLoaded => IsLoaded && Carousel.BeatmapSetsLoaded; - - /// - /// Creates any "action" menu items for the provided beatmap (ie. "Select", "Play", "Edit"). - /// These will always be placed at the top of the context menu, with common items added below them. - /// - /// The beatmap to create items for. - /// The menu items. - public virtual MenuItem[] CreateForwardNavigationMenuItemsForBeatmap(Func getBeatmap) => new MenuItem[] - { - new OsuMenuItem(@"Select", MenuItemType.Highlighted, () => FinaliseSelection(getBeatmap())) - }; - - [Resolved] - private OsuGameBase game { get; set; } = null!; - - [Resolved] - private Bindable> selectedMods { get; set; } = null!; - - protected BeatmapCarousel Carousel { get; private set; } = null!; - - private ParallaxContainer wedgeBackground = null!; - - protected Container LeftArea { get; private set; } = null!; - - private BeatmapInfoWedge beatmapInfoWedge = null!; - - [Resolved] - private IDialogOverlay? dialogOverlay { get; set; } - - [Resolved] - private BeatmapManager beatmaps { get; set; } = null!; - - protected ModSelectOverlay ModSelect { get; private set; } = null!; - - protected Sample? SampleConfirm { get; private set; } - - private Sample sampleChangeDifficulty = null!; - private Sample sampleChangeBeatmap = null!; - - private bool pendingFilterApplication; - - private Container carouselContainer = null!; - - protected BeatmapDetailArea BeatmapDetails { get; private set; } = null!; - - private FooterButtonOptions beatmapOptionsButton = null!; - - private readonly Bindable decoupledRuleset = new Bindable(); - - private double audioFeedbackLastPlaybackTime; - - private IDisposable? modSelectOverlayRegistration; - private ModSpeedHotkeyHandler modSpeedHotkeyHandler = null!; - - private AdvancedStats advancedStats = null!; - - [Resolved] - private MusicController music { get; set; } = null!; - - [Resolved] - internal IOverlayManager? OverlayManager { get; private set; } - - private Bindable configBackgroundBlur = null!; - - [BackgroundDependencyLoader(true)] - private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender, OsuConfigManager config) - { - configBackgroundBlur = config.GetBindable(OsuSetting.SongSelectBackgroundBlur); - configBackgroundBlur.BindValueChanged(e => - { - if (!this.IsCurrentScreen()) - return; - - ApplyToBackground(applyBlurToBackground); - }); - - // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). - transferRulesetValue(); - - AddRangeInternal(new Drawable[] - { - new GlobalScrollAdjustsVolume(), - new VerticalMaskingContainer - { - Children = new Drawable[] - { - new GlobalScrollAdjustsVolume(), - new GridContainer // used for max width implementation - { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.Relative, 0.5f, maxSize: 850), - }, - Content = new[] - { - new Drawable[] - { - wedgeBackground = new ParallaxContainer - { - ParallaxAmount = 0.005f, - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Child = new WedgeBackground - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Right = -150 }, - }, - }, - carouselContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding - { - Top = FilterControl.HEIGHT, - Bottom = Select.Footer.HEIGHT - }, - Child = new LoadingSpinner(true) { State = { Value = Visibility.Visible } } - } - }, - } - }, - FilterControl = CreateFilterControl().With(d => - { - d.RelativeSizeAxes = Axes.X; - d.Height = FilterControl.HEIGHT; - }), - new GridContainer // used for max width implementation - { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.Relative, 0.5f, maxSize: 650), - }, - Content = new[] - { - new Drawable[] - { - LeftArea = new Container - { - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 5 }, - Children = new Drawable[] - { - new LeftSideInteractionContainer(() => Carousel.ScrollToSelected()) - { - RelativeSizeAxes = Axes.Both, - }, - beatmapInfoWedge = new BeatmapInfoWedge - { - Height = WEDGE_HEIGHT, - RelativeSizeAxes = Axes.X, - Margin = new MarginPadding - { - Right = left_area_padding, - Left = -BeatmapInfoWedge.BORDER_THICKNESS, // Hide the left border - }, - }, - new Container - { - RelativeSizeAxes = Axes.X, - Height = 90, - Padding = new MarginPadding(10) - { - Left = left_area_padding, - Right = left_area_padding * 2 + 5, - }, - Y = WEDGE_HEIGHT, - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 10, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Colour4.Black.Opacity(0.3f), - }, - advancedStats = new AdvancedStats(2) - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Padding = new MarginPadding(10), - }, - } - }, - } - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding - { - Bottom = Select.Footer.HEIGHT, - Top = WEDGE_HEIGHT + 70, - Left = left_area_padding, - Right = left_area_padding * 2, - }, - Child = BeatmapDetails = CreateBeatmapDetailArea().With(d => - { - d.RelativeSizeAxes = Axes.Both; - d.Padding = new MarginPadding { Top = 10, Right = 5 }; - }) - }, - } - }, - }, - } - } - } - }, - new SkinnableContainer(new GlobalSkinnableContainerLookup(GlobalSkinnableContainers.SongSelect)) - { - RelativeSizeAxes = Axes.Both, - }, - modSpeedHotkeyHandler = new ModSpeedHotkeyHandler(), - }); - - // Important to load this after the filter control is loaded (so we have initial filter criteria prepared). - LoadComponentAsync(Carousel = new BeatmapCarousel(FilterControl.CreateCriteria()) - { - AllowSelection = false, // delay any selection until our bindables are ready to make a good choice. - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.Both, - BleedTop = FilterControl.HEIGHT, - BleedBottom = Select.Footer.HEIGHT, - SelectionChanged = updateSelectedBeatmap, - BeatmapSetsChanged = carouselBeatmapsLoaded, - FilterApplied = () => Scheduler.AddOnce(updateVisibleBeatmapCount), - GetRecommendedBeatmap = s => recommender?.GetRecommendedBeatmap(s), - }, c => carouselContainer.Child = c); - - FilterControl.FilterChanged = criteria => - { - // If a filter operation is applied when we're in a state that doesn't allow selection, - // we might end up in an unexpected state. This is because currently carousel panels are in charge - // of updating the global selection (which is very hard to deal with). - // - // For now let's just avoid filtering when selection isn't allowed locally. - // This should be nuked from existence when we get around to fixing the complexity of song select <-> beatmap carousel. - // The debounce part of BeatmapCarousel's filtering should probably also be removed and handled locally. - if (Carousel.AllowSelection) - Carousel.Filter(criteria); - else - pendingFilterApplication = true; - }; - - if (ShowSongSelectFooter) - { - AddRangeInternal(new Drawable[] - { - FooterPanels = new Container - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Bottom = Select.Footer.HEIGHT }, - Children = new Drawable[] - { - BeatmapOptions = new BeatmapOptionsOverlay(), - } - }, - SongSelectFooter = new Footer() - }); - } - - // preload the mod select overlay for later use in `LoadComplete()`. - // therein it will be registered at the `OsuGame` level to properly function as a blocking overlay. - LoadComponent(ModSelect = CreateModSelectOverlay()); - - if (SongSelectFooter != null) - { - foreach (var (button, overlay) in CreateSongSelectFooterButtons()) - SongSelectFooter.AddButton(button, overlay); - - BeatmapOptions.AddButton(@"Manage", @"collections", FontAwesome.Solid.Book, colours.Green, () => manageCollectionsDialog?.Show()); - BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => DeleteBeatmap(Beatmap.Value.BeatmapSetInfo)); - BeatmapOptions.AddButton(@"Mark", @"as played", FontAwesome.Regular.TimesCircle, colours.Purple, () => beatmaps.MarkPlayed(Beatmap.Value.BeatmapInfo)); - BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, () => ClearScores(Beatmap.Value.BeatmapInfo)); - } - - sampleChangeDifficulty = audio.Samples.Get(@"SongSelect/select-difficulty"); - sampleChangeBeatmap = audio.Samples.Get(@"SongSelect/select-expand"); - SampleConfirm = audio.Samples.Get(@"SongSelect/confirm-selection"); - } - - protected virtual FilterControl CreateFilterControl() => new FilterControl(); - - protected override void LoadComplete() - { - base.LoadComplete(); - - modSelectOverlayRegistration = OverlayManager?.RegisterBlockingOverlay(ModSelect); - } - - protected override bool OnScroll(ScrollEvent e) - { - // Match stable behaviour of only alt-scroll adjusting volume. - // Supporting scroll adjust without a modifier key just feels bad, since there are so many scrollable elements on the screen. - if (!e.CurrentState.Keyboard.AltPressed) - return true; - - return base.OnScroll(e); - } - - /// - /// Creates the buttons to be displayed in the footer. - /// - /// A set of and an optional which the button opens when pressed. - protected virtual IEnumerable<(FooterButton button, OverlayContainer? overlay)> CreateSongSelectFooterButtons() => new (FooterButton, OverlayContainer?)[] - { - (ModsFooterButton = new FooterButtonMods { Current = Mods }, ModSelect), - (new FooterButtonRandom - { - NextRandom = () => Carousel.SelectNextRandom(), - PreviousRandom = Carousel.SelectPreviousRandom - }, null), - (beatmapOptionsButton = new FooterButtonOptions(), BeatmapOptions) - }; - - protected virtual ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay - { - ShowPresets = true, - }; - - private DependencyContainer dependencies = null!; - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - - dependencies.CacheAs(this); - dependencies.CacheAs(decoupledRuleset); - dependencies.CacheAs>(decoupledRuleset); - - return dependencies; - } - - /// - /// Creates the beatmap details to be displayed underneath the wedge. - /// - protected abstract BeatmapDetailArea CreateBeatmapDetailArea(); - - public void Edit(BeatmapInfo? beatmapInfo = null) - { - if (!AllowEditing) - throw new InvalidOperationException($"Attempted to edit when {nameof(AllowEditing)} is disabled"); - - // Forced refetch is important here to guarantee correct invalidation across all difficulties. - Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo ?? beatmapInfoNoDebounce, true); - - FinaliseSelection(customStartAction: () => this.Push(new EditorLoader())); - } - - /// - /// Set the query to the search text box. - /// - /// The string to search. - public void Search(string query) - { - FilterControl.CurrentTextSearch.Value = query; - } - - /// - /// Call to make a selection and perform the default action for this SongSelect. - /// - /// An optional beatmap to override the current carousel selection. - /// An optional ruleset to override the current carousel selection. - /// An optional custom action to perform instead of . - public void FinaliseSelection(BeatmapInfo? beatmapInfo = null, RulesetInfo? ruleset = null, Action? customStartAction = null) - { - // This is very important as we have not yet bound to screen-level bindables before the carousel load is completed. - if (!Carousel.BeatmapSetsLoaded) - { - Logger.Log($"{nameof(FinaliseSelection)} aborted as carousel beatmaps are not yet loaded"); - return; - } - - if (ruleset != null) - Ruleset.Value = ruleset; - - transferRulesetValue(); - - // while transferRulesetValue will flush, it only does so if the ruleset changes. - // the user could have changed a filter, and we want to ensure we are 100% up-to-date and consistent here. - Carousel.FlushPendingFilterOperations(); - - // avoid attempting to continue before a selection has been obtained. - // this could happen via a user interaction while the carousel is still in a loading state. - if (Carousel.SelectedBeatmapInfo == null) return; - - if (beatmapInfo != null) - Carousel.SelectBeatmap(beatmapInfo); - - if (selectionChangedDebounce?.Completed == false) - { - selectionChangedDebounce.RunTask(); - selectionChangedDebounce?.Cancel(); // cancel the already scheduled task. - selectionChangedDebounce = null; - } - - if (customStartAction != null) - { - customStartAction(); - Carousel.AllowSelection = false; - } - else if (OnStart()) - Carousel.AllowSelection = false; - } - - /// - /// Called when a selection is made. - /// - /// If a resultant action occurred that takes the user away from SongSelect. - protected abstract bool OnStart(); - - private ScheduledDelegate? selectionChangedDebounce; - - private void updateCarouselSelection(ValueChangedEvent e = default) - { - var beatmap = e.NewValue ?? Beatmap.Value; - if (beatmap is DummyWorkingBeatmap || !this.IsCurrentScreen()) return; - - if (beatmap.BeatmapSetInfo.Protected) - { - Logger.Log($"Denying working beatmap switch to protected beatmap {beatmap}"); - Beatmap.Value = e.OldValue; - return; - } - - Logger.Log($"Song select working beatmap updated to {beatmap}"); - - if (!Carousel.SelectBeatmap(beatmap.BeatmapInfo, false)) - { - // 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 (!beatmap.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) - { - Ruleset.Value = beatmap.BeatmapInfo.Ruleset; - transferRulesetValue(); - } - - // Even if a ruleset mismatch was not the cause (ie. a text filter is applied), - // we still want to temporarily show the new beatmap, bypassing filters. - // This will be undone the next time the user changes the filter. - var criteria = FilterControl.CreateCriteria(); - criteria.SelectedBeatmapSet = beatmap.BeatmapInfo.BeatmapSet; - Carousel.Filter(criteria); - - Carousel.SelectBeatmap(beatmap.BeatmapInfo); - } - } - - // We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds. - private BeatmapInfo? beatmapInfoPrevious; - private BeatmapInfo? beatmapInfoNoDebounce; - private RulesetInfo? rulesetNoDebounce; - - private void updateSelectedBeatmap(BeatmapInfo? beatmapInfo) - { - if (beatmapInfo == null && beatmapInfoNoDebounce == null) - return; - - if (beatmapInfo?.Equals(beatmapInfoNoDebounce) == true) - return; - - beatmapInfoNoDebounce = beatmapInfo; - performUpdateSelected(); - } - - private void updateSelectedRuleset(RulesetInfo? ruleset) - { - if (ruleset == null && rulesetNoDebounce == null) - return; - - if (ruleset?.Equals(rulesetNoDebounce) == true) - return; - - rulesetNoDebounce = ruleset; - performUpdateSelected(); - } - - /// - /// Selection has been changed as the result of a user interaction. - /// - private void performUpdateSelected() - { - var beatmap = beatmapInfoNoDebounce; - RulesetInfo? ruleset = rulesetNoDebounce; - - selectionChangedDebounce?.Cancel(); - - if (beatmapInfoNoDebounce == null) - run(); - else - { - // Intentionally slightly higher than repeat_tick_rate to avoid loading songs when holding left / right arrows. - // See https://github.com/ppy/osu-framework/blob/master/osu.Framework/Input/InputManager.cs#L44 - selectionChangedDebounce = Scheduler.AddDelayed(run, 80); - } - - if (beatmap?.Equals(beatmapInfoPrevious) != true) - { - if (beatmap != null && beatmapInfoPrevious != null && Time.Current - audioFeedbackLastPlaybackTime >= 50) - { - if (beatmap.BeatmapSet?.ID == beatmapInfoPrevious.BeatmapSet?.ID) - sampleChangeDifficulty.Play(); - else - sampleChangeBeatmap.Play(); - - audioFeedbackLastPlaybackTime = Time.Current; - } - - beatmapInfoPrevious = beatmap; - } - - void run() - { - // clear pending task immediately to track any potential nested debounce operation. - selectionChangedDebounce = null; - - Logger.Log($"Song select updating selection with beatmap: {beatmap} {beatmap?.ID.ToString() ?? "null"} ruleset:{ruleset?.ShortName ?? "null"}"); - - if (transferRulesetValue()) - { - // transferRulesetValue() may trigger a re-filter. If the current selection does not match the new ruleset, we want to switch away from it. - // The default logic on WorkingBeatmap change is to switch to a matching ruleset (see workingBeatmapChanged()), but we don't want that here. - // We perform an early selection attempt and clear out the beatmap selection to avoid a second ruleset change (revert). - if (beatmap != null && !Carousel.SelectBeatmap(beatmap, false)) - beatmap = null; - } - - if (selectionChangedDebounce != null) - { - // a new nested operation was started; switch to it for further selection. - // this avoids having two separate debounces trigger from the same source. - selectionChangedDebounce.RunTask(); - return; - } - - // We may be arriving here due to another component changing the bindable Beatmap. - // In these cases, the other component has already loaded the beatmap, so we don't need to do so again. - if (!EqualityComparer.Default.Equals(beatmap, Beatmap.Value.BeatmapInfo)) - { - Logger.Log($"Song select changing beatmap from \"{Beatmap.Value.BeatmapInfo}\" to \"{beatmap?.ToString() ?? "null"}\""); - Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap); - } - - if (this.IsCurrentScreen()) - ensurePlayingSelected(); - - updateComponentFromBeatmap(Beatmap.Value); - } - } - - public override void OnEntering(ScreenTransitionEvent e) - { - base.OnEntering(e); - - this.FadeInFromZero(250); - FilterControl.Activate(); - - ModSelect.SelectedMods.BindTo(selectedMods); - - beginLooping(); - } - - private const double logo_transition = 250; - - protected override void LogoArriving(OsuLogo logo, bool resuming) - { - base.LogoArriving(logo, resuming); - - logo.RelativePositionAxes = Axes.None; - logo.ChangeAnchor(Anchor.BottomRight); - - Vector2 position = new Vector2(-76, -36); - - if (logo.Alpha > 0.8f) - { - logo.MoveTo(position, 500, Easing.OutQuint); - } - else - { - logo.Hide(); - logo.ScaleTo(0.2f); - logo.MoveTo(position); - } - - logo.FadeIn(logo_transition, Easing.OutQuint); - logo.ScaleTo(0.4f, logo_transition, Easing.OutQuint); - - logo.Action = () => - { - if (this.IsCurrentScreen()) - FinaliseSelection(); - return false; - }; - } - - protected override void LogoExiting(OsuLogo logo) - { - base.LogoExiting(logo); - logo.ScaleTo(0.2f, logo_transition / 2, Easing.Out); - logo.FadeOut(logo_transition / 2, Easing.Out); - } - - public override void OnResuming(ScreenTransitionEvent e) - { - base.OnResuming(e); - - // required due to https://github.com/ppy/osu-framework/issues/3218 - ModSelect.SelectedMods.Disabled = false; - ModSelect.SelectedMods.BindTo(selectedMods); - - Carousel.AllowSelection = true; - - BeatmapDetails.Refresh(); - - beginLooping(); - - if (!Beatmap.Value.BeatmapSetInfo.DeletePending) - { - updateCarouselSelection(); - - updateComponentFromBeatmap(Beatmap.Value); - - if (ControlGlobalMusic) - { - // restart playback on returning to song select, regardless. - // not sure this should be a permanent thing (we may want to leave a user pause paused even on returning) - music.ResetTrackAdjustments(); - music.Play(requestedByUser: true); - } - } - - LeftArea.MoveToX(0, 400, Easing.OutQuint); - LeftArea.FadeIn(100, Easing.OutQuint); - - FilterControl.MoveToY(0, 400, Easing.OutQuint); - FilterControl.FadeIn(100, Easing.OutQuint); - - this.FadeIn(250, Easing.OutQuint); - - wedgeBackground.ScaleTo(1, 500, Easing.OutQuint); - - FilterControl.Activate(); - } - - protected override void Update() - { - base.Update(); - - if (Carousel.AllowSelection && pendingFilterApplication) - { - Carousel.Filter(FilterControl.CreateCriteria()); - pendingFilterApplication = false; - } - } - - public override void OnSuspending(ScreenTransitionEvent e) - { - // Handle the case where FinaliseSelection is never called (ie. when a screen is pushed externally). - // Without this, it's possible for a transfer to happen while we are not the current screen. - transferRulesetValue(); - - ModSelect.SelectedMods.UnbindFrom(selectedMods); - - playExitingTransition(); - base.OnSuspending(e); - } - - public override bool OnExiting(ScreenExitEvent e) - { - if (base.OnExiting(e)) - return true; - - playExitingTransition(); - return false; - } - - private void playExitingTransition() - { - ModSelect.Hide(); - - BeatmapOptions.Hide(); - - Carousel.AllowSelection = false; - - endLooping(); - - FilterControl.MoveToY(-120, 500, Easing.OutQuint); - FilterControl.FadeOut(200, Easing.OutQuint); - - LeftArea.MoveToX(-150, 1800, Easing.OutQuint); - LeftArea.FadeOut(200, Easing.OutQuint); - - wedgeBackground.ScaleTo(2.4f, 400, Easing.OutQuint); - - this.FadeOut(400, Easing.OutQuint); - - FilterControl.Deactivate(); - } - - private bool isHandlingLooping; - - private void beginLooping() - { - if (!ControlGlobalMusic) - return; - - Debug.Assert(!isHandlingLooping); - - isHandlingLooping = true; - - ensureTrackLooping(Beatmap.Value, TrackChangeDirection.None); - - music.TrackChanged += ensureTrackLooping; - } - - private void endLooping() - { - // may be called multiple times during screen exit process. - if (!isHandlingLooping) - return; - - music.CurrentTrack.Looping = isHandlingLooping = false; - - music.TrackChanged -= ensureTrackLooping; - } - - private void ensureTrackLooping(IWorkingBeatmap beatmap, TrackChangeDirection changeDirection) - => beatmap.PrepareTrackForPreview(true); - - public override bool OnBackButton() - { - if (ModSelect.State.Value == Visibility.Visible) - { - ModSelect.Hide(); - return true; - } - - return false; - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - decoupledRuleset.UnbindAll(); - - if (music.IsNotNull()) - music.TrackChanged -= ensureTrackLooping; - - modSelectOverlayRegistration?.Dispose(); - } - - /// - /// Allow components in SongSelect to update their loaded beatmap details. - /// This is a debounced call (unlike directly binding to WorkingBeatmap.ValueChanged). - /// - /// The working beatmap. - private void updateComponentFromBeatmap(WorkingBeatmap beatmap) - { - // If not the current screen, this will be applied in OnResuming. - if (this.IsCurrentScreen()) - { - ApplyToBackground(backgroundModeBeatmap => - { - backgroundModeBeatmap.Beatmap = beatmap; - backgroundModeBeatmap.IgnoreUserSettings.Value = true; - backgroundModeBeatmap.FadeColour(Color4.White, 250); - - applyBlurToBackground(backgroundModeBeatmap); - }); - } - - beatmapInfoWedge.Beatmap = beatmap; - - BeatmapDetails.Beatmap = beatmap; - - ModSelect.Beatmap.Value = beatmap; - - advancedStats.BeatmapInfo = beatmap.BeatmapInfo; - advancedStats.Mods.Value = selectedMods.Value; - advancedStats.Ruleset.Value = Ruleset.Value; - - bool beatmapSelected = beatmap is not DummyWorkingBeatmap; - - if (beatmapSelected) - beatmapOptionsButton.Enabled.Value = true; - else - { - beatmapOptionsButton.Enabled.Value = false; - BeatmapOptions.Hide(); - } - } - - private void applyBlurToBackground(BackgroundScreenBeatmap backgroundModeBeatmap) - { - backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value ? BACKGROUND_BLUR : 0f; - backgroundModeBeatmap.DimWhenUserSettingsIgnored.Value = configBackgroundBlur.Value ? 0 : 0.4f; - - wedgeBackground.FadeTo(configBackgroundBlur.Value ? 0.5f : 0.2f, UserDimContainer.BACKGROUND_FADE_DURATION, Easing.OutQuint); - } - - private readonly WeakReference lastTrack = new WeakReference(null); - - /// - /// Ensures some music is playing for the current track. - /// Will resume playback from a manual user pause if the track has changed. - /// - private void ensurePlayingSelected() - { - if (!ControlGlobalMusic) - return; - - ITrack track = music.CurrentTrack; - - bool isNewTrack = !lastTrack.TryGetTarget(out var last) || last != track; - - if (!track.IsRunning && (music.UserPauseRequested != true || isNewTrack)) - { - Logger.Log($"Song select decided to {nameof(ensurePlayingSelected)}"); - music.Play(true); - } - - lastTrack.SetTarget(track); - } - - private void carouselBeatmapsLoaded() - { - bindBindables(); - Scheduler.AddOnce(updateVisibleBeatmapCount); - - Carousel.AllowSelection = true; - - // If a selection was already obtained, do not attempt to update the selected beatmap. - if (Carousel.SelectedBeatmapSet != null) - return; - - // Attempt to select the current beatmap on the carousel, if it is valid to be selected. - if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false) - { - if (Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false)) - return; - - // prefer not changing ruleset at this point, so look for another difficulty in the currently playing beatmap - var found = Beatmap.Value.BeatmapSetInfo.Beatmaps.FirstOrDefault(b => b.Ruleset.Equals(decoupledRuleset.Value)); - - if (found != null && Carousel.SelectBeatmap(found, false)) - return; - } - - // If the current active beatmap could not be selected, select a new random beatmap. - if (!Carousel.SelectNextRandom()) - { - // in the case random selection failed, we want to trigger selectionChanged - // to show the dummy beatmap (we have nothing else to display). - performUpdateSelected(); - } - } - - private void updateVisibleBeatmapCount() - { - // Intentionally not localised until we have proper support for this (see https://github.com/ppy/osu-framework/pull/4918 - // but also in this case we want support for formatting a number within a string). - int carouselCountDisplayed = Carousel.CountDisplayed; - FilterControl.InformationalText = carouselCountDisplayed != 1 ? $"{carouselCountDisplayed:#,0} matches" : $"{carouselCountDisplayed:#,0} match"; - } - - private bool boundLocalBindables; - - private void bindBindables() - { - if (boundLocalBindables) - return; - - // manual binding to parent ruleset to allow for delayed load in the incoming direction. - transferRulesetValue(); - - Ruleset.ValueChanged += r => updateSelectedRuleset(r.NewValue); - - decoupledRuleset.ValueChanged += r => - { - bool wasDisabled = Ruleset.Disabled; - - // a sub-screen may have taken a lease on this decoupled ruleset bindable, - // which would indirectly propagate to the game-global bindable via the `DisabledChanged` callback below. - // to make sure changes sync without crashes, lift the disable for a short while to sync, and then restore the old value. - Ruleset.Disabled = false; - Ruleset.Value = r.NewValue; - Ruleset.Disabled = wasDisabled; - }; - decoupledRuleset.DisabledChanged += r => Ruleset.Disabled = r; - - Beatmap.BindValueChanged(updateCarouselSelection); - - selectedMods.BindValueChanged(_ => - { - if (decoupledRuleset.Value.Equals(rulesetNoDebounce)) - advancedStats.Mods.Value = selectedMods.Value; - }, true); - - boundLocalBindables = true; - } - - /// - /// Transfer the game-wide ruleset to the local decoupled ruleset. - /// Will immediately run filter operations if required. - /// - /// Whether a transfer occurred. - private bool transferRulesetValue() - { - if (decoupledRuleset.Value?.Equals(Ruleset.Value) == true) - return false; - - Logger.Log($"decoupled ruleset transferred (\"{decoupledRuleset.Value}\" -> \"{Ruleset.Value}\")"); - rulesetNoDebounce = decoupledRuleset.Value = Ruleset.Value; - - // if we have a pending filter operation, we want to run it now. - // it could change selection (ie. if the ruleset has been changed). - if (IsLoaded) - Carousel.FlushPendingFilterOperations(); - - return true; - } - - /// - /// Request to delete a specific beatmap. - /// - public void DeleteBeatmap(BeatmapSetInfo? beatmap) - { - if (beatmap == null) return; - - dialogOverlay?.Push(new BeatmapDeleteDialog(beatmap)); - } - - /// - /// Request to clear the scores of a specific beatmap. - /// - public void ClearScores(BeatmapInfo? beatmapInfo) - { - if (beatmapInfo == null) return; - - dialogOverlay?.Push(new BeatmapClearScoresDialog(beatmapInfo, () => - // schedule done here rather than inside the dialog as the dialog may fade out and never callback. - Schedule(() => BeatmapDetails.Refresh()))); - } - - public virtual bool OnPressed(KeyBindingPressEvent e) - { - if (!this.IsCurrentScreen()) return false; - - switch (e.Action) - { - case GlobalAction.IncreaseModSpeed: - return modSpeedHotkeyHandler.ChangeSpeed(0.05, ModUtils.FlattenMods(game.AvailableMods.Value.SelectMany(kv => kv.Value))); - - case GlobalAction.DecreaseModSpeed: - return modSpeedHotkeyHandler.ChangeSpeed(-0.05, ModUtils.FlattenMods(game.AvailableMods.Value.SelectMany(kv => kv.Value))); - } - - if (e.Repeat) - return false; - - switch (e.Action) - { - case GlobalAction.Select: - FinaliseSelection(); - return true; - } - - return false; - } - - public void OnReleased(KeyBindingReleaseEvent e) - { - } - - protected override bool OnKeyDown(KeyDownEvent e) - { - if (e.Repeat) return false; - - switch (e.Key) - { - case Key.Delete: - if (e.ShiftPressed) - { - if (!Beatmap.IsDefault) - DeleteBeatmap(Beatmap.Value.BeatmapSetInfo); - return true; - } - - break; - } - - return base.OnKeyDown(e); - } - - private partial class VerticalMaskingContainer : Container - { - private const float panel_overflow = 1.2f; - - protected override Container Content { get; } - - public VerticalMaskingContainer() - { - RelativeSizeAxes = Axes.Both; - Masking = true; - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - Width = panel_overflow; // avoid horizontal masking so the panels don't clip when screen stack is pushed. - InternalChild = Content = new OsuContextMenuContainer - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Width = 1 / panel_overflow, - }; - } - } - - /// - /// Handles mouse interactions required when moving away from the carousel. - /// - internal partial class LeftSideInteractionContainer : Container - { - private readonly Action? resetCarouselPosition; - - private bool mouseContained; - - private InputManager inputManager = null!; - - public LeftSideInteractionContainer(Action resetCarouselPosition) - { - this.resetCarouselPosition = resetCarouselPosition; - } - - // we want to block plain scrolls on the left side so that they don't scroll the carousel, - // but also we *don't* want to handle scrolls when they're combined with keyboard modifiers - // as those will usually correspond to other interactions like adjusting volume. - protected override bool OnScroll(ScrollEvent e) => !e.ControlPressed && !e.AltPressed && !e.ShiftPressed && !e.SuperPressed; - - protected override bool OnMouseDown(MouseDownEvent e) => true; - - protected override void LoadComplete() - { - inputManager = GetContainingInputManager()!; - base.LoadComplete(); - } - - protected override void Update() - { - base.Update(); - - // We want to trigger an action whenever the cursor is in the left area of song select. - // Other elements in song select handle input, so rather than using `OnHover` let's check the true mouse position. - if (Contains(inputManager.CurrentState.Mouse.Position)) - { - if (!mouseContained) - { - mouseContained = true; - resetCarouselPosition?.Invoke(); - } - } - else - { - mouseContained = false; - } - } - } - } -} diff --git a/osu.Game/Screens/Select/WedgeBackground.cs b/osu.Game/Screens/Select/WedgeBackground.cs deleted file mode 100644 index 2e2b43cd70..0000000000 --- a/osu.Game/Screens/Select/WedgeBackground.cs +++ /dev/null @@ -1,39 +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.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Select -{ - public partial class WedgeBackground : Container - { - public WedgeBackground() - { - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Size = new Vector2(1, 0.5f), - Colour = Color4.Black, - Shear = new Vector2(0.15f, 0), - EdgeSmoothness = new Vector2(2, 0), - }, - new Box - { - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Y, - Size = new Vector2(1, -0.5f), - Position = new Vector2(0, 1), - Colour = Color4.Black, - Shear = new Vector2(-0.15f, 0), - EdgeSmoothness = new Vector2(2, 0), - }, - }; - } - } -} diff --git a/osu.Game/Screens/SelectV2/LeftSideInteractionContainer.cs b/osu.Game/Screens/SelectV2/LeftSideInteractionContainer.cs new file mode 100644 index 0000000000..212bb233f4 --- /dev/null +++ b/osu.Game/Screens/SelectV2/LeftSideInteractionContainer.cs @@ -0,0 +1,60 @@ +// 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 osu.Framework.Graphics.Containers; +using osu.Framework.Input; +using osu.Framework.Input.Events; + +namespace osu.Game.Screens.SelectV2 +{ + /// + /// Handles mouse interactions required when moving away from the carousel. + /// + internal partial class LeftSideInteractionContainer : Container + { + private readonly Action? resetCarouselPosition; + + private bool mouseContained; + + private InputManager inputManager = null!; + + public LeftSideInteractionContainer(Action resetCarouselPosition) + { + this.resetCarouselPosition = resetCarouselPosition; + } + + // we want to block plain scrolls on the left side so that they don't scroll the carousel, + // but also we *don't* want to handle scrolls when they're combined with keyboard modifiers + // as those will usually correspond to other interactions like adjusting volume. + protected override bool OnScroll(ScrollEvent e) => !e.ControlPressed && !e.AltPressed && !e.ShiftPressed && !e.SuperPressed; + + protected override bool OnMouseDown(MouseDownEvent e) => true; + + protected override void LoadComplete() + { + inputManager = GetContainingInputManager()!; + base.LoadComplete(); + } + + protected override void Update() + { + base.Update(); + + // We want to trigger an action whenever the cursor is in the left area of song select. + // Other elements in song select handle input, so rather than using `OnHover` let's check the true mouse position. + if (Contains(inputManager.CurrentState.Mouse.Position)) + { + if (!mouseContained) + { + mouseContained = true; + resetCarouselPosition?.Invoke(); + } + } + else + { + mouseContained = false; + } + } + } +} diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index b12d6d1018..d47155ee6b 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -61,7 +61,7 @@ namespace osu.Game.Screens.SelectV2 { /// /// This screen is intended to house all components introduced in the new song select design to add transitions and examine the overall look. - /// This will be gradually built upon and ultimately replace once everything is in place. + /// This will be gradually built upon and ultimately replace once everything is in place. /// public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler, ISongSelect, IHandlePresentBeatmap, IProvideCursor { @@ -228,7 +228,7 @@ namespace osu.Game.Screens.SelectV2 // Pad enough to only reset scroll when well into the left wedge areas. Padding = new MarginPadding { Right = 40 }, RelativeSizeAxes = Axes.Both, - Child = new Select.SongSelect.LeftSideInteractionContainer(() => carousel.ScrollToSelection()) + Child = new LeftSideInteractionContainer(() => carousel.ScrollToSelection()) { RelativeSizeAxes = Axes.Both, }, From 7e7421e1ea741427378715cea7a155ec5104b261 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 19:29:45 +0900 Subject: [PATCH 11/15] Update `TestSceneDeleteLocalScore` to use newer leaderboard --- .../TestSceneDeleteLocalScore.cs | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index c2277f2c7c..5eec60e9ec 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -26,7 +26,7 @@ using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osuTK; using osuTK.Input; @@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual.UserInterface public partial class TestSceneDeleteLocalScore : OsuManualInputManagerTestScene { private readonly ContextMenuContainer contextMenuContainer; - private readonly BeatmapLeaderboard leaderboard; + private readonly BeatmapLeaderboardWedge leaderboard; private RulesetStore rulesets = null!; private BeatmapManager beatmapManager; @@ -46,9 +46,16 @@ namespace osu.Game.Tests.Visual.UserInterface private BeatmapInfo beatmapInfo; + private LeaderboardManager leaderboardManager { get; set; } + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + [Cached(typeof(IDialogOverlay))] private readonly DialogOverlay dialogOverlay; + private IEnumerable scores => leaderboardManager.Scores.Value?.AllScores ?? Enumerable.Empty(); + public TestSceneDeleteLocalScore() { Children = new Drawable[] @@ -56,13 +63,11 @@ namespace osu.Game.Tests.Visual.UserInterface contextMenuContainer = new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, - Child = leaderboard = new BeatmapLeaderboard + Child = leaderboard = new BeatmapLeaderboardWedge { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Size = new Vector2(550f, 450f), - Scope = BeatmapLeaderboardScope.Local, - BeatmapInfo = TestResources.CreateTestBeatmapSetInfo().Beatmaps.First() + Size = new Vector2(0.6f), } }, dialogOverlay = new DialogOverlay() @@ -76,8 +81,11 @@ namespace osu.Game.Tests.Visual.UserInterface dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default)); dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get(), () => beatmapManager, LocalStorage, Realm, API)); + dependencies.Cache(leaderboardManager = new LeaderboardManager()); Dependencies.Cache(Realm); + Add(leaderboardManager); + return dependencies; } @@ -125,13 +133,13 @@ namespace osu.Game.Tests.Visual.UserInterface }); AddStep("set up leaderboard", () => { - leaderboard.BeatmapInfo = beatmapInfo; - leaderboard.RefetchScores(); // Required in the case that the beatmap hasn't changed + Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapInfo); + leaderboard.Show(); }); // Ensure the leaderboard items have finished showing up AddStep("finish transforms", () => leaderboard.FinishTransforms(true)); - AddUntilStep("wait for drawables", () => leaderboard.ChildrenOfType().Any()); + AddUntilStep("wait for drawables", () => leaderboard.ChildrenOfType().Any()); } [Test] @@ -140,7 +148,7 @@ namespace osu.Game.Tests.Visual.UserInterface ScoreInfo scoreBeingDeleted = null; AddStep("open menu for top score", () => { - var leaderboardScore = leaderboard.ChildrenOfType().First(); + var leaderboardScore = leaderboard.ChildrenOfType().First(); scoreBeingDeleted = leaderboardScore.Score; @@ -167,8 +175,8 @@ namespace osu.Game.Tests.Visual.UserInterface InputManager.PressButton(MouseButton.Left); }); - AddUntilStep("wait for fetch", () => leaderboard.Scores.Any()); - AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != scoreBeingDeleted.OnlineID)); + AddUntilStep("wait for fetch", () => scores.Any()); + AddUntilStep("score removed from leaderboard", () => scores.All(s => s.OnlineID != scoreBeingDeleted.OnlineID)); // "Clean up" AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left)); @@ -178,8 +186,8 @@ namespace osu.Game.Tests.Visual.UserInterface public void TestDeleteViaDatabase() { AddStep("delete top score", () => scoreManager.Delete(importedScores[0])); - AddUntilStep("wait for fetch", () => leaderboard.Scores.Any()); - AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != importedScores[0].OnlineID)); + AddUntilStep("wait for fetch", () => scores.Any()); + AddUntilStep("score removed from leaderboard", () => scores.All(s => s.OnlineID != importedScores[0].OnlineID)); } protected override void Dispose(bool isDisposing) From b4f40639a1ab5e2eb1120f7c6f43448f0977ee27 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 19:37:19 +0900 Subject: [PATCH 12/15] Add special not regarding collection dropdown --- .../TestSceneCollectionDropdown.cs | 7 +- osu.Game/Collections/CollectionDropdown.cs | 1 + osu.Game/Screens/Select/CollectionDropdown.cs | 257 ++++++++++++++++++ 3 files changed, 263 insertions(+), 2 deletions(-) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneCollectionDropdown.cs (97%) create mode 100644 osu.Game/Screens/Select/CollectionDropdown.cs diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneCollectionDropdown.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs similarity index 97% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneCollectionDropdown.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs index 8cee78e0b8..e1c39ce4f2 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneCollectionDropdown.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs @@ -24,10 +24,13 @@ using osu.Game.Rulesets; using osu.Game.Tests.Resources; using osuTK.Input; using Realms; -using CollectionDropdown = osu.Game.Screens.SelectV2.CollectionDropdown; +using CollectionDropdown = osu.Game.Screens.Select.CollectionDropdown; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { + /// + /// WARNING: TODO: we have TWO `CollectionDropdowns` with diverging functionality. This is not good. + /// public partial class TestSceneCollectionDropdown : OsuManualInputManagerTestScene { private RulesetStore rulesets = null!; diff --git a/osu.Game/Collections/CollectionDropdown.cs b/osu.Game/Collections/CollectionDropdown.cs index 2f9e94fef7..e9fec32e12 100644 --- a/osu.Game/Collections/CollectionDropdown.cs +++ b/osu.Game/Collections/CollectionDropdown.cs @@ -24,6 +24,7 @@ namespace osu.Game.Collections { /// /// A dropdown to select the collection to be used to filter results. + /// WARNING: TODO: we have TWO `CollectionDropdowns` with diverging functionality. This is not good. /// public partial class CollectionDropdown : OsuDropdown { diff --git a/osu.Game/Screens/Select/CollectionDropdown.cs b/osu.Game/Screens/Select/CollectionDropdown.cs new file mode 100644 index 0000000000..ee22637541 --- /dev/null +++ b/osu.Game/Screens/Select/CollectionDropdown.cs @@ -0,0 +1,257 @@ +// 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.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Game.Beatmaps; +using osu.Game.Collections; +using osu.Game.Database; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Localisation; +using osuTK; +using Realms; + +namespace osu.Game.Screens.Select +{ + /// + /// A dropdown to select the collection to be used to filter results. + /// WARNING: TODO: we have TWO `CollectionDropdowns` with diverging functionality. This is not good. + /// + public partial class CollectionDropdown : ShearedDropdown // TODO: partial class under FilterControl? + { + /// + /// Whether to show the "manage collections..." menu item in the dropdown. + /// + protected virtual bool ShowManageCollectionsItem => true; + + private readonly BindableList filters = new BindableList(); + + [Resolved] + private ManageCollectionsDialog? manageCollectionsDialog { get; set; } + + [Resolved] + private RealmAccess realm { get; set; } = null!; + + private IDisposable? realmSubscription; + + private readonly CollectionFilterMenuItem allBeatmapsItem = new AllBeatmapsCollectionFilterMenuItem(); + + public CollectionDropdown() + : base(CollectionsStrings.Collection) + { + ItemSource = filters; + + Current.Value = allBeatmapsItem; + AlwaysShowSearchBar = true; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + realmSubscription = realm.RegisterForNotifications(r => r.All().OrderBy(c => c.Name), collectionsChanged); + + Current.BindValueChanged(selectionChanged); + } + + private void collectionsChanged(IRealmCollection collections, ChangeSet? changes) + { + if (changes == null) + { + filters.Clear(); + filters.Add(allBeatmapsItem); + filters.AddRange(collections.Select(c => new CollectionFilterMenuItem(c.ToLive(realm)))); + if (ShowManageCollectionsItem) + filters.Add(new ManageCollectionsFilterMenuItem()); + } + else + { + foreach (int i in changes.DeletedIndices.OrderDescending()) + filters.RemoveAt(i + 1); + + foreach (int i in changes.InsertedIndices) + filters.Insert(i + 1, new CollectionFilterMenuItem(collections[i].ToLive(realm))); + + var selectedItem = SelectedItem?.Value; + + foreach (int i in changes.NewModifiedIndices) + { + var updatedItem = collections[i]; + + // This is responsible for updating the state of the +/- button and the collection's name. + // TODO: we can probably make the menu items update with changes to avoid this. + filters.RemoveAt(i + 1); + filters.Insert(i + 1, new CollectionFilterMenuItem(updatedItem.ToLive(realm))); + + if (updatedItem.ID == selectedItem?.Collection?.ID) + { + // This current update and schedule is required to work around dropdown headers not updating text even when the selected item + // changes. It's not great but honestly the whole dropdown menu structure isn't great. This needs to be fixed, but I'll issue + // a warning that it's going to be a frustrating journey. + Current.Value = allBeatmapsItem; + Schedule(() => + { + // current may have changed before the scheduled call is run. + if (Current.Value != allBeatmapsItem) + return; + + Current.Value = filters.SingleOrDefault(f => f.Collection?.ID == selectedItem.Collection?.ID) ?? filters[0]; + }); + + break; + } + } + } + } + + private void selectionChanged(ValueChangedEvent filter) + { + // May be null during .Clear(). + if (filter.NewValue.IsNull()) + return; + + // Never select the manage collection filter - rollback to the previous filter. + // This is done after the above since it is important that bindable is unbound from OldValue, which is lost after forcing it back to the old value. + if (filter.NewValue is ManageCollectionsFilterMenuItem) + { + Current.Value = filter.OldValue; + manageCollectionsDialog?.Show(); + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + realmSubscription?.Dispose(); + } + + protected override LocalisableString GenerateItemText(CollectionFilterMenuItem item) => item.CollectionName; + + protected sealed override DropdownMenu CreateMenu() => CreateCollectionMenu(); + + protected virtual ShearedCollectionDropdownMenu CreateCollectionMenu() => new ShearedCollectionDropdownMenu(); + + protected partial class ShearedCollectionDropdownMenu : ShearedDropdownMenu + { + public ShearedCollectionDropdownMenu() + { + MaxHeight = 200; + } + + protected override DrawableDropdownMenuItem CreateDrawableDropdownMenuItem(MenuItem item) => new DrawableCollectionMenuItem(item) + { + BackgroundColourHover = HoverColour, + BackgroundColourSelected = SelectionColour + }; + } + + protected partial class DrawableCollectionMenuItem : ShearedDropdownMenu.ShearedMenuItem + { + private IconButton addOrRemoveButton = null!; + + private bool beatmapInCollection; + + private readonly Live? collection; + + [Resolved] + private IBindable beatmap { get; set; } = null!; + + public DrawableCollectionMenuItem(MenuItem item) + : base(item) + { + collection = ((DropdownMenuItem)item).Value.Collection; + } + + [BackgroundDependencyLoader] + private void load() + { + AddInternal(addOrRemoveButton = new NoFocusChangeIconButton + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Shear = -OsuGame.SHEAR, + X = -OsuScrollContainer.SCROLL_BAR_WIDTH, + Scale = new Vector2(0.65f), + Action = addOrRemove, + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + if (collection != null) + { + beatmap.BindValueChanged(_ => + { + beatmapInCollection = collection.PerformRead(c => c.BeatmapMD5Hashes.Contains(beatmap.Value.BeatmapInfo.MD5Hash)); + + addOrRemoveButton.Enabled.Value = !beatmap.IsDefault; + addOrRemoveButton.Icon = beatmapInCollection ? FontAwesome.Solid.MinusSquare : FontAwesome.Solid.PlusSquare; + addOrRemoveButton.TooltipText = beatmapInCollection ? CollectionsStrings.RemoveSelectedBeatmap : CollectionsStrings.AddSelectedBeatmap; + + updateButtonVisibility(); + }, true); + } + + updateButtonVisibility(); + } + + protected override bool OnHover(HoverEvent e) + { + updateButtonVisibility(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateButtonVisibility(); + base.OnHoverLost(e); + } + + protected override void OnSelectChange() + { + base.OnSelectChange(); + updateButtonVisibility(); + } + + private void updateButtonVisibility() + { + if (collection == null) + addOrRemoveButton.Alpha = 0; + else + addOrRemoveButton.Alpha = IsHovered || IsPreSelected || beatmapInCollection ? 1 : 0; + } + + private void addOrRemove() + { + Debug.Assert(collection != null); + + Task.Run(() => collection.PerformWrite(c => + { + if (!c.BeatmapMD5Hashes.Remove(beatmap.Value.BeatmapInfo.MD5Hash)) + c.BeatmapMD5Hashes.Add(beatmap.Value.BeatmapInfo.MD5Hash); + })); + } + + protected override Drawable CreateContent() => (Content)base.CreateContent(); + + private partial class NoFocusChangeIconButton : IconButton + { + public override bool ChangeFocusOnClick => false; + } + } + } +} From c28c64940aeb21bff5429c8f32f664b8e5931394 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Feb 2026 19:39:45 +0900 Subject: [PATCH 13/15] Move v2 files to final location This contains only renames and namespace updates. --- .../NonVisual/Filtering/FilterMatchingTest.cs | 1 - .../Background/TestSceneUserDimBackgrounds.cs | 2 +- .../DailyChallenge/TestSceneDailyChallenge.cs | 2 +- .../Visual/Editing/TestSceneEditorSaving.cs | 2 +- .../Editing/TestSceneOpenEditorTimestamp.cs | 2 +- .../Visual/Multiplayer/QueueModeTestScene.cs | 4 +- .../Multiplayer/TestSceneHostOnlyQueueMode.cs | 4 +- .../TestSceneBeatmapEditorNavigation.cs | 2 +- .../TestSceneButtonSystemNavigation.cs | 2 +- .../TestSceneChangeAndUseGameplayBindings.cs | 2 +- .../TestSceneMouseWheelVolumeAdjust.cs | 2 +- .../Navigation/TestScenePerformFromScreen.cs | 2 +- .../Navigation/TestScenePresentBeatmap.cs | 2 +- .../Navigation/TestScenePresentScore.cs | 4 +- .../Navigation/TestSceneScreenNavigation.cs | 29 +- .../TestSceneSkinEditorNavigation.cs | 2 +- .../TestSceneSongSelectNavigation.cs | 8 +- .../BeatmapCarouselFilterGroupingTest.cs | 3 +- .../BeatmapCarouselFilterSortingTest.cs | 3 +- .../BeatmapCarouselTestScene.cs | 4 +- .../SongSelectComponentsTestScene.cs | 2 +- .../SongSelectTestScene.cs | 6 +- .../TestSceneBeatmapCarousel.cs | 4 +- .../TestSceneBeatmapCarouselArtistGrouping.cs | 4 +- ...tSceneBeatmapCarouselCollectionGrouping.cs | 2 +- ...tSceneBeatmapCarouselDifficultyGrouping.cs | 4 +- .../TestSceneBeatmapCarouselFiltering.cs | 4 +- .../TestSceneBeatmapCarouselNoGrouping.cs | 4 +- .../TestSceneBeatmapCarouselRandom.cs | 4 +- .../TestSceneBeatmapCarouselScrolling.cs | 4 +- .../TestSceneBeatmapCarouselSetsSplitApart.cs | 4 +- .../TestSceneBeatmapCarouselUpdateHandling.cs | 4 +- .../TestSceneBeatmapFilterControl.cs | 4 +- .../TestSceneBeatmapLeaderboardScore.cs | 4 +- .../TestSceneBeatmapLeaderboardSorting.cs | 6 +- .../TestSceneBeatmapLeaderboardWedge.cs | 4 +- .../TestSceneBeatmapMetadataWedge.cs | 24 +- .../TestSceneBeatmapRecommendations.cs | 2 +- .../TestSceneBeatmapTitleWedge.cs | 47 +++- .../TestSceneBeatmapTitleWedgeStatistic.cs | 4 +- .../TestSceneDifficultyRangeSlider.cs | 4 +- .../TestSceneDifficultyStatisticsDisplay.cs | 4 +- .../TestSceneFooterButtonMods.cs | 4 +- .../TestScenePanelBeatmap.cs | 4 +- .../TestScenePanelBeatmapStandalone.cs | 4 +- .../TestScenePanelGroup.cs | 6 +- .../TestScenePanelSet.cs | 4 +- .../TestScenePanelUpdateBeatmapButton.cs | 4 +- .../TestSceneSongSelect.cs | 13 +- ...neSongSelectCurrentSelectionInvalidated.cs | 6 +- .../TestSceneSongSelectFiltering.cs | 8 +- .../TestSceneSongSelectGrouping.cs | 4 +- .../UserInterface/TestSceneScreenFooter.cs | 2 +- osu.Game/Beatmaps/BeatmapMetadata.cs | 2 +- .../Online/Leaderboards/LeaderboardScore.cs | 2 +- osu.Game/OsuGame.cs | 2 +- .../Overlays/FirstRunSetup/ScreenUIScale.cs | 2 +- .../Overlays/SkinEditor/SkinEditorOverlay.cs | 2 +- .../SkinEditor/SkinEditorSceneLibrary.cs | 2 +- .../Submission/BeatmapSubmissionScreen.cs | 2 +- osu.Game/Screens/Menu/MainMenu.cs | 2 +- .../DailyChallengeLeaderboard.cs | 2 +- .../OnlinePlay/FooterButtonFreeMods.cs | 2 +- .../Multiplayer/MultiplayerMatchSongSelect.cs | 2 +- .../OnlinePlay/OnlinePlayFreestyleSelect.cs | 1 - .../Playlists/PlaylistsSongSelect.cs | 2 +- .../{SelectV2 => Select}/BeatmapCarousel.cs | 5 +- .../BeatmapCarouselFilterGrouping.cs | 3 +- .../BeatmapCarouselFilterMatching.cs | 3 +- .../BeatmapCarouselFilterSorting.cs | 3 +- .../BeatmapDetailsArea.Header.cs | 3 +- .../BeatmapDetailsArea.WedgeSelector.cs | 2 +- .../BeatmapDetailsArea.cs | 2 +- .../BeatmapLeaderboardScore.Tooltip.cs | 2 +- .../BeatmapLeaderboardScore.cs | 3 +- .../BeatmapLeaderboardWedge.cs | 2 +- .../BeatmapMetadataWedge.FailRetryDisplay.cs | 2 +- .../BeatmapMetadataWedge.MetadataDisplay.cs | 2 +- ...eatmapMetadataWedge.RatingSpreadDisplay.cs | 2 +- ...BeatmapMetadataWedge.SuccessRateDisplay.cs | 2 +- .../BeatmapMetadataWedge.TagsLine.cs | 2 +- .../BeatmapMetadataWedge.UserRatingDisplay.cs | 2 +- .../BeatmapMetadataWedge.cs | 2 +- .../BeatmapTitleWedge.DifficultyDisplay.cs | 2 +- ...pTitleWedge.DifficultyStatisticsDisplay.cs | 2 +- .../BeatmapTitleWedge.FavouriteButton.cs | 2 +- .../BeatmapTitleWedge.Statistic.cs | 2 +- .../BeatmapTitleWedge.StatisticDifficulty.cs | 2 +- .../BeatmapTitleWedge.StatisticPlayCount.cs | 2 +- .../{SelectV2 => Select}/BeatmapTitleWedge.cs | 2 +- .../FilterControl.DifficultyRangeSlider.cs | 2 +- .../FilterControl.ScopedBeatmapSetDisplay.cs | 2 +- .../{SelectV2 => Select}/FilterControl.cs | 3 +- .../{SelectV2 => Select}/FooterButtonMods.cs | 2 +- .../FooterButtonOptions.Popover.cs | 2 +- .../FooterButtonOptions.cs | 2 +- .../FooterButtonRandom.cs | 2 +- .../{SelectV2 => Select}/ISongSelect.cs | 2 +- .../LeftSideInteractionContainer.cs | 2 +- .../NoResultsPlaceholder.cs | 3 +- .../Screens/{SelectV2 => Select}/Panel.cs | 2 +- .../{SelectV2 => Select}/PanelBeatmap.cs | 2 +- .../PanelBeatmapSet.SpreadDisplay.cs | 2 +- .../{SelectV2 => Select}/PanelBeatmapSet.cs | 2 +- .../PanelBeatmapStandalone.SpreadDisplay.cs | 2 +- .../PanelBeatmapStandalone.cs | 2 +- .../{SelectV2 => Select}/PanelGroup.cs | 2 +- .../PanelGroupRankDisplay.cs | 2 +- .../PanelGroupRankedStatus.cs | 2 +- .../PanelGroupStarDifficulty.cs | 2 +- .../PanelLocalRankDisplay.cs | 2 +- .../PanelSetBackground.cs | 2 +- .../PanelUpdateBeatmapButton.cs | 3 +- .../RealmPopulatingOnlineLookupSource.cs | 2 +- .../{SelectV2 => Select}/SoloSongSelect.cs | 3 +- .../{SelectV2 => Select}/SongSelect.cs | 3 +- .../UpdateLocalConfirmationDialog.cs | 4 +- .../{SelectV2 => Select}/WedgeBackground.cs | 2 +- .../Screens/SelectV2/CollectionDropdown.cs | 256 ------------------ .../Tests/Visual/EditorSavingTestScene.cs | 2 +- 120 files changed, 220 insertions(+), 472 deletions(-) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/BeatmapCarouselFilterGroupingTest.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/BeatmapCarouselFilterSortingTest.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/BeatmapCarouselTestScene.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/SongSelectComponentsTestScene.cs (97%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/SongSelectTestScene.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarousel.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselArtistGrouping.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselCollectionGrouping.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselDifficultyGrouping.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselFiltering.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselNoGrouping.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselRandom.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselScrolling.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselSetsSplitApart.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapCarouselUpdateHandling.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapFilterControl.cs (93%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapLeaderboardScore.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapLeaderboardSorting.cs (95%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapLeaderboardWedge.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapMetadataWedge.cs (90%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapTitleWedge.cs (88%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneBeatmapTitleWedgeStatistic.cs (97%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneDifficultyRangeSlider.cs (96%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneDifficultyStatisticsDisplay.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneFooterButtonMods.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestScenePanelBeatmap.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestScenePanelBeatmapStandalone.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestScenePanelGroup.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestScenePanelSet.cs (97%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestScenePanelUpdateBeatmapButton.cs (95%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneSongSelect.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneSongSelectCurrentSelectionInvalidated.cs (98%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneSongSelectFiltering.cs (99%) rename osu.Game.Tests/Visual/{SongSelectV2 => SongSelect}/TestSceneSongSelectGrouping.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapCarousel.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapCarouselFilterGrouping.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapCarouselFilterMatching.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapCarouselFilterSorting.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapDetailsArea.Header.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapDetailsArea.WedgeSelector.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapDetailsArea.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapLeaderboardScore.Tooltip.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapLeaderboardScore.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapLeaderboardWedge.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapMetadataWedge.FailRetryDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapMetadataWedge.MetadataDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapMetadataWedge.RatingSpreadDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapMetadataWedge.SuccessRateDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapMetadataWedge.TagsLine.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapMetadataWedge.UserRatingDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapMetadataWedge.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapTitleWedge.DifficultyDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapTitleWedge.FavouriteButton.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapTitleWedge.Statistic.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapTitleWedge.StatisticDifficulty.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapTitleWedge.StatisticPlayCount.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/BeatmapTitleWedge.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/FilterControl.DifficultyRangeSlider.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/FilterControl.ScopedBeatmapSetDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/FilterControl.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/FooterButtonMods.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/FooterButtonOptions.Popover.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/FooterButtonOptions.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/FooterButtonRandom.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/ISongSelect.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/LeftSideInteractionContainer.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/NoResultsPlaceholder.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/Panel.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelBeatmap.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelBeatmapSet.SpreadDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelBeatmapSet.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelBeatmapStandalone.SpreadDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelBeatmapStandalone.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelGroup.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelGroupRankDisplay.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelGroupRankedStatus.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelGroupStarDifficulty.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelLocalRankDisplay.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/PanelSetBackground.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/PanelUpdateBeatmapButton.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/RealmPopulatingOnlineLookupSource.cs (99%) rename osu.Game/Screens/{SelectV2 => Select}/SoloSongSelect.cs (98%) rename osu.Game/Screens/{SelectV2 => Select}/SongSelect.cs (99%) rename osu.Game/Screens/Select/{Carousel => }/UpdateLocalConfirmationDialog.cs (94%) rename osu.Game/Screens/{SelectV2 => Select}/WedgeBackground.cs (98%) delete mode 100644 osu.Game/Screens/SelectV2/CollectionDropdown.cs diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs index 7dcb8621bf..5455963ff8 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs @@ -11,7 +11,6 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Filter; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select; -using osu.Game.Screens.Select.Carousel; using osu.Game.Screens.Select.Filter; namespace osu.Game.Tests.NonVisual.Filtering diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs index 1365d95a55..3b531e2036 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs @@ -32,7 +32,7 @@ using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Play; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Screens.Ranking; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Storyboards.Drawables; using osu.Game.Tests.Resources; using osuTK; diff --git a/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallenge.cs b/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallenge.cs index f1422b4654..bf88cee11b 100644 --- a/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallenge.cs +++ b/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallenge.cs @@ -15,7 +15,7 @@ using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual.Metadata; using osu.Game.Tests.Visual.OnlinePlay; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs index 66a039f36e..4ab7571636 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs @@ -15,7 +15,7 @@ using osu.Game.Beatmaps.ControlPoints; using osu.Game.Overlays; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose.Components.Timeline; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK.Input; namespace osu.Game.Tests.Visual.Editing diff --git a/osu.Game.Tests/Visual/Editing/TestSceneOpenEditorTimestamp.cs b/osu.Game.Tests/Visual/Editing/TestSceneOpenEditorTimestamp.cs index e3b79d4053..46f47f6a92 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneOpenEditorTimestamp.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneOpenEditorTimestamp.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Edit; using osu.Game.Screens.Menu; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Editing diff --git a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs index f0b7d643b2..b10be77fb6 100644 --- a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs @@ -125,7 +125,7 @@ namespace osu.Game.Tests.Visual.Multiplayer protected void AddBeatmapFromSongSelect(Func beatmap, RulesetInfo? ruleset = null, IReadOnlyList? mods = null) { - Screens.SelectV2.SongSelect? songSelect = null; + Screens.Select.SongSelect? songSelect = null; AddStep("click add button", () => { @@ -133,7 +133,7 @@ namespace osu.Game.Tests.Visual.Multiplayer InputManager.Click(MouseButton.Left); }); - AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.SelectV2.SongSelect) != null); + AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.Select.SongSelect) != null); AddUntilStep("wait for loaded", () => songSelect.IsCurrentScreen() && !songSelect.AsNonNull().IsFiltering); if (ruleset != null) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs index 89980b4257..a1ced5698e 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs @@ -89,7 +89,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private void selectNewItem(Func beatmap) { - Screens.SelectV2.SongSelect? songSelect = null; + Screens.Select.SongSelect? songSelect = null; AddUntilStep("wait for playlist panels to load", () => { @@ -103,7 +103,7 @@ namespace osu.Game.Tests.Visual.Multiplayer InputManager.Click(MouseButton.Left); }); - AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.SelectV2.SongSelect) != null); + AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.Select.SongSelect) != null); AddUntilStep("wait for loaded", () => songSelect.IsCurrentScreen() && !songSelect.AsNonNull().IsFiltering); BeatmapInfo otherBeatmap = null!; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneBeatmapEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneBeatmapEditorNavigation.cs index c7499c98b5..09e8253080 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneBeatmapEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneBeatmapEditorNavigation.cs @@ -26,8 +26,8 @@ using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.GameplayTest; using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Menu; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneButtonSystemNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneButtonSystemNavigation.cs index 0ccfb5a4e3..a908c9cf1b 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneButtonSystemNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneButtonSystemNavigation.cs @@ -5,7 +5,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Screens.Menu; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK.Input; namespace osu.Game.Tests.Visual.Navigation diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs index 4f27d9b323..6ddd784329 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs @@ -15,7 +15,7 @@ using osu.Game.Input.Bindings; using osu.Game.Overlays.Settings.Sections.Input; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Beatmaps.IO; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs b/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs index 0a4349d73f..d3321753c1 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs @@ -5,7 +5,7 @@ using NUnit.Framework; using osu.Framework.Extensions; using osu.Game.Configuration; using osu.Game.Screens.Play; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Beatmaps.IO; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs index 04d7b15295..f86727ab10 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs @@ -17,7 +17,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Screens; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Beatmaps.IO; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs index 1dd39e5bf9..4acc174f72 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs @@ -16,7 +16,7 @@ using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Menu; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.Navigation { diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs index fa337a3ec2..06ea5c7da2 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs @@ -18,8 +18,8 @@ using osu.Game.Screens; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; -using osu.Game.Screens.SelectV2; -using FilterControl = osu.Game.Screens.SelectV2.FilterControl; +using osu.Game.Screens.Select; +using FilterControl = osu.Game.Screens.Select.FilterControl; namespace osu.Game.Tests.Visual.Navigation { diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 1062f32efb..68aaba6c68 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -51,12 +51,13 @@ using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Screens.Ranking; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Beatmaps.IO; using osu.Game.Tests.Resources; using osu.Game.Utils; using osuTK; using osuTK.Input; +using CollectionDropdown = osu.Game.Screens.Select.CollectionDropdown; namespace osu.Game.Tests.Visual.Navigation { @@ -197,14 +198,14 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("set filter again", () => filterControlTextBox().Current.Value = "test"); AddStep("open collections dropdown", () => { - InputManager.MoveMouseTo(songSelect.ChildrenOfType().Single()); + InputManager.MoveMouseTo(songSelect.ChildrenOfType().Single()); InputManager.Click(MouseButton.Left); }); AddStep("press back once", () => InputManager.Click(MouseButton.Button1)); AddAssert("still at song select", () => Game.ScreenStack.CurrentScreen == songSelect); AddAssert("collections dropdown closed", () => songSelect - .ChildrenOfType().Single() + .ChildrenOfType().Single() .ChildrenOfType.DropdownMenu>().Single().State == MenuState.Closed); AddStep("press back a second time", () => InputManager.Click(MouseButton.Button1)); @@ -317,7 +318,7 @@ namespace osu.Game.Tests.Visual.Navigation [Test] public void TestAttemptPlayBeatmapWrongHashFails() { - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).GetResultSafely()); PushAndConfirm(() => songSelect = new SoloSongSelect()); @@ -352,7 +353,7 @@ namespace osu.Game.Tests.Visual.Navigation [Test] public void TestAttemptPlayBeatmapMissingFails() { - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).GetResultSafely()); PushAndConfirm(() => songSelect = new SoloSongSelect()); @@ -386,7 +387,7 @@ namespace osu.Game.Tests.Visual.Navigation { Player player = null; - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; PushAndConfirm(() => songSelect = new SoloSongSelect()); AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented); @@ -429,7 +430,7 @@ namespace osu.Game.Tests.Visual.Navigation { Player player = null; - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; PushAndConfirm(() => songSelect = new SoloSongSelect()); AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented); @@ -483,7 +484,7 @@ namespace osu.Game.Tests.Visual.Navigation { Player player = null; - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; PushAndConfirm(() => songSelect = new SoloSongSelect()); AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented); @@ -526,7 +527,7 @@ namespace osu.Game.Tests.Visual.Navigation { Player player = null; - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; PushAndConfirm(() => songSelect = new SoloSongSelect()); AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented); @@ -1194,9 +1195,9 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("close settings sidebar", () => InputManager.Key(Key.Escape)); - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; AddRepeatStep("go to solo", () => InputManager.Key(Key.P), 3); - AddUntilStep("wait for song select", () => (songSelect = Game.ScreenStack.CurrentScreen as Screens.SelectV2.SongSelect) != null); + AddUntilStep("wait for song select", () => (songSelect = Game.ScreenStack.CurrentScreen as Screens.Select.SongSelect) != null); AddUntilStep("wait for beatmap sets loaded", () => songSelect.CarouselItemsPresented); AddStep("switch to osu! ruleset", () => @@ -1281,7 +1282,7 @@ namespace osu.Game.Tests.Visual.Navigation [Test] public void TestExitSongSelectAndImmediatelyClickLogo() { - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; PushAndConfirm(() => songSelect = new SoloSongSelect()); AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented); @@ -1312,7 +1313,7 @@ namespace osu.Game.Tests.Visual.Navigation { BeatmapSetInfo beatmap = null; - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; PushAndConfirm(() => songSelect = new SoloSongSelect()); AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented); @@ -1371,7 +1372,7 @@ namespace osu.Game.Tests.Visual.Navigation IWorkingBeatmap beatmap() => Game.Beatmap.Value; - Screens.SelectV2.SongSelect songSelect = null; + Screens.Select.SongSelect songSelect = null; PushAndConfirm(() => songSelect = new SoloSongSelect()); AddUntilStep("wait for song select", () => songSelect.CarouselItemsPresented); diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index 9ddeb7870b..97dfcd75b5 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -27,7 +27,7 @@ using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD.HitErrorMeters; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Skinning; using osu.Game.Tests.Beatmaps.IO; using osuTK; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs index 4295e9e88e..2984613807 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs @@ -24,17 +24,13 @@ using osu.Game.Screens.Footer; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Beatmaps.IO; using osu.Game.Tests.Resources; using osuTK.Input; namespace osu.Game.Tests.Visual.Navigation { - /// - /// Tests copied out of `TestSceneScreenNavigation` which are specific to song select. - /// These are for SongSelectV2. Eventually, the tests in the above class should be deleted along with old song select. - /// public partial class TestSceneSongSelectNavigation : OsuGameTestScene { [Test] @@ -277,7 +273,7 @@ namespace osu.Game.Tests.Visual.Navigation /// /// Note: This test was written to demonstrate the failure described at https://github.com/ppy/osu/issues/35023, /// but because the failure scenario there entailed a race condition, it was possible for the test to pass regardless - /// unless was increased. + /// unless was increased. /// [Test] public void TestPresentFromResults() diff --git a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselFilterGroupingTest.cs b/osu.Game.Tests/Visual/SongSelect/BeatmapCarouselFilterGroupingTest.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselFilterGroupingTest.cs rename to osu.Game.Tests/Visual/SongSelect/BeatmapCarouselFilterGroupingTest.cs index 3e935ac5d7..814e93014b 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselFilterGroupingTest.cs +++ b/osu.Game.Tests/Visual/SongSelect/BeatmapCarouselFilterGroupingTest.cs @@ -14,10 +14,9 @@ using osu.Game.Graphics.Carousel; using osu.Game.Scoring; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class BeatmapCarouselFilterGroupingTest diff --git a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselFilterSortingTest.cs b/osu.Game.Tests/Visual/SongSelect/BeatmapCarouselFilterSortingTest.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselFilterSortingTest.cs rename to osu.Game.Tests/Visual/SongSelect/BeatmapCarouselFilterSortingTest.cs index 868abf9583..d6729d2141 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselFilterSortingTest.cs +++ b/osu.Game.Tests/Visual/SongSelect/BeatmapCarouselFilterSortingTest.cs @@ -12,10 +12,9 @@ using osu.Game.Beatmaps; using osu.Game.Graphics.Carousel; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class BeatmapCarouselFilterSortingTest diff --git a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs b/osu.Game.Tests/Visual/SongSelect/BeatmapCarouselTestScene.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs rename to osu.Game.Tests/Visual/SongSelect/BeatmapCarouselTestScene.cs index dc3a49c068..ae31606abb 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs +++ b/osu.Game.Tests/Visual/SongSelect/BeatmapCarouselTestScene.cs @@ -25,15 +25,13 @@ using osu.Game.Overlays; using osu.Game.Scoring; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Beatmaps; using osu.Game.Tests.Resources; using osuTK; using osuTK.Graphics; using osuTK.Input; -using BeatmapCarousel = osu.Game.Screens.SelectV2.BeatmapCarousel; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public abstract partial class BeatmapCarouselTestScene : OsuManualInputManagerTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/SongSelectComponentsTestScene.cs b/osu.Game.Tests/Visual/SongSelect/SongSelectComponentsTestScene.cs similarity index 97% rename from osu.Game.Tests/Visual/SongSelectV2/SongSelectComponentsTestScene.cs rename to osu.Game.Tests/Visual/SongSelect/SongSelectComponentsTestScene.cs index 843d65b7f8..94ca56897e 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/SongSelectComponentsTestScene.cs +++ b/osu.Game.Tests/Visual/SongSelect/SongSelectComponentsTestScene.cs @@ -9,7 +9,7 @@ using osu.Framework.Testing; using osu.Game.Graphics.Cursor; using osu.Game.Overlays; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public abstract partial class SongSelectComponentsTestScene : OsuManualInputManagerTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/SongSelectTestScene.cs b/osu.Game.Tests/Visual/SongSelect/SongSelectTestScene.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/SongSelectTestScene.cs rename to osu.Game.Tests/Visual/SongSelect/SongSelectTestScene.cs index ac8591699a..e5fce29812 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/SongSelectTestScene.cs +++ b/osu.Game.Tests/Visual/SongSelect/SongSelectTestScene.cs @@ -23,11 +23,11 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Menu; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public abstract partial class SongSelectTestScene : ScreenTestScene { @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 private RealmDetachedBeatmapStore beatmapStore = null!; - protected Screens.SelectV2.SongSelect SongSelect { get; private set; } = null!; + protected Screens.Select.SongSelect SongSelect { get; private set; } = null!; protected BeatmapCarousel Carousel => SongSelect.ChildrenOfType().Single(); [Cached] diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarousel.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index ce671c7e7f..b7c113cffb 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -10,11 +10,11 @@ using osu.Framework.Testing; using osu.Framework.Threading; using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { /// /// Covers common steps which can be used for manual testing. diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselArtistGrouping.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselArtistGrouping.cs index 28cdca34e1..a591dff010 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselArtistGrouping.cs @@ -7,12 +7,12 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Graphics.Carousel; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; using osuTK; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselArtistGrouping : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselCollectionGrouping.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselCollectionGrouping.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselCollectionGrouping.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselCollectionGrouping.cs index e410d66ce8..0d7b9c2991 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselCollectionGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselCollectionGrouping.cs @@ -8,7 +8,7 @@ using osu.Framework.Testing; using osu.Game.Collections; using osu.Game.Screens.Select.Filter; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselCollectionGrouping : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselDifficultyGrouping.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselDifficultyGrouping.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselDifficultyGrouping.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselDifficultyGrouping.cs index 2cffe60ec1..4a41612c30 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselDifficultyGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselDifficultyGrouping.cs @@ -5,11 +5,11 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Graphics.Carousel; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osuTK; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselDifficultyGrouping : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselFiltering.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselFiltering.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselFiltering.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselFiltering.cs index b1bd9fd3ed..73596a768d 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselFiltering.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselFiltering.cs @@ -9,11 +9,11 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselFiltering : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselNoGrouping.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselNoGrouping.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselNoGrouping.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselNoGrouping.cs index c839a28055..1ff87712de 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselNoGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselNoGrouping.cs @@ -4,12 +4,12 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Testing; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osuTK; using osuTK.Input; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselNoGrouping : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselRandom.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselRandom.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselRandom.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselRandom.cs index ce68d587c8..66328de8dd 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselRandom.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselRandom.cs @@ -5,10 +5,10 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselRandom : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselScrolling.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselScrolling.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselScrolling.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselScrolling.cs index c1cee4e398..319803ef5f 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselScrolling.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselScrolling.cs @@ -5,9 +5,9 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Graphics.Primitives; using osu.Framework.Testing; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselScrolling : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselSetsSplitApart.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselSetsSplitApart.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselSetsSplitApart.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselSetsSplitApart.cs index 31488e399a..12d70702d5 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselSetsSplitApart.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselSetsSplitApart.cs @@ -6,10 +6,10 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselSetsSplitApart : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselUpdateHandling.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselUpdateHandling.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselUpdateHandling.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselUpdateHandling.cs index 17f328b549..1033a17e05 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselUpdateHandling.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarouselUpdateHandling.cs @@ -12,11 +12,11 @@ using osu.Game.Database; using osu.Game.Extensions; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] public partial class TestSceneBeatmapCarouselUpdateHandling : BeatmapCarouselTestScene diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapFilterControl.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapFilterControl.cs similarity index 93% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapFilterControl.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapFilterControl.cs index 284484d2df..81f6cbc70d 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapFilterControl.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapFilterControl.cs @@ -4,9 +4,9 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneBeatmapFilterControl : SongSelectComponentsTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardScore.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardScore.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardScore.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardScore.cs index 0aca2d6a1c..856a4be67d 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardScore.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardScore.cs @@ -21,13 +21,13 @@ using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Users; using osuTK; using osuTK.Input; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneBeatmapLeaderboardScore : SongSelectComponentsTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardSorting.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardSorting.cs similarity index 95% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardSorting.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardSorting.cs index a37700f6be..9c50bccd6e 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardSorting.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardSorting.cs @@ -24,11 +24,11 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Users; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneBeatmapLeaderboardSorting : SongSelectComponentsTestScene { @@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 private LeaderboardManager leaderboardManager = null!; - private readonly IBindable onlineLookupResult = new Bindable(); + private readonly IBindable onlineLookupResult = new Bindable(); protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardWedge.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardWedge.cs index 4609bd8936..c6d6339c98 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboardWedge.cs @@ -26,12 +26,12 @@ using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Scoring; using osu.Game.Screens.Play.Leaderboards; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Users; using osuTK.Input; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneBeatmapLeaderboardWedge : SongSelectComponentsTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapMetadataWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataWedge.cs similarity index 90% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapMetadataWedge.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataWedge.cs index 0266584389..769d6bb8f8 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapMetadataWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataWedge.cs @@ -13,16 +13,16 @@ using osu.Game.Extensions; using osu.Game.Graphics.Sprites; using osu.Game.Models; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneBeatmapMetadataWedge : SongSelectComponentsTestScene { private BeatmapMetadataWedge wedge = null!; - [Cached(typeof(IBindable))] - private Bindable onlineLookupResult = new Bindable(); + [Cached(typeof(IBindable))] + private Bindable onlineLookupResult = new Bindable(); protected override void LoadComplete() { @@ -103,7 +103,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 working.BeatmapInfo.OnlineID = 0; Beatmap.Value = working; - onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(null); + onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(null); }); } @@ -154,7 +154,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 var (working, _) = createTestBeatmap(); Beatmap.Value = working; - onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(null); + onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(null); }); AddAssert("rating wedge still hidden", () => !wedge.RatingsVisible); AddAssert("fail time wedge still hidden", () => !wedge.FailRetryVisible); @@ -189,7 +189,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 var (working, online) = createTestBeatmap(); Beatmap.Value = working; - onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress(); + onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.InProgress(); Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500); }); AddWaitStep("wait", 5); @@ -203,7 +203,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 online.Result!.RelatedTags[2].Name = "some/tag"; Beatmap.Value = working; - onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress(); + onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.InProgress(); Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500); }); AddWaitStep("wait", 5); @@ -217,7 +217,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear(); Beatmap.Value = working; - onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress(); + onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.InProgress(); Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500); }); AddWaitStep("wait", 5); @@ -231,13 +231,13 @@ namespace osu.Game.Tests.Visual.SongSelectV2 working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear(); Beatmap.Value = working; - onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress(); + onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.InProgress(); Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500); }); AddWaitStep("wait", 5); } - private (WorkingBeatmap, Screens.SelectV2.SongSelect.BeatmapSetLookupResult) createTestBeatmap() + private (WorkingBeatmap, Screens.Select.SongSelect.BeatmapSetLookupResult) createTestBeatmap() { var working = CreateWorkingBeatmap(Ruleset.Value); var onlineSet = new APIBeatmapSet @@ -292,7 +292,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 working.BeatmapSetInfo.DateSubmitted = DateTimeOffset.Now; working.BeatmapSetInfo.DateRanked = DateTimeOffset.Now; working.Metadata.UserTags.AddRange(onlineSet.RelatedTags.Select(t => t.Name)); - return (working, Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(onlineSet)); + return (working, Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(onlineSet)); } } } diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index 832e8fc90f..f2b4e41470 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -23,7 +23,7 @@ using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Taiko; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Users; using osu.Game.Utils; diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedge.cs similarity index 88% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedge.cs index d89d90ea84..0d14de8b9e 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedge.cs @@ -29,11 +29,10 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Skinning; -using osu.Game.Tests.Visual.SongSelect; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneBeatmapTitleWedge : SongSelectComponentsTestScene { @@ -42,8 +41,8 @@ namespace osu.Game.Tests.Visual.SongSelectV2 private BeatmapTitleWedge titleWedge = null!; private BeatmapTitleWedge.DifficultyDisplay difficultyDisplay => titleWedge.ChildrenOfType().Single(); - [Cached(typeof(IBindable))] - private Bindable onlineLookupResult = new Bindable(); + [Cached(typeof(IBindable))] + private Bindable onlineLookupResult = new Bindable(); [BackgroundDependencyLoader] private void load(RulesetStore rulesets) @@ -86,7 +85,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 foreach (var rulesetInfo in rulesets.AvailableRulesets) { - var testBeatmap = TestSceneBeatmapInfoWedge.CreateTestBeatmap(rulesetInfo); + var testBeatmap = createTestBeatmapFromRuleset(rulesetInfo); setRuleset(rulesetInfo); selectBeatmap(testBeatmap); @@ -108,7 +107,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 public void TestBPMUpdates() { const double bpm = 120; - IBeatmap beatmap = TestSceneBeatmapInfoWedge.CreateTestBeatmap(new OsuRuleset().RulesetInfo); + IBeatmap beatmap = createTestBeatmapFromRuleset(new OsuRuleset().RulesetInfo); beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 60 * 1000 / bpm }); OsuModDoubleTime doubleTime = null!; @@ -160,7 +159,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 var (working, _) = createTestBeatmap(); Beatmap.Value = working; - onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(null); + onlineLookupResult.Value = Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(null); }); AddUntilStep("play count is -", () => this.ChildrenOfType().ElementAt(0).Text.ToString(), () => Is.EqualTo("-")); AddUntilStep("favourites count is -", () => this.ChildrenOfType().Single().Text.ToString(), () => Is.EqualTo("-")); @@ -255,7 +254,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 [TestCase(120, 120.4, "DT", "180-181 (mostly 180)")] public void TestVaryingBPM(double commonBpm, double otherBpm, string? mod, string expectedDisplay) { - IBeatmap beatmap = TestSceneBeatmapInfoWedge.CreateTestBeatmap(new OsuRuleset().RulesetInfo); + IBeatmap beatmap = createTestBeatmapFromRuleset(new OsuRuleset().RulesetInfo); beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 60 * 1000 / commonBpm }); beatmap.ControlPointInfo.Add(100, new TimingControlPoint { BeatLength = 60 * 1000 / otherBpm }); beatmap.ControlPointInfo.Add(200, new TimingControlPoint { BeatLength = 60 * 1000 / commonBpm }); @@ -299,7 +298,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 }); } - private (WorkingBeatmap, Screens.SelectV2.SongSelect.BeatmapSetLookupResult) createTestBeatmap() + private (WorkingBeatmap, Screens.Select.SongSelect.BeatmapSetLookupResult) createTestBeatmap() { var working = CreateWorkingBeatmap(Ruleset.Value); var onlineSet = new APIBeatmapSet @@ -320,7 +319,33 @@ namespace osu.Game.Tests.Visual.SongSelectV2 working.BeatmapSetInfo.DateSubmitted = DateTimeOffset.Now; working.BeatmapSetInfo.DateRanked = DateTimeOffset.Now; - return (working, Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(onlineSet)); + return (working, Screens.Select.SongSelect.BeatmapSetLookupResult.Completed(onlineSet)); + } + + private static IBeatmap createTestBeatmapFromRuleset(RulesetInfo ruleset) + { + List objects = new List(); + for (double i = 0; i < 50000; i += 1000) + objects.Add(new TestHitObject { StartTime = i }); + + return new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + Metadata = new BeatmapMetadata + { + Author = { Username = $"{ruleset.ShortName}Author" }, + Artist = $"{ruleset.ShortName}Artist", + Source = $"{ruleset.ShortName}Source", + Title = $"{ruleset.ShortName}Title" + }, + Ruleset = ruleset, + StarRating = 6, + DifficultyName = $"{ruleset.ShortName}Version", + Difficulty = new BeatmapDifficulty() + }, + HitObjects = objects + }; } private class TestHitObject : ConvertHitObject; diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedgeStatistic.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedgeStatistic.cs similarity index 97% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedgeStatistic.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedgeStatistic.cs index 6bf9469021..f0691f05a1 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapTitleWedgeStatistic.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapTitleWedgeStatistic.cs @@ -8,10 +8,10 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Graphics; using osu.Game.Overlays; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Visual.UserInterface; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneBeatmapTitleWedgeStatistic : ThemeComparisonTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneDifficultyRangeSlider.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeSlider.cs similarity index 96% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneDifficultyRangeSlider.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeSlider.cs index f97af65fd9..ed7ade4914 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneDifficultyRangeSlider.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeSlider.cs @@ -7,12 +7,12 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Overlays; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Visual.UserInterface; using osuTK; using osuTK.Graphics; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneDifficultyRangeSlider : ThemeComparisonTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneDifficultyStatisticsDisplay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyStatisticsDisplay.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneDifficultyStatisticsDisplay.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyStatisticsDisplay.cs index 0ee742a09d..5b15add2ad 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneDifficultyStatisticsDisplay.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyStatisticsDisplay.cs @@ -11,10 +11,10 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Testing; using osu.Game.Overlays; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK.Graphics; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneDifficultyStatisticsDisplay : OsuTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneFooterButtonMods.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneFooterButtonMods.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneFooterButtonMods.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneFooterButtonMods.cs index c339f16bb4..08d02015a2 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneFooterButtonMods.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneFooterButtonMods.cs @@ -13,10 +13,10 @@ using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Utils; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneFooterButtonMods : OsuTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelBeatmap.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePanelBeatmap.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestScenePanelBeatmap.cs rename to osu.Game.Tests/Visual/SongSelect/TestScenePanelBeatmap.cs index 618b9e0d48..ca71f5a212 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelBeatmap.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePanelBeatmap.cs @@ -19,12 +19,12 @@ using osu.Game.Overlays; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Scoring; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual.UserInterface; using osuTK; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestScenePanelBeatmap : ThemeComparisonTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelBeatmapStandalone.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePanelBeatmapStandalone.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestScenePanelBeatmapStandalone.cs rename to osu.Game.Tests/Visual/SongSelect/TestScenePanelBeatmapStandalone.cs index 67a9f54f1a..48c0fef48a 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelBeatmapStandalone.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePanelBeatmapStandalone.cs @@ -19,12 +19,12 @@ using osu.Game.Overlays; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Scoring; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual.UserInterface; using osuTK; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestScenePanelBeatmapStandalone : ThemeComparisonTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelGroup.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePanelGroup.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestScenePanelGroup.cs rename to osu.Game.Tests/Visual/SongSelect/TestScenePanelGroup.cs index 12557a80f4..62c8a9c8c5 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelGroup.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePanelGroup.cs @@ -7,15 +7,15 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; -using osu.Game.Overlays; using osu.Game.Graphics.Carousel; using osu.Game.Graphics.Cursor; +using osu.Game.Overlays; using osu.Game.Scoring; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Visual.UserInterface; using osuTK; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestScenePanelGroup : ThemeComparisonTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelSet.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePanelSet.cs similarity index 97% rename from osu.Game.Tests/Visual/SongSelectV2/TestScenePanelSet.cs rename to osu.Game.Tests/Visual/SongSelect/TestScenePanelSet.cs index b574262d55..a903f8c83f 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelSet.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePanelSet.cs @@ -11,12 +11,12 @@ using osu.Game.Beatmaps; using osu.Game.Graphics.Carousel; using osu.Game.Graphics.Cursor; using osu.Game.Overlays; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual.UserInterface; using osuTK; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestScenePanelSet : ThemeComparisonTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelUpdateBeatmapButton.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePanelUpdateBeatmapButton.cs similarity index 95% rename from osu.Game.Tests/Visual/SongSelectV2/TestScenePanelUpdateBeatmapButton.cs rename to osu.Game.Tests/Visual/SongSelect/TestScenePanelUpdateBeatmapButton.cs index 8156842eb9..02715ade3a 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestScenePanelUpdateBeatmapButton.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePanelUpdateBeatmapButton.cs @@ -5,9 +5,9 @@ using System; using NUnit.Framework; using osu.Framework.Graphics; using osu.Game.Beatmaps; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestScenePanelUpdateBeatmapButton : OsuTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelect.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneSongSelect.cs index 2434924393..6eddc8e1d8 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelect.cs @@ -23,15 +23,14 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; using osu.Game.Screens.Select; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; using osuTK.Input; -using BeatmapCarousel = osu.Game.Screens.SelectV2.BeatmapCarousel; -using FooterButtonMods = osu.Game.Screens.SelectV2.FooterButtonMods; -using FooterButtonOptions = osu.Game.Screens.SelectV2.FooterButtonOptions; -using FooterButtonRandom = osu.Game.Screens.SelectV2.FooterButtonRandom; +using BeatmapCarousel = osu.Game.Screens.Select.BeatmapCarousel; +using FooterButtonMods = osu.Game.Screens.Select.FooterButtonMods; +using FooterButtonOptions = osu.Game.Screens.Select.FooterButtonOptions; +using FooterButtonRandom = osu.Game.Screens.Select.FooterButtonRandom; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneSongSelect : SongSelectTestScene { @@ -324,7 +323,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 AddStep("exit gameplay", () => Stack.CurrentScreen.Exit()); - AddUntilStep("wait for song select", () => Stack.CurrentScreen is Screens.SelectV2.SongSelect); + AddUntilStep("wait for song select", () => Stack.CurrentScreen is Screens.Select.SongSelect); AddUntilStep("wait for filtered", () => SongSelect.ChildrenOfType().Single().FilterCount, () => Is.EqualTo(2)); } diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectCurrentSelectionInvalidated.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectCurrentSelectionInvalidated.cs similarity index 98% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectCurrentSelectionInvalidated.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectCurrentSelectionInvalidated.cs index 0ec61f59da..59c9074ddb 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectCurrentSelectionInvalidated.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectCurrentSelectionInvalidated.cs @@ -8,11 +8,11 @@ using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osuTK.Input; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { /// /// The fallback behaviour guaranteed by SongSelect is that a random selection will happen in worst case scenario. @@ -226,7 +226,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 Beatmaps.Delete(Beatmaps.GetAllUsableBeatmapSets().Last()); // check selection during debounce - Scheduler.AddDelayed(() => selectedBeatmapDuringDebounce = Beatmap.Value.BeatmapInfo, Screens.SelectV2.SongSelect.SELECTION_DEBOUNCE / 2f); + Scheduler.AddDelayed(() => selectedBeatmapDuringDebounce = Beatmap.Value.BeatmapInfo, Screens.Select.SongSelect.SELECTION_DEBOUNCE / 2f); }); WaitForFiltering(); diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFiltering.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFiltering.cs index 2e7e08b331..a479a28657 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFiltering.cs @@ -16,13 +16,13 @@ using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osuTK.Input; -using FilterControl = osu.Game.Screens.SelectV2.FilterControl; -using NoResultsPlaceholder = osu.Game.Screens.SelectV2.NoResultsPlaceholder; +using FilterControl = osu.Game.Screens.Select.FilterControl; +using NoResultsPlaceholder = osu.Game.Screens.Select.NoResultsPlaceholder; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneSongSelectFiltering : SongSelectTestScene { diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectGrouping.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectGrouping.cs similarity index 99% rename from osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectGrouping.cs rename to osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectGrouping.cs index e65c9553c2..eb282d3d3c 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectGrouping.cs @@ -16,11 +16,11 @@ using osu.Game.Models; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Scoring; +using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; -using osu.Game.Screens.SelectV2; using osu.Game.Tests.Resources; -namespace osu.Game.Tests.Visual.SongSelectV2 +namespace osu.Game.Tests.Visual.SongSelect { /// /// Test suite for grouping modes which require the presence of API / realm. diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs index 0da7c3eb95..a958c5f43e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs @@ -17,7 +17,7 @@ using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Screens; using osu.Game.Screens.Footer; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.UserInterface { diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 1603a9848c..d8bf2c752b 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using JetBrains.Annotations; using Newtonsoft.Json; using osu.Game.Models; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Users; using osu.Game.Utils; using Realms; diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index 1e4d3484b7..57682513d4 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -34,7 +34,7 @@ using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Mods; using osu.Game.Utils; using CommonStrings = osu.Game.Localisation.CommonStrings; -using SongSelect = osu.Game.Screens.SelectV2.SongSelect; +using SongSelect = osu.Game.Screens.Select.SongSelect; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; namespace osu.Game.Online.Leaderboards diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 0785ecaeaf..77ccf7edfc 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -71,7 +71,7 @@ using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Play; using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Seasonal; using osu.Game.Skinning; using osu.Game.Updater; diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs index edadc333c8..09bdb8b843 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs @@ -25,7 +25,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Screens; using osu.Game.Screens.Footer; using osu.Game.Screens.Menu; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Tests.Visual; using osuTK; diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs index 19b2757e4c..134bed22af 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs @@ -28,7 +28,7 @@ using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Users; using osu.Game.Utils; diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs b/osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs index efc305b492..52dcadd977 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorSceneLibrary.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Screens; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK; namespace osu.Game.Overlays.SkinEditor diff --git a/osu.Game/Screens/Edit/Submission/BeatmapSubmissionScreen.cs b/osu.Game/Screens/Edit/Submission/BeatmapSubmissionScreen.cs index 8d78d76428..78066edc7e 100644 --- a/osu.Game/Screens/Edit/Submission/BeatmapSubmissionScreen.cs +++ b/osu.Game/Screens/Edit/Submission/BeatmapSubmissionScreen.cs @@ -30,7 +30,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK; namespace osu.Game.Screens.Edit.Submission diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 2296213dd6..ee734acb60 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -39,7 +39,7 @@ using osu.Game.Screens.Edit; using osu.Game.Screens.OnlinePlay.DailyChallenge; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Playlists; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Seasonal; using osuTK; using osuTK.Graphics; diff --git a/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallengeLeaderboard.cs b/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallengeLeaderboard.cs index 65805a970d..62c5c0c8df 100644 --- a/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallengeLeaderboard.cs +++ b/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallengeLeaderboard.cs @@ -17,7 +17,7 @@ using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK; namespace osu.Game.Screens.OnlinePlay.DailyChallenge diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs index aff9b803c6..28154180e6 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs @@ -20,7 +20,7 @@ using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Footer; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK; namespace osu.Game.Screens.OnlinePlay diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index f234bed697..ce5d68b004 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -24,9 +24,9 @@ using osu.Game.Overlays.Mods; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Footer; +using osu.Game.Screens.Select; using osu.Game.Users; using osu.Game.Utils; -using osu.Game.Screens.SelectV2; namespace osu.Game.Screens.OnlinePlay.Multiplayer { diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs index 0ff3ade809..150cdb859d 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayFreestyleSelect.cs @@ -13,7 +13,6 @@ using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Screens.Footer; using osu.Game.Screens.Select; -using SongSelect = osu.Game.Screens.SelectV2.SongSelect; namespace osu.Game.Screens.OnlinePlay { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs index fb921f219a..7c1b3cd620 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs @@ -18,7 +18,7 @@ using osu.Game.Overlays.Mods; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Footer; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osu.Game.Utils; namespace osu.Game.Screens.OnlinePlay.Playlists diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapCarousel.cs rename to osu.Game/Screens/Select/BeatmapCarousel.cs index adf6588727..2cf8c7d2d0 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -13,8 +13,8 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; -using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; @@ -31,10 +31,9 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Scoring; -using osu.Game.Screens.Select; using Realms; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { [Cached] public partial class BeatmapCarousel : Carousel diff --git a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs b/osu.Game/Screens/Select/BeatmapCarouselFilterGrouping.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs rename to osu.Game/Screens/Select/BeatmapCarouselFilterGrouping.cs index 280db188ef..8db8ed5cb0 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs +++ b/osu.Game/Screens/Select/BeatmapCarouselFilterGrouping.cs @@ -11,11 +11,10 @@ using osu.Game.Beatmaps; using osu.Game.Collections; using osu.Game.Graphics.Carousel; using osu.Game.Scoring; -using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; using osu.Game.Utils; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public class BeatmapCarouselFilterGrouping : ICarouselFilter { diff --git a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs b/osu.Game/Screens/Select/BeatmapCarouselFilterMatching.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs rename to osu.Game/Screens/Select/BeatmapCarouselFilterMatching.cs index 80f7f058f7..5011166bb1 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterMatching.cs +++ b/osu.Game/Screens/Select/BeatmapCarouselFilterMatching.cs @@ -8,10 +8,9 @@ using System.Threading; using System.Threading.Tasks; using osu.Game.Beatmaps; using osu.Game.Graphics.Carousel; -using osu.Game.Screens.Select; using osu.Game.Utils; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public class BeatmapCarouselFilterMatching : ICarouselFilter { diff --git a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterSorting.cs b/osu.Game/Screens/Select/BeatmapCarouselFilterSorting.cs similarity index 98% rename from osu.Game/Screens/SelectV2/BeatmapCarouselFilterSorting.cs rename to osu.Game/Screens/Select/BeatmapCarouselFilterSorting.cs index e9d65f7108..60e94299b2 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterSorting.cs +++ b/osu.Game/Screens/Select/BeatmapCarouselFilterSorting.cs @@ -8,11 +8,10 @@ using System.Threading; using System.Threading.Tasks; using osu.Game.Beatmaps; using osu.Game.Graphics.Carousel; -using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; using osu.Game.Utils; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public class BeatmapCarouselFilterSorting : ICarouselFilter { diff --git a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs b/osu.Game/Screens/Select/BeatmapDetailsArea.Header.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs rename to osu.Game/Screens/Select/BeatmapDetailsArea.Header.cs index 5b3f27ce64..fd6437d1a9 100644 --- a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs +++ b/osu.Game/Screens/Select/BeatmapDetailsArea.Header.cs @@ -14,10 +14,9 @@ using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osu.Game.Online.Leaderboards; using osu.Game.Screens.Play.Leaderboards; -using osu.Game.Screens.Select; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapDetailsArea { diff --git a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.WedgeSelector.cs b/osu.Game/Screens/Select/BeatmapDetailsArea.WedgeSelector.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapDetailsArea.WedgeSelector.cs rename to osu.Game/Screens/Select/BeatmapDetailsArea.WedgeSelector.cs index 95f60fb423..9a5db9b818 100644 --- a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.WedgeSelector.cs +++ b/osu.Game/Screens/Select/BeatmapDetailsArea.WedgeSelector.cs @@ -18,7 +18,7 @@ using osu.Game.Localisation; using osu.Game.Overlays; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapDetailsArea { diff --git a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.cs b/osu.Game/Screens/Select/BeatmapDetailsArea.cs similarity index 98% rename from osu.Game/Screens/SelectV2/BeatmapDetailsArea.cs rename to osu.Game/Screens/Select/BeatmapDetailsArea.cs index 7a2068b0cf..f83fd1539d 100644 --- a/osu.Game/Screens/SelectV2/BeatmapDetailsArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailsArea.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { /// /// The left portion of the song select screen which houses the metadata or leaderboards wedge, along with controls diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.Tooltip.cs b/osu.Game/Screens/Select/BeatmapLeaderboardScore.Tooltip.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.Tooltip.cs rename to osu.Game/Screens/Select/BeatmapLeaderboardScore.Tooltip.cs index 1f92699887..bd3b6f16b3 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.Tooltip.cs +++ b/osu.Game/Screens/Select/BeatmapLeaderboardScore.Tooltip.cs @@ -34,7 +34,7 @@ using osu.Game.Utils; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapLeaderboardScore { diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs b/osu.Game/Screens/Select/BeatmapLeaderboardScore.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs rename to osu.Game/Screens/Select/BeatmapLeaderboardScore.cs index 079f4192e0..c6d52a7ace 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs +++ b/osu.Game/Screens/Select/BeatmapLeaderboardScore.cs @@ -32,7 +32,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; -using osu.Game.Screens.Select; using osu.Game.Users; using osu.Game.Users.Drawables; using osu.Game.Utils; @@ -40,7 +39,7 @@ using osuTK; using osuTK.Graphics; using CommonStrings = osu.Game.Localisation.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public sealed partial class BeatmapLeaderboardScore : OsuClickableContainer, IHasContextMenu, IHasCustomTooltip { diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs b/osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs rename to osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs index 18b1bc2e27..25eac3e182 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardWedge.cs +++ b/osu.Game/Screens/Select/BeatmapLeaderboardWedge.cs @@ -37,7 +37,7 @@ using osu.Game.Screens.Play.Leaderboards; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapLeaderboardWedge : VisibilityContainer { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.FailRetryDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.FailRetryDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge.FailRetryDisplay.cs rename to osu.Game/Screens/Select/BeatmapMetadataWedge.FailRetryDisplay.cs index 9ee61b7c5c..1bbce94f4f 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.FailRetryDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.FailRetryDisplay.cs @@ -17,7 +17,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.MetadataDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.MetadataDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge.MetadataDisplay.cs rename to osu.Game/Screens/Select/BeatmapMetadataWedge.MetadataDisplay.cs index 84948678d0..3b9d31380a 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.MetadataDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.MetadataDisplay.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.RatingSpreadDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.RatingSpreadDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge.RatingSpreadDisplay.cs rename to osu.Game/Screens/Select/BeatmapMetadataWedge.RatingSpreadDisplay.cs index ee938ecdd9..3a6017f4ec 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.RatingSpreadDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.RatingSpreadDisplay.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.SuccessRateDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.SuccessRateDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge.SuccessRateDisplay.cs rename to osu.Game/Screens/Select/BeatmapMetadataWedge.SuccessRateDisplay.cs index 6118547274..48680b5b29 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.SuccessRateDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.SuccessRateDisplay.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays; using osu.Game.Resources.Localisation.Web; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.TagsLine.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.TagsLine.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge.TagsLine.cs rename to osu.Game/Screens/Select/BeatmapMetadataWedge.TagsLine.cs index e48b4f20da..975dfd6212 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.TagsLine.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.TagsLine.cs @@ -22,7 +22,7 @@ using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Overlays; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.UserRatingDisplay.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.UserRatingDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge.UserRatingDisplay.cs rename to osu.Game/Screens/Select/BeatmapMetadataWedge.UserRatingDisplay.cs index 2f38079577..2d8d039d99 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.UserRatingDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.UserRatingDisplay.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays; using osu.Game.Resources.Localisation.Web; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.cs b/osu.Game/Screens/Select/BeatmapMetadataWedge.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge.cs rename to osu.Game/Screens/Select/BeatmapMetadataWedge.cs index 9c0ab105e2..128dde88c9 100644 --- a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.cs +++ b/osu.Game/Screens/Select/BeatmapMetadataWedge.cs @@ -22,7 +22,7 @@ using osu.Game.Online.Chat; using osu.Game.Resources.Localisation.Web; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapMetadataWedge : VisibilityContainer { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs b/osu.Game/Screens/Select/BeatmapTitleWedge.DifficultyDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs rename to osu.Game/Screens/Select/BeatmapTitleWedge.DifficultyDisplay.cs index fc6ce0ac20..432ba22c31 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapTitleWedge.DifficultyDisplay.cs @@ -26,7 +26,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapTitleWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs b/osu.Game/Screens/Select/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs rename to osu.Game/Screens/Select/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs index 595959cfce..e07eea1491 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs +++ b/osu.Game/Screens/Select/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs @@ -17,7 +17,7 @@ using osu.Game.Overlays; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapTitleWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.FavouriteButton.cs b/osu.Game/Screens/Select/BeatmapTitleWedge.FavouriteButton.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge.FavouriteButton.cs rename to osu.Game/Screens/Select/BeatmapTitleWedge.FavouriteButton.cs index 62ac8a07b4..bd3aaaa239 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.FavouriteButton.cs +++ b/osu.Game/Screens/Select/BeatmapTitleWedge.FavouriteButton.cs @@ -26,7 +26,7 @@ using osu.Game.Resources.Localisation.Web; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapTitleWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.Statistic.cs b/osu.Game/Screens/Select/BeatmapTitleWedge.Statistic.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge.Statistic.cs rename to osu.Game/Screens/Select/BeatmapTitleWedge.Statistic.cs index 85a0382360..1ed08ce124 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.Statistic.cs +++ b/osu.Game/Screens/Select/BeatmapTitleWedge.Statistic.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapTitleWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticDifficulty.cs b/osu.Game/Screens/Select/BeatmapTitleWedge.StatisticDifficulty.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticDifficulty.cs rename to osu.Game/Screens/Select/BeatmapTitleWedge.StatisticDifficulty.cs index bcce78246d..3133f8a67b 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticDifficulty.cs +++ b/osu.Game/Screens/Select/BeatmapTitleWedge.StatisticDifficulty.cs @@ -19,7 +19,7 @@ using osu.Game.Rulesets.Difficulty; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapTitleWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticPlayCount.cs b/osu.Game/Screens/Select/BeatmapTitleWedge.StatisticPlayCount.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticPlayCount.cs rename to osu.Game/Screens/Select/BeatmapTitleWedge.StatisticPlayCount.cs index d193cbe286..f8f5fe3782 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticPlayCount.cs +++ b/osu.Game/Screens/Select/BeatmapTitleWedge.StatisticPlayCount.cs @@ -18,7 +18,7 @@ using osu.Game.Overlays; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapTitleWedge { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs b/osu.Game/Screens/Select/BeatmapTitleWedge.cs similarity index 99% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs rename to osu.Game/Screens/Select/BeatmapTitleWedge.cs index fdbed98885..657e3ba15b 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs +++ b/osu.Game/Screens/Select/BeatmapTitleWedge.cs @@ -28,7 +28,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Utils; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class BeatmapTitleWedge : VisibilityContainer { diff --git a/osu.Game/Screens/SelectV2/FilterControl.DifficultyRangeSlider.cs b/osu.Game/Screens/Select/FilterControl.DifficultyRangeSlider.cs similarity index 99% rename from osu.Game/Screens/SelectV2/FilterControl.DifficultyRangeSlider.cs rename to osu.Game/Screens/Select/FilterControl.DifficultyRangeSlider.cs index f15cfa4b4d..902b335c62 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.DifficultyRangeSlider.cs +++ b/osu.Game/Screens/Select/FilterControl.DifficultyRangeSlider.cs @@ -21,7 +21,7 @@ using osu.Game.Resources.Localisation.Web; using osu.Game.Utils; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class FilterControl { diff --git a/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs b/osu.Game/Screens/Select/FilterControl.ScopedBeatmapSetDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs rename to osu.Game/Screens/Select/FilterControl.ScopedBeatmapSetDisplay.cs index 378db5cb2d..78dfb163ad 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.ScopedBeatmapSetDisplay.cs +++ b/osu.Game/Screens/Select/FilterControl.ScopedBeatmapSetDisplay.cs @@ -16,7 +16,7 @@ using osu.Game.Input.Bindings; using osu.Game.Localisation; using osu.Game.Overlays; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class FilterControl { diff --git a/osu.Game/Screens/SelectV2/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs similarity index 99% rename from osu.Game/Screens/SelectV2/FilterControl.cs rename to osu.Game/Screens/Select/FilterControl.cs index 20a55e3e09..7473a21531 100644 --- a/osu.Game/Screens/SelectV2/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -25,12 +25,11 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; using osuTK; using osuTK.Input; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public sealed partial class FilterControl : OverlayContainer { diff --git a/osu.Game/Screens/SelectV2/FooterButtonMods.cs b/osu.Game/Screens/Select/FooterButtonMods.cs similarity index 99% rename from osu.Game/Screens/SelectV2/FooterButtonMods.cs rename to osu.Game/Screens/Select/FooterButtonMods.cs index 27e0ac68f9..81668cc414 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonMods.cs +++ b/osu.Game/Screens/Select/FooterButtonMods.cs @@ -30,7 +30,7 @@ using osuTK; using osuTK.Graphics; using osuTK.Input; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class FooterButtonMods : ScreenFooterButton, IHasCurrentValue> { diff --git a/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs b/osu.Game/Screens/Select/FooterButtonOptions.Popover.cs similarity index 99% rename from osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs rename to osu.Game/Screens/Select/FooterButtonOptions.Popover.cs index 2f0f36c99c..d4b7a13d9c 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs +++ b/osu.Game/Screens/Select/FooterButtonOptions.Popover.cs @@ -23,7 +23,7 @@ using osuTK; using osuTK.Graphics; using osuTK.Input; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class FooterButtonOptions { diff --git a/osu.Game/Screens/SelectV2/FooterButtonOptions.cs b/osu.Game/Screens/Select/FooterButtonOptions.cs similarity index 98% rename from osu.Game/Screens/SelectV2/FooterButtonOptions.cs rename to osu.Game/Screens/Select/FooterButtonOptions.cs index 4da40559e9..819b51aea5 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonOptions.cs +++ b/osu.Game/Screens/Select/FooterButtonOptions.cs @@ -14,7 +14,7 @@ using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Screens.Footer; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class FooterButtonOptions : ScreenFooterButton, IHasPopover { diff --git a/osu.Game/Screens/SelectV2/FooterButtonRandom.cs b/osu.Game/Screens/Select/FooterButtonRandom.cs similarity index 99% rename from osu.Game/Screens/SelectV2/FooterButtonRandom.cs rename to osu.Game/Screens/Select/FooterButtonRandom.cs index 4bd42497eb..bf001b7b8f 100644 --- a/osu.Game/Screens/SelectV2/FooterButtonRandom.cs +++ b/osu.Game/Screens/Select/FooterButtonRandom.cs @@ -15,7 +15,7 @@ using osu.Game.Screens.Footer; using osuTK; using osuTK.Input; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class FooterButtonRandom : ScreenFooterButton { diff --git a/osu.Game/Screens/SelectV2/ISongSelect.cs b/osu.Game/Screens/Select/ISongSelect.cs similarity index 98% rename from osu.Game/Screens/SelectV2/ISongSelect.cs rename to osu.Game/Screens/Select/ISongSelect.cs index 5de1d4e75e..b1c32435bf 100644 --- a/osu.Game/Screens/SelectV2/ISongSelect.cs +++ b/osu.Game/Screens/Select/ISongSelect.cs @@ -8,7 +8,7 @@ using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; using osu.Game.Scoring; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { /// /// Actions exposed by song select which are used by subcomponents to perform top-level operations. diff --git a/osu.Game/Screens/SelectV2/LeftSideInteractionContainer.cs b/osu.Game/Screens/Select/LeftSideInteractionContainer.cs similarity index 98% rename from osu.Game/Screens/SelectV2/LeftSideInteractionContainer.cs rename to osu.Game/Screens/Select/LeftSideInteractionContainer.cs index 212bb233f4..4b28213f4e 100644 --- a/osu.Game/Screens/SelectV2/LeftSideInteractionContainer.cs +++ b/osu.Game/Screens/Select/LeftSideInteractionContainer.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Input.Events; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { /// /// Handles mouse interactions required when moving away from the carousel. diff --git a/osu.Game/Screens/SelectV2/NoResultsPlaceholder.cs b/osu.Game/Screens/Select/NoResultsPlaceholder.cs similarity index 99% rename from osu.Game/Screens/SelectV2/NoResultsPlaceholder.cs rename to osu.Game/Screens/Select/NoResultsPlaceholder.cs index 597b6de851..cd38ce2f6c 100644 --- a/osu.Game/Screens/SelectV2/NoResultsPlaceholder.cs +++ b/osu.Game/Screens/Select/NoResultsPlaceholder.cs @@ -14,10 +14,9 @@ using osu.Game.Graphics.Sprites; using osu.Game.Localisation; using osu.Game.Online.Chat; using osu.Game.Overlays; -using osu.Game.Screens.Select; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class NoResultsPlaceholder : VisibilityContainer { diff --git a/osu.Game/Screens/SelectV2/Panel.cs b/osu.Game/Screens/Select/Panel.cs similarity index 99% rename from osu.Game/Screens/SelectV2/Panel.cs rename to osu.Game/Screens/Select/Panel.cs index 241002fa76..60175d0a0d 100644 --- a/osu.Game/Screens/SelectV2/Panel.cs +++ b/osu.Game/Screens/Select/Panel.cs @@ -24,7 +24,7 @@ using osu.Game.Overlays; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public abstract partial class Panel : PoolableDrawable, ICarouselPanel, IHasContextMenu { diff --git a/osu.Game/Screens/SelectV2/PanelBeatmap.cs b/osu.Game/Screens/Select/PanelBeatmap.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelBeatmap.cs rename to osu.Game/Screens/Select/PanelBeatmap.cs index 6dc2286f44..4c259a6355 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmap.cs +++ b/osu.Game/Screens/Select/PanelBeatmap.cs @@ -27,7 +27,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelBeatmap : Panel { diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs b/osu.Game/Screens/Select/PanelBeatmapSet.SpreadDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs rename to osu.Game/Screens/Select/PanelBeatmapSet.SpreadDisplay.cs index 89916b13d8..338b4036bd 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs +++ b/osu.Game/Screens/Select/PanelBeatmapSet.SpreadDisplay.cs @@ -20,7 +20,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelBeatmapSet { diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs b/osu.Game/Screens/Select/PanelBeatmapSet.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelBeatmapSet.cs rename to osu.Game/Screens/Select/PanelBeatmapSet.cs index f6a33e5ce0..5a9508a823 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs +++ b/osu.Game/Screens/Select/PanelBeatmapSet.cs @@ -32,7 +32,7 @@ using osuTK; using osuTK.Graphics; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelBeatmapSet : Panel { diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs b/osu.Game/Screens/Select/PanelBeatmapStandalone.SpreadDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs rename to osu.Game/Screens/Select/PanelBeatmapStandalone.SpreadDisplay.cs index f8f5883c99..1e4efe495c 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.SpreadDisplay.cs +++ b/osu.Game/Screens/Select/PanelBeatmapStandalone.SpreadDisplay.cs @@ -18,7 +18,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelBeatmapStandalone { diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs b/osu.Game/Screens/Select/PanelBeatmapStandalone.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs rename to osu.Game/Screens/Select/PanelBeatmapStandalone.cs index 5fc6be3d62..77cdbc356c 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs +++ b/osu.Game/Screens/Select/PanelBeatmapStandalone.cs @@ -24,7 +24,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osuTK; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelBeatmapStandalone : Panel { diff --git a/osu.Game/Screens/SelectV2/PanelGroup.cs b/osu.Game/Screens/Select/PanelGroup.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelGroup.cs rename to osu.Game/Screens/Select/PanelGroup.cs index d2ae495610..0b3fed9278 100644 --- a/osu.Game/Screens/SelectV2/PanelGroup.cs +++ b/osu.Game/Screens/Select/PanelGroup.cs @@ -22,7 +22,7 @@ using osuTK; using osuTK.Graphics; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelGroup : Panel { diff --git a/osu.Game/Screens/SelectV2/PanelGroupRankDisplay.cs b/osu.Game/Screens/Select/PanelGroupRankDisplay.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelGroupRankDisplay.cs rename to osu.Game/Screens/Select/PanelGroupRankDisplay.cs index 6895c30fee..0697e992f4 100644 --- a/osu.Game/Screens/SelectV2/PanelGroupRankDisplay.cs +++ b/osu.Game/Screens/Select/PanelGroupRankDisplay.cs @@ -23,7 +23,7 @@ using osuTK; using osuTK.Graphics; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelGroupRankDisplay : Panel { diff --git a/osu.Game/Screens/SelectV2/PanelGroupRankedStatus.cs b/osu.Game/Screens/Select/PanelGroupRankedStatus.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelGroupRankedStatus.cs rename to osu.Game/Screens/Select/PanelGroupRankedStatus.cs index ce175efcf6..fdd48a0a10 100644 --- a/osu.Game/Screens/SelectV2/PanelGroupRankedStatus.cs +++ b/osu.Game/Screens/Select/PanelGroupRankedStatus.cs @@ -22,7 +22,7 @@ using osuTK; using osuTK.Graphics; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelGroupRankedStatus : Panel { diff --git a/osu.Game/Screens/SelectV2/PanelGroupStarDifficulty.cs b/osu.Game/Screens/Select/PanelGroupStarDifficulty.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelGroupStarDifficulty.cs rename to osu.Game/Screens/Select/PanelGroupStarDifficulty.cs index e6b59334cd..1abbd44d9f 100644 --- a/osu.Game/Screens/SelectV2/PanelGroupStarDifficulty.cs +++ b/osu.Game/Screens/Select/PanelGroupStarDifficulty.cs @@ -21,7 +21,7 @@ using osuTK; using osuTK.Graphics; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelGroupStarDifficulty : Panel { diff --git a/osu.Game/Screens/SelectV2/PanelLocalRankDisplay.cs b/osu.Game/Screens/Select/PanelLocalRankDisplay.cs similarity index 98% rename from osu.Game/Screens/SelectV2/PanelLocalRankDisplay.cs rename to osu.Game/Screens/Select/PanelLocalRankDisplay.cs index c72835144f..a0fdb82a43 100644 --- a/osu.Game/Screens/SelectV2/PanelLocalRankDisplay.cs +++ b/osu.Game/Screens/Select/PanelLocalRankDisplay.cs @@ -16,7 +16,7 @@ using osu.Game.Scoring; using osuTK; using Realms; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelLocalRankDisplay : CompositeDrawable { diff --git a/osu.Game/Screens/SelectV2/PanelSetBackground.cs b/osu.Game/Screens/Select/PanelSetBackground.cs similarity index 99% rename from osu.Game/Screens/SelectV2/PanelSetBackground.cs rename to osu.Game/Screens/Select/PanelSetBackground.cs index 7f15a23b9a..b6c4be7fd6 100644 --- a/osu.Game/Screens/SelectV2/PanelSetBackground.cs +++ b/osu.Game/Screens/Select/PanelSetBackground.cs @@ -17,7 +17,7 @@ using osu.Game.Overlays; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelSetBackground : Container { diff --git a/osu.Game/Screens/SelectV2/PanelUpdateBeatmapButton.cs b/osu.Game/Screens/Select/PanelUpdateBeatmapButton.cs similarity index 98% rename from osu.Game/Screens/SelectV2/PanelUpdateBeatmapButton.cs rename to osu.Game/Screens/Select/PanelUpdateBeatmapButton.cs index e7204eefaf..fc83fa77ef 100644 --- a/osu.Game/Screens/SelectV2/PanelUpdateBeatmapButton.cs +++ b/osu.Game/Screens/Select/PanelUpdateBeatmapButton.cs @@ -18,12 +18,11 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Overlays; -using osu.Game.Screens.Select.Carousel; using osuTK; using osuTK.Graphics; using CommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class PanelUpdateBeatmapButton : OsuAnimatedButton { diff --git a/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs b/osu.Game/Screens/Select/RealmPopulatingOnlineLookupSource.cs similarity index 99% rename from osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs rename to osu.Game/Screens/Select/RealmPopulatingOnlineLookupSource.cs index 2b75820587..132a160106 100644 --- a/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs +++ b/osu.Game/Screens/Select/RealmPopulatingOnlineLookupSource.cs @@ -15,7 +15,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using Realms; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { /// /// This component is designed to perform lookups of online data diff --git a/osu.Game/Screens/SelectV2/SoloSongSelect.cs b/osu.Game/Screens/Select/SoloSongSelect.cs similarity index 98% rename from osu.Game/Screens/SelectV2/SoloSongSelect.cs rename to osu.Game/Screens/Select/SoloSongSelect.cs index cf87a3466f..270d8f326a 100644 --- a/osu.Game/Screens/SelectV2/SoloSongSelect.cs +++ b/osu.Game/Screens/Select/SoloSongSelect.cs @@ -19,12 +19,11 @@ using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Edit; using osu.Game.Screens.Play; -using osu.Game.Screens.Select; using osu.Game.Users; using osu.Game.Utils; using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { public partial class SoloSongSelect : SongSelect { diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs similarity index 99% rename from osu.Game/Screens/SelectV2/SongSelect.cs rename to osu.Game/Screens/Select/SongSelect.cs index d47155ee6b..3b29c100b2 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -50,14 +50,13 @@ using osu.Game.Screens.Footer; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select; using osu.Game.Skinning; using osu.Game.Utils; using osuTK; using osuTK.Graphics; using osuTK.Input; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { /// /// This screen is intended to house all components introduced in the new song select design to add transitions and examine the overall look. diff --git a/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs b/osu.Game/Screens/Select/UpdateLocalConfirmationDialog.cs similarity index 94% rename from osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs rename to osu.Game/Screens/Select/UpdateLocalConfirmationDialog.cs index 6157e8f6a5..3f847c6816 100644 --- a/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs +++ b/osu.Game/Screens/Select/UpdateLocalConfirmationDialog.cs @@ -3,10 +3,10 @@ using System; using osu.Framework.Graphics.Sprites; -using osu.Game.Overlays.Dialog; using osu.Game.Localisation; +using osu.Game.Overlays.Dialog; -namespace osu.Game.Screens.Select.Carousel +namespace osu.Game.Screens.Select { public partial class UpdateLocalConfirmationDialog : DangerousActionDialog { diff --git a/osu.Game/Screens/SelectV2/WedgeBackground.cs b/osu.Game/Screens/Select/WedgeBackground.cs similarity index 98% rename from osu.Game/Screens/SelectV2/WedgeBackground.cs rename to osu.Game/Screens/Select/WedgeBackground.cs index 3fa21beee2..aa1ce025bd 100644 --- a/osu.Game/Screens/SelectV2/WedgeBackground.cs +++ b/osu.Game/Screens/Select/WedgeBackground.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Overlays; -namespace osu.Game.Screens.SelectV2 +namespace osu.Game.Screens.Select { internal sealed partial class WedgeBackground : InputBlockingContainer { diff --git a/osu.Game/Screens/SelectV2/CollectionDropdown.cs b/osu.Game/Screens/SelectV2/CollectionDropdown.cs deleted file mode 100644 index 9f1950ac5f..0000000000 --- a/osu.Game/Screens/SelectV2/CollectionDropdown.cs +++ /dev/null @@ -1,256 +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 System; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Game.Beatmaps; -using osu.Game.Collections; -using osu.Game.Database; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; -using osu.Game.Graphics.UserInterfaceV2; -using osu.Game.Localisation; -using osuTK; -using Realms; - -namespace osu.Game.Screens.SelectV2 -{ - /// - /// A dropdown to select the collection to be used to filter results. - /// - public partial class CollectionDropdown : ShearedDropdown // TODO: partial class under FilterControl? - { - /// - /// Whether to show the "manage collections..." menu item in the dropdown. - /// - protected virtual bool ShowManageCollectionsItem => true; - - private readonly BindableList filters = new BindableList(); - - [Resolved] - private ManageCollectionsDialog? manageCollectionsDialog { get; set; } - - [Resolved] - private RealmAccess realm { get; set; } = null!; - - private IDisposable? realmSubscription; - - private readonly CollectionFilterMenuItem allBeatmapsItem = new AllBeatmapsCollectionFilterMenuItem(); - - public CollectionDropdown() - : base(CollectionsStrings.Collection) - { - ItemSource = filters; - - Current.Value = allBeatmapsItem; - AlwaysShowSearchBar = true; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - realmSubscription = realm.RegisterForNotifications(r => r.All().OrderBy(c => c.Name), collectionsChanged); - - Current.BindValueChanged(selectionChanged); - } - - private void collectionsChanged(IRealmCollection collections, ChangeSet? changes) - { - if (changes == null) - { - filters.Clear(); - filters.Add(allBeatmapsItem); - filters.AddRange(collections.Select(c => new CollectionFilterMenuItem(c.ToLive(realm)))); - if (ShowManageCollectionsItem) - filters.Add(new ManageCollectionsFilterMenuItem()); - } - else - { - foreach (int i in changes.DeletedIndices.OrderDescending()) - filters.RemoveAt(i + 1); - - foreach (int i in changes.InsertedIndices) - filters.Insert(i + 1, new CollectionFilterMenuItem(collections[i].ToLive(realm))); - - var selectedItem = SelectedItem?.Value; - - foreach (int i in changes.NewModifiedIndices) - { - var updatedItem = collections[i]; - - // This is responsible for updating the state of the +/- button and the collection's name. - // TODO: we can probably make the menu items update with changes to avoid this. - filters.RemoveAt(i + 1); - filters.Insert(i + 1, new CollectionFilterMenuItem(updatedItem.ToLive(realm))); - - if (updatedItem.ID == selectedItem?.Collection?.ID) - { - // This current update and schedule is required to work around dropdown headers not updating text even when the selected item - // changes. It's not great but honestly the whole dropdown menu structure isn't great. This needs to be fixed, but I'll issue - // a warning that it's going to be a frustrating journey. - Current.Value = allBeatmapsItem; - Schedule(() => - { - // current may have changed before the scheduled call is run. - if (Current.Value != allBeatmapsItem) - return; - - Current.Value = filters.SingleOrDefault(f => f.Collection?.ID == selectedItem.Collection?.ID) ?? filters[0]; - }); - - break; - } - } - } - } - - private void selectionChanged(ValueChangedEvent filter) - { - // May be null during .Clear(). - if (filter.NewValue.IsNull()) - return; - - // Never select the manage collection filter - rollback to the previous filter. - // This is done after the above since it is important that bindable is unbound from OldValue, which is lost after forcing it back to the old value. - if (filter.NewValue is ManageCollectionsFilterMenuItem) - { - Current.Value = filter.OldValue; - manageCollectionsDialog?.Show(); - } - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - realmSubscription?.Dispose(); - } - - protected override LocalisableString GenerateItemText(CollectionFilterMenuItem item) => item.CollectionName; - - protected sealed override DropdownMenu CreateMenu() => CreateCollectionMenu(); - - protected virtual ShearedCollectionDropdownMenu CreateCollectionMenu() => new ShearedCollectionDropdownMenu(); - - protected partial class ShearedCollectionDropdownMenu : ShearedDropdownMenu - { - public ShearedCollectionDropdownMenu() - { - MaxHeight = 200; - } - - protected override DrawableDropdownMenuItem CreateDrawableDropdownMenuItem(MenuItem item) => new DrawableCollectionMenuItem(item) - { - BackgroundColourHover = HoverColour, - BackgroundColourSelected = SelectionColour - }; - } - - protected partial class DrawableCollectionMenuItem : ShearedDropdownMenu.ShearedMenuItem - { - private IconButton addOrRemoveButton = null!; - - private bool beatmapInCollection; - - private readonly Live? collection; - - [Resolved] - private IBindable beatmap { get; set; } = null!; - - public DrawableCollectionMenuItem(MenuItem item) - : base(item) - { - collection = ((DropdownMenuItem)item).Value.Collection; - } - - [BackgroundDependencyLoader] - private void load() - { - AddInternal(addOrRemoveButton = new NoFocusChangeIconButton - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Shear = -OsuGame.SHEAR, - X = -OsuScrollContainer.SCROLL_BAR_WIDTH, - Scale = new Vector2(0.65f), - Action = addOrRemove, - }); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - if (collection != null) - { - beatmap.BindValueChanged(_ => - { - beatmapInCollection = collection.PerformRead(c => c.BeatmapMD5Hashes.Contains(beatmap.Value.BeatmapInfo.MD5Hash)); - - addOrRemoveButton.Enabled.Value = !beatmap.IsDefault; - addOrRemoveButton.Icon = beatmapInCollection ? FontAwesome.Solid.MinusSquare : FontAwesome.Solid.PlusSquare; - addOrRemoveButton.TooltipText = beatmapInCollection ? CollectionsStrings.RemoveSelectedBeatmap : CollectionsStrings.AddSelectedBeatmap; - - updateButtonVisibility(); - }, true); - } - - updateButtonVisibility(); - } - - protected override bool OnHover(HoverEvent e) - { - updateButtonVisibility(); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - updateButtonVisibility(); - base.OnHoverLost(e); - } - - protected override void OnSelectChange() - { - base.OnSelectChange(); - updateButtonVisibility(); - } - - private void updateButtonVisibility() - { - if (collection == null) - addOrRemoveButton.Alpha = 0; - else - addOrRemoveButton.Alpha = IsHovered || IsPreSelected || beatmapInCollection ? 1 : 0; - } - - private void addOrRemove() - { - Debug.Assert(collection != null); - - Task.Run(() => collection.PerformWrite(c => - { - if (!c.BeatmapMD5Hashes.Remove(beatmap.Value.BeatmapInfo.MD5Hash)) - c.BeatmapMD5Hashes.Add(beatmap.Value.BeatmapInfo.MD5Hash); - })); - } - - protected override Drawable CreateContent() => (Content)base.CreateContent(); - - private partial class NoFocusChangeIconButton : IconButton - { - public override bool ChangeFocusOnClick => false; - } - } - } -} diff --git a/osu.Game/Tests/Visual/EditorSavingTestScene.cs b/osu.Game/Tests/Visual/EditorSavingTestScene.cs index 8d27618c00..5a3f5c432e 100644 --- a/osu.Game/Tests/Visual/EditorSavingTestScene.cs +++ b/osu.Game/Tests/Visual/EditorSavingTestScene.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Menu; -using osu.Game.Screens.SelectV2; +using osu.Game.Screens.Select; using osuTK.Input; namespace osu.Game.Tests.Visual From a028f0ba4ae070771ae4b5d66ec7ee71222c7a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 3 Mar 2026 15:40:08 +0100 Subject: [PATCH 14/15] Fix loose spacers at top of leaderboard score context menu (#36799) Closes https://github.com/ppy/osu/issues/36777. --- osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs b/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs index 079f4192e0..1f290ca12f 100644 --- a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs +++ b/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.cs @@ -628,7 +628,9 @@ namespace osu.Game.Screens.SelectV2 if (Score.Files.Count <= 0) return items.ToArray(); - items.Add(new OsuMenuItemSpacer()); + if (items.Count > 0) + items.Add(new OsuMenuItemSpacer()); + items.Add(new OsuMenuItem(SongSelectStrings.WatchReplay, MenuItemType.Standard, () => game?.PresentScore(Score, ScorePresentType.Gameplay))); items.Add(new OsuMenuItem(CommonStrings.Export, MenuItemType.Standard, () => scoreManager.Export(Score))); items.Add(new OsuMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score)))); From 43af89f75c16b29655dcfc1c86fd6e4b68c36f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 4 Mar 2026 08:44:31 +0100 Subject: [PATCH 15/15] Remove outdated xmldoc --- osu.Game/Screens/Select/SongSelect.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 3b29c100b2..56a1476c38 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -58,10 +58,6 @@ using osuTK.Input; namespace osu.Game.Screens.Select { - /// - /// This screen is intended to house all components introduced in the new song select design to add transitions and examine the overall look. - /// This will be gradually built upon and ultimately replace once everything is in place. - /// public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler, ISongSelect, IHandlePresentBeatmap, IProvideCursor { ///