mirror of
https://github.com/ppy/osu.git
synced 2025-01-31 14:25:10 +08:00
Merge pull request #31632 from peppy/beatmap-carousel-v2-cleanups
Initial carousel additions in preparation for selection logic
This commit is contained in:
commit
beaadfa1fa
@ -16,6 +16,7 @@ using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Screens.Select.Filter;
|
||||
@ -117,12 +118,11 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
}
|
||||
}
|
||||
},
|
||||
stats = new OsuTextFlowContainer(cp => cp.Font = FrameworkFont.Regular.With())
|
||||
stats = new OsuTextFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding(10),
|
||||
TextAnchor = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
},
|
||||
};
|
||||
});
|
||||
@ -258,16 +258,29 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
if (carousel.IsNull())
|
||||
return;
|
||||
|
||||
stats.Text = $"""
|
||||
store
|
||||
sets: {beatmapSets.Count}
|
||||
beatmaps: {beatmapCount}
|
||||
carousel:
|
||||
sorting: {carousel.IsFiltering}
|
||||
tracked: {carousel.ItemsTracked}
|
||||
displayable: {carousel.DisplayableItems}
|
||||
displayed: {carousel.VisibleItems}
|
||||
""";
|
||||
stats.Clear();
|
||||
createHeader("beatmap store");
|
||||
stats.AddParagraph($"""
|
||||
sets: {beatmapSets.Count}
|
||||
beatmaps: {beatmapCount}
|
||||
""");
|
||||
createHeader("carousel");
|
||||
stats.AddParagraph($"""
|
||||
sorting: {carousel.IsFiltering}
|
||||
tracked: {carousel.ItemsTracked}
|
||||
displayable: {carousel.DisplayableItems}
|
||||
displayed: {carousel.VisibleItems}
|
||||
selected: {carousel.CurrentSelection}
|
||||
""");
|
||||
|
||||
void createHeader(string text)
|
||||
{
|
||||
stats.AddParagraph(string.Empty);
|
||||
stats.AddParagraph(text, cp =>
|
||||
{
|
||||
cp.Font = cp.Font.With(size: 18, weight: FontWeight.Bold);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -14,7 +13,6 @@ using osu.Framework.Graphics.Pooling;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Screens.Select;
|
||||
|
||||
namespace osu.Game.Screens.SelectV2
|
||||
@ -93,14 +91,8 @@ namespace osu.Game.Screens.SelectV2
|
||||
public void Filter(FilterCriteria criteria)
|
||||
{
|
||||
Criteria = criteria;
|
||||
FilterAsync().FireAndForget();
|
||||
}
|
||||
|
||||
protected override async Task FilterAsync()
|
||||
{
|
||||
loading.Show();
|
||||
await base.FilterAsync().ConfigureAwait(true);
|
||||
loading.Hide();
|
||||
FilterAsync().ContinueWith(_ => Schedule(() => loading.Hide()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,10 +30,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
/// </summary>
|
||||
public abstract partial class Carousel<T> : CompositeDrawable
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection of filters which should be run each time a <see cref="FilterAsync"/> is executed.
|
||||
/// </summary>
|
||||
protected IEnumerable<ICarouselFilter> Filters { get; init; } = Enumerable.Empty<ICarouselFilter>();
|
||||
#region Properties and methods for external usage
|
||||
|
||||
/// <summary>
|
||||
/// Height of the area above the carousel that should be treated as visible due to transparency of elements in front of it.
|
||||
@ -75,22 +72,13 @@ namespace osu.Game.Screens.SelectV2
|
||||
/// <summary>
|
||||
/// The number of carousel items currently in rotation for display.
|
||||
/// </summary>
|
||||
public int DisplayableItems => displayedCarouselItems?.Count ?? 0;
|
||||
public int DisplayableItems => carouselItems?.Count ?? 0;
|
||||
|
||||
/// <summary>
|
||||
/// The number of items currently actualised into drawables.
|
||||
/// </summary>
|
||||
public int VisibleItems => scroll.Panels.Count;
|
||||
|
||||
/// <summary>
|
||||
/// All items which are to be considered for display in this carousel.
|
||||
/// Mutating this list will automatically queue a <see cref="FilterAsync"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that an <see cref="ICarouselFilter"/> may add new items which are displayed but not tracked in this list.
|
||||
/// </remarks>
|
||||
protected readonly BindableList<T> Items = new BindableList<T>();
|
||||
|
||||
/// <summary>
|
||||
/// The currently selected model.
|
||||
/// </summary>
|
||||
@ -114,20 +102,31 @@ namespace osu.Game.Screens.SelectV2
|
||||
}
|
||||
}
|
||||
|
||||
private List<CarouselItem>? displayedCarouselItems;
|
||||
#endregion
|
||||
|
||||
private readonly CarouselScrollContainer scroll;
|
||||
#region Properties and methods concerning implementations
|
||||
|
||||
protected Carousel()
|
||||
{
|
||||
InternalChild = scroll = new CarouselScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = false,
|
||||
};
|
||||
/// <summary>
|
||||
/// A collection of filters which should be run each time a <see cref="FilterAsync"/> is executed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Implementations should add all required filters as part of their initialisation.
|
||||
///
|
||||
/// Importantly, each filter is sequentially run in the order provided.
|
||||
/// Each filter receives the output of the previous filter.
|
||||
///
|
||||
/// A filter may add, mutate or remove items.
|
||||
/// </remarks>
|
||||
protected IEnumerable<ICarouselFilter> Filters { get; init; } = Enumerable.Empty<ICarouselFilter>();
|
||||
|
||||
Items.BindCollectionChanged((_, _) => FilterAsync());
|
||||
}
|
||||
/// <summary>
|
||||
/// All items which are to be considered for display in this carousel.
|
||||
/// Mutating this list will automatically queue a <see cref="FilterAsync"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that an <see cref="ICarouselFilter"/> may add new items which are displayed but not tracked in this list.
|
||||
/// </remarks>
|
||||
protected readonly BindableList<T> Items = new BindableList<T>();
|
||||
|
||||
/// <summary>
|
||||
/// Queue an asynchronous filter operation.
|
||||
@ -151,8 +150,29 @@ namespace osu.Game.Screens.SelectV2
|
||||
/// <returns>A <see cref="CarouselItem"/> representing the model.</returns>
|
||||
protected abstract CarouselItem CreateCarouselItemForModel(T model);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Initialisation
|
||||
|
||||
private readonly CarouselScrollContainer scroll;
|
||||
|
||||
protected Carousel()
|
||||
{
|
||||
InternalChild = scroll = new CarouselScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = false,
|
||||
};
|
||||
|
||||
Items.BindCollectionChanged((_, _) => FilterAsync());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Filtering and display preparation
|
||||
|
||||
private List<CarouselItem>? carouselItems;
|
||||
|
||||
private Task filterTask = Task.CompletedTask;
|
||||
private CancellationTokenSource cancellationSource = new CancellationTokenSource();
|
||||
|
||||
@ -202,7 +222,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
return;
|
||||
|
||||
log("Items ready for display");
|
||||
displayedCarouselItems = items.ToList();
|
||||
carouselItems = items.ToList();
|
||||
displayedRange = null;
|
||||
|
||||
updateSelection();
|
||||
@ -233,9 +253,9 @@ namespace osu.Game.Screens.SelectV2
|
||||
{
|
||||
currentSelectionCarouselItem = null;
|
||||
|
||||
if (displayedCarouselItems == null) return;
|
||||
if (carouselItems == null) return;
|
||||
|
||||
foreach (var item in displayedCarouselItems)
|
||||
foreach (var item in carouselItems)
|
||||
{
|
||||
bool isSelected = item.Model == currentSelection;
|
||||
|
||||
@ -286,7 +306,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (displayedCarouselItems == null)
|
||||
if (carouselItems == null)
|
||||
return;
|
||||
|
||||
var range = getDisplayRange();
|
||||
@ -336,15 +356,15 @@ namespace osu.Game.Screens.SelectV2
|
||||
|
||||
private DisplayRange getDisplayRange()
|
||||
{
|
||||
Debug.Assert(displayedCarouselItems != null);
|
||||
Debug.Assert(carouselItems != null);
|
||||
|
||||
// Find index range of all items that should be on-screen
|
||||
carouselBoundsItem.CarouselYPosition = visibleUpperBound - DistanceOffscreenToPreload;
|
||||
int firstIndex = displayedCarouselItems.BinarySearch(carouselBoundsItem);
|
||||
int firstIndex = carouselItems.BinarySearch(carouselBoundsItem);
|
||||
if (firstIndex < 0) firstIndex = ~firstIndex;
|
||||
|
||||
carouselBoundsItem.CarouselYPosition = visibleBottomBound + DistanceOffscreenToPreload;
|
||||
int lastIndex = displayedCarouselItems.BinarySearch(carouselBoundsItem);
|
||||
int lastIndex = carouselItems.BinarySearch(carouselBoundsItem);
|
||||
if (lastIndex < 0) lastIndex = ~lastIndex;
|
||||
|
||||
firstIndex = Math.Max(0, firstIndex - 1);
|
||||
@ -355,11 +375,11 @@ namespace osu.Game.Screens.SelectV2
|
||||
|
||||
private void updateDisplayedRange(DisplayRange range)
|
||||
{
|
||||
Debug.Assert(displayedCarouselItems != null);
|
||||
Debug.Assert(carouselItems != null);
|
||||
|
||||
List<CarouselItem> toDisplay = range.Last - range.First == 0
|
||||
? new List<CarouselItem>()
|
||||
: displayedCarouselItems.GetRange(range.First, range.Last - range.First + 1);
|
||||
: carouselItems.GetRange(range.First, range.Last - range.First + 1);
|
||||
|
||||
// Iterate over all panels which are already displayed and figure which need to be displayed / removed.
|
||||
foreach (var panel in scroll.Panels)
|
||||
@ -395,9 +415,9 @@ namespace osu.Game.Screens.SelectV2
|
||||
|
||||
// Update the total height of all items (to make the scroll container scrollable through the full height even though
|
||||
// most items are not displayed / loaded).
|
||||
if (displayedCarouselItems.Count > 0)
|
||||
if (carouselItems.Count > 0)
|
||||
{
|
||||
var lastItem = displayedCarouselItems[^1];
|
||||
var lastItem = carouselItems[^1];
|
||||
scroll.SetLayoutHeight((float)(lastItem.CarouselYPosition + lastItem.DrawHeight + visibleHalfHeight));
|
||||
}
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user