1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 16:19:35 +08:00

Add support for adding/removing items

Tests accompany of course
This commit is contained in:
Dean Herbert 2017-12-14 16:59:08 +09:00
parent 7814b2df14
commit b4b2f12116
3 changed files with 66 additions and 50 deletions

View File

@ -141,7 +141,7 @@ namespace osu.Game.Tests.Visual
}); });
void ensureRandomDidntRepeat() => void ensureRandomDidntRepeat() =>
AddAssert("ensure no repeats", () => selectedSets.Distinct().Count() == selectedSets.Count()); AddAssert("ensure no repeats", () => selectedSets.Distinct().Count() == selectedSets.Count);
void prevRandom() => AddStep("select random last", () => void prevRandom() => AddStep("select random last", () =>
{ {
@ -153,6 +153,7 @@ namespace osu.Game.Tests.Visual
AddAssert("ensure prev random fetch worked", () => selectedSets.Peek() == carousel.SelectedBeatmapSet); AddAssert("ensure prev random fetch worked", () => selectedSets.Peek() == carousel.SelectedBeatmapSet);
setSelected(1, 1); setSelected(1, 1);
nextRandom(); nextRandom();
ensureRandomDidntRepeat(); ensureRandomDidntRepeat();
nextRandom(); nextRandom();
@ -172,29 +173,44 @@ namespace osu.Game.Tests.Visual
nextRandom(); nextRandom();
AddAssert("ensure repeat", () => selectedSets.Contains(carousel.SelectedBeatmapSet)); AddAssert("ensure repeat", () => selectedSets.Contains(carousel.SelectedBeatmapSet));
// test adding and removing
AddStep("Add new set #5", () => carousel.UpdateBeatmapSet(createTestBeatmapSet(5)));
AddStep("Add new set #6", () => carousel.UpdateBeatmapSet(createTestBeatmapSet(6)));
checkVisibleItemCount(false, 6);
AddStep("Remove set #4", () => carousel.RemoveBeatmapSet(createTestBeatmapSet(4)));
checkVisibleItemCount(false, 5);
} }
private BeatmapSetInfo createTestBeatmapSet(int i) private BeatmapSetInfo createTestBeatmapSet(int i)
{ {
return new BeatmapSetInfo return new BeatmapSetInfo
{ {
OnlineBeatmapSetID = 1234 + i, ID = i,
OnlineBeatmapSetID = i,
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
{ {
OnlineBeatmapSetID = 1234 + i, OnlineBeatmapSetID = i,
// Create random metadata, then we can check if sorting works based on these // Create random metadata, then we can check if sorting works based on these
Artist = "peppy", Artist = "peppy",
Title = "test set #" + i, Title = "test set #" + i,
AuthorString = "peppy" AuthorString = "peppy",
}, },
Beatmaps = new List<BeatmapInfo>(new[] Beatmaps = new List<BeatmapInfo>(new[]
{ {
new BeatmapInfo new BeatmapInfo
{ {
OnlineBeatmapID = 1234 + i, OnlineBeatmapID = i * 10,
Path = "normal.osu", Path = "normal.osu",
Version = "Normal", Version = "Normal",
StarDifficulty = 2,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {
OverallDifficulty = 3.5f, OverallDifficulty = 3.5f,
@ -202,9 +218,10 @@ namespace osu.Game.Tests.Visual
}, },
new BeatmapInfo new BeatmapInfo
{ {
OnlineBeatmapID = 1235 + i, OnlineBeatmapID = i * 10 + 1,
Path = "hard.osu", Path = "hard.osu",
Version = "Hard", Version = "Hard",
StarDifficulty = 5,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {
OverallDifficulty = 5, OverallDifficulty = 5,
@ -212,9 +229,10 @@ namespace osu.Game.Tests.Visual
}, },
new BeatmapInfo new BeatmapInfo
{ {
OnlineBeatmapID = 1236 + i, OnlineBeatmapID = i * 10 + 2,
Path = "insane.osu", Path = "insane.osu",
Version = "Insane", Version = "Insane",
StarDifficulty = 6,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {
OverallDifficulty = 7, OverallDifficulty = 7,

View File

@ -71,22 +71,31 @@ namespace osu.Game.Screens.Select
Task.Run(() => Task.Run(() =>
{ {
newSets = value.Select(createGroup).Where(g => g != null).ToList(); newSets = value.Select(createCarouselSet).Where(g => g != null).ToList();
newSets.ForEach(g => g.Filter(criteria)); newSets.ForEach(g => g.Filter(criteria));
}).ContinueWith(t => }).ContinueWith(t =>
{ {
Schedule(() => Schedule(() =>
{ {
beatmapSets.AddRange(newSets); beatmapSets.AddRange(newSets);
updateItems();
});
});
}
}
root = new CarouselGroup(newSets.OfType<CarouselItem>().ToList()); /// <summary>
/// Call after altering <see cref="BeatmapSets"/> in any way.
/// </summary>
private void updateItems()
{
scrollableContent.Clear(false);
root = new CarouselGroup(beatmapSets.OfType<CarouselItem>().ToList());
Items = root.Drawables.Value.ToList(); Items = root.Drawables.Value.ToList();
yPositionsCache.Invalidate(); yPositionsCache.Invalidate();
BeatmapSetsChanged?.Invoke(); BeatmapSetsChanged?.Invoke();
});
});
}
} }
private readonly List<float> yPositions = new List<float>(); private readonly List<float> yPositions = new List<float>();
@ -94,16 +103,13 @@ namespace osu.Game.Screens.Select
private readonly Container<DrawableCarouselItem> scrollableContent; private readonly Container<DrawableCarouselItem> scrollableContent;
public Bindable<RandomSelectAlgorithm> RandomAlgorithm = new Bindable<RandomSelectAlgorithm>(); public Bindable<RandomSelectAlgorithm> RandomAlgorithm = new Bindable<RandomSelectAlgorithm>();
private readonly List<CarouselBeatmapSet> previouslyVisitedRandomSets = new List<CarouselBeatmapSet>(); private readonly List<CarouselBeatmapSet> previouslyVisitedRandomSets = new List<CarouselBeatmapSet>();
private readonly Stack<CarouselBeatmap> randomSelectedBeatmaps = new Stack<CarouselBeatmap>();
protected List<DrawableCarouselItem> Items = new List<DrawableCarouselItem>(); protected List<DrawableCarouselItem> Items = new List<DrawableCarouselItem>();
private CarouselGroup root = new CarouselGroup(); private CarouselGroup root = new CarouselGroup();
private readonly Stack<CarouselBeatmap> randomSelectedBeatmaps = new Stack<CarouselBeatmap>();
public BeatmapCarousel() public BeatmapCarousel()
{ {
Child = new OsuContextMenuContainer Child = new OsuContextMenuContainer
@ -119,19 +125,28 @@ namespace osu.Game.Screens.Select
public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet)
{ {
Schedule(() => removeBeatmapSet(beatmapSets.Find(b => b.BeatmapSet.ID == beatmapSet.ID))); var existingSet = beatmapSets.Find(b => b.BeatmapSet.ID == beatmapSet.ID);
if (existingSet == null)
return;
beatmapSets.Remove(existingSet);
updateItems();
if (existingSet.State == CarouselItemState.Selected)
SelectNext();
} }
public void UpdateBeatmapSet(BeatmapSetInfo beatmapSet) public void UpdateBeatmapSet(BeatmapSetInfo beatmapSet)
{ {
// todo: this method should be smarter as to not recreate items that haven't changed, etc. CarouselBeatmapSet existingSet = beatmapSets.Find(b => b.BeatmapSet.ID == beatmapSet.ID);
var oldGroup = beatmapSets.Find(b => b.BeatmapSet.ID == beatmapSet.ID);
bool hadSelection = oldGroup?.State == CarouselItemState.Selected; bool hadSelection = existingSet?.State?.Value == CarouselItemState.Selected;
var newSet = createGroup(beatmapSet); var newSet = createCarouselSet(beatmapSet);
int index = beatmapSets.IndexOf(oldGroup); int index = beatmapSets.IndexOf(existingSet);
if (index >= 0) if (index >= 0)
beatmapSets.RemoveAt(index); beatmapSets.RemoveAt(index);
@ -139,8 +154,8 @@ namespace osu.Game.Screens.Select
{ {
if (index >= 0) if (index >= 0)
beatmapSets.Insert(index, newSet); beatmapSets.Insert(index, newSet);
//else else
// addBeatmapSet(newSet); beatmapSets.Add(newSet);
} }
if (hadSelection && newSet == null) if (hadSelection && newSet == null)
@ -154,10 +169,12 @@ namespace osu.Game.Screens.Select
var newSelection = newSet.Beatmaps.Find(b => b.Beatmap.ID == selectedBeatmap?.Beatmap.ID); var newSelection = newSet.Beatmaps.Find(b => b.Beatmap.ID == selectedBeatmap?.Beatmap.ID);
if (newSelection == null && selectedBeatmap != null) if (newSelection == null && selectedBeatmap != null)
newSelection = newSet.Beatmaps[Math.Min(newSet.Beatmaps.Count - 1, oldGroup.Beatmaps.IndexOf(selectedBeatmap))]; newSelection = newSet.Beatmaps[Math.Min(newSet.Beatmaps.Count - 1, existingSet.Beatmaps.IndexOf(selectedBeatmap))];
select(newSelection); select(newSelection);
} }
updateItems();
} }
public void SelectBeatmap(BeatmapInfo beatmap, bool animated = true) public void SelectBeatmap(BeatmapInfo beatmap, bool animated = true)
@ -252,11 +269,11 @@ namespace osu.Game.Screens.Select
notYetVisitedSets = visible; notYetVisitedSets = visible;
} }
set = notYetVisitedSets.ElementAt(RNG.Next(notYetVisitedSets.Count())); set = notYetVisitedSets.ElementAt(RNG.Next(notYetVisitedSets.Count));
previouslyVisitedRandomSets.Add(set); previouslyVisitedRandomSets.Add(set);
} }
else else
set = visible.ElementAt(RNG.Next(visible.Count())); set = visible.ElementAt(RNG.Next(visible.Count));
select(set.Beatmaps[RNG.Next(set.Beatmaps.Count)]); select(set.Beatmaps[RNG.Next(set.Beatmaps.Count)]);
} }
@ -337,7 +354,7 @@ namespace osu.Game.Screens.Select
ScrollTo(selectedY, animated); ScrollTo(selectedY, animated);
} }
private CarouselBeatmapSet createGroup(BeatmapSetInfo beatmapSet) private CarouselBeatmapSet createCarouselSet(BeatmapSetInfo beatmapSet)
{ {
if (beatmapSet.Beatmaps.All(b => b.Hidden)) if (beatmapSet.Beatmaps.All(b => b.Hidden))
return null; return null;
@ -373,25 +390,6 @@ namespace osu.Game.Screens.Select
config.BindWith(OsuSetting.RandomSelectAlgorithm, RandomAlgorithm); config.BindWith(OsuSetting.RandomSelectAlgorithm, RandomAlgorithm);
} }
private void removeBeatmapSet(CarouselBeatmapSet set)
{
if (set == null)
return;
beatmapSets.Remove(set);
foreach (var d in set.Drawables.Value)
{
Items.Remove(d);
scrollableContent.Remove(d);
}
if (set.State == CarouselItemState.Selected)
SelectNext();
yPositionsCache.Invalidate();
}
/// <summary> /// <summary>
/// Computes the target Y positions for every item in the carousel. /// Computes the target Y positions for every item in the carousel.
/// </summary> /// </summary>

View File

@ -52,7 +52,7 @@ namespace osu.Game.Screens.Select.Carousel
new PanelBackground(manager.GetWorkingBeatmap(beatmapSet.Beatmaps.FirstOrDefault())) new PanelBackground(manager.GetWorkingBeatmap(beatmapSet.Beatmaps.FirstOrDefault()))
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), OnLoadComplete = d => d.FadeInFromZero(1000, Easing.OutQuint),
}, 300 }, 300
), ),
new FillFlowContainer new FillFlowContainer