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:
parent
7814b2df14
commit
b4b2f12116
@ -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,
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user