diff --git a/osu.Android.props b/osu.Android.props
index 896b10133d..f76297c197 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -63,6 +63,6 @@
-
+
diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkinTransformer.cs
index 5957b81d7e..6b6a08ed21 100644
--- a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkinTransformer.cs
+++ b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkinTransformer.cs
@@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
return null;
case OsuSkinComponents.HitCircleText:
- var font = GetConfig(OsuSkinConfiguration.HitCircleFont)?.Value ?? "default";
+ var font = GetConfig(OsuSkinConfiguration.HitCirclePrefix)?.Value ?? "default";
var overlap = GetConfig(OsuSkinConfiguration.HitCircleOverlap)?.Value ?? 0;
return !hasFont(font)
diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuSkinConfiguration.cs b/osu.Game.Rulesets.Osu/Skinning/OsuSkinConfiguration.cs
index a6b87150ae..e7b686d27d 100644
--- a/osu.Game.Rulesets.Osu/Skinning/OsuSkinConfiguration.cs
+++ b/osu.Game.Rulesets.Osu/Skinning/OsuSkinConfiguration.cs
@@ -5,7 +5,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
{
public enum OsuSkinConfiguration
{
- HitCircleFont,
+ HitCirclePrefix,
HitCircleOverlap,
SliderBorderSize,
SliderPathRadius,
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLineTruncation.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLineTruncation.cs
new file mode 100644
index 0000000000..4773e84a5e
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneChatLineTruncation.cs
@@ -0,0 +1,108 @@
+// 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 NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics.Containers;
+using osu.Game.Online.Chat;
+using osu.Game.Overlays.Chat;
+using osu.Game.Users;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ [TestFixture]
+ public class TestSceneChatLineTruncation : OsuTestScene
+ {
+ private readonly TestChatLineContainer textContainer;
+
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(ChatLine),
+ typeof(Message),
+ typeof(LinkFlowContainer),
+ typeof(MessageFormatter)
+ };
+
+ public TestSceneChatLineTruncation()
+ {
+ Add(textContainer = new TestChatLineContainer
+ {
+ Padding = new MarginPadding { Left = 20, Right = 20 },
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ });
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ testFormatting();
+ }
+
+ private void clear() => AddStep("clear messages", textContainer.Clear);
+
+ private void addMessageWithChecks(string text, bool isAction = false, bool isImportant = false, string username = null)
+ {
+ int index = textContainer.Count + 1;
+ var newLine = new ChatLine(new DummyMessage(text, isAction, isImportant, index, username));
+ textContainer.Add(newLine);
+ }
+
+ private void testFormatting()
+ {
+ for (int a = 0; a < 25; a++)
+ addMessageWithChecks($"Wide {a} character username.", username: new string('w', a));
+ addMessageWithChecks("Short name with spaces.", username: "sho rt name");
+ addMessageWithChecks("Long name with spaces.", username: "long name with s p a c e s");
+ }
+
+ private class DummyMessage : Message
+ {
+ private static long messageCounter;
+
+ internal static readonly User TEST_SENDER_BACKGROUND = new User
+ {
+ Username = @"i-am-important",
+ Id = 42,
+ Colour = "#250cc9",
+ };
+
+ internal static readonly User TEST_SENDER = new User
+ {
+ Username = @"Somebody",
+ Id = 1,
+ };
+
+ public new DateTimeOffset Timestamp = DateTimeOffset.Now;
+
+ public DummyMessage(string text, bool isAction = false, bool isImportant = false, int number = 0, string username = null)
+ : base(messageCounter++)
+ {
+ Content = text;
+ IsAction = isAction;
+ Sender = new User
+ {
+ Username = username ?? $"user {number}",
+ Id = number,
+ Colour = isImportant ? "#250cc9" : null,
+ };
+ }
+ }
+
+ private class TestChatLineContainer : FillFlowContainer
+ {
+ protected override int Compare(Drawable x, Drawable y)
+ {
+ var xC = (ChatLine)x;
+ var yC = (ChatLine)y;
+
+ return xC.Message.CompareTo(yC.Message);
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs
index 7b97a27732..ed9e01a67e 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs
@@ -9,6 +9,7 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Screens.Select;
+using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual.SongSelect
@@ -30,45 +31,44 @@ namespace osu.Game.Tests.Visual.SongSelect
Size = new Vector2(550f, 450f),
});
- AddStep("all metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
+ AddStep("all metrics", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
+ {
+ BeatmapInfo =
{
- BeatmapSetInfo =
+ BeatmapSet = new BeatmapSetInfo
{
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
},
- BeatmapInfo =
+ Version = "All Metrics",
+ Metadata = new BeatmapMetadata
{
- Version = "All Metrics",
- Metadata = new BeatmapMetadata
- {
- Source = "osu!lazer",
- Tags = "this beatmap has all the metrics",
- },
- BaseDifficulty = new BeatmapDifficulty
- {
- CircleSize = 7,
- DrainRate = 1,
- OverallDifficulty = 5.7f,
- ApproachRate = 3.5f,
- },
- StarDifficulty = 5.3f,
- Metrics = new BeatmapMetrics
- {
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
- },
- }
+ Source = "osu!lazer",
+ Tags = "this beatmap has all the metrics",
+ },
+ BaseDifficulty = new BeatmapDifficulty
+ {
+ CircleSize = 7,
+ DrainRate = 1,
+ OverallDifficulty = 5.7f,
+ ApproachRate = 3.5f,
+ },
+ StarDifficulty = 5.3f,
+ Metrics = new BeatmapMetrics
+ {
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
+ },
}
- );
+ }));
- AddStep("all except source", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
+ AddStep("all except source", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
{
- BeatmapSetInfo =
- {
- Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
- },
BeatmapInfo =
{
+ BeatmapSet = new BeatmapSetInfo
+ {
+ Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
+ },
Version = "All Metrics",
Metadata = new BeatmapMetadata
{
@@ -88,16 +88,16 @@ namespace osu.Game.Tests.Visual.SongSelect
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
}
- });
+ }));
- AddStep("ratings", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
+ AddStep("ratings", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
{
- BeatmapSetInfo =
- {
- Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
- },
BeatmapInfo =
{
+ BeatmapSet = new BeatmapSetInfo
+ {
+ Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
+ },
Version = "Only Ratings",
Metadata = new BeatmapMetadata
{
@@ -113,9 +113,9 @@ namespace osu.Game.Tests.Visual.SongSelect
},
StarDifficulty = 4.8f
}
- });
+ }));
- AddStep("fails+retries", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
+ AddStep("fails+retries", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
{
BeatmapInfo =
{
@@ -139,9 +139,9 @@ namespace osu.Game.Tests.Visual.SongSelect
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
}
- });
+ }));
- AddStep("null metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
+ AddStep("null metrics", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
{
BeatmapInfo =
{
@@ -160,7 +160,7 @@ namespace osu.Game.Tests.Visual.SongSelect
},
StarDifficulty = 1.97f,
}
- });
+ }));
AddStep("null beatmap", () => detailsArea.Beatmap = null);
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs
index 8e358a77db..186f27a8b2 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs
@@ -42,6 +42,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep(@"No supporter", () => leaderboard.SetRetrievalState(PlaceholderState.NotSupporter));
AddStep(@"Not logged in", () => leaderboard.SetRetrievalState(PlaceholderState.NotLoggedIn));
AddStep(@"Unavailable", () => leaderboard.SetRetrievalState(PlaceholderState.Unavailable));
+ AddStep(@"None selected", () => leaderboard.SetRetrievalState(PlaceholderState.NoneSelected));
foreach (BeatmapSetOnlineStatus status in Enum.GetValues(typeof(BeatmapSetOnlineStatus)))
AddStep($"{status} beatmap", () => showBeatmapWithStatus(status));
}
diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs
index 98f15599fc..147556b78b 100644
--- a/osu.Game/Online/Leaderboards/Leaderboard.cs
+++ b/osu.Game/Online/Leaderboards/Leaderboard.cs
@@ -133,6 +133,10 @@ namespace osu.Game.Online.Leaderboards
});
break;
+ case PlaceholderState.NoneSelected:
+ replacePlaceholder(new MessagePlaceholder(@"Please select a beatmap!"));
+ break;
+
case PlaceholderState.Unavailable:
replacePlaceholder(new MessagePlaceholder(@"Leaderboards are not available for this beatmap!"));
break;
diff --git a/osu.Game/Online/Leaderboards/PlaceholderState.cs b/osu.Game/Online/Leaderboards/PlaceholderState.cs
index 930e1df484..297241fa73 100644
--- a/osu.Game/Online/Leaderboards/PlaceholderState.cs
+++ b/osu.Game/Online/Leaderboards/PlaceholderState.cs
@@ -9,6 +9,7 @@ namespace osu.Game.Online.Leaderboards
Retrieving,
NetworkFailure,
Unavailable,
+ NoneSelected,
NoScores,
NotLoggedIn,
NotSupporter,
diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs
index 2576b38ec8..7596231a3d 100644
--- a/osu.Game/Overlays/Chat/ChatLine.cs
+++ b/osu.Game/Overlays/Chat/ChatLine.cs
@@ -31,6 +31,8 @@ namespace osu.Game.Overlays.Chat
protected virtual float MessagePadding => default_message_padding;
+ private const float timestamp_padding = 65;
+
private const float default_horizontal_padding = 15;
protected virtual float HorizontalPadding => default_horizontal_padding;
@@ -87,7 +89,12 @@ namespace osu.Game.Overlays.Chat
{
Shadow = false,
Colour = hasBackground ? customUsernameColour : username_colours[message.Sender.Id % username_colours.Length],
- Font = OsuFont.GetFont(size: TextSize, weight: FontWeight.Bold, italics: true)
+ Truncate = true,
+ EllipsisString = "… :",
+ Font = OsuFont.GetFont(size: TextSize, weight: FontWeight.Bold, italics: true),
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ MaxWidth = default_message_padding - timestamp_padding
};
if (hasBackground)
@@ -142,6 +149,7 @@ namespace osu.Game.Overlays.Chat
new MessageSender(message.Sender)
{
AutoSizeAxes = Axes.Both,
+ Padding = new MarginPadding { Left = timestamp_padding },
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
Child = effectedUsername,
diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs
index b66a2ffe0f..5348de68d6 100644
--- a/osu.Game/Screens/Select/BeatmapDetailArea.cs
+++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs
@@ -27,8 +27,8 @@ namespace osu.Game.Screens.Select
set
{
beatmap = value;
- Leaderboard.Beatmap = beatmap?.BeatmapInfo;
Details.Beatmap = beatmap?.BeatmapInfo;
+ Leaderboard.Beatmap = beatmap is DummyWorkingBeatmap ? null : beatmap?.BeatmapInfo;
}
}
diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
index cb45c00f66..33f040755e 100644
--- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
+++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
@@ -83,6 +83,12 @@ namespace osu.Game.Screens.Select.Leaderboards
protected override APIRequest FetchScores(Action> scoresCallback)
{
+ if (Beatmap == null)
+ {
+ PlaceholderState = PlaceholderState.NoneSelected;
+ return null;
+ }
+
if (Scope == BeatmapLeaderboardScope.Local)
{
var scores = scoreManager
@@ -113,7 +119,7 @@ namespace osu.Game.Screens.Select.Leaderboards
return null;
}
- if (Beatmap?.OnlineBeatmapID == null || Beatmap?.Status <= BeatmapSetOnlineStatus.Pending)
+ if (Beatmap.OnlineBeatmapID == null || Beatmap?.Status <= BeatmapSetOnlineStatus.Pending)
{
PlaceholderState = PlaceholderState.Unavailable;
return null;
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 5f2aad24dc..791d2fe285 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -26,7 +26,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 5027a4ef8c..0560c45edf 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -118,8 +118,8 @@
-
-
+
+