diff --git a/osu.Android.props b/osu.Android.props
index dec994bcb2..4887e3a95f 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,7 +52,7 @@
-
+
diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
new file mode 100644
index 0000000000..d1b21547dc
--- /dev/null
+++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
@@ -0,0 +1,181 @@
+// 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 System.Linq;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.Drawables.Cards;
+using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Overlays;
+using osu.Game.Users;
+using osuTK;
+
+namespace osu.Game.Tests.Visual.Beatmaps
+{
+ public class TestSceneBeatmapCard : OsuTestScene
+ {
+ private APIBeatmapSet[] testCases;
+
+ #region Test case generation
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ var normal = CreateAPIBeatmapSet(Ruleset.Value);
+ normal.HasVideo = true;
+ normal.HasStoryboard = true;
+
+ var undownloadable = getUndownloadableBeatmapSet();
+
+ var someDifficulties = getManyDifficultiesBeatmapSet(11);
+ someDifficulties.Title = someDifficulties.TitleUnicode = "some difficulties";
+ someDifficulties.Status = BeatmapSetOnlineStatus.Qualified;
+
+ var manyDifficulties = getManyDifficultiesBeatmapSet(100);
+ manyDifficulties.Status = BeatmapSetOnlineStatus.Pending;
+
+ var explicitMap = CreateAPIBeatmapSet(Ruleset.Value);
+ explicitMap.HasExplicitContent = true;
+
+ var featuredMap = CreateAPIBeatmapSet(Ruleset.Value);
+ featuredMap.TrackId = 1;
+
+ var explicitFeaturedMap = CreateAPIBeatmapSet(Ruleset.Value);
+ explicitFeaturedMap.HasExplicitContent = true;
+ explicitFeaturedMap.TrackId = 2;
+
+ var longName = CreateAPIBeatmapSet(Ruleset.Value);
+ longName.Title = longName.TitleUnicode = "this track has an incredibly and implausibly long title";
+ longName.Artist = longName.ArtistUnicode = "and this artist! who would have thunk it. it's really such a long name.";
+ longName.HasExplicitContent = true;
+ longName.TrackId = 444;
+
+ testCases = new[]
+ {
+ normal,
+ undownloadable,
+ someDifficulties,
+ manyDifficulties,
+ explicitMap,
+ featuredMap,
+ explicitFeaturedMap,
+ longName
+ };
+ }
+
+ private APIBeatmapSet getUndownloadableBeatmapSet() => new APIBeatmapSet
+ {
+ OnlineID = 123,
+ Title = "undownloadable beatmap",
+ Artist = "test",
+ Source = "more tests",
+ Author = new User
+ {
+ Username = "BanchoBot",
+ Id = 3,
+ },
+ Availability = new BeatmapSetOnlineAvailability
+ {
+ DownloadDisabled = true,
+ },
+ Preview = @"https://b.ppy.sh/preview/12345.mp3",
+ PlayCount = 123,
+ FavouriteCount = 456,
+ BPM = 111,
+ HasVideo = true,
+ HasStoryboard = true,
+ Covers = new BeatmapSetOnlineCovers(),
+ Beatmaps = new List
+ {
+ new APIBeatmap
+ {
+ RulesetID = Ruleset.Value.OnlineID,
+ DifficultyName = "Test",
+ StarRating = 6.42,
+ }
+ }
+ };
+
+ private static APIBeatmapSet getManyDifficultiesBeatmapSet(int count)
+ {
+ var beatmaps = new List();
+
+ for (int i = 0; i < count; i++)
+ {
+ beatmaps.Add(new APIBeatmap
+ {
+ RulesetID = i % 4,
+ StarRating = 2 + i % 4 * 2,
+ });
+ }
+
+ return new APIBeatmapSet
+ {
+ OnlineID = 1,
+ Title = "many difficulties beatmap",
+ Artist = "test",
+ Author = new User
+ {
+ Username = "BanchoBot",
+ Id = 3,
+ },
+ HasVideo = true,
+ HasStoryboard = true,
+ Covers = new BeatmapSetOnlineCovers(),
+ Beatmaps = beatmaps,
+ };
+ }
+
+ #endregion
+
+ private Drawable createContent(OverlayColourScheme colourScheme, Func creationFunc)
+ {
+ var colourProvider = new OverlayColourProvider(colourScheme);
+
+ return new DependencyProvidingContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ CachedDependencies = new (Type, object)[]
+ {
+ (typeof(OverlayColourProvider), colourProvider)
+ },
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = colourProvider.Background5
+ },
+ new BasicScrollContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Full,
+ Padding = new MarginPadding(10),
+ Spacing = new Vector2(10),
+ ChildrenEnumerable = testCases.Select(creationFunc)
+ }
+ }
+ }
+ };
+ }
+
+ private void createTestCase(Func creationFunc)
+ {
+ foreach (var scheme in Enum.GetValues(typeof(OverlayColourScheme)).Cast())
+ AddStep($"set {scheme} scheme", () => Child = createContent(scheme, creationFunc));
+ }
+
+ [Test]
+ public void TestNormal() => createTestCase(beatmapSetInfo => new BeatmapCard(beatmapSetInfo));
+ }
+}
diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs
index 9a0cdb387d..035f438b89 100644
--- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs
+++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs
@@ -131,7 +131,7 @@ namespace osu.Game.Beatmaps
var localRulesetInfo = rulesetInfo as RulesetInfo;
// Difficulty can only be computed if the beatmap and ruleset are locally available.
- if (localBeatmapInfo == null || localRulesetInfo == null)
+ if (localBeatmapInfo == null || localBeatmapInfo.ID == 0 || localRulesetInfo == null)
{
// If not, fall back to the existing star difficulty (e.g. from an online source).
return Task.FromResult(new StarDifficulty(beatmapInfo.StarRating, (beatmapInfo as IBeatmapOnlineInfo)?.MaxCombo ?? 0));
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index 0509a9db47..0caee8f9cd 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -249,6 +249,23 @@ namespace osu.Game.Beatmaps
public IBindable>> DownloadFailed => beatmapModelDownloader.DownloadFailed;
+ // Temporary method until this class supports IBeatmapSetInfo or otherwise.
+ public bool Download(IBeatmapSetInfo model, bool minimiseDownloadSize = false)
+ {
+ return beatmapModelDownloader.Download(new BeatmapSetInfo
+ {
+ OnlineBeatmapSetID = model.OnlineID,
+ Metadata = new BeatmapMetadata
+ {
+ Title = model.Metadata?.Title,
+ Artist = model.Metadata?.Artist,
+ TitleUnicode = model.Metadata?.TitleUnicode,
+ ArtistUnicode = model.Metadata?.ArtistUnicode,
+ Author = new User { Username = model.Metadata?.Author },
+ }
+ }, minimiseDownloadSize);
+ }
+
public bool Download(BeatmapSetInfo model, bool minimiseDownloadSize = false)
{
return beatmapModelDownloader.Download(model, minimiseDownloadSize);
diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs
new file mode 100644
index 0000000000..8136ebbd70
--- /dev/null
+++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs
@@ -0,0 +1,280 @@
+// 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.Framework.Graphics.Sprites;
+using osu.Framework.Input.Events;
+using osu.Framework.Localisation;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Overlays;
+using osu.Game.Overlays.BeatmapSet;
+using osuTK;
+using osu.Game.Overlays.BeatmapListing.Panels;
+using osu.Game.Resources.Localisation.Web;
+using osuTK.Graphics;
+
+namespace osu.Game.Beatmaps.Drawables.Cards
+{
+ public class BeatmapCard : OsuClickableContainer
+ {
+ public const float TRANSITION_DURATION = 400;
+
+ private const float width = 408;
+ private const float height = 100;
+ private const float corner_radius = 10;
+
+ private readonly APIBeatmapSet beatmapSet;
+
+ private UpdateableOnlineBeatmapSetCover leftCover;
+ private FillFlowContainer iconArea;
+
+ private Container mainContent;
+ private BeatmapCardContentBackground mainContentBackground;
+
+ private GridContainer titleContainer;
+ private GridContainer artistContainer;
+
+ [Resolved]
+ private OverlayColourProvider colourProvider { get; set; }
+
+ public BeatmapCard(APIBeatmapSet beatmapSet)
+ : base(HoverSampleSet.Submit)
+ {
+ this.beatmapSet = beatmapSet;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Width = width;
+ Height = height;
+ CornerRadius = corner_radius;
+ Masking = true;
+
+ InternalChildren = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = colourProvider.Background3
+ },
+ new Container
+ {
+ Name = @"Left (icon) area",
+ Size = new Vector2(height),
+ Children = new Drawable[]
+ {
+ leftCover = new UpdateableOnlineBeatmapSetCover(BeatmapSetCoverType.List)
+ {
+ RelativeSizeAxes = Axes.Both,
+ OnlineInfo = beatmapSet
+ },
+ iconArea = new FillFlowContainer
+ {
+ Margin = new MarginPadding(5),
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(1)
+ }
+ }
+ },
+ mainContent = new Container
+ {
+ Name = @"Main content",
+ X = height - corner_radius,
+ Height = height,
+ CornerRadius = corner_radius,
+ Masking = true,
+ Children = new Drawable[]
+ {
+ mainContentBackground = new BeatmapCardContentBackground(beatmapSet)
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding
+ {
+ Horizontal = 10,
+ Vertical = 4
+ },
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ titleContainer = new GridContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ ColumnDimensions = new[]
+ {
+ new Dimension(),
+ new Dimension(GridSizeMode.AutoSize)
+ },
+ RowDimensions = new[]
+ {
+ new Dimension(GridSizeMode.AutoSize)
+ },
+ Content = new[]
+ {
+ new[]
+ {
+ new OsuSpriteText
+ {
+ Text = new RomanisableString(beatmapSet.TitleUnicode, beatmapSet.Title),
+ Font = OsuFont.Default.With(size: 22.5f, weight: FontWeight.SemiBold),
+ RelativeSizeAxes = Axes.X,
+ Truncate = true
+ },
+ Empty()
+ }
+ }
+ },
+ artistContainer = new GridContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ ColumnDimensions = new[]
+ {
+ new Dimension(),
+ new Dimension(GridSizeMode.AutoSize)
+ },
+ RowDimensions = new[]
+ {
+ new Dimension(GridSizeMode.AutoSize)
+ },
+ Content = new[]
+ {
+ new[]
+ {
+ new OsuSpriteText
+ {
+ Text = createArtistText(),
+ Font = OsuFont.Default.With(size: 17.5f, weight: FontWeight.SemiBold),
+ RelativeSizeAxes = Axes.X,
+ Truncate = true
+ },
+ Empty()
+ },
+ }
+ },
+ new LinkFlowContainer(s =>
+ {
+ s.Shadow = false;
+ s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold);
+ }).With(d =>
+ {
+ d.AutoSizeAxes = Axes.Both;
+ d.Margin = new MarginPadding { Top = 2 };
+ d.AddText("mapped by ", t => t.Colour = colourProvider.Content2);
+ d.AddUserLink(beatmapSet.Author);
+ }),
+ }
+ },
+ new FillFlowContainer
+ {
+ Name = @"Bottom content",
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Horizontal,
+ Padding = new MarginPadding
+ {
+ Horizontal = 10,
+ Vertical = 4
+ },
+ Spacing = new Vector2(4, 0),
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ Children = new Drawable[]
+ {
+ new BeatmapSetOnlineStatusPill
+ {
+ AutoSizeAxes = Axes.Both,
+ Status = beatmapSet.Status,
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft
+ },
+ new DifficultySpectrumDisplay(beatmapSet)
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ DotSize = new Vector2(6, 12)
+ }
+ }
+ }
+ }
+ }
+ };
+
+ if (beatmapSet.HasVideo)
+ iconArea.Add(new IconPill(FontAwesome.Solid.Film));
+
+ if (beatmapSet.HasStoryboard)
+ iconArea.Add(new IconPill(FontAwesome.Solid.Image));
+
+ if (beatmapSet.HasExplicitContent)
+ {
+ titleContainer.Content[0][1] = new ExplicitContentBeatmapPill
+ {
+ Anchor = Anchor.BottomRight,
+ Origin = Anchor.BottomRight,
+ Margin = new MarginPadding { Left = 5 }
+ };
+ }
+
+ if (beatmapSet.TrackId != null)
+ {
+ artistContainer.Content[0][1] = new FeaturedArtistBeatmapPill
+ {
+ Anchor = Anchor.BottomRight,
+ Origin = Anchor.BottomRight,
+ Margin = new MarginPadding { Left = 5 }
+ };
+ }
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ updateState();
+ FinishTransforms(true);
+ }
+
+ protected override bool OnHover(HoverEvent e)
+ {
+ updateState();
+ return base.OnHover(e);
+ }
+
+ protected override void OnHoverLost(HoverLostEvent e)
+ {
+ updateState();
+ base.OnHoverLost(e);
+ }
+
+ private LocalisableString createArtistText()
+ {
+ var romanisableArtist = new RomanisableString(beatmapSet.ArtistUnicode, beatmapSet.Artist);
+ return BeatmapsetsStrings.ShowDetailsByArtist(romanisableArtist);
+ }
+
+ private void updateState()
+ {
+ float targetWidth = width - height;
+ if (IsHovered)
+ targetWidth -= 20;
+
+ mainContent.ResizeWidthTo(targetWidth, TRANSITION_DURATION, Easing.OutQuint);
+ mainContentBackground.Dimmed.Value = IsHovered;
+
+ leftCover.FadeColour(IsHovered ? OsuColour.Gray(0.2f) : Color4.White, TRANSITION_DURATION, Easing.OutQuint);
+ }
+ }
+}
diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContentBackground.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContentBackground.cs
new file mode 100644
index 0000000000..392f5d1bfa
--- /dev/null
+++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContentBackground.cs
@@ -0,0 +1,71 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+#nullable enable
+
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Colour;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Overlays;
+
+namespace osu.Game.Beatmaps.Drawables.Cards
+{
+ public class BeatmapCardContentBackground : CompositeDrawable
+ {
+ public BindableBool Dimmed { get; } = new BindableBool();
+
+ private readonly Box background;
+ private readonly DelayedLoadUnloadWrapper cover;
+
+ [Resolved]
+ private OverlayColourProvider colourProvider { get; set; } = null!;
+
+ public BeatmapCardContentBackground(IBeatmapSetOnlineInfo onlineInfo)
+ {
+ InternalChildren = new Drawable[]
+ {
+ background = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ cover = new DelayedLoadUnloadWrapper(() => createCover(onlineInfo), 500, 500)
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Colour4.Transparent
+ }
+ };
+ }
+
+ private static Drawable createCover(IBeatmapSetOnlineInfo onlineInfo) => new OnlineBeatmapSetCover(onlineInfo)
+ {
+ RelativeSizeAxes = Axes.Both,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ FillMode = FillMode.Fill
+ };
+
+ [BackgroundDependencyLoader]
+ private void load(OverlayColourProvider colourProvider)
+ {
+ background.Colour = colourProvider.Background2;
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ Dimmed.BindValueChanged(_ => updateState(), true);
+ FinishTransforms(true);
+ }
+
+ private void updateState() => Schedule(() =>
+ {
+ background.FadeColour(Dimmed.Value ? colourProvider.Background4 : colourProvider.Background2, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
+
+ var gradient = ColourInfo.GradientHorizontal(Colour4.White.Opacity(0), Colour4.White.Opacity(0.2f));
+ cover.FadeColour(gradient, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
+ });
+ }
+}
diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs
index 64412675bb..6e573cc2a0 100644
--- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs
+++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs
@@ -60,8 +60,9 @@ namespace osu.Game.Beatmaps.Drawables
/// The ruleset to show the difficulty with.
/// The mods to show the difficulty with.
/// Whether to display a tooltip when hovered.
- public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList mods, bool shouldShowTooltip = true)
- : this(beatmapInfo, shouldShowTooltip)
+ /// Whether to perform difficulty lookup (including calculation if necessary).
+ public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList mods, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true)
+ : this(beatmapInfo, shouldShowTooltip, performBackgroundDifficultyLookup)
{
this.ruleset = ruleset ?? beatmapInfo.Ruleset;
this.mods = mods ?? Array.Empty();
diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
index 0b43c16ebe..7d1210d0e3 100644
--- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs
+++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
@@ -7,12 +7,10 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
using System.Collections.Generic;
-using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation;
using osu.Framework.Platform;
-using osu.Game.Graphics.Sprites;
using osu.Game.Users;
namespace osu.Game.Graphics.Containers
@@ -58,23 +56,14 @@ namespace osu.Game.Graphics.Containers
AddText(text.Substring(previousLinkEnd));
}
- public void AddLink(string text, string url, Action creationParameters = null) =>
+ public void AddLink(LocalisableString text, string url, Action creationParameters = null) =>
createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.External, url), url);
- public void AddLink(string text, Action action, string tooltipText = null, Action creationParameters = null)
+ public void AddLink(LocalisableString text, Action action, string tooltipText = null, Action creationParameters = null)
=> createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.Custom, string.Empty), tooltipText, action);
- public void AddLink(string text, LinkAction action, string argument, string tooltipText = null, Action creationParameters = null)
- => createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(action, argument), tooltipText);
-
public void AddLink(LocalisableString text, LinkAction action, string argument, string tooltipText = null, Action creationParameters = null)
- {
- var spriteText = new OsuSpriteText { Text = text };
-
- AddText(spriteText, creationParameters);
- RemoveInternal(spriteText); // TODO: temporary, will go away when TextParts support localisation properly.
- createLink(new TextPartManual(spriteText.Yield()), new LinkDetails(action, argument), tooltipText);
- }
+ => createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(action, argument), tooltipText);
public void AddLink(IEnumerable text, LinkAction action, string linkArgument, string tooltipText = null)
{
diff --git a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs
index e8f80dec57..da511d8212 100644
--- a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs
@@ -8,6 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
+using osu.Framework.Localisation;
using osu.Game.Graphics.Containers;
namespace osu.Game.Graphics.UserInterface
@@ -19,7 +20,7 @@ namespace osu.Game.Graphics.UserInterface
///
protected virtual bool PlaySoundsOnUserChange => true;
- public string LabelText
+ public LocalisableString LabelText
{
set
{
diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
index d5f76733cf..95884f1515 100644
--- a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
+++ b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
@@ -8,6 +8,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
+using osu.Framework.Localisation;
using osu.Game.Graphics.Containers;
using osu.Game.Overlays;
using osuTK;
@@ -156,18 +157,18 @@ namespace osu.Game.Graphics.UserInterfaceV2
descriptionText.Colour = osuColour.Yellow;
}
- public string Label
+ public LocalisableString Label
{
set => labelText.Text = value;
}
- public string Description
+ public LocalisableString Description
{
set
{
descriptionText.Text = value;
- if (!string.IsNullOrEmpty(value))
+ if (value == default)
descriptionText.Show();
else
descriptionText.Hide();
diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs
index d60c9cfe65..69d72226ba 100644
--- a/osu.Game/Online/API/APIRequest.cs
+++ b/osu.Game/Online/API/APIRequest.cs
@@ -107,7 +107,8 @@ namespace osu.Game.Online.API
WebRequest = CreateWebRequest();
WebRequest.Failed += Fail;
WebRequest.AllowRetryOnTimeout = false;
- WebRequest.AddHeader("Authorization", $"Bearer {API.AccessToken}");
+ if (!string.IsNullOrEmpty(API.AccessToken))
+ WebRequest.AddHeader("Authorization", $"Bearer {API.AccessToken}");
if (isFailing) return;
diff --git a/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs
index 2e41723f34..5395fe0429 100644
--- a/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs
@@ -37,6 +37,7 @@ namespace osu.Game.Online.API.Requests.Responses
public DateTimeOffset Date { get; set; }
[JsonProperty(@"beatmap")]
+ [CanBeNull]
public APIBeatmap Beatmap { get; set; }
[JsonProperty("accuracy")]
@@ -46,6 +47,7 @@ namespace osu.Game.Online.API.Requests.Responses
public double? PP { get; set; }
[JsonProperty(@"beatmapset")]
+ [CanBeNull]
public APIBeatmapSet BeatmapSet
{
set
@@ -96,7 +98,7 @@ namespace osu.Game.Online.API.Requests.Responses
{
TotalScore = TotalScore,
MaxCombo = MaxCombo,
- BeatmapInfo = Beatmap.ToBeatmapInfo(rulesets),
+ BeatmapInfo = Beatmap?.ToBeatmapInfo(rulesets),
User = User,
Accuracy = Accuracy,
OnlineScoreID = OnlineID,
diff --git a/osu.Game/Online/Placeholders/ClickablePlaceholder.cs b/osu.Game/Online/Placeholders/ClickablePlaceholder.cs
index 936ad79c64..054a4a3c39 100644
--- a/osu.Game/Online/Placeholders/ClickablePlaceholder.cs
+++ b/osu.Game/Online/Placeholders/ClickablePlaceholder.cs
@@ -3,6 +3,7 @@
using System;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Localisation;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
@@ -12,7 +13,7 @@ namespace osu.Game.Online.Placeholders
{
public Action Action;
- public ClickablePlaceholder(string actionMessage, IconUsage icon)
+ public ClickablePlaceholder(LocalisableString actionMessage, IconUsage icon)
{
OsuTextFlowContainer textFlow;
diff --git a/osu.Game/Online/Placeholders/MessagePlaceholder.cs b/osu.Game/Online/Placeholders/MessagePlaceholder.cs
index 7342765ca4..1676ba6cf2 100644
--- a/osu.Game/Online/Placeholders/MessagePlaceholder.cs
+++ b/osu.Game/Online/Placeholders/MessagePlaceholder.cs
@@ -3,14 +3,15 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Localisation;
namespace osu.Game.Online.Placeholders
{
public class MessagePlaceholder : Placeholder
{
- private readonly string message;
+ private readonly LocalisableString message;
- public MessagePlaceholder(string message)
+ public MessagePlaceholder(LocalisableString message)
{
AddIcon(FontAwesome.Solid.ExclamationCircle, cp =>
{
diff --git a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs
index 6cd735af23..a642e283f9 100644
--- a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs
+++ b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs
@@ -53,7 +53,10 @@ namespace osu.Game.Online.Rooms
downloadTracker?.RemoveAndDisposeImmediately();
downloadTracker = new BeatmapDownloadTracker(item.NewValue.Beatmap.Value.BeatmapSet);
- downloadTracker.State.BindValueChanged(_ => updateAvailability());
+
+ AddInternal(downloadTracker);
+
+ downloadTracker.State.BindValueChanged(_ => updateAvailability(), true);
downloadTracker.Progress.BindValueChanged(_ =>
{
if (downloadTracker.State.Value != DownloadState.Downloading)
@@ -63,9 +66,7 @@ namespace osu.Game.Online.Rooms
// we don't want to flood the network with this, so rate limit how often we send progress updates.
if (progressUpdate?.Completed != false)
progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500);
- });
-
- AddInternal(downloadTracker);
+ }, true);
}, true);
}
diff --git a/osu.Game/Online/Rooms/SubmitRoomScoreRequest.cs b/osu.Game/Online/Rooms/SubmitRoomScoreRequest.cs
index 9e432fa99e..d5da6c401c 100644
--- a/osu.Game/Online/Rooms/SubmitRoomScoreRequest.cs
+++ b/osu.Game/Online/Rooms/SubmitRoomScoreRequest.cs
@@ -5,6 +5,7 @@ using System.Net.Http;
using Newtonsoft.Json;
using osu.Framework.IO.Network;
using osu.Game.Online.API;
+using osu.Game.Online.Solo;
using osu.Game.Scoring;
namespace osu.Game.Online.Rooms
@@ -14,14 +15,14 @@ namespace osu.Game.Online.Rooms
private readonly long scoreId;
private readonly long roomId;
private readonly long playlistItemId;
- private readonly ScoreInfo scoreInfo;
+ private readonly SubmittableScore score;
public SubmitRoomScoreRequest(long scoreId, long roomId, long playlistItemId, ScoreInfo scoreInfo)
{
this.scoreId = scoreId;
this.roomId = roomId;
this.playlistItemId = playlistItemId;
- this.scoreInfo = scoreInfo;
+ score = new SubmittableScore(scoreInfo);
}
protected override WebRequest CreateWebRequest()
@@ -31,7 +32,7 @@ namespace osu.Game.Online.Rooms
req.ContentType = "application/json";
req.Method = HttpMethod.Put;
- req.AddRaw(JsonConvert.SerializeObject(scoreInfo, new JsonSerializerSettings
+ req.AddRaw(JsonConvert.SerializeObject(score, new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
}));
diff --git a/osu.Game/Online/ScoreDownloadTracker.cs b/osu.Game/Online/ScoreDownloadTracker.cs
index 675dbf608c..e679071ac1 100644
--- a/osu.Game/Online/ScoreDownloadTracker.cs
+++ b/osu.Game/Online/ScoreDownloadTracker.cs
@@ -35,7 +35,11 @@ namespace osu.Game.Online
return;
// Used to interact with manager classes that don't support interface types. Will eventually be replaced.
- var scoreInfo = new ScoreInfo { OnlineScoreID = TrackedItem.OnlineScoreID };
+ var scoreInfo = new ScoreInfo
+ {
+ ID = TrackedItem.ID,
+ OnlineScoreID = TrackedItem.OnlineScoreID
+ };
if (Manager.IsAvailableLocally(scoreInfo))
UpdateState(DownloadState.LocallyAvailable);
diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
index 8ee3b1cb2e..2ba8fc3ae2 100644
--- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
+++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
@@ -5,7 +5,6 @@ using System;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
-using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Utils;
@@ -135,7 +134,16 @@ namespace osu.Game.Overlays.AccountCreation
characterCheckText = passwordDescription.AddText("8 characters long");
passwordDescription.AddText(". Choose something long but also something you will remember, like a line from your favourite song.");
- passwordTextBox.Current.ValueChanged += password => { characterCheckText.Drawables.ForEach(s => s.Colour = password.NewValue.Length == 0 ? Color4.White : Interpolation.ValueAt(password.NewValue.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In)); };
+ passwordTextBox.Current.BindValueChanged(_ => updateCharacterCheckTextColour(), true);
+ characterCheckText.DrawablePartsRecreated += _ => updateCharacterCheckTextColour();
+ }
+
+ private void updateCharacterCheckTextColour()
+ {
+ string password = passwordTextBox.Text;
+
+ foreach (var d in characterCheckText.Drawables)
+ d.Colour = password.Length == 0 ? Color4.White : Interpolation.ValueAt(password.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In);
}
public override void OnEntering(IScreen last)
diff --git a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs
index d7c2837f4d..5ed49cf384 100644
--- a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs
@@ -86,7 +86,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
break;
default:
- beatmaps.Download(new BeatmapSetInfo { OnlineBeatmapSetID = beatmapSet.OnlineID }, noVideoSetting.Value);
+ beatmaps.Download(beatmapSet, noVideoSetting.Value);
break;
}
};
diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs
index 6862864c55..bd7723d3c0 100644
--- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs
+++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs
@@ -108,7 +108,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
return;
}
- beatmaps.Download(new BeatmapSetInfo { OnlineBeatmapSetID = beatmapSet.OnlineID }, noVideo);
+ beatmaps.Download(beatmapSet, noVideo);
};
localUser.BindTo(api.LocalUser);
diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs
index 5cc598ae70..e84eee15be 100644
--- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs
+++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs
@@ -101,7 +101,7 @@ namespace osu.Game.Overlays.Changelog
t.Colour = colour.PinkLighter;
})
{
- Text = ChangelogStrings.SupportText2.ToString(),
+ Text = ChangelogStrings.SupportText2,
Margin = new MarginPadding { Top = 10 },
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs
index 78ef2ec795..0f953f92bb 100644
--- a/osu.Game/Overlays/Dialog/PopupDialog.cs
+++ b/osu.Game/Overlays/Dialog/PopupDialog.cs
@@ -10,6 +10,7 @@ using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
+using osu.Framework.Localisation;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
using osuTK;
@@ -42,9 +43,9 @@ namespace osu.Game.Overlays.Dialog
set => icon.Icon = value;
}
- private string headerText;
+ private LocalisableString headerText;
- public string HeaderText
+ public LocalisableString HeaderText
{
get => headerText;
set
@@ -57,9 +58,9 @@ namespace osu.Game.Overlays.Dialog
}
}
- private string bodyText;
+ private LocalisableString bodyText;
- public string BodyText
+ public LocalisableString BodyText
{
get => bodyText;
set
diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs
index eea2a9dc7e..04c12b8cd7 100644
--- a/osu.Game/Overlays/Music/PlaylistItem.cs
+++ b/osu.Game/Overlays/Music/PlaylistItem.cs
@@ -25,11 +25,8 @@ namespace osu.Game.Overlays.Music
private TextFlowContainer text;
private ITextPart titlePart;
- private ILocalisedBindableString title;
- private ILocalisedBindableString artist;
-
- private Color4 selectedColour;
- private Color4 artistColour;
+ [Resolved]
+ private OsuColour colours { get; set; }
public PlaylistItem(BeatmapSetInfo item)
: base(item)
@@ -40,22 +37,15 @@ namespace osu.Game.Overlays.Music
}
[BackgroundDependencyLoader]
- private void load(OsuColour colours, LocalisationManager localisation)
+ private void load()
{
- selectedColour = colours.Yellow;
- artistColour = colours.Gray9;
HandleColour = colours.Gray5;
-
- title = localisation.GetLocalisedString(new RomanisableString(Model.Metadata.TitleUnicode, Model.Metadata.Title));
- artist = localisation.GetLocalisedString(new RomanisableString(Model.Metadata.ArtistUnicode, Model.Metadata.Artist));
}
protected override void LoadComplete()
{
base.LoadComplete();
- artist.BindValueChanged(_ => recreateText(), true);
-
SelectedSet.BindValueChanged(set =>
{
if (set.OldValue?.Equals(Model) != true && set.NewValue?.Equals(Model) != true)
@@ -68,7 +58,7 @@ namespace osu.Game.Overlays.Music
private void updateSelectionState(bool instant)
{
foreach (Drawable s in titlePart.Drawables)
- s.FadeColour(SelectedSet.Value?.Equals(Model) == true ? selectedColour : Color4.White, instant ? 0 : FADE_DURATION);
+ s.FadeColour(SelectedSet.Value?.Equals(Model) == true ? colours.Yellow : Color4.White, instant ? 0 : FADE_DURATION);
}
protected override Drawable CreateContent() => text = new OsuTextFlowContainer
@@ -77,18 +67,23 @@ namespace osu.Game.Overlays.Music
AutoSizeAxes = Axes.Y,
};
- private void recreateText()
+ protected override void LoadAsyncComplete()
{
- text.Clear();
+ base.LoadAsyncComplete();
- // space after the title to put a space between the title and artist
- titlePart = text.AddText(title.Value + @" ", sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular));
+ var title = new RomanisableString(Model.Metadata.TitleUnicode, Model.Metadata.Title);
+ var artist = new RomanisableString(Model.Metadata.ArtistUnicode, Model.Metadata.Artist);
+
+ titlePart = text.AddText(title, sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular));
updateSelectionState(true);
+ titlePart.DrawablePartsRecreated += _ => updateSelectionState(true);
- text.AddText(artist.Value, sprite =>
+ text.AddText(@" "); // to separate the title from the artist.
+
+ text.AddText(artist, sprite =>
{
sprite.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold);
- sprite.Colour = artistColour;
+ sprite.Colour = colours.Gray9;
sprite.Padding = new MarginPadding { Top = 1 };
});
}
diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs
index b27e15dd2c..c44b88ad29 100644
--- a/osu.Game/Overlays/Notifications/ProgressNotification.cs
+++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs
@@ -10,6 +10,7 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
@@ -22,7 +23,7 @@ namespace osu.Game.Overlays.Notifications
{
private const float loading_spinner_size = 22;
- public string Text
+ public LocalisableString Text
{
set => Schedule(() => textDrawable.Text = value);
}
diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs
index 3a3136b1ea..17ec12a4ca 100644
--- a/osu.Game/Overlays/Notifications/SimpleNotification.cs
+++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs
@@ -7,6 +7,7 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osuTK;
@@ -15,9 +16,9 @@ namespace osu.Game.Overlays.Notifications
{
public class SimpleNotification : Notification
{
- private string text = string.Empty;
+ private LocalisableString text;
- public string Text
+ public LocalisableString Text
{
get => text;
set
diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
index ca5534dbc2..fb464e1b41 100644
--- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
+++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
@@ -91,7 +91,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
{
new OsuSpriteText
{
- Text = $"{Score.Beatmap.DifficultyName}",
+ Text = $"{Score.Beatmap?.DifficultyName}",
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
Colour = colours.Yellow
},
diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs
index e509cac2f1..0814e3c824 100644
--- a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs
+++ b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs
@@ -83,7 +83,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
cp.Font = OsuFont.Default.With(size: 24);
})
{
- Text = HeaderText.ToString(),
+ Text = HeaderText,
TextAnchor = Anchor.TopCentre,
Margin = new MarginPadding(10),
RelativeSizeAxes = Axes.X,
diff --git a/osu.Game/Overlays/Settings/SettingsCheckbox.cs b/osu.Game/Overlays/Settings/SettingsCheckbox.cs
index 8b7ac80a5b..8a8fed4d30 100644
--- a/osu.Game/Overlays/Settings/SettingsCheckbox.cs
+++ b/osu.Game/Overlays/Settings/SettingsCheckbox.cs
@@ -16,8 +16,7 @@ namespace osu.Game.Overlays.Settings
public override LocalisableString LabelText
{
get => labelText;
- // checkbox doesn't properly support localisation yet.
- set => ((OsuCheckbox)Control).LabelText = (labelText = value).ToString();
+ set => ((OsuCheckbox)Control).LabelText = labelText = value;
}
}
}
diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs
index b593dea576..e709be1343 100644
--- a/osu.Game/Overlays/Settings/SettingsItem.cs
+++ b/osu.Game/Overlays/Settings/SettingsItem.cs
@@ -68,7 +68,7 @@ namespace osu.Game.Overlays.Settings
{
set
{
- bool hasValue = !string.IsNullOrWhiteSpace(value.ToString());
+ bool hasValue = value != default;
if (warningText == null)
{
@@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Settings
}
warningText.Alpha = hasValue ? 1 : 0;
- warningText.Text = value.ToString(); // TODO: Remove ToString() call after TextFlowContainer supports localisation (see https://github.com/ppy/osu-framework/issues/4636).
+ warningText.Text = value ?? default;
}
}
diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs
index eab81186d5..5b4284dc2f 100644
--- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs
+++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs
@@ -58,6 +58,11 @@ namespace osu.Game.Rulesets.Difficulty
return CreateDifficultyAttributes(Beatmap, playableMods, skills, clockRate);
}
+ ///
+ /// Calculates the difficulty of the beatmap and returns a set of representing the difficulty at every relevant time value in the beatmap.
+ ///
+ /// The mods that should be applied to the beatmap.
+ /// The set of .
public List CalculateTimed(params Mod[] mods)
{
preProcess(mods);
@@ -77,7 +82,7 @@ namespace osu.Game.Rulesets.Difficulty
foreach (var skill in skills)
skill.ProcessInternal(hitObject);
- attribs.Add(new TimedDifficultyAttributes(hitObject.EndTime, CreateDifficultyAttributes(progressiveBeatmap, playableMods, skills, clockRate)));
+ attribs.Add(new TimedDifficultyAttributes(hitObject.EndTime * clockRate, CreateDifficultyAttributes(progressiveBeatmap, playableMods, skills, clockRate)));
}
return attribs;
diff --git a/osu.Game/Rulesets/Difficulty/TimedDifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/TimedDifficultyAttributes.cs
index 973b2dacb2..2509971389 100644
--- a/osu.Game/Rulesets/Difficulty/TimedDifficultyAttributes.cs
+++ b/osu.Game/Rulesets/Difficulty/TimedDifficultyAttributes.cs
@@ -11,9 +11,21 @@ namespace osu.Game.Rulesets.Difficulty
///
public class TimedDifficultyAttributes : IComparable
{
+ ///
+ /// The non-clock-adjusted time value at which the attributes take effect.
+ ///
public readonly double Time;
+
+ ///
+ /// The attributes.
+ ///
public readonly DifficultyAttributes Attributes;
+ ///
+ /// Creates new .
+ ///
+ /// The non-clock-adjusted time value at which the attributes take effect.
+ /// The attributes.
public TimedDifficultyAttributes(double time, DifficultyAttributes attributes)
{
Time = time;
diff --git a/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs b/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs
index 10a5771520..6c004a7c8b 100644
--- a/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs
+++ b/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs
@@ -6,6 +6,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Overlays.Settings;
@@ -16,7 +17,7 @@ namespace osu.Game.Screens.Edit.Timing
{
private readonly SettingsSlider slider;
- public SliderWithTextBoxInput(string labelText)
+ public SliderWithTextBoxInput(LocalisableString labelText)
{
LabelledTextBox textbox;
diff --git a/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs b/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs
index 2901758332..e948c1adae 100644
--- a/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs
+++ b/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs
@@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
-using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat;
namespace osu.Game.Screens.OnlinePlay.Components
@@ -69,24 +68,14 @@ namespace osu.Game.Screens.OnlinePlay.Components
}
else
{
- textFlow.AddLink(new[]
- {
- new OsuSpriteText
- {
- Text = new RomanisableString(beatmap.Value.Metadata.ArtistUnicode, beatmap.Value.Metadata.Artist),
- Font = OsuFont.GetFont(size: TextSize),
- },
- new OsuSpriteText
- {
- Text = " - ",
- Font = OsuFont.GetFont(size: TextSize),
- },
- new OsuSpriteText
- {
- Text = new RomanisableString(beatmap.Value.Metadata.TitleUnicode, beatmap.Value.Metadata.Title),
- Font = OsuFont.GetFont(size: TextSize),
- }
- }, LinkAction.OpenBeatmap, beatmap.Value.OnlineID.ToString(), "Open beatmap");
+ var metadataInfo = beatmap.Value.Metadata;
+
+ string artistUnicode = string.IsNullOrEmpty(metadataInfo.ArtistUnicode) ? metadataInfo.Artist : metadataInfo.ArtistUnicode;
+ string titleUnicode = string.IsNullOrEmpty(metadataInfo.TitleUnicode) ? metadataInfo.Title : metadataInfo.TitleUnicode;
+
+ var title = new RomanisableString($"{artistUnicode} - {titleUnicode}".Trim(), $"{metadataInfo.Artist} - {metadataInfo.Title}".Trim());
+
+ textFlow.AddLink(title, LinkAction.OpenBeatmap, beatmap.Value.OnlineID.ToString(), "Open beatmap");
}
}
}
diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs
index 69ab7225ac..675b5e4c04 100644
--- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs
+++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs
@@ -105,13 +105,12 @@ namespace osu.Game.Screens.OnlinePlay
private void refresh()
{
- difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value, requiredMods) { Size = new Vector2(32) };
+ difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(32) };
beatmapText.Clear();
beatmapText.AddLink(Item.Beatmap.Value.GetDisplayTitleRomanisable(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineBeatmapID.ToString(), null, text =>
{
text.Truncate = true;
- text.RelativeSizeAxes = Axes.X;
});
authorText.Clear();
diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs
index 2fe3c7b668..ef2c2df4a6 100644
--- a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs
+++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs
@@ -4,6 +4,7 @@
using System.Collections.Specialized;
using Humanizer;
using osu.Framework.Allocation;
+using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
@@ -46,7 +47,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
private void updateCount(object sender, NotifyCollectionChangedEventArgs e)
{
count.Clear();
- count.AddText(Playlist.Count.ToString(), s => s.Font = s.Font.With(weight: FontWeight.Bold));
+ count.AddText(Playlist.Count.ToLocalisableString(), s => s.Font = s.Font.With(weight: FontWeight.Bold));
count.AddText(" ");
count.AddText("Beatmap".ToQuantity(Playlist.Count, ShowQuantityAs.None));
}
diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs
index 2de72beaad..89eed14e6d 100644
--- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs
+++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs
@@ -188,8 +188,8 @@ namespace osu.Game.Screens.Select
RelativeSizeAxes = Axes.Both;
- titleBinding = localisation.GetLocalisedString(new RomanisableString(metadata.TitleUnicode, metadata.Title));
- artistBinding = localisation.GetLocalisedString(new RomanisableString(metadata.ArtistUnicode, metadata.Artist));
+ titleBinding = localisation.GetLocalisedBindableString(new RomanisableString(metadata.TitleUnicode, metadata.Title));
+ artistBinding = localisation.GetLocalisedBindableString(new RomanisableString(metadata.ArtistUnicode, metadata.Artist));
const float top_height = 0.7f;
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index c1c3336b5c..972d64a997 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -36,7 +36,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 0baf067a63..f6e4f61fde 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
-
+
@@ -93,7 +93,7 @@
-
+