1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 16:27:26 +08:00

Merge branch 'aim-refactor-slider' of https://github.com/emu1337/osu into aim-refactor-slider

This commit is contained in:
Xexxar 2021-11-03 17:59:33 +00:00
commit 3010889783
38 changed files with 666 additions and 102 deletions

View File

@ -52,7 +52,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1029.0" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2021.1103.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Transitive Dependencies"> <ItemGroup Label="Transitive Dependencies">
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. --> <!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->

View File

@ -0,0 +1,181 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. 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<APIBeatmap>
{
new APIBeatmap
{
RulesetID = Ruleset.Value.OnlineID,
DifficultyName = "Test",
StarRating = 6.42,
}
}
};
private static APIBeatmapSet getManyDifficultiesBeatmapSet(int count)
{
var beatmaps = new List<APIBeatmap>();
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<APIBeatmapSet, Drawable> 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<APIBeatmapSet, Drawable> creationFunc)
{
foreach (var scheme in Enum.GetValues(typeof(OverlayColourScheme)).Cast<OverlayColourScheme>())
AddStep($"set {scheme} scheme", () => Child = createContent(scheme, creationFunc));
}
[Test]
public void TestNormal() => createTestCase(beatmapSetInfo => new BeatmapCard(beatmapSetInfo));
}
}

View File

@ -131,7 +131,7 @@ namespace osu.Game.Beatmaps
var localRulesetInfo = rulesetInfo as RulesetInfo; var localRulesetInfo = rulesetInfo as RulesetInfo;
// Difficulty can only be computed if the beatmap and ruleset are locally available. // 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). // 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)); return Task.FromResult(new StarDifficulty(beatmapInfo.StarRating, (beatmapInfo as IBeatmapOnlineInfo)?.MaxCombo ?? 0));

View File

@ -249,6 +249,23 @@ namespace osu.Game.Beatmaps
public IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> DownloadFailed => beatmapModelDownloader.DownloadFailed; public IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> 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) public bool Download(BeatmapSetInfo model, bool minimiseDownloadSize = false)
{ {
return beatmapModelDownloader.Download(model, minimiseDownloadSize); return beatmapModelDownloader.Download(model, minimiseDownloadSize);

View File

@ -0,0 +1,280 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. 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);
}
}
}

View File

@ -0,0 +1,71 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. 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);
});
}
}

View File

@ -60,8 +60,9 @@ namespace osu.Game.Beatmaps.Drawables
/// <param name="ruleset">The ruleset to show the difficulty with.</param> /// <param name="ruleset">The ruleset to show the difficulty with.</param>
/// <param name="mods">The mods to show the difficulty with.</param> /// <param name="mods">The mods to show the difficulty with.</param>
/// <param name="shouldShowTooltip">Whether to display a tooltip when hovered.</param> /// <param name="shouldShowTooltip">Whether to display a tooltip when hovered.</param>
public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList<Mod> mods, bool shouldShowTooltip = true) /// <param name="performBackgroundDifficultyLookup">Whether to perform difficulty lookup (including calculation if necessary).</param>
: this(beatmapInfo, shouldShowTooltip) public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList<Mod> mods, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true)
: this(beatmapInfo, shouldShowTooltip, performBackgroundDifficultyLookup)
{ {
this.ruleset = ruleset ?? beatmapInfo.Ruleset; this.ruleset = ruleset ?? beatmapInfo.Ruleset;
this.mods = mods ?? Array.Empty<Mod>(); this.mods = mods ?? Array.Empty<Mod>();

View File

@ -7,12 +7,10 @@ using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Game.Graphics.Sprites;
using osu.Game.Users; using osu.Game.Users;
namespace osu.Game.Graphics.Containers namespace osu.Game.Graphics.Containers
@ -58,23 +56,14 @@ namespace osu.Game.Graphics.Containers
AddText(text.Substring(previousLinkEnd)); AddText(text.Substring(previousLinkEnd));
} }
public void AddLink(string text, string url, Action<SpriteText> creationParameters = null) => public void AddLink(LocalisableString text, string url, Action<SpriteText> creationParameters = null) =>
createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.External, url), url); createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.External, url), url);
public void AddLink(string text, Action action, string tooltipText = null, Action<SpriteText> creationParameters = null) public void AddLink(LocalisableString text, Action action, string tooltipText = null, Action<SpriteText> creationParameters = null)
=> createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.Custom, string.Empty), tooltipText, action); => 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<SpriteText> 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<SpriteText> creationParameters = null) public void AddLink(LocalisableString text, LinkAction action, string argument, string tooltipText = null, Action<SpriteText> creationParameters = null)
{ => createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(action, argument), tooltipText);
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);
}
public void AddLink(IEnumerable<SpriteText> text, LinkAction action, string linkArgument, string tooltipText = null) public void AddLink(IEnumerable<SpriteText> text, LinkAction action, string linkArgument, string tooltipText = null)
{ {

View File

@ -8,6 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
namespace osu.Game.Graphics.UserInterface namespace osu.Game.Graphics.UserInterface
@ -19,7 +20,7 @@ namespace osu.Game.Graphics.UserInterface
/// </summary> /// </summary>
protected virtual bool PlaySoundsOnUserChange => true; protected virtual bool PlaySoundsOnUserChange => true;
public string LabelText public LocalisableString LabelText
{ {
set set
{ {

View File

@ -8,6 +8,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Overlays; using osu.Game.Overlays;
using osuTK; using osuTK;
@ -156,18 +157,18 @@ namespace osu.Game.Graphics.UserInterfaceV2
descriptionText.Colour = osuColour.Yellow; descriptionText.Colour = osuColour.Yellow;
} }
public string Label public LocalisableString Label
{ {
set => labelText.Text = value; set => labelText.Text = value;
} }
public string Description public LocalisableString Description
{ {
set set
{ {
descriptionText.Text = value; descriptionText.Text = value;
if (!string.IsNullOrEmpty(value)) if (value == default)
descriptionText.Show(); descriptionText.Show();
else else
descriptionText.Hide(); descriptionText.Hide();

View File

@ -107,7 +107,8 @@ namespace osu.Game.Online.API
WebRequest = CreateWebRequest(); WebRequest = CreateWebRequest();
WebRequest.Failed += Fail; WebRequest.Failed += Fail;
WebRequest.AllowRetryOnTimeout = false; WebRequest.AllowRetryOnTimeout = false;
WebRequest.AddHeader("Authorization", $"Bearer {API.AccessToken}"); if (!string.IsNullOrEmpty(API.AccessToken))
WebRequest.AddHeader("Authorization", $"Bearer {API.AccessToken}");
if (isFailing) return; if (isFailing) return;

View File

@ -37,6 +37,7 @@ namespace osu.Game.Online.API.Requests.Responses
public DateTimeOffset Date { get; set; } public DateTimeOffset Date { get; set; }
[JsonProperty(@"beatmap")] [JsonProperty(@"beatmap")]
[CanBeNull]
public APIBeatmap Beatmap { get; set; } public APIBeatmap Beatmap { get; set; }
[JsonProperty("accuracy")] [JsonProperty("accuracy")]
@ -46,6 +47,7 @@ namespace osu.Game.Online.API.Requests.Responses
public double? PP { get; set; } public double? PP { get; set; }
[JsonProperty(@"beatmapset")] [JsonProperty(@"beatmapset")]
[CanBeNull]
public APIBeatmapSet BeatmapSet public APIBeatmapSet BeatmapSet
{ {
set set
@ -96,7 +98,7 @@ namespace osu.Game.Online.API.Requests.Responses
{ {
TotalScore = TotalScore, TotalScore = TotalScore,
MaxCombo = MaxCombo, MaxCombo = MaxCombo,
BeatmapInfo = Beatmap.ToBeatmapInfo(rulesets), BeatmapInfo = Beatmap?.ToBeatmapInfo(rulesets),
User = User, User = User,
Accuracy = Accuracy, Accuracy = Accuracy,
OnlineScoreID = OnlineID, OnlineScoreID = OnlineID,

View File

@ -3,6 +3,7 @@
using System; using System;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
@ -12,7 +13,7 @@ namespace osu.Game.Online.Placeholders
{ {
public Action Action; public Action Action;
public ClickablePlaceholder(string actionMessage, IconUsage icon) public ClickablePlaceholder(LocalisableString actionMessage, IconUsage icon)
{ {
OsuTextFlowContainer textFlow; OsuTextFlowContainer textFlow;

View File

@ -3,14 +3,15 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
namespace osu.Game.Online.Placeholders namespace osu.Game.Online.Placeholders
{ {
public class MessagePlaceholder : Placeholder 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 => AddIcon(FontAwesome.Solid.ExclamationCircle, cp =>
{ {

View File

@ -53,7 +53,10 @@ namespace osu.Game.Online.Rooms
downloadTracker?.RemoveAndDisposeImmediately(); downloadTracker?.RemoveAndDisposeImmediately();
downloadTracker = new BeatmapDownloadTracker(item.NewValue.Beatmap.Value.BeatmapSet); downloadTracker = new BeatmapDownloadTracker(item.NewValue.Beatmap.Value.BeatmapSet);
downloadTracker.State.BindValueChanged(_ => updateAvailability());
AddInternal(downloadTracker);
downloadTracker.State.BindValueChanged(_ => updateAvailability(), true);
downloadTracker.Progress.BindValueChanged(_ => downloadTracker.Progress.BindValueChanged(_ =>
{ {
if (downloadTracker.State.Value != DownloadState.Downloading) 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. // we don't want to flood the network with this, so rate limit how often we send progress updates.
if (progressUpdate?.Completed != false) if (progressUpdate?.Completed != false)
progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500); progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500);
}); }, true);
AddInternal(downloadTracker);
}, true); }, true);
} }

View File

@ -5,6 +5,7 @@ using System.Net.Http;
using Newtonsoft.Json; using Newtonsoft.Json;
using osu.Framework.IO.Network; using osu.Framework.IO.Network;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.Solo;
using osu.Game.Scoring; using osu.Game.Scoring;
namespace osu.Game.Online.Rooms namespace osu.Game.Online.Rooms
@ -14,14 +15,14 @@ namespace osu.Game.Online.Rooms
private readonly long scoreId; private readonly long scoreId;
private readonly long roomId; private readonly long roomId;
private readonly long playlistItemId; private readonly long playlistItemId;
private readonly ScoreInfo scoreInfo; private readonly SubmittableScore score;
public SubmitRoomScoreRequest(long scoreId, long roomId, long playlistItemId, ScoreInfo scoreInfo) public SubmitRoomScoreRequest(long scoreId, long roomId, long playlistItemId, ScoreInfo scoreInfo)
{ {
this.scoreId = scoreId; this.scoreId = scoreId;
this.roomId = roomId; this.roomId = roomId;
this.playlistItemId = playlistItemId; this.playlistItemId = playlistItemId;
this.scoreInfo = scoreInfo; score = new SubmittableScore(scoreInfo);
} }
protected override WebRequest CreateWebRequest() protected override WebRequest CreateWebRequest()
@ -31,7 +32,7 @@ namespace osu.Game.Online.Rooms
req.ContentType = "application/json"; req.ContentType = "application/json";
req.Method = HttpMethod.Put; req.Method = HttpMethod.Put;
req.AddRaw(JsonConvert.SerializeObject(scoreInfo, new JsonSerializerSettings req.AddRaw(JsonConvert.SerializeObject(score, new JsonSerializerSettings
{ {
ReferenceLoopHandling = ReferenceLoopHandling.Ignore ReferenceLoopHandling = ReferenceLoopHandling.Ignore
})); }));

View File

@ -35,7 +35,11 @@ namespace osu.Game.Online
return; return;
// Used to interact with manager classes that don't support interface types. Will eventually be replaced. // 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)) if (Manager.IsAvailableLocally(scoreInfo))
UpdateState(DownloadState.LocallyAvailable); UpdateState(DownloadState.LocallyAvailable);

View File

@ -5,7 +5,6 @@ using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Utils; using osu.Framework.Utils;
@ -135,7 +134,16 @@ namespace osu.Game.Overlays.AccountCreation
characterCheckText = passwordDescription.AddText("8 characters long"); characterCheckText = passwordDescription.AddText("8 characters long");
passwordDescription.AddText(". Choose something long but also something you will remember, like a line from your favourite song."); 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) public override void OnEntering(IScreen last)

View File

@ -86,7 +86,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
break; break;
default: default:
beatmaps.Download(new BeatmapSetInfo { OnlineBeatmapSetID = beatmapSet.OnlineID }, noVideoSetting.Value); beatmaps.Download(beatmapSet, noVideoSetting.Value);
break; break;
} }
}; };

View File

@ -108,7 +108,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
return; return;
} }
beatmaps.Download(new BeatmapSetInfo { OnlineBeatmapSetID = beatmapSet.OnlineID }, noVideo); beatmaps.Download(beatmapSet, noVideo);
}; };
localUser.BindTo(api.LocalUser); localUser.BindTo(api.LocalUser);

View File

@ -101,7 +101,7 @@ namespace osu.Game.Overlays.Changelog
t.Colour = colour.PinkLighter; t.Colour = colour.PinkLighter;
}) })
{ {
Text = ChangelogStrings.SupportText2.ToString(), Text = ChangelogStrings.SupportText2,
Margin = new MarginPadding { Top = 10 }, Margin = new MarginPadding { Top = 10 },
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,

View File

@ -10,6 +10,7 @@ using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osuTK; using osuTK;
@ -42,9 +43,9 @@ namespace osu.Game.Overlays.Dialog
set => icon.Icon = value; set => icon.Icon = value;
} }
private string headerText; private LocalisableString headerText;
public string HeaderText public LocalisableString HeaderText
{ {
get => headerText; get => headerText;
set set
@ -57,9 +58,9 @@ namespace osu.Game.Overlays.Dialog
} }
} }
private string bodyText; private LocalisableString bodyText;
public string BodyText public LocalisableString BodyText
{ {
get => bodyText; get => bodyText;
set set

View File

@ -25,11 +25,8 @@ namespace osu.Game.Overlays.Music
private TextFlowContainer text; private TextFlowContainer text;
private ITextPart titlePart; private ITextPart titlePart;
private ILocalisedBindableString title; [Resolved]
private ILocalisedBindableString artist; private OsuColour colours { get; set; }
private Color4 selectedColour;
private Color4 artistColour;
public PlaylistItem(BeatmapSetInfo item) public PlaylistItem(BeatmapSetInfo item)
: base(item) : base(item)
@ -40,22 +37,15 @@ namespace osu.Game.Overlays.Music
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours, LocalisationManager localisation) private void load()
{ {
selectedColour = colours.Yellow;
artistColour = colours.Gray9;
HandleColour = colours.Gray5; 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() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
artist.BindValueChanged(_ => recreateText(), true);
SelectedSet.BindValueChanged(set => SelectedSet.BindValueChanged(set =>
{ {
if (set.OldValue?.Equals(Model) != true && set.NewValue?.Equals(Model) != true) 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) private void updateSelectionState(bool instant)
{ {
foreach (Drawable s in titlePart.Drawables) 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 protected override Drawable CreateContent() => text = new OsuTextFlowContainer
@ -77,18 +67,23 @@ namespace osu.Game.Overlays.Music
AutoSizeAxes = Axes.Y, 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 var title = new RomanisableString(Model.Metadata.TitleUnicode, Model.Metadata.Title);
titlePart = text.AddText(title.Value + @" ", sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular)); var artist = new RomanisableString(Model.Metadata.ArtistUnicode, Model.Metadata.Artist);
titlePart = text.AddText(title, sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular));
updateSelectionState(true); 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.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold);
sprite.Colour = artistColour; sprite.Colour = colours.Gray9;
sprite.Padding = new MarginPadding { Top = 1 }; sprite.Padding = new MarginPadding { Top = 1 };
}); });
} }

View File

@ -10,6 +10,7 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
@ -22,7 +23,7 @@ namespace osu.Game.Overlays.Notifications
{ {
private const float loading_spinner_size = 22; private const float loading_spinner_size = 22;
public string Text public LocalisableString Text
{ {
set => Schedule(() => textDrawable.Text = value); set => Schedule(() => textDrawable.Text = value);
} }

View File

@ -7,6 +7,7 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osuTK; using osuTK;
@ -15,9 +16,9 @@ namespace osu.Game.Overlays.Notifications
{ {
public class SimpleNotification : Notification public class SimpleNotification : Notification
{ {
private string text = string.Empty; private LocalisableString text;
public string Text public LocalisableString Text
{ {
get => text; get => text;
set set

View File

@ -91,7 +91,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
{ {
new OsuSpriteText new OsuSpriteText
{ {
Text = $"{Score.Beatmap.DifficultyName}", Text = $"{Score.Beatmap?.DifficultyName}",
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular), Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
Colour = colours.Yellow Colour = colours.Yellow
}, },

View File

@ -83,7 +83,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
cp.Font = OsuFont.Default.With(size: 24); cp.Font = OsuFont.Default.With(size: 24);
}) })
{ {
Text = HeaderText.ToString(), Text = HeaderText,
TextAnchor = Anchor.TopCentre, TextAnchor = Anchor.TopCentre,
Margin = new MarginPadding(10), Margin = new MarginPadding(10),
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,

View File

@ -16,8 +16,7 @@ namespace osu.Game.Overlays.Settings
public override LocalisableString LabelText public override LocalisableString LabelText
{ {
get => labelText; get => labelText;
// checkbox doesn't properly support localisation yet. set => ((OsuCheckbox)Control).LabelText = labelText = value;
set => ((OsuCheckbox)Control).LabelText = (labelText = value).ToString();
} }
} }
} }

View File

@ -68,7 +68,7 @@ namespace osu.Game.Overlays.Settings
{ {
set set
{ {
bool hasValue = !string.IsNullOrWhiteSpace(value.ToString()); bool hasValue = value != default;
if (warningText == null) if (warningText == null)
{ {
@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Settings
} }
warningText.Alpha = hasValue ? 1 : 0; 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;
} }
} }

View File

@ -58,6 +58,11 @@ namespace osu.Game.Rulesets.Difficulty
return CreateDifficultyAttributes(Beatmap, playableMods, skills, clockRate); return CreateDifficultyAttributes(Beatmap, playableMods, skills, clockRate);
} }
/// <summary>
/// Calculates the difficulty of the beatmap and returns a set of <see cref="TimedDifficultyAttributes"/> representing the difficulty at every relevant time value in the beatmap.
/// </summary>
/// <param name="mods">The mods that should be applied to the beatmap.</param>
/// <returns>The set of <see cref="TimedDifficultyAttributes"/>.</returns>
public List<TimedDifficultyAttributes> CalculateTimed(params Mod[] mods) public List<TimedDifficultyAttributes> CalculateTimed(params Mod[] mods)
{ {
preProcess(mods); preProcess(mods);
@ -77,7 +82,7 @@ namespace osu.Game.Rulesets.Difficulty
foreach (var skill in skills) foreach (var skill in skills)
skill.ProcessInternal(hitObject); 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; return attribs;

View File

@ -11,9 +11,21 @@ namespace osu.Game.Rulesets.Difficulty
/// </summary> /// </summary>
public class TimedDifficultyAttributes : IComparable<TimedDifficultyAttributes> public class TimedDifficultyAttributes : IComparable<TimedDifficultyAttributes>
{ {
/// <summary>
/// The non-clock-adjusted time value at which the attributes take effect.
/// </summary>
public readonly double Time; public readonly double Time;
/// <summary>
/// The attributes.
/// </summary>
public readonly DifficultyAttributes Attributes; public readonly DifficultyAttributes Attributes;
/// <summary>
/// Creates new <see cref="TimedDifficultyAttributes"/>.
/// </summary>
/// <param name="time">The non-clock-adjusted time value at which the attributes take effect.</param>
/// <param name="attributes">The attributes.</param>
public TimedDifficultyAttributes(double time, DifficultyAttributes attributes) public TimedDifficultyAttributes(double time, DifficultyAttributes attributes)
{ {
Time = time; Time = time;

View File

@ -6,6 +6,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings;
@ -16,7 +17,7 @@ namespace osu.Game.Screens.Edit.Timing
{ {
private readonly SettingsSlider<T> slider; private readonly SettingsSlider<T> slider;
public SliderWithTextBoxInput(string labelText) public SliderWithTextBoxInput(LocalisableString labelText)
{ {
LabelledTextBox textbox; LabelledTextBox textbox;

View File

@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat; using osu.Game.Online.Chat;
namespace osu.Game.Screens.OnlinePlay.Components namespace osu.Game.Screens.OnlinePlay.Components
@ -69,24 +68,14 @@ namespace osu.Game.Screens.OnlinePlay.Components
} }
else else
{ {
textFlow.AddLink(new[] var metadataInfo = beatmap.Value.Metadata;
{
new OsuSpriteText string artistUnicode = string.IsNullOrEmpty(metadataInfo.ArtistUnicode) ? metadataInfo.Artist : metadataInfo.ArtistUnicode;
{ string titleUnicode = string.IsNullOrEmpty(metadataInfo.TitleUnicode) ? metadataInfo.Title : metadataInfo.TitleUnicode;
Text = new RomanisableString(beatmap.Value.Metadata.ArtistUnicode, beatmap.Value.Metadata.Artist),
Font = OsuFont.GetFont(size: TextSize), var title = new RomanisableString($"{artistUnicode} - {titleUnicode}".Trim(), $"{metadataInfo.Artist} - {metadataInfo.Title}".Trim());
},
new OsuSpriteText textFlow.AddLink(title, LinkAction.OpenBeatmap, beatmap.Value.OnlineID.ToString(), "Open beatmap");
{
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");
} }
} }
} }

View File

@ -105,13 +105,12 @@ namespace osu.Game.Screens.OnlinePlay
private void refresh() 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.Clear();
beatmapText.AddLink(Item.Beatmap.Value.GetDisplayTitleRomanisable(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineBeatmapID.ToString(), null, text => beatmapText.AddLink(Item.Beatmap.Value.GetDisplayTitleRomanisable(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineBeatmapID.ToString(), null, text =>
{ {
text.Truncate = true; text.Truncate = true;
text.RelativeSizeAxes = Axes.X;
}); });
authorText.Clear(); authorText.Clear();

View File

@ -4,6 +4,7 @@
using System.Collections.Specialized; using System.Collections.Specialized;
using Humanizer; using Humanizer;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
@ -46,7 +47,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
private void updateCount(object sender, NotifyCollectionChangedEventArgs e) private void updateCount(object sender, NotifyCollectionChangedEventArgs e)
{ {
count.Clear(); 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(" ");
count.AddText("Beatmap".ToQuantity(Playlist.Count, ShowQuantityAs.None)); count.AddText("Beatmap".ToQuantity(Playlist.Count, ShowQuantityAs.None));
} }

View File

@ -188,8 +188,8 @@ namespace osu.Game.Screens.Select
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
titleBinding = localisation.GetLocalisedString(new RomanisableString(metadata.TitleUnicode, metadata.Title)); titleBinding = localisation.GetLocalisedBindableString(new RomanisableString(metadata.TitleUnicode, metadata.Title));
artistBinding = localisation.GetLocalisedString(new RomanisableString(metadata.ArtistUnicode, metadata.Artist)); artistBinding = localisation.GetLocalisedBindableString(new RomanisableString(metadata.ArtistUnicode, metadata.Artist));
const float top_height = 0.7f; const float top_height = 0.7f;

View File

@ -36,7 +36,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Realm" Version="10.6.0" /> <PackageReference Include="Realm" Version="10.6.0" />
<PackageReference Include="ppy.osu.Framework" Version="2021.1029.0" /> <PackageReference Include="ppy.osu.Framework" Version="2021.1103.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" />
<PackageReference Include="Sentry" Version="3.10.0" /> <PackageReference Include="Sentry" Version="3.10.0" />
<PackageReference Include="SharpCompress" Version="0.30.0" /> <PackageReference Include="SharpCompress" Version="0.30.0" />

View File

@ -70,7 +70,7 @@
<Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.1029.0" /> <PackageReference Include="ppy.osu.Framework.iOS" Version="2021.1103.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" />
</ItemGroup> </ItemGroup>
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) --> <!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
@ -93,7 +93,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2021.1029.0" /> <PackageReference Include="ppy.osu.Framework" Version="2021.1103.0" />
<PackageReference Include="SharpCompress" Version="0.30.0" /> <PackageReference Include="SharpCompress" Version="0.30.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="SharpRaven" Version="2.4.0" /> <PackageReference Include="SharpRaven" Version="2.4.0" />