Skip to content

Commit

Permalink
Merge pull request #30320 from smoogipoo/refactor-bat-component
Browse files Browse the repository at this point in the history
Refactor `BeatmapAttributeText` to compute values on the fly
  • Loading branch information
bdach authored Oct 18, 2024
2 parents 2ef5fa3 + 8e01020 commit 6576131
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 53 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. 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.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Models;
using osu.Game.Rulesets.Osu;
using osu.Game.Skinning.Components;
using osu.Game.Tests.Beatmaps;

namespace osu.Game.Tests.Visual.UserInterface
{
public partial class TestSceneBeatmapAttributeText : OsuTestScene
{
private readonly BeatmapAttributeText text;

public TestSceneBeatmapAttributeText()
{
Child = text = new BeatmapAttributeText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
};
}

[SetUp]
public void Setup() => Schedule(() =>
{
Beatmap.Value = CreateWorkingBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo)
{
BeatmapInfo =
{
BPM = 100,
DifficultyName = "_Difficulty",
Status = BeatmapOnlineStatus.Loved,
Metadata =
{
Title = "_Title",
TitleUnicode = "_Title",
Artist = "_Artist",
ArtistUnicode = "_Artist",
Author = new RealmUser { Username = "_Creator" },
Source = "_Source",
},
Difficulty =
{
CircleSize = 1,
DrainRate = 2,
OverallDifficulty = 3,
ApproachRate = 4,
}
}
});
});

[TestCase(BeatmapAttribute.CircleSize, "Circle Size: 1.00")]
[TestCase(BeatmapAttribute.HPDrain, "HP Drain: 2.00")]
[TestCase(BeatmapAttribute.Accuracy, "Accuracy: 3.00")]
[TestCase(BeatmapAttribute.ApproachRate, "Approach Rate: 4.00")]
[TestCase(BeatmapAttribute.Title, "Title: _Title")]
[TestCase(BeatmapAttribute.Artist, "Artist: _Artist")]
[TestCase(BeatmapAttribute.Creator, "Creator: _Creator")]
[TestCase(BeatmapAttribute.DifficultyName, "Difficulty: _Difficulty")]
[TestCase(BeatmapAttribute.Source, "Source: _Source")]
[TestCase(BeatmapAttribute.RankedStatus, "Beatmap Status: Loved")]
public void TestAttributeDisplay(BeatmapAttribute attribute, string expectedText)
{
AddStep($"set attribute: {attribute}", () => text.Attribute.Value = attribute);
AddAssert("check correct text", getText, () => Is.EqualTo(expectedText));
}

[Test]
public void TestChangeBeatmap()
{
AddStep("set title attribute", () => text.Attribute.Value = BeatmapAttribute.Title);
AddAssert("check initial title", getText, () => Is.EqualTo("Title: _Title"));

AddStep("change to beatmap with another title", () => Beatmap.Value = CreateWorkingBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo)
{
BeatmapInfo =
{
Metadata =
{
Title = "Another"
}
}
}));

AddAssert("check new title", getText, () => Is.EqualTo("Title: Another"));
}

private string getText() => text.ChildrenOfType<SpriteText>().Single().Text.ToString();
}
}
168 changes: 115 additions & 53 deletions osu.Game/Skinning/Components/BeatmapAttributeText.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
Expand Down Expand Up @@ -35,25 +33,6 @@ public partial class BeatmapAttributeText : FontAdjustableSkinComponent
[Resolved]
private IBindable<WorkingBeatmap> beatmap { get; set; } = null!;

private readonly Dictionary<BeatmapAttribute, LocalisableString> valueDictionary = new Dictionary<BeatmapAttribute, LocalisableString>();

private static readonly ImmutableDictionary<BeatmapAttribute, LocalisableString> label_dictionary = new Dictionary<BeatmapAttribute, LocalisableString>
{
[BeatmapAttribute.CircleSize] = BeatmapsetsStrings.ShowStatsCs,
[BeatmapAttribute.Accuracy] = BeatmapsetsStrings.ShowStatsAccuracy,
[BeatmapAttribute.HPDrain] = BeatmapsetsStrings.ShowStatsDrain,
[BeatmapAttribute.ApproachRate] = BeatmapsetsStrings.ShowStatsAr,
[BeatmapAttribute.StarRating] = BeatmapsetsStrings.ShowStatsStars,
[BeatmapAttribute.Title] = EditorSetupStrings.Title,
[BeatmapAttribute.Artist] = EditorSetupStrings.Artist,
[BeatmapAttribute.DifficultyName] = EditorSetupStrings.DifficultyHeader,
[BeatmapAttribute.Creator] = EditorSetupStrings.Creator,
[BeatmapAttribute.Source] = EditorSetupStrings.Source,
[BeatmapAttribute.Length] = ArtistStrings.TracklistLength.ToTitle(),
[BeatmapAttribute.RankedStatus] = BeatmapDiscussionsStrings.IndexFormBeatmapsetStatusDefault,
[BeatmapAttribute.BPM] = BeatmapsetsStrings.ShowStatsBpm,
}.ToImmutableDictionary();

private readonly OsuSpriteText text;

public BeatmapAttributeText()
Expand All @@ -74,52 +53,135 @@ protected override void LoadComplete()
{
base.LoadComplete();

Attribute.BindValueChanged(_ => updateLabel());
Template.BindValueChanged(_ => updateLabel());
beatmap.BindValueChanged(b =>
{
updateBeatmapContent(b.NewValue);
updateLabel();
}, true);
}
Attribute.BindValueChanged(_ => updateText());
Template.BindValueChanged(_ => updateText());
beatmap.BindValueChanged(_ => updateText());

private void updateBeatmapContent(WorkingBeatmap workingBeatmap)
{
valueDictionary[BeatmapAttribute.Title] = new RomanisableString(workingBeatmap.BeatmapInfo.Metadata.TitleUnicode, workingBeatmap.BeatmapInfo.Metadata.Title);
valueDictionary[BeatmapAttribute.Artist] = new RomanisableString(workingBeatmap.BeatmapInfo.Metadata.ArtistUnicode, workingBeatmap.BeatmapInfo.Metadata.Artist);
valueDictionary[BeatmapAttribute.DifficultyName] = workingBeatmap.BeatmapInfo.DifficultyName;
valueDictionary[BeatmapAttribute.Creator] = workingBeatmap.BeatmapInfo.Metadata.Author.Username;
valueDictionary[BeatmapAttribute.Source] = workingBeatmap.BeatmapInfo.Metadata.Source;
valueDictionary[BeatmapAttribute.Length] = TimeSpan.FromMilliseconds(workingBeatmap.BeatmapInfo.Length).ToFormattedDuration();
valueDictionary[BeatmapAttribute.RankedStatus] = workingBeatmap.BeatmapInfo.Status.GetLocalisableDescription();
valueDictionary[BeatmapAttribute.BPM] = workingBeatmap.BeatmapInfo.BPM.ToLocalisableString(@"F2");
valueDictionary[BeatmapAttribute.CircleSize] = ((double)workingBeatmap.BeatmapInfo.Difficulty.CircleSize).ToLocalisableString(@"F2");
valueDictionary[BeatmapAttribute.HPDrain] = ((double)workingBeatmap.BeatmapInfo.Difficulty.DrainRate).ToLocalisableString(@"F2");
valueDictionary[BeatmapAttribute.Accuracy] = ((double)workingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty).ToLocalisableString(@"F2");
valueDictionary[BeatmapAttribute.ApproachRate] = ((double)workingBeatmap.BeatmapInfo.Difficulty.ApproachRate).ToLocalisableString(@"F2");
valueDictionary[BeatmapAttribute.StarRating] = workingBeatmap.BeatmapInfo.StarRating.ToLocalisableString(@"F2");
updateText();
}

private void updateLabel()
private void updateText()
{
string numberedTemplate = Template.Value
.Replace("{", "{{")
.Replace("}", "}}")
.Replace(@"{{Label}}", "{0}")
.Replace(@"{{Value}}", $"{{{1 + (int)Attribute.Value}}}");
.Replace(@"{{Value}}", "{1}");

object?[] args = valueDictionary.OrderBy(pair => pair.Key)
.Select(pair => pair.Value)
.Prepend(label_dictionary[Attribute.Value])
.Cast<object?>()
.ToArray();
List<object?> values = new List<object?>
{
getLabelString(Attribute.Value),
getValueString(Attribute.Value)
};

foreach (var type in Enum.GetValues<BeatmapAttribute>())
{
numberedTemplate = numberedTemplate.Replace($"{{{{{type}}}}}", $"{{{1 + (int)type}}}");
string replaced = numberedTemplate.Replace($@"{{{{{type}}}}}", $@"{{{values.Count}}}");

if (numberedTemplate != replaced)
{
numberedTemplate = replaced;
values.Add(getValueString(type));
}
}

text.Text = LocalisableString.Format(numberedTemplate, args);
text.Text = LocalisableString.Format(numberedTemplate, values.ToArray());
}

private LocalisableString getLabelString(BeatmapAttribute attribute)
{
switch (attribute)
{
case BeatmapAttribute.CircleSize:
return BeatmapsetsStrings.ShowStatsCs;

case BeatmapAttribute.Accuracy:
return BeatmapsetsStrings.ShowStatsAccuracy;

case BeatmapAttribute.HPDrain:
return BeatmapsetsStrings.ShowStatsDrain;

case BeatmapAttribute.ApproachRate:
return BeatmapsetsStrings.ShowStatsAr;

case BeatmapAttribute.StarRating:
return BeatmapsetsStrings.ShowStatsStars;

case BeatmapAttribute.Title:
return EditorSetupStrings.Title;

case BeatmapAttribute.Artist:
return EditorSetupStrings.Artist;

case BeatmapAttribute.DifficultyName:
return EditorSetupStrings.DifficultyHeader;

case BeatmapAttribute.Creator:
return EditorSetupStrings.Creator;

case BeatmapAttribute.Source:
return EditorSetupStrings.Source;

case BeatmapAttribute.Length:
return ArtistStrings.TracklistLength.ToTitle();

case BeatmapAttribute.RankedStatus:
return BeatmapDiscussionsStrings.IndexFormBeatmapsetStatusDefault;

case BeatmapAttribute.BPM:
return BeatmapsetsStrings.ShowStatsBpm;

default:
return string.Empty;
}
}

private LocalisableString getValueString(BeatmapAttribute attribute)
{
switch (attribute)
{
case BeatmapAttribute.Title:
return new RomanisableString(beatmap.Value.BeatmapInfo.Metadata.TitleUnicode, beatmap.Value.BeatmapInfo.Metadata.Title);

case BeatmapAttribute.Artist:
return new RomanisableString(beatmap.Value.BeatmapInfo.Metadata.ArtistUnicode, beatmap.Value.BeatmapInfo.Metadata.Artist);

case BeatmapAttribute.DifficultyName:
return beatmap.Value.BeatmapInfo.DifficultyName;

case BeatmapAttribute.Creator:
return beatmap.Value.BeatmapInfo.Metadata.Author.Username;

case BeatmapAttribute.Source:
return beatmap.Value.BeatmapInfo.Metadata.Source;

case BeatmapAttribute.Length:
return TimeSpan.FromMilliseconds(beatmap.Value.BeatmapInfo.Length).ToFormattedDuration();

case BeatmapAttribute.RankedStatus:
return beatmap.Value.BeatmapInfo.Status.GetLocalisableDescription();

case BeatmapAttribute.BPM:
return beatmap.Value.BeatmapInfo.BPM.ToLocalisableString(@"F2");

case BeatmapAttribute.CircleSize:
return ((double)beatmap.Value.BeatmapInfo.Difficulty.CircleSize).ToLocalisableString(@"F2");

case BeatmapAttribute.HPDrain:
return ((double)beatmap.Value.BeatmapInfo.Difficulty.DrainRate).ToLocalisableString(@"F2");

case BeatmapAttribute.Accuracy:
return ((double)beatmap.Value.BeatmapInfo.Difficulty.OverallDifficulty).ToLocalisableString(@"F2");

case BeatmapAttribute.ApproachRate:
return ((double)beatmap.Value.BeatmapInfo.Difficulty.ApproachRate).ToLocalisableString(@"F2");

case BeatmapAttribute.StarRating:
return beatmap.Value.BeatmapInfo.StarRating.ToLocalisableString(@"F2");

default:
return string.Empty;
}
}

protected override void SetFont(FontUsage font) => text.Font = font.With(size: 40);
Expand Down

0 comments on commit 6576131

Please sign in to comment.