diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchSection.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchSection.cs new file mode 100644 index 0000000000..1d8db71527 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchSection.cs @@ -0,0 +1,90 @@ +// 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 NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; +using osu.Game.Overlays.BeatmapListing; +using osuTK; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneBeatmapListingSearchSection : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(BeatmapListingSearchSection), + }; + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + private readonly BeatmapListingSearchSection section; + + public TestSceneBeatmapListingSearchSection() + { + OsuSpriteText query; + OsuSpriteText ruleset; + OsuSpriteText category; + + Add(section = new BeatmapListingSearchSection + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + + Add(new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 5), + Children = new Drawable[] + { + query = new OsuSpriteText(), + ruleset = new OsuSpriteText(), + category = new OsuSpriteText(), + } + }); + + section.Query.BindValueChanged(q => query.Text = $"Query: {q.NewValue}", true); + section.Ruleset.BindValueChanged(r => ruleset.Text = $"Ruleset: {r.NewValue}", true); + section.Category.BindValueChanged(c => category.Text = $"Category: {c.NewValue}", true); + } + + [Test] + public void TestCovers() + { + AddStep("Set beatmap", () => section.BeatmapSet = beatmap_set); + AddStep("Set beatmap (no cover)", () => section.BeatmapSet = no_cover_beatmap_set); + AddStep("Set null beatmap", () => section.BeatmapSet = null); + } + + private static readonly BeatmapSetInfo beatmap_set = new BeatmapSetInfo + { + OnlineInfo = new BeatmapSetOnlineInfo + { + Covers = new BeatmapSetOnlineCovers + { + Cover = "https://assets.ppy.sh/beatmaps/1094296/covers/cover@2x.jpg?1581416305" + } + } + }; + + private static readonly BeatmapSetInfo no_cover_beatmap_set = new BeatmapSetInfo + { + OnlineInfo = new BeatmapSetOnlineInfo + { + Covers = new BeatmapSetOnlineCovers + { + Cover = string.Empty + } + } + }; + } +} diff --git a/osu.Game/Graphics/UserInterface/SearchTextBox.cs b/osu.Game/Graphics/UserInterface/SearchTextBox.cs index fe8756a4d2..fe92054d25 100644 --- a/osu.Game/Graphics/UserInterface/SearchTextBox.cs +++ b/osu.Game/Graphics/UserInterface/SearchTextBox.cs @@ -17,18 +17,16 @@ namespace osu.Game.Graphics.UserInterface public SearchTextBox() { Height = 35; - AddRange(new Drawable[] + Add(new SpriteIcon { - new SpriteIcon - { - Icon = FontAwesome.Solid.Search, - Origin = Anchor.CentreRight, - Anchor = Anchor.CentreRight, - Margin = new MarginPadding { Right = 10 }, - Size = new Vector2(20), - } + Icon = FontAwesome.Solid.Search, + Origin = Anchor.CentreRight, + Anchor = Anchor.CentreRight, + Margin = new MarginPadding { Right = 10 }, + Size = new Vector2(20), }); + TextFlow.Padding = new MarginPadding { Right = 35 }; PlaceholderText = "type to search"; } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchSection.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchSection.cs new file mode 100644 index 0000000000..f47144e5d8 --- /dev/null +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchSection.cs @@ -0,0 +1,125 @@ +// 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.Game.Online.API.Requests; +using osu.Game.Rulesets; +using osuTK; +using osu.Framework.Bindables; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Beatmaps; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osuTK.Graphics; + +namespace osu.Game.Overlays.BeatmapListing +{ + public class BeatmapListingSearchSection : CompositeDrawable + { + public Bindable Query => textBox.Current; + + public Bindable Ruleset => modeFilter.Current; + + public Bindable Category => categoryFilter.Current; + + public BeatmapSetInfo BeatmapSet + { + set + { + if (value == null || string.IsNullOrEmpty(value.OnlineInfo.Covers.Cover)) + { + beatmapCover.FadeOut(600, Easing.OutQuint); + return; + } + + beatmapCover.BeatmapSet = value; + beatmapCover.FadeTo(0.1f, 200, Easing.OutQuint); + } + } + + private readonly BeatmapSearchTextBox textBox; + private readonly BeatmapSearchRulesetFilterRow modeFilter; + private readonly BeatmapSearchFilterRow categoryFilter; + + private readonly Box background; + private readonly UpdateableBeatmapSetCover beatmapCover; + + public BeatmapListingSearchSection() + { + AutoSizeAxes = Axes.Y; + RelativeSizeAxes = Axes.X; + AddRangeInternal(new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Child = beatmapCover = new UpdateableBeatmapSetCover + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + } + }, + new Container + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Padding = new MarginPadding + { + Vertical = 20, + Horizontal = 40, + }, + Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Children = new Drawable[] + { + textBox = new BeatmapSearchTextBox + { + RelativeSizeAxes = Axes.X, + }, + new ReverseChildIDFillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Padding = new MarginPadding { Horizontal = 10 }, + Children = new Drawable[] + { + modeFilter = new BeatmapSearchRulesetFilterRow(), + categoryFilter = new BeatmapSearchFilterRow(@"Categories"), + } + } + } + } + } + }); + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + background.Colour = colourProvider.Dark6; + } + + private class BeatmapSearchTextBox : SearchTextBox + { + protected override Color4 SelectionColour => Color4.Gray; + + public BeatmapSearchTextBox() + { + PlaceholderText = @"type in keywords..."; + } + } + } +} diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 8cafbc694a..de2f916946 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -26,8 +26,9 @@ namespace osu.Game.Overlays.Music private TextFlowContainer text; private IEnumerable titleSprites; - private ILocalisedBindableString titleBind; - private ILocalisedBindableString artistBind; + + private ILocalisedBindableString title; + private ILocalisedBindableString artist; private Color4 selectedColour; private Color4 artistColour; @@ -47,24 +48,24 @@ namespace osu.Game.Overlays.Music artistColour = colours.Gray9; HandleColour = colours.Gray5; - titleBind = localisation.GetLocalisedString(new LocalisedString((Model.Metadata.TitleUnicode, Model.Metadata.Title))); - artistBind = localisation.GetLocalisedString(new LocalisedString((Model.Metadata.ArtistUnicode, Model.Metadata.Artist))); + title = localisation.GetLocalisedString(new LocalisedString((Model.Metadata.TitleUnicode, Model.Metadata.Title))); + artist = localisation.GetLocalisedString(new LocalisedString((Model.Metadata.ArtistUnicode, Model.Metadata.Artist))); } protected override void LoadComplete() { base.LoadComplete(); + artist.BindValueChanged(_ => recreateText(), true); + SelectedSet.BindValueChanged(set => { - if (set.OldValue != Model && set.NewValue != Model) + if (set.OldValue?.Equals(Model) != true && set.NewValue?.Equals(Model) != true) return; foreach (Drawable s in titleSprites) - s.FadeColour(set.NewValue == Model ? selectedColour : Color4.White, FADE_DURATION); + s.FadeColour(set.NewValue.Equals(Model) ? selectedColour : Color4.White, FADE_DURATION); }, true); - - artistBind.BindValueChanged(_ => recreateText(), true); } protected override Drawable CreateContent() => text = new OsuTextFlowContainer @@ -78,9 +79,9 @@ namespace osu.Game.Overlays.Music text.Clear(); //space after the title to put a space between the title and artist - titleSprites = text.AddText(titleBind.Value + @" ", sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular)).OfType(); + titleSprites = text.AddText(title.Value + @" ", sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular)).OfType(); - text.AddText(artistBind.Value, sprite => + text.AddText(artist.Value, sprite => { sprite.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold); sprite.Colour = artistColour; diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index 2674b3a81e..a89360bd3c 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -11,23 +11,21 @@ namespace osu.Game.Overlays.Rankings { public class RankingsOverlayHeader : TabControlOverlayHeader { - public readonly Bindable Ruleset = new Bindable(); - public readonly Bindable Country = new Bindable(); + public Bindable Ruleset => rulesetSelector.Current; + + public Bindable Country => countryFilter.Current; + + private OverlayRulesetSelector rulesetSelector; + private CountryFilter countryFilter; protected override ScreenTitle CreateTitle() => new RankingsTitle { Scope = { BindTarget = Current } }; - protected override Drawable CreateTitleContent() => new OverlayRulesetSelector - { - Current = Ruleset - }; + protected override Drawable CreateTitleContent() => rulesetSelector = new OverlayRulesetSelector(); - protected override Drawable CreateContent() => new CountryFilter - { - Current = Country - }; + protected override Drawable CreateContent() => countryFilter = new CountryFilter(); private class RankingsTitle : ScreenTitle { diff --git a/osu.Game/Overlays/RankingsOverlay.cs b/osu.Game/Overlays/RankingsOverlay.cs index f3215d07fa..2c5ea61315 100644 --- a/osu.Game/Overlays/RankingsOverlay.cs +++ b/osu.Game/Overlays/RankingsOverlay.cs @@ -19,14 +19,17 @@ namespace osu.Game.Overlays { public class RankingsOverlay : FullscreenOverlay { - protected readonly Bindable Country = new Bindable(); - protected readonly Bindable Scope = new Bindable(); - private readonly Bindable ruleset = new Bindable(); + protected Bindable Country => header.Country; + + protected Bindable Scope => header.Current; + + private Bindable ruleset => header.Ruleset; private readonly BasicScrollContainer scrollFlow; private readonly Container contentContainer; private readonly DimmedLoadingLayer loading; private readonly Box background; + private readonly RankingsOverlayHeader header; private APIRequest lastRequest; private CancellationTokenSource cancellationToken; @@ -54,14 +57,11 @@ namespace osu.Game.Overlays Direction = FillDirection.Vertical, Children = new Drawable[] { - new RankingsOverlayHeader + header = new RankingsOverlayHeader { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Depth = -float.MaxValue, - Country = { BindTarget = Country }, - Current = { BindTarget = Scope }, - Ruleset = { BindTarget = ruleset } + Depth = -float.MaxValue }, new Container { @@ -94,6 +94,8 @@ namespace osu.Game.Overlays protected override void LoadComplete() { + base.LoadComplete(); + Country.BindValueChanged(_ => { // if a country is requested, force performance scope. @@ -101,7 +103,7 @@ namespace osu.Game.Overlays Scope.Value = RankingsScope.Performance; Scheduler.AddOnce(loadNewContent); - }, true); + }); Scope.BindValueChanged(_ => { @@ -110,7 +112,7 @@ namespace osu.Game.Overlays Country.Value = null; Scheduler.AddOnce(loadNewContent); - }, true); + }); ruleset.BindValueChanged(_ => { @@ -118,9 +120,7 @@ namespace osu.Game.Overlays return; Scheduler.AddOnce(loadNewContent); - }, true); - - base.LoadComplete(); + }); } public void ShowCountry(Country requested) @@ -158,8 +158,8 @@ namespace osu.Game.Overlays return; } - request.Success += () => loadContent(createTableFromResponse(request)); - request.Failure += _ => loadContent(null); + request.Success += () => Schedule(() => loadContent(createTableFromResponse(request))); + request.Failure += _ => Schedule(() => loadContent(null)); api.Queue(request); } @@ -221,5 +221,13 @@ namespace osu.Game.Overlays contentContainer.Child = loaded; }, (cancellationToken = new CancellationTokenSource()).Token); } + + protected override void Dispose(bool isDisposing) + { + lastRequest?.Cancel(); + cancellationToken?.Cancel(); + + base.Dispose(isDisposing); + } } }