diff --git a/Gemfile.lock b/Gemfile.lock
index a4b49af7e4..8ac863c9a8 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,27 +1,27 @@
GEM
remote: https://rubygems.org/
specs:
- CFPropertyList (3.0.2)
+ CFPropertyList (3.0.3)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
atomos (0.1.3)
aws-eventstream (1.1.0)
- aws-partitions (1.354.0)
- aws-sdk-core (3.104.3)
+ aws-partitions (1.413.0)
+ aws-sdk-core (3.110.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.239.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
- aws-sdk-kms (1.36.0)
- aws-sdk-core (~> 3, >= 3.99.0)
+ aws-sdk-kms (1.40.0)
+ aws-sdk-core (~> 3, >= 3.109.0)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.78.0)
- aws-sdk-core (~> 3, >= 3.104.3)
+ aws-sdk-s3 (1.87.0)
+ aws-sdk-core (~> 3, >= 3.109.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1)
- aws-sigv4 (1.2.1)
+ aws-sigv4 (1.2.2)
aws-eventstream (~> 1, >= 1.0.2)
- babosa (1.0.3)
+ babosa (1.0.4)
claide (1.0.3)
colored (1.2)
colored2 (3.1.2)
@@ -29,22 +29,23 @@ GEM
highline (~> 1.7.2)
declarative (0.0.20)
declarative-option (0.1.0)
- digest-crc (0.6.1)
- rake (~> 13.0)
+ digest-crc (0.6.3)
+ rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.6)
- emoji_regex (3.0.0)
- excon (0.76.0)
- faraday (1.0.1)
+ emoji_regex (3.2.1)
+ excon (0.78.1)
+ faraday (1.2.0)
multipart-post (>= 1.2, < 3)
- faraday-cookie_jar (0.0.6)
- faraday (>= 0.7.4)
+ ruby2_keywords
+ faraday-cookie_jar (0.0.7)
+ faraday (>= 0.8.0)
http-cookie (~> 1.0.0)
faraday_middleware (1.0.0)
faraday (~> 1.0)
- fastimage (2.2.0)
- fastlane (2.156.0)
+ fastimage (2.2.1)
+ fastlane (2.170.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0)
aws-sdk-s3 (~> 1.0)
@@ -96,17 +97,17 @@ GEM
google-cloud-core (1.5.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
- google-cloud-env (1.3.3)
+ google-cloud-env (1.4.0)
faraday (>= 0.17.3, < 2.0)
google-cloud-errors (1.0.1)
- google-cloud-storage (1.27.0)
+ google-cloud-storage (1.29.2)
addressable (~> 2.5)
digest-crc (~> 0.4)
google-api-client (~> 0.33)
google-cloud-core (~> 1.2)
googleauth (~> 0.9)
mini_mime (~> 1.0)
- googleauth (0.13.1)
+ googleauth (0.14.0)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
@@ -118,10 +119,10 @@ GEM
domain_name (~> 0.5)
httpclient (2.8.3)
jmespath (1.4.0)
- json (2.3.1)
- jwt (2.2.1)
+ json (2.5.1)
+ jwt (2.2.2)
memoist (0.16.2)
- mini_magick (4.10.1)
+ mini_magick (4.11.0)
mini_mime (1.0.2)
mini_portile2 (2.4.0)
multi_json (1.15.0)
@@ -132,14 +133,15 @@ GEM
mini_portile2 (~> 2.4.0)
os (1.1.1)
plist (3.5.0)
- public_suffix (4.0.5)
- rake (13.0.1)
+ public_suffix (4.0.6)
+ rake (13.0.3)
representable (3.0.4)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rouge (2.0.7)
+ ruby2_keywords (0.0.2)
rubyzip (2.3.0)
security (0.1.3)
signet (0.14.0)
@@ -168,7 +170,7 @@ GEM
unf_ext (0.0.7.7)
unicode-display_width (1.7.0)
word_wrap (1.0.0)
- xcodeproj (1.18.0)
+ xcodeproj (1.19.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
diff --git a/osu.Android.props b/osu.Android.props
index fc01f9bf1d..cd2ce58c55 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,6 +52,6 @@
-
+
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs
index 8078c7b994..975c54c3f6 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs
@@ -20,14 +20,17 @@ using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.Play.HUD;
+using osu.Game.Tests.Visual.Multiplayer;
using osu.Game.Tests.Visual.Online;
namespace osu.Game.Tests.Visual.Gameplay
{
- public class TestSceneMultiplayerGameplayLeaderboard : OsuTestScene
+ public class TestSceneMultiplayerGameplayLeaderboard : MultiplayerTestScene
{
+ private const int users = 16;
+
[Cached(typeof(SpectatorStreamingClient))]
- private TestMultiplayerStreaming streamingClient = new TestMultiplayerStreaming(16);
+ private TestMultiplayerStreaming streamingClient = new TestMultiplayerStreaming(users);
[Cached(typeof(UserLookupCache))]
private UserLookupCache lookupCache = new TestSceneCurrentlyPlayingDisplay.TestUserLookupCache();
@@ -47,10 +50,12 @@ namespace osu.Game.Tests.Visual.Gameplay
}
[SetUpSteps]
- public void SetUpSteps()
+ public override void SetUpSteps()
{
AddStep("create leaderboard", () =>
{
+ leaderboard?.Expire();
+
OsuScoreProcessor scoreProcessor;
Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value);
@@ -58,6 +63,9 @@ namespace osu.Game.Tests.Visual.Gameplay
streamingClient.Start(Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0);
+ Client.PlayingUsers.Clear();
+ Client.PlayingUsers.AddRange(streamingClient.PlayingUsers);
+
Children = new Drawable[]
{
scoreProcessor = new OsuScoreProcessor(),
@@ -81,6 +89,12 @@ namespace osu.Game.Tests.Visual.Gameplay
AddRepeatStep("update state", () => streamingClient.RandomlyUpdateState(), 100);
}
+ [Test]
+ public void TestUserQuit()
+ {
+ AddRepeatStep("mark user quit", () => Client.PlayingUsers.RemoveAt(0), users);
+ }
+
public class TestMultiplayerStreaming : SpectatorStreamingClient
{
public new BindableList PlayingUsers => (BindableList)base.PlayingUsers;
diff --git a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs
index dcfe0432a8..3d65e7e4ba 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@@ -13,13 +14,12 @@ namespace osu.Game.Tests.Visual.Online
public class TestSceneAccountCreationOverlay : OsuTestScene
{
private readonly Container userPanelArea;
+ private readonly AccountCreationOverlay accountCreation;
private IBindable localUser;
public TestSceneAccountCreationOverlay()
{
- AccountCreationOverlay accountCreation;
-
Children = new Drawable[]
{
accountCreation = new AccountCreationOverlay(),
@@ -31,8 +31,6 @@ namespace osu.Game.Tests.Visual.Online
Origin = Anchor.TopRight,
},
};
-
- AddStep("show", () => accountCreation.Show());
}
[BackgroundDependencyLoader]
@@ -42,8 +40,19 @@ namespace osu.Game.Tests.Visual.Online
localUser = API.LocalUser.GetBoundCopy();
localUser.BindValueChanged(user => { userPanelArea.Child = new UserGridPanel(user.NewValue) { Width = 200 }; }, true);
+ }
- AddStep("logout", API.Logout);
+ [Test]
+ public void TestOverlayVisibility()
+ {
+ AddStep("start hidden", () => accountCreation.Hide());
+ AddStep("log out", API.Logout);
+
+ AddStep("show manually", () => accountCreation.Show());
+ AddUntilStep("overlay is visible", () => accountCreation.State.Value == Visibility.Visible);
+
+ AddStep("log back in", () => API.Login("dummy", "password"));
+ AddUntilStep("overlay is hidden", () => accountCreation.State.Value == Visibility.Hidden);
}
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
index 998e42b478..cd2c4e9346 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
@@ -1,8 +1,13 @@
// 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 Humanizer;
using NUnit.Framework;
+using osu.Game.Online.API;
+using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Overlays.Changelog;
@@ -12,13 +17,61 @@ namespace osu.Game.Tests.Visual.Online
[TestFixture]
public class TestSceneChangelogOverlay : OsuTestScene
{
+ private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
+
+ private readonly Dictionary streams;
+ private readonly Dictionary builds;
+
+ private APIChangelogBuild requestedBuild;
private TestChangelogOverlay changelog;
- protected override bool UseOnlineAPI => true;
+ public TestSceneChangelogOverlay()
+ {
+ streams = APIUpdateStream.KNOWN_STREAMS.Keys.Select((stream, id) => new APIUpdateStream
+ {
+ Id = id + 1,
+ Name = stream,
+ DisplayName = stream.Humanize(), // not quite there, but good enough.
+ }).ToDictionary(stream => stream.Name);
+
+ string version = DateTimeOffset.Now.ToString("yyyy.Mdd.0");
+ builds = APIUpdateStream.KNOWN_STREAMS.Keys.Select(stream => new APIChangelogBuild
+ {
+ Version = version,
+ DisplayVersion = version,
+ UpdateStream = streams[stream],
+ ChangelogEntries = new List()
+ }).ToDictionary(build => build.UpdateStream.Name);
+
+ foreach (var stream in streams.Values)
+ stream.LatestBuild = builds[stream.Name];
+ }
[SetUp]
public void SetUp() => Schedule(() =>
{
+ requestedBuild = null;
+
+ dummyAPI.HandleRequest = request =>
+ {
+ switch (request)
+ {
+ case GetChangelogRequest changelogRequest:
+ var changelogResponse = new APIChangelogIndex
+ {
+ Streams = streams.Values.ToList(),
+ Builds = builds.Values.ToList()
+ };
+ changelogRequest.TriggerSuccess(changelogResponse);
+ break;
+
+ case GetChangelogBuildRequest buildRequest:
+ if (requestedBuild != null)
+ buildRequest.TriggerSuccess(requestedBuild);
+ break;
+ }
+ };
+
Child = changelog = new TestChangelogOverlay();
});
@@ -41,26 +94,60 @@ namespace osu.Game.Tests.Visual.Online
}
[Test]
- [Ignore("needs to be updated to not be so server dependent")]
public void ShowWithBuild()
{
- AddStep(@"Show with Lazer 2018.712.0", () =>
+ showBuild(() => new APIChangelogBuild
{
- changelog.ShowBuild(new APIChangelogBuild
+ Version = "2018.712.0",
+ DisplayVersion = "2018.712.0",
+ UpdateStream = streams[OsuGameBase.CLIENT_STREAM_NAME],
+ ChangelogEntries = new List
{
- Version = "2018.712.0",
- DisplayVersion = "2018.712.0",
- UpdateStream = new APIUpdateStream { Id = 5, Name = OsuGameBase.CLIENT_STREAM_NAME },
- ChangelogEntries = new List
+ new APIChangelogEntry
{
- new APIChangelogEntry
+ Type = ChangelogEntryType.Fix,
+ Category = "osu!",
+ Title = "Fix thing",
+ MessageHtml = "Additional info goes here.",
+ Repository = "osu",
+ GithubPullRequestId = 11100,
+ GithubUser = new APIChangelogUser
{
- Category = "Test",
- Title = "Title",
- MessageHtml = "Message",
+ OsuUsername = "smoogipoo",
+ UserId = 1040328
}
+ },
+ new APIChangelogEntry
+ {
+ Type = ChangelogEntryType.Add,
+ Category = "osu!",
+ Title = "Add thing",
+ Major = true,
+ Repository = "ppy/osu-framework",
+ GithubPullRequestId = 4444,
+ GithubUser = new APIChangelogUser
+ {
+ DisplayName = "frenzibyte",
+ GithubUrl = "https://github.com/frenzibyte"
+ }
+ },
+ new APIChangelogEntry
+ {
+ Type = ChangelogEntryType.Misc,
+ Category = "Code quality",
+ Title = "Clean up thing",
+ GithubUser = new APIChangelogUser
+ {
+ DisplayName = "some dude"
+ }
+ },
+ new APIChangelogEntry
+ {
+ Type = ChangelogEntryType.Misc,
+ Category = "Code quality",
+ Title = "Clean up another thing"
}
- });
+ }
});
AddUntilStep(@"wait for streams", () => changelog.Streams?.Count > 0);
@@ -71,35 +158,38 @@ namespace osu.Game.Tests.Visual.Online
[Test]
public void TestHTMLUnescaping()
{
- AddStep(@"Ensure HTML string unescaping", () =>
+ showBuild(() => new APIChangelogBuild
{
- changelog.ShowBuild(new APIChangelogBuild
+ Version = "2019.920.0",
+ DisplayVersion = "2019.920.0",
+ UpdateStream = new APIUpdateStream
{
- Version = "2019.920.0",
- DisplayVersion = "2019.920.0",
- UpdateStream = new APIUpdateStream
+ Name = "Test",
+ DisplayName = "Test"
+ },
+ ChangelogEntries = new List
+ {
+ new APIChangelogEntry
{
- Name = "Test",
- DisplayName = "Test"
- },
- ChangelogEntries = new List
- {
- new APIChangelogEntry
+ Category = "Testing HTML strings unescaping",
+ Title = "Ensuring HTML strings are being unescaped",
+ MessageHtml = """"This text should appear triple-quoted""" >_<",
+ GithubUser = new APIChangelogUser
{
- Category = "Testing HTML strings unescaping",
- Title = "Ensuring HTML strings are being unescaped",
- MessageHtml = """"This text should appear triple-quoted""" >_<",
- GithubUser = new APIChangelogUser
- {
- DisplayName = "Dummy",
- OsuUsername = "Dummy",
- }
- },
- }
- });
+ DisplayName = "Dummy",
+ OsuUsername = "Dummy",
+ }
+ },
+ }
});
}
+ private void showBuild(Func build)
+ {
+ AddStep("set up build", () => requestedBuild = build.Invoke());
+ AddStep("show build", () => changelog.ShowBuild(requestedBuild));
+ }
+
private class TestChangelogOverlay : ChangelogOverlay
{
public new List Streams => base.Streams;
diff --git a/osu.Game/Online/API/Requests/Responses/APIUpdateStream.cs b/osu.Game/Online/API/Requests/Responses/APIUpdateStream.cs
index d9e48373bb..5af7d6a01c 100644
--- a/osu.Game/Online/API/Requests/Responses/APIUpdateStream.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIUpdateStream.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Collections.Generic;
using Newtonsoft.Json;
using osu.Framework.Graphics.Colour;
using osuTK.Graphics;
@@ -27,34 +28,16 @@ namespace osu.Game.Online.API.Requests.Responses
public bool Equals(APIUpdateStream other) => Id == other?.Id;
- public ColourInfo Colour
+ internal static readonly Dictionary KNOWN_STREAMS = new Dictionary
{
- get
- {
- switch (Name)
- {
- case "stable40":
- return new Color4(102, 204, 255, 255);
+ ["stable40"] = new Color4(102, 204, 255, 255),
+ ["stable"] = new Color4(34, 153, 187, 255),
+ ["beta40"] = new Color4(255, 221, 85, 255),
+ ["cuttingedge"] = new Color4(238, 170, 0, 255),
+ [OsuGameBase.CLIENT_STREAM_NAME] = new Color4(237, 18, 33, 255),
+ ["web"] = new Color4(136, 102, 238, 255)
+ };
- case "stable":
- return new Color4(34, 153, 187, 255);
-
- case "beta40":
- return new Color4(255, 221, 85, 255);
-
- case "cuttingedge":
- return new Color4(238, 170, 0, 255);
-
- case OsuGameBase.CLIENT_STREAM_NAME:
- return new Color4(237, 18, 33, 255);
-
- case "web":
- return new Color4(136, 102, 238, 255);
-
- default:
- return new Color4(0, 0, 0, 255);
- }
- }
- }
+ public ColourInfo Colour => KNOWN_STREAMS.TryGetValue(Name, out var colour) ? colour : new Color4(0, 0, 0, 255);
}
}
diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
index d8207aa8f4..5608002513 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
@@ -78,7 +78,7 @@ namespace osu.Game.Online.Leaderboards
statisticsLabels = GetStatistics(score).Select(s => new ScoreComponentLabel(s)).ToList();
- DrawableAvatar innerAvatar;
+ ClickableAvatar innerAvatar;
Children = new Drawable[]
{
@@ -115,7 +115,7 @@ namespace osu.Game.Online.Leaderboards
Children = new[]
{
avatar = new DelayedLoadWrapper(
- innerAvatar = new DrawableAvatar(user)
+ innerAvatar = new ClickableAvatar(user)
{
RelativeSizeAxes = Axes.Both,
CornerRadius = corner_radius,
diff --git a/osu.Game/Overlays/AccountCreationOverlay.cs b/osu.Game/Overlays/AccountCreationOverlay.cs
index 58ede5502a..3084c7475a 100644
--- a/osu.Game/Overlays/AccountCreationOverlay.cs
+++ b/osu.Game/Overlays/AccountCreationOverlay.cs
@@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Screens;
+using osu.Framework.Threading;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
@@ -93,6 +94,11 @@ namespace osu.Game.Overlays
if (welcomeScreen.GetChildScreen() != null)
welcomeScreen.MakeCurrent();
+
+ // there might be a stale scheduled hide from a previous API state change.
+ // cancel it here so that the overlay is not hidden again after one frame.
+ scheduledHide?.Cancel();
+ scheduledHide = null;
}
protected override void PopOut()
@@ -101,7 +107,9 @@ namespace osu.Game.Overlays
this.FadeOut(100);
}
- private void apiStateChanged(ValueChangedEvent state) => Schedule(() =>
+ private ScheduledDelegate scheduledHide;
+
+ private void apiStateChanged(ValueChangedEvent state)
{
switch (state.NewValue)
{
@@ -113,9 +121,10 @@ namespace osu.Game.Overlays
break;
case APIState.Online:
- Hide();
+ scheduledHide?.Cancel();
+ scheduledHide = Schedule(Hide);
break;
}
- });
+ }
}
}
diff --git a/osu.Game/Overlays/Changelog/ChangelogBuild.cs b/osu.Game/Overlays/Changelog/ChangelogBuild.cs
index 65ff0fef92..2d071b7345 100644
--- a/osu.Game/Overlays/Changelog/ChangelogBuild.cs
+++ b/osu.Game/Overlays/Changelog/ChangelogBuild.cs
@@ -9,14 +9,8 @@ using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests.Responses;
using System;
using System.Linq;
-using System.Text.RegularExpressions;
using osu.Game.Graphics.Sprites;
-using osu.Game.Users;
-using osuTK.Graphics;
using osu.Framework.Allocation;
-using System.Net;
-using osuTK;
-using osu.Framework.Extensions.Color4Extensions;
namespace osu.Game.Overlays.Changelog
{
@@ -63,126 +57,7 @@ namespace osu.Game.Overlays.Changelog
Margin = new MarginPadding { Top = 35, Bottom = 15 },
});
- var fontLarge = OsuFont.GetFont(size: 16);
- var fontMedium = OsuFont.GetFont(size: 12);
-
- foreach (var entry in categoryEntries)
- {
- var entryColour = entry.Major ? colours.YellowLight : Color4.White;
-
- LinkFlowContainer title;
-
- var titleContainer = new Container
- {
- AutoSizeAxes = Axes.Y,
- RelativeSizeAxes = Axes.X,
- Margin = new MarginPadding { Vertical = 5 },
- Children = new Drawable[]
- {
- new SpriteIcon
- {
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.CentreRight,
- Size = new Vector2(10),
- Icon = entry.Type == ChangelogEntryType.Fix ? FontAwesome.Solid.Check : FontAwesome.Solid.Plus,
- Colour = entryColour.Opacity(0.5f),
- Margin = new MarginPadding { Right = 5 },
- },
- title = new LinkFlowContainer
- {
- Direction = FillDirection.Full,
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- TextAnchor = Anchor.BottomLeft,
- }
- }
- };
-
- title.AddText(entry.Title, t =>
- {
- t.Font = fontLarge;
- t.Colour = entryColour;
- });
-
- if (!string.IsNullOrEmpty(entry.Repository))
- {
- title.AddText(" (", t =>
- {
- t.Font = fontLarge;
- t.Colour = entryColour;
- });
- title.AddLink($"{entry.Repository.Replace("ppy/", "")}#{entry.GithubPullRequestId}", entry.GithubUrl,
- creationParameters: t =>
- {
- t.Font = fontLarge;
- t.Colour = entryColour;
- });
- title.AddText(")", t =>
- {
- t.Font = fontLarge;
- t.Colour = entryColour;
- });
- }
-
- title.AddText("by ", t =>
- {
- t.Font = fontMedium;
- t.Colour = entryColour;
- t.Padding = new MarginPadding { Left = 10 };
- });
-
- if (entry.GithubUser != null)
- {
- if (entry.GithubUser.UserId != null)
- {
- title.AddUserLink(new User
- {
- Username = entry.GithubUser.OsuUsername,
- Id = entry.GithubUser.UserId.Value
- }, t =>
- {
- t.Font = fontMedium;
- t.Colour = entryColour;
- });
- }
- else if (entry.GithubUser.GithubUrl != null)
- {
- title.AddLink(entry.GithubUser.DisplayName, entry.GithubUser.GithubUrl, t =>
- {
- t.Font = fontMedium;
- t.Colour = entryColour;
- });
- }
- else
- {
- title.AddText(entry.GithubUser.DisplayName, t =>
- {
- t.Font = fontMedium;
- t.Colour = entryColour;
- });
- }
- }
-
- ChangelogEntries.Add(titleContainer);
-
- if (!string.IsNullOrEmpty(entry.MessageHtml))
- {
- var message = new TextFlowContainer
- {
- AutoSizeAxes = Axes.Y,
- RelativeSizeAxes = Axes.X,
- };
-
- // todo: use markdown parsing once API returns markdown
- message.AddText(WebUtility.HtmlDecode(Regex.Replace(entry.MessageHtml, @"<(.|\n)*?>", string.Empty)), t =>
- {
- t.Font = fontMedium;
- t.Colour = colourProvider.Foreground1;
- });
-
- ChangelogEntries.Add(message);
- }
- }
+ ChangelogEntries.AddRange(categoryEntries.Select(entry => new ChangelogEntry(entry)));
}
}
diff --git a/osu.Game/Overlays/Changelog/ChangelogEntry.cs b/osu.Game/Overlays/Changelog/ChangelogEntry.cs
new file mode 100644
index 0000000000..55edb40283
--- /dev/null
+++ b/osu.Game/Overlays/Changelog/ChangelogEntry.cs
@@ -0,0 +1,202 @@
+// 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.Net;
+using System.Text.RegularExpressions;
+using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
+using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Users;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Overlays.Changelog
+{
+ public class ChangelogEntry : FillFlowContainer
+ {
+ private readonly APIChangelogEntry entry;
+
+ [Resolved]
+ private OsuColour colours { get; set; }
+
+ [Resolved]
+ private OverlayColourProvider colourProvider { get; set; }
+
+ private FontUsage fontLarge;
+ private FontUsage fontMedium;
+
+ public ChangelogEntry(APIChangelogEntry entry)
+ {
+ this.entry = entry;
+
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+ Direction = FillDirection.Vertical;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ fontLarge = OsuFont.GetFont(size: 16);
+ fontMedium = OsuFont.GetFont(size: 12);
+
+ Children = new[]
+ {
+ createTitle(),
+ createMessage()
+ };
+ }
+
+ private Drawable createTitle()
+ {
+ var entryColour = entry.Major ? colours.YellowLight : Color4.White;
+
+ LinkFlowContainer title;
+
+ var titleContainer = new Container
+ {
+ AutoSizeAxes = Axes.Y,
+ RelativeSizeAxes = Axes.X,
+ Margin = new MarginPadding { Vertical = 5 },
+ Children = new Drawable[]
+ {
+ new SpriteIcon
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreRight,
+ Size = new Vector2(10),
+ Icon = getIconForChangelogEntry(entry.Type),
+ Colour = entryColour.Opacity(0.5f),
+ Margin = new MarginPadding { Right = 5 },
+ },
+ title = new LinkFlowContainer
+ {
+ Direction = FillDirection.Full,
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ TextAnchor = Anchor.BottomLeft,
+ }
+ }
+ };
+
+ title.AddText(entry.Title, t =>
+ {
+ t.Font = fontLarge;
+ t.Colour = entryColour;
+ });
+
+ if (!string.IsNullOrEmpty(entry.Repository))
+ addRepositoryReference(title, entryColour);
+
+ if (entry.GithubUser != null)
+ addGithubAuthorReference(title, entryColour);
+
+ return titleContainer;
+ }
+
+ private void addRepositoryReference(LinkFlowContainer title, Color4 entryColour)
+ {
+ title.AddText(" (", t =>
+ {
+ t.Font = fontLarge;
+ t.Colour = entryColour;
+ });
+ title.AddLink($"{entry.Repository.Replace("ppy/", "")}#{entry.GithubPullRequestId}", entry.GithubUrl,
+ t =>
+ {
+ t.Font = fontLarge;
+ t.Colour = entryColour;
+ });
+ title.AddText(")", t =>
+ {
+ t.Font = fontLarge;
+ t.Colour = entryColour;
+ });
+ }
+
+ private void addGithubAuthorReference(LinkFlowContainer title, Color4 entryColour)
+ {
+ title.AddText("by ", t =>
+ {
+ t.Font = fontMedium;
+ t.Colour = entryColour;
+ t.Padding = new MarginPadding { Left = 10 };
+ });
+
+ if (entry.GithubUser.UserId != null)
+ {
+ title.AddUserLink(new User
+ {
+ Username = entry.GithubUser.OsuUsername,
+ Id = entry.GithubUser.UserId.Value
+ }, t =>
+ {
+ t.Font = fontMedium;
+ t.Colour = entryColour;
+ });
+ }
+ else if (entry.GithubUser.GithubUrl != null)
+ {
+ title.AddLink(entry.GithubUser.DisplayName, entry.GithubUser.GithubUrl, t =>
+ {
+ t.Font = fontMedium;
+ t.Colour = entryColour;
+ });
+ }
+ else
+ {
+ title.AddText(entry.GithubUser.DisplayName, t =>
+ {
+ t.Font = fontMedium;
+ t.Colour = entryColour;
+ });
+ }
+ }
+
+ private Drawable createMessage()
+ {
+ if (string.IsNullOrEmpty(entry.MessageHtml))
+ return Empty();
+
+ var message = new TextFlowContainer
+ {
+ AutoSizeAxes = Axes.Y,
+ RelativeSizeAxes = Axes.X,
+ };
+
+ // todo: use markdown parsing once API returns markdown
+ message.AddText(WebUtility.HtmlDecode(Regex.Replace(entry.MessageHtml, @"<(.|\n)*?>", string.Empty)), t =>
+ {
+ t.Font = fontMedium;
+ t.Colour = colourProvider.Foreground1;
+ });
+
+ return message;
+ }
+
+ private static IconUsage getIconForChangelogEntry(ChangelogEntryType entryType)
+ {
+ // compare: https://github.com/ppy/osu-web/blob/master/resources/assets/coffee/react/_components/changelog-entry.coffee#L8-L11
+ switch (entryType)
+ {
+ case ChangelogEntryType.Add:
+ return FontAwesome.Solid.Plus;
+
+ case ChangelogEntryType.Fix:
+ return FontAwesome.Solid.Check;
+
+ case ChangelogEntryType.Misc:
+ return FontAwesome.Regular.Circle;
+
+ default:
+ throw new ArgumentOutOfRangeException(nameof(entryType), $"Unrecognised entry type {entryType}");
+ }
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs
index 509a6dabae..6bbff045b5 100644
--- a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs
+++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs
@@ -8,5 +8,11 @@ namespace osu.Game.Overlays.Changelog
public class ChangelogUpdateStreamControl : OverlayStreamControl
{
protected override OverlayStreamItem CreateStreamItem(APIUpdateStream value) => new ChangelogUpdateStreamItem(value);
+
+ protected override void LoadComplete()
+ {
+ // suppress base logic of immediately selecting first item if one exists
+ // (we always want to start with no stream selected).
+ }
}
}
diff --git a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs
index 5b428a3825..00f46b0035 100644
--- a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs
+++ b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs
@@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Chat.Tabs
if (value.Type != ChannelType.PM)
throw new ArgumentException("Argument value needs to have the targettype user!");
- DrawableAvatar avatar;
+ ClickableAvatar avatar;
AddRange(new Drawable[]
{
@@ -48,7 +48,7 @@ namespace osu.Game.Overlays.Chat.Tabs
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Masking = true,
- Child = new DelayedLoadWrapper(avatar = new DrawableAvatar(value.Users.First())
+ Child = new DelayedLoadWrapper(avatar = new ClickableAvatar(value.Users.First())
{
RelativeSizeAxes = Axes.Both,
OpenOnClick = { Value = false },
diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs
index 58281debf1..83b70911c6 100644
--- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs
+++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs
@@ -34,6 +34,7 @@ namespace osu.Game.Screens.Play.HUD
public BindableDouble TotalScore { get; } = new BindableDouble();
public BindableDouble Accuracy { get; } = new BindableDouble(1);
public BindableInt Combo { get; } = new BindableInt();
+ public BindableBool HasQuit { get; } = new BindableBool();
private int? scorePosition;
@@ -51,7 +52,7 @@ namespace osu.Game.Screens.Play.HUD
positionText.Text = $"#{scorePosition.Value.FormatRank()}";
positionText.FadeTo(scorePosition.HasValue ? 1 : 0);
- updateColour();
+ updateState();
}
}
@@ -78,6 +79,8 @@ namespace osu.Game.Screens.Play.HUD
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
+ Container avatarContainer;
+
InternalChildren = new Drawable[]
{
mainFillContainer = new Container
@@ -152,7 +155,7 @@ namespace osu.Game.Screens.Play.HUD
Spacing = new Vector2(4f, 0f),
Children = new Drawable[]
{
- new CircularContainer
+ avatarContainer = new CircularContainer
{
Masking = true,
Anchor = Anchor.CentreLeft,
@@ -166,11 +169,7 @@ namespace osu.Game.Screens.Play.HUD
Alpha = 0.3f,
RelativeSizeAxes = Axes.Both,
Colour = colours.Gray4,
- },
- new UpdateableAvatar(User)
- {
- RelativeSizeAxes = Axes.Both,
- },
+ }
}
},
usernameText = new OsuSpriteText
@@ -227,23 +226,36 @@ namespace osu.Game.Screens.Play.HUD
}
};
+ LoadComponentAsync(new DrawableAvatar(User), avatarContainer.Add);
+
TotalScore.BindValueChanged(v => scoreText.Text = v.NewValue.ToString("N0"), true);
Accuracy.BindValueChanged(v => accuracyText.Text = v.NewValue.FormatAccuracy(), true);
Combo.BindValueChanged(v => comboText.Text = $"{v.NewValue}x", true);
+ HasQuit.BindValueChanged(_ => updateState());
}
protected override void LoadComplete()
{
base.LoadComplete();
- updateColour();
+ updateState();
FinishTransforms(true);
}
private const double panel_transition_duration = 500;
- private void updateColour()
+ private void updateState()
{
+ if (HasQuit.Value)
+ {
+ // we will probably want to display this in a better way once we have a design.
+ // and also show states other than quit.
+ mainFillContainer.ResizeWidthTo(regular_width, panel_transition_duration, Easing.OutElastic);
+ panelColour = Color4.Gray;
+ textColour = Color4.White;
+ return;
+ }
+
if (scorePosition == 1)
{
mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, panel_transition_duration, Easing.OutElastic);
diff --git a/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs b/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs
index bc1a03c5aa..83b6f6621b 100644
--- a/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs
+++ b/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs
@@ -10,5 +10,7 @@ namespace osu.Game.Screens.Play.HUD
BindableDouble TotalScore { get; }
BindableDouble Accuracy { get; }
BindableInt Combo { get; }
+
+ BindableBool HasQuit { get; }
}
}
diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs
index c10ec9e004..00e2b8bfa7 100644
--- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs
+++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs
@@ -2,12 +2,15 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.Online.API;
+using osu.Game.Online.Multiplayer;
using osu.Game.Online.Spectator;
using osu.Game.Rulesets.Scoring;
@@ -18,10 +21,21 @@ namespace osu.Game.Screens.Play.HUD
{
private readonly ScoreProcessor scoreProcessor;
- private readonly int[] userIds;
-
private readonly Dictionary userScores = new Dictionary();
+ [Resolved]
+ private SpectatorStreamingClient streamingClient { get; set; }
+
+ [Resolved]
+ private StatefulMultiplayerClient multiplayerClient { get; set; }
+
+ [Resolved]
+ private UserLookupCache userLookupCache { get; set; }
+
+ private Bindable scoringMode;
+
+ private readonly BindableList playingUsers;
+
///
/// Construct a new leaderboard.
///
@@ -33,43 +47,68 @@ namespace osu.Game.Screens.Play.HUD
this.scoreProcessor = scoreProcessor;
// todo: this will likely be passed in as User instances.
- this.userIds = userIds;
+ playingUsers = new BindableList(userIds);
}
- [Resolved]
- private SpectatorStreamingClient streamingClient { get; set; }
-
- [Resolved]
- private UserLookupCache userLookupCache { get; set; }
-
- private Bindable scoringMode;
-
[BackgroundDependencyLoader]
private void load(OsuConfigManager config, IAPIProvider api)
{
streamingClient.OnNewFrames += handleIncomingFrames;
- foreach (var user in userIds)
+ foreach (var userId in playingUsers)
{
- streamingClient.WatchUser(user);
+ streamingClient.WatchUser(userId);
// probably won't be required in the final implementation.
- var resolvedUser = userLookupCache.GetUserAsync(user).Result;
+ var resolvedUser = userLookupCache.GetUserAsync(userId).Result;
var trackedUser = new TrackedUserData();
- userScores[user] = trackedUser;
+ userScores[userId] = trackedUser;
var leaderboardScore = AddPlayer(resolvedUser, resolvedUser.Id == api.LocalUser.Value.Id);
((IBindable)leaderboardScore.Accuracy).BindTo(trackedUser.Accuracy);
((IBindable)leaderboardScore.TotalScore).BindTo(trackedUser.Score);
((IBindable)leaderboardScore.Combo).BindTo(trackedUser.CurrentCombo);
+ ((IBindable)leaderboardScore.HasQuit).BindTo(trackedUser.UserQuit);
}
scoringMode = config.GetBindable(OsuSetting.ScoreDisplayMode);
scoringMode.BindValueChanged(updateAllScores, true);
}
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ // BindableList handles binding in a really bad way (Clear then AddRange) so we need to do this manually..
+ foreach (int userId in playingUsers)
+ {
+ if (!multiplayerClient.PlayingUsers.Contains(userId))
+ usersChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new[] { userId }));
+ }
+
+ playingUsers.BindTo(multiplayerClient.PlayingUsers);
+ playingUsers.BindCollectionChanged(usersChanged);
+ }
+
+ private void usersChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ switch (e.Action)
+ {
+ case NotifyCollectionChangedAction.Remove:
+ foreach (var userId in e.OldItems.OfType())
+ {
+ streamingClient.StopWatchingUser(userId);
+
+ if (userScores.TryGetValue(userId, out var trackedData))
+ trackedData.MarkUserQuit();
+ }
+
+ break;
+ }
+ }
+
private void updateAllScores(ValueChangedEvent mode)
{
foreach (var trackedData in userScores.Values)
@@ -91,7 +130,7 @@ namespace osu.Game.Screens.Play.HUD
if (streamingClient != null)
{
- foreach (var user in userIds)
+ foreach (var user in playingUsers)
{
streamingClient.StopWatchingUser(user);
}
@@ -114,9 +153,15 @@ namespace osu.Game.Screens.Play.HUD
private readonly BindableInt currentCombo = new BindableInt();
+ public IBindable UserQuit => userQuit;
+
+ private readonly BindableBool userQuit = new BindableBool();
+
[CanBeNull]
public FrameHeader LastHeader;
+ public void MarkUserQuit() => userQuit.Value = true;
+
public void UpdateScore(ScoreProcessor processor, ScoringMode mode)
{
if (LastHeader == null)
diff --git a/osu.Game/Users/Drawables/ClickableAvatar.cs b/osu.Game/Users/Drawables/ClickableAvatar.cs
new file mode 100644
index 0000000000..0fca9c7c9b
--- /dev/null
+++ b/osu.Game/Users/Drawables/ClickableAvatar.cs
@@ -0,0 +1,73 @@
+// 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.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Textures;
+using osu.Framework.Input.Events;
+using osu.Game.Graphics.Containers;
+
+namespace osu.Game.Users.Drawables
+{
+ public class ClickableAvatar : Container
+ {
+ ///
+ /// Whether to open the user's profile when clicked.
+ ///
+ public readonly BindableBool OpenOnClick = new BindableBool(true);
+
+ private readonly User user;
+
+ [Resolved(CanBeNull = true)]
+ private OsuGame game { get; set; }
+
+ ///
+ /// A clickable avatar for the specified user, with UI sounds included.
+ /// If is true, clicking will open the user's profile.
+ ///
+ /// The user. A null value will get a placeholder avatar.
+ public ClickableAvatar(User user = null)
+ {
+ this.user = user;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(LargeTextureStore textures)
+ {
+ ClickableArea clickableArea;
+ Add(clickableArea = new ClickableArea
+ {
+ RelativeSizeAxes = Axes.Both,
+ Action = openProfile
+ });
+
+ LoadComponentAsync(new DrawableAvatar(user), clickableArea.Add);
+
+ clickableArea.Enabled.BindTo(OpenOnClick);
+ }
+
+ private void openProfile()
+ {
+ if (!OpenOnClick.Value)
+ return;
+
+ if (user?.Id > 1)
+ game?.ShowUser(user.Id);
+ }
+
+ private class ClickableArea : OsuClickableContainer
+ {
+ public override string TooltipText => Enabled.Value ? @"view profile" : null;
+
+ protected override bool OnClick(ClickEvent e)
+ {
+ if (!Enabled.Value)
+ return false;
+
+ return base.OnClick(e);
+ }
+ }
+ }
+}
diff --git a/osu.Game/Users/Drawables/DrawableAvatar.cs b/osu.Game/Users/Drawables/DrawableAvatar.cs
index 42d2dbb1c6..3dae3afe3f 100644
--- a/osu.Game/Users/Drawables/DrawableAvatar.cs
+++ b/osu.Game/Users/Drawables/DrawableAvatar.cs
@@ -1,88 +1,45 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// 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 osu.Framework.Allocation;
-using osu.Framework.Bindables;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
-using osu.Framework.Input.Events;
-using osu.Game.Graphics.Containers;
namespace osu.Game.Users.Drawables
{
[LongRunningLoad]
- public class DrawableAvatar : Container
+ public class DrawableAvatar : Sprite
{
- ///
- /// Whether to open the user's profile when clicked.
- ///
- public readonly BindableBool OpenOnClick = new BindableBool(true);
-
private readonly User user;
- [Resolved(CanBeNull = true)]
- private OsuGame game { get; set; }
-
///
- /// An avatar for specified user.
+ /// A simple, non-interactable avatar sprite for the specified user.
///
/// The user. A null value will get a placeholder avatar.
public DrawableAvatar(User user = null)
{
this.user = user;
+
+ RelativeSizeAxes = Axes.Both;
+ FillMode = FillMode.Fit;
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
}
[BackgroundDependencyLoader]
private void load(LargeTextureStore textures)
{
- if (textures == null)
- throw new ArgumentNullException(nameof(textures));
+ if (user != null && user.Id > 1)
+ Texture = textures.Get($@"https://a.ppy.sh/{user.Id}");
- Texture texture = null;
- if (user != null && user.Id > 1) texture = textures.Get($@"https://a.ppy.sh/{user.Id}");
- texture ??= textures.Get(@"Online/avatar-guest");
-
- ClickableArea clickableArea;
- Add(clickableArea = new ClickableArea
- {
- RelativeSizeAxes = Axes.Both,
- Child = new Sprite
- {
- RelativeSizeAxes = Axes.Both,
- Texture = texture,
- FillMode = FillMode.Fit,
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre
- },
- Action = openProfile
- });
-
- clickableArea.Enabled.BindTo(OpenOnClick);
+ Texture ??= textures.Get(@"Online/avatar-guest");
}
- private void openProfile()
+ protected override void LoadComplete()
{
- if (!OpenOnClick.Value)
- return;
-
- if (user?.Id > 1)
- game?.ShowUser(user.Id);
- }
-
- private class ClickableArea : OsuClickableContainer
- {
- public override string TooltipText => Enabled.Value ? @"view profile" : null;
-
- protected override bool OnClick(ClickEvent e)
- {
- if (!Enabled.Value)
- return false;
-
- return base.OnClick(e);
- }
+ base.LoadComplete();
+ this.FadeInFromZero(300, Easing.OutQuint);
}
}
}
diff --git a/osu.Game/Users/Drawables/UpdateableAvatar.cs b/osu.Game/Users/Drawables/UpdateableAvatar.cs
index 171462f3fc..927e48cb56 100644
--- a/osu.Game/Users/Drawables/UpdateableAvatar.cs
+++ b/osu.Game/Users/Drawables/UpdateableAvatar.cs
@@ -65,12 +65,11 @@ namespace osu.Game.Users.Drawables
if (user == null && !ShowGuestOnNull)
return null;
- var avatar = new DrawableAvatar(user)
+ var avatar = new ClickableAvatar(user)
{
RelativeSizeAxes = Axes.Both,
};
- avatar.OnLoadComplete += d => d.FadeInFromZero(300, Easing.OutQuint);
avatar.OpenOnClick.BindTo(OpenOnClick);
return avatar;
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index cbf9f6f1bd..3e1b56c29c 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 adbcc0ef1c..85ba0590ea 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
-
+
@@ -88,7 +88,7 @@
-
+