From 1a974f64ded87e5f1fa575a5b6c8e291cdba5982 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 4 Dec 2018 20:33:29 +0900 Subject: [PATCH 01/38] Initial design for user registration dialog --- .../Objects/Drawables/DrawableOsuHitObject.cs | 6 +- .../Visual/TestCaseAccountCreationOverlay.cs | 19 ++ .../Containers/OsuFocusedOverlayContainer.cs | 1 - .../Graphics/Containers/ShakeContainer.cs | 32 ++- osu.Game/Online/API/APIAccess.cs | 5 + osu.Game/Online/API/RegsitrationRequest.cs | 23 ++ osu.Game/OsuGame.cs | 8 + .../AccountCreation/RegistrationBackground.cs | 45 ++++ osu.Game/Overlays/AccountCreationOverlay.cs | 234 ++++++++++++++++++ .../Sections/General/LoginSettings.cs | 28 ++- osu.Game/osu.Game.csproj | 3 + 11 files changed, 384 insertions(+), 20 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseAccountCreationOverlay.cs create mode 100644 osu.Game/Online/API/RegsitrationRequest.cs create mode 100644 osu.Game/Overlays/AccountCreation/RegistrationBackground.cs create mode 100644 osu.Game/Overlays/AccountCreationOverlay.cs diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 2ac46a14f2..56c4ea639b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -21,7 +21,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected DrawableOsuHitObject(OsuHitObject hitObject) : base(hitObject) { - base.AddInternal(shakeContainer = new ShakeContainer { RelativeSizeAxes = Axes.Both }); + base.AddInternal(shakeContainer = new ShakeContainer + { + ShakeDuration = 30, + RelativeSizeAxes = Axes.Both + }); Alpha = 0; } diff --git a/osu.Game.Tests/Visual/TestCaseAccountCreationOverlay.cs b/osu.Game.Tests/Visual/TestCaseAccountCreationOverlay.cs new file mode 100644 index 0000000000..c8ee86e5fd --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseAccountCreationOverlay.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics.Containers; +using osu.Game.Overlays; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseAccountCreationOverlay : OsuTestCase + { + public TestCaseAccountCreationOverlay() + { + var accountCreation = new AccountCreationOverlay(); + Child = accountCreation; + + accountCreation.State = Visibility.Visible; + } + } +} diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index a24b6594e0..ad46e50344 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -26,7 +26,6 @@ namespace osu.Game.Graphics.Containers private PreviewTrackManager previewTrackManager; - protected readonly Bindable OverlayActivationMode = new Bindable(OverlayActivation.All); protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) diff --git a/osu.Game/Graphics/Containers/ShakeContainer.cs b/osu.Game/Graphics/Containers/ShakeContainer.cs index fde4d59f46..6b7b59bbd9 100644 --- a/osu.Game/Graphics/Containers/ShakeContainer.cs +++ b/osu.Game/Graphics/Containers/ShakeContainer.cs @@ -11,29 +11,43 @@ namespace osu.Game.Graphics.Containers /// public class ShakeContainer : Container { + /// + /// The length of a single shake. + /// + public float ShakeDuration = 80; + + /// + /// Total number of shakes. May be shortened if possible. + /// + public float TotalShakes = 4; + + /// + /// Pixels of displacement per shake. + /// + public float ShakeMagnitude = 8; + /// /// Shake the contents of this container. /// /// The maximum length the shake should last. - public void Shake(double maximumLength) + public void Shake(double? maximumLength = null) { const float shake_amount = 8; - const float shake_duration = 30; // if we don't have enough time, don't bother shaking. - if (maximumLength < shake_duration * 2) + if (maximumLength < ShakeDuration * 2) return; - var sequence = this.MoveToX(shake_amount, shake_duration / 2, Easing.OutSine).Then() - .MoveToX(-shake_amount, shake_duration, Easing.InOutSine).Then(); + var sequence = this.MoveToX(shake_amount, ShakeDuration / 2, Easing.OutSine).Then() + .MoveToX(-shake_amount, ShakeDuration, Easing.InOutSine).Then(); // if we don't have enough time for the second shake, skip it. - if (maximumLength > shake_duration * 4) + if (!maximumLength.HasValue || maximumLength >= ShakeDuration * 4) sequence = sequence - .MoveToX(shake_amount, shake_duration, Easing.InOutSine).Then() - .MoveToX(-shake_amount, shake_duration, Easing.InOutSine).Then(); + .MoveToX(shake_amount, ShakeDuration, Easing.InOutSine).Then() + .MoveToX(-shake_amount, ShakeDuration, Easing.InOutSine).Then(); - sequence.MoveToX(0, shake_duration / 2, Easing.InSine); + sequence.MoveToX(0, ShakeDuration / 2, Easing.InSine); } } } diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 1dda257c95..52bb2f5eeb 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -189,6 +189,11 @@ namespace osu.Game.Online.API this.password = password; } + public void CreateAccount(string email, string username, string password) + { + Debug.Assert(State == APIState.Offline); + } + /// /// Handle a single API request. /// diff --git a/osu.Game/Online/API/RegsitrationRequest.cs b/osu.Game/Online/API/RegsitrationRequest.cs new file mode 100644 index 0000000000..134bf45263 --- /dev/null +++ b/osu.Game/Online/API/RegsitrationRequest.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.IO.Network; + +namespace osu.Game.Online.API +{ + internal class RegsitrationRequest : JsonWebRequest + { + internal string Username; + internal string Email; + internal string Password; + + protected override void PrePerform() + { + AddParameter("user", Username); + AddParameter("user_email", Email); + AddParameter("password", Password); + + base.PrePerform(); + } + } +} diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index cd40d4793a..a5dd7ab071 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -61,6 +61,8 @@ namespace osu.Game private DialogOverlay dialogOverlay; + private AccountCreationOverlay accountCreation; + private DirectOverlay direct; private SocialOverlay social; @@ -405,6 +407,11 @@ namespace osu.Game Depth = -6, }, overlayContent.Add); + loadComponentSingleFile(accountCreation = new AccountCreationOverlay + { + Depth = -7, + }, overlayContent.Add); + dependencies.Cache(idleTracker); dependencies.Cache(settings); dependencies.Cache(onscreenDisplay); @@ -417,6 +424,7 @@ namespace osu.Game dependencies.Cache(beatmapSetOverlay); dependencies.Cache(notifications); dependencies.Cache(dialogOverlay); + dependencies.Cache(accountCreation); Add(externalLinkOpener = new ExternalLinkOpener()); diff --git a/osu.Game/Overlays/AccountCreation/RegistrationBackground.cs b/osu.Game/Overlays/AccountCreation/RegistrationBackground.cs new file mode 100644 index 0000000000..45c495d142 --- /dev/null +++ b/osu.Game/Overlays/AccountCreation/RegistrationBackground.cs @@ -0,0 +1,45 @@ +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; + +namespace osu.Game.Overlays.AccountCreation +{ + public class AccountCreationBackground : Sprite + { + public AccountCreationBackground() + { + FillMode = FillMode.Fill; + RelativeSizeAxes = Axes.Both; + + Anchor = Anchor.CentreRight; + Origin = Anchor.CentreRight; + } + + [BackgroundDependencyLoader] + private void load(LargeTextureStore textures) + { + Texture = textures.Get("Backgrounds/registration"); + } + + protected override void LoadComplete() + { + const float x_movement = 80; + + const float initial_move_time = 5000; + const float loop_move_time = 10000; + + base.LoadComplete(); + this.FadeInFromZero(initial_move_time / 4, Easing.OutQuint); + this.MoveToX(x_movement / 2).MoveToX(0, initial_move_time, Easing.OutQuint); + + using (BeginDelayedSequence(initial_move_time)) + { + this + .MoveToX(x_movement, loop_move_time, Easing.InOutSine) + .Then().MoveToX(0, loop_move_time, Easing.InOutSine) + .Loop(); + } + } + } +} diff --git a/osu.Game/Overlays/AccountCreationOverlay.cs b/osu.Game/Overlays/AccountCreationOverlay.cs new file mode 100644 index 0000000000..b8d428a839 --- /dev/null +++ b/osu.Game/Overlays/AccountCreationOverlay.cs @@ -0,0 +1,234 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osuTK.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.MathUtils; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; +using osu.Game.Overlays.AccountCreation; +using osu.Game.Overlays.Settings; +using osuTK; + +namespace osu.Game.Overlays +{ + public class AccountCreationOverlay : OsuFocusedOverlayContainer, IOnlineComponent + { + private OsuTextFlowContainer usernameDescription; + private OsuTextFlowContainer emailAddressDescription; + private OsuTextFlowContainer passwordDescription; + + private OsuTextBox usernameTextBox; + private OsuTextBox emailTextBox; + private OsuPasswordTextBox passwordTextBox; + + private APIAccess api; + private ShakeContainer registerShake; + private IEnumerable characterCheckText; + + private const float transition_time = 400; + + public AccountCreationOverlay() + { + Size = new Vector2(620, 450); + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + State = Visibility.Visible; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours, APIAccess api) + { + this.api = api; + + api.Register(this); + + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 5, + Colour = Color4.Black.Opacity(0.2f), + }, + Masking = true, + CornerRadius = 10, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.6f, + }, + new DelayedLoadWrapper(new AccountCreationBackground(), 0), + new Container + { + RelativeSizeAxes = Axes.Both, + Width = 0.6f, + AutoSizeDuration = transition_time, + AutoSizeEasing = Easing.OutQuint, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.9f, + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Padding = new MarginPadding(20), + Spacing = new Vector2(0, 10), + Children = new Drawable[] + { + new OsuSpriteText + { + TextSize = 20, + Margin = new MarginPadding { Vertical = 10 }, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "Let's create an account!", + }, + usernameTextBox = new OsuTextBox + { + PlaceholderText = "username", + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this + }, + usernameDescription = new OsuTextFlowContainer(cp => { cp.TextSize = 12; }) + { + RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y + }, + emailTextBox = new OsuTextBox + { + PlaceholderText = "email address", + RelativeSizeAxes = Axes.X, + Text = api.ProvidedUsername ?? string.Empty, + TabbableContentContainer = this + }, + emailAddressDescription = new OsuTextFlowContainer(cp => { cp.TextSize = 12; }) + { + RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y + }, + passwordTextBox = new OsuPasswordTextBox + { + PlaceholderText = "password", + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + }, + passwordDescription = new OsuTextFlowContainer(cp => { cp.TextSize = 12; }) + { + RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + registerShake = new ShakeContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = new SettingsButton + { + Text = "Register", + Margin = new MarginPadding { Vertical = 20 }, + Action = performRegistration + } + } + } + }, + } + }, + } + } + } + } + }; + + usernameDescription.AddText("This will be your public presence. No profanity, no impersonation. Avoid exposing your own personal details, too!"); + + emailAddressDescription.AddText("Will be used for notifications, account verification and in the case you forget your password. No spam, ever."); + emailAddressDescription.AddText(" Make sure to get it right!", cp => cp.Font = "Exo2.0-Bold"); + + passwordDescription.AddText("At least "); + characterCheckText = passwordDescription.AddText("8 characters long"); + passwordDescription.AddText(". Choose something long but also something you will remember, like a line from your favourite song."); + + passwordTextBox.Current.ValueChanged += text => { + characterCheckText.ForEach(s => s.Colour = text.Length == 0 ? Color4.White : Interpolation.ValueAt(text.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In)); + }; + } + + private void performRegistration() + { + var textbox = nextUnfilledTextbox(); + + if (textbox != null) + { + Schedule(() => GetContainingInputManager().ChangeFocus(textbox)); + registerShake.Shake(); + return; + } + + api.CreateAccount(emailTextBox.Text, usernameTextBox.Text, passwordTextBox.Text); + } + + private OsuTextBox nextUnfilledTextbox() + { + OsuTextBox textboxIfUsable(OsuTextBox textbox) => !string.IsNullOrEmpty(textbox.Text) ? null : textbox; + + return textboxIfUsable(usernameTextBox) ?? textboxIfUsable(emailTextBox) ?? textboxIfUsable(passwordTextBox); + } + + protected override void PopIn() + { + base.PopIn(); + this.FadeIn(transition_time, Easing.OutQuint); + + var nextTextbox = nextUnfilledTextbox(); + if (nextTextbox != null) + Schedule(() => GetContainingInputManager().ChangeFocus(nextTextbox)); + } + + protected override void PopOut() + { + base.PopOut(); + this.FadeOut(100); + } + + public void APIStateChanged(APIAccess api, APIState state) + { + switch (state) + { + case APIState.Offline: + case APIState.Failing: + break; + case APIState.Connecting: + break; + case APIState.Online: + break; + } + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index 6623fbc73b..0cb6d2d1aa 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -79,7 +79,10 @@ namespace osu.Game.Overlays.Settings.Sections.General Margin = new MarginPadding { Bottom = 5 }, Font = @"Exo2.0-Black", }, - form = new LoginForm() + form = new LoginForm + { + RequestHide = RequestHide + } }; break; case APIState.Failing: @@ -189,6 +192,8 @@ namespace osu.Game.Overlays.Settings.Sections.General private TextBox password; private APIAccess api; + public Action RequestHide; + private void performLogin() { if (!string.IsNullOrEmpty(username.Text) && !string.IsNullOrEmpty(password.Text)) @@ -196,7 +201,7 @@ namespace osu.Game.Overlays.Settings.Sections.General } [BackgroundDependencyLoader(permitNulls: true)] - private void load(APIAccess api, OsuConfigManager config) + private void load(APIAccess api, OsuConfigManager config, AccountCreationOverlay accountCreation) { this.api = api; Direction = FillDirection.Vertical; @@ -207,14 +212,14 @@ namespace osu.Game.Overlays.Settings.Sections.General { username = new OsuTextBox { - PlaceholderText = "Email address", + PlaceholderText = "email address", RelativeSizeAxes = Axes.X, Text = api?.ProvidedUsername ?? string.Empty, TabbableContentContainer = this }, password = new OsuPasswordTextBox { - PlaceholderText = "Password", + PlaceholderText = "password", RelativeSizeAxes = Axes.X, TabbableContentContainer = this, OnCommit = (sender, newText) => performLogin() @@ -237,7 +242,11 @@ namespace osu.Game.Overlays.Settings.Sections.General new SettingsButton { Text = "Register", - //Action = registerLink + Action = () => + { + RequestHide(); + accountCreation.Show(); + } } }; } @@ -322,12 +331,10 @@ namespace osu.Game.Overlays.Settings.Sections.General public const float LABEL_LEFT_MARGIN = 20; private readonly SpriteIcon statusIcon; + public Color4 StatusColour { - set - { - statusIcon.FadeColour(value, 500, Easing.OutQuint); - } + set { statusIcon.FadeColour(value, 500, Easing.OutQuint); } } public UserDropdownHeader() @@ -368,10 +375,13 @@ namespace osu.Game.Overlays.Settings.Sections.General private enum UserAction { Online, + [Description(@"Do not disturb")] DoNotDisturb, + [Description(@"Appear offline")] AppearOffline, + [Description(@"Sign out")] SignOut, } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 85eabb0350..78496830d8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -24,4 +24,7 @@ + + + From f3f449c749f548938238e1352d88e9d233249c35 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Dec 2018 13:08:35 +0900 Subject: [PATCH 02/38] wip --- osu.Game/Online/API/APIAccess.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 52bb2f5eeb..3c99290080 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -192,6 +192,10 @@ namespace osu.Game.Online.API public void CreateAccount(string email, string username, string password) { Debug.Assert(State == APIState.Offline); + + var req = new RegistrationRequest(); + + req.Perform(); } /// From 1ca00f66628c25831b083271f20c99874b673541 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Dec 2018 17:13:22 +0900 Subject: [PATCH 03/38] Add registration API call and related error handling --- osu.Game/Online/API/APIAccess.cs | 32 ++++++++- osu.Game/Online/API/RegsitrationRequest.cs | 26 +++++-- .../AccountCreation/ErrorTextFlowContainer.cs | 35 +++++++++ osu.Game/Overlays/AccountCreationOverlay.cs | 71 +++++++++++++++---- 4 files changed, 142 insertions(+), 22 deletions(-) create mode 100644 osu.Game/Overlays/AccountCreation/ErrorTextFlowContainer.cs diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 3c99290080..cf2aae753e 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -5,7 +5,9 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Net; +using System.Net.Http; using System.Threading; +using Newtonsoft.Json.Linq; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Logging; @@ -189,13 +191,37 @@ namespace osu.Game.Online.API this.password = password; } - public void CreateAccount(string email, string username, string password) + public RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, string username, string password) { Debug.Assert(State == APIState.Offline); - var req = new RegistrationRequest(); + var req = new RegistrationRequest + { + Url = $@"{Endpoint}/users", + Method = HttpMethod.Post, + Username = username, + Email = email, + Password = password + }; - req.Perform(); + try + { + req.Perform(); + } + catch (Exception e) + { + try + { + return JObject.Parse(req.ResponseString).SelectToken("form_error", true).ToObject(); + } + catch + { + // if we couldn't deserialize the error message let's throw the original exception outwards. + throw e; + } + } + + return null; } /// diff --git a/osu.Game/Online/API/RegsitrationRequest.cs b/osu.Game/Online/API/RegsitrationRequest.cs index 134bf45263..f703927101 100644 --- a/osu.Game/Online/API/RegsitrationRequest.cs +++ b/osu.Game/Online/API/RegsitrationRequest.cs @@ -1,11 +1,12 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using Newtonsoft.Json; using osu.Framework.IO.Network; namespace osu.Game.Online.API { - internal class RegsitrationRequest : JsonWebRequest + public class RegistrationRequest : WebRequest { internal string Username; internal string Email; @@ -13,11 +14,28 @@ namespace osu.Game.Online.API protected override void PrePerform() { - AddParameter("user", Username); - AddParameter("user_email", Email); - AddParameter("password", Password); + AddParameter("user[username]", Username); + AddParameter("user[user_email]", Email); + AddParameter("user[password]", Password); base.PrePerform(); } + + public class RegistrationRequestErrors + { + public UserErrors User; + + public class UserErrors + { + [JsonProperty("username")] + public string[] Username; + + [JsonProperty("user_email")] + public string[] Email; + + [JsonProperty("password")] + public string[] Password; + } + } } } diff --git a/osu.Game/Overlays/AccountCreation/ErrorTextFlowContainer.cs b/osu.Game/Overlays/AccountCreation/ErrorTextFlowContainer.cs new file mode 100644 index 0000000000..9ff6a5a7ef --- /dev/null +++ b/osu.Game/Overlays/AccountCreation/ErrorTextFlowContainer.cs @@ -0,0 +1,35 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Game.Graphics.Containers; +using osuTK.Graphics; + +namespace osu.Game.Overlays.AccountCreation +{ + public class ErrorTextFlowContainer : OsuTextFlowContainer + { + private readonly List errorDrawables = new List(); + + public ErrorTextFlowContainer() + : base(cp => { cp.TextSize = 12; }) + { + } + + public void ClearErrors() + { + errorDrawables.ForEach(d => d.Expire()); + } + + public void AddErrors(string[] errors) + { + ClearErrors(); + + if (errors == null) return; + + foreach (var error in errors) + errorDrawables.AddRange(AddParagraph(error, cp => cp.Colour = Color4.Red)); + } + } +} diff --git a/osu.Game/Overlays/AccountCreationOverlay.cs b/osu.Game/Overlays/AccountCreationOverlay.cs index b8d428a839..6be7ad031c 100644 --- a/osu.Game/Overlays/AccountCreationOverlay.cs +++ b/osu.Game/Overlays/AccountCreationOverlay.cs @@ -1,7 +1,9 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Collections.Generic; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.IEnumerableExtensions; @@ -24,9 +26,9 @@ namespace osu.Game.Overlays { public class AccountCreationOverlay : OsuFocusedOverlayContainer, IOnlineComponent { - private OsuTextFlowContainer usernameDescription; - private OsuTextFlowContainer emailAddressDescription; - private OsuTextFlowContainer passwordDescription; + private ErrorTextFlowContainer usernameDescription; + private ErrorTextFlowContainer emailAddressDescription; + private ErrorTextFlowContainer passwordDescription; private OsuTextBox usernameTextBox; private OsuTextBox emailTextBox; @@ -43,8 +45,6 @@ namespace osu.Game.Overlays Size = new Vector2(620, 450); Anchor = Anchor.Centre; Origin = Anchor.Centre; - - State = Visibility.Visible; } [BackgroundDependencyLoader] @@ -114,9 +114,10 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.X, TabbableContentContainer = this }, - usernameDescription = new OsuTextFlowContainer(cp => { cp.TextSize = 12; }) + usernameDescription = new ErrorTextFlowContainer { - RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y }, emailTextBox = new OsuTextBox { @@ -125,9 +126,10 @@ namespace osu.Game.Overlays Text = api.ProvidedUsername ?? string.Empty, TabbableContentContainer = this }, - emailAddressDescription = new OsuTextFlowContainer(cp => { cp.TextSize = 12; }) + emailAddressDescription = new ErrorTextFlowContainer { - RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y }, passwordTextBox = new OsuPasswordTextBox { @@ -135,9 +137,10 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.X, TabbableContentContainer = this, }, - passwordDescription = new OsuTextFlowContainer(cp => { cp.TextSize = 12; }) + passwordDescription = new ErrorTextFlowContainer { - RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y }, new Container { @@ -175,9 +178,7 @@ namespace osu.Game.Overlays characterCheckText = passwordDescription.AddText("8 characters long"); passwordDescription.AddText(". Choose something long but also something you will remember, like a line from your favourite song."); - passwordTextBox.Current.ValueChanged += text => { - characterCheckText.ForEach(s => s.Colour = text.Length == 0 ? Color4.White : Interpolation.ValueAt(text.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In)); - }; + passwordTextBox.Current.ValueChanged += text => { characterCheckText.ForEach(s => s.Colour = text.Length == 0 ? Color4.White : Interpolation.ValueAt(text.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In)); }; } private void performRegistration() @@ -191,7 +192,47 @@ namespace osu.Game.Overlays return; } - api.CreateAccount(emailTextBox.Text, usernameTextBox.Text, passwordTextBox.Text); + usernameDescription.ClearErrors(); + emailAddressDescription.ClearErrors(); + passwordDescription.ClearErrors(); + + Task.Run(() => + { + bool success; + RegistrationRequest.RegistrationRequestErrors errors = null; + + try + { + errors = api.CreateAccount(emailTextBox.Text, usernameTextBox.Text, passwordTextBox.Text); + success = errors == null; + } + catch (Exception) + { + success = false; + } + + Schedule(() => + { + if (!success) + { + if (errors != null) + { + usernameDescription.AddErrors(errors.User.Username); + emailAddressDescription.AddErrors(errors.User.Email); + passwordDescription.AddErrors(errors.User.Password); + } + else + { + passwordDescription.AddErrors(new[] { "Something happened... but we're not sure what." }); + } + + registerShake.Shake(); + return; + } + + api.Login(emailTextBox.Text, passwordTextBox.Text); + }); + }); } private OsuTextBox nextUnfilledTextbox() From 4f46fa4798d81464f26f20bce7da38c6ed2561e9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Dec 2018 17:30:16 +0900 Subject: [PATCH 04/38] Hide on connect --- osu.Game/Overlays/AccountCreationOverlay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/AccountCreationOverlay.cs b/osu.Game/Overlays/AccountCreationOverlay.cs index 6be7ad031c..ba54538d61 100644 --- a/osu.Game/Overlays/AccountCreationOverlay.cs +++ b/osu.Game/Overlays/AccountCreationOverlay.cs @@ -268,6 +268,7 @@ namespace osu.Game.Overlays case APIState.Connecting: break; case APIState.Online: + State = Visibility.Hidden; break; } } From 669a17529a49512d04ca7e461a860c1da745f9e4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Dec 2018 11:55:58 +0900 Subject: [PATCH 05/38] Move external link opened to top most level --- osu.Game/OsuGame.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index a5dd7ab071..e12723a61d 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -402,16 +402,21 @@ namespace osu.Game Origin = Anchor.TopRight, }, overlayContent.Add); - loadComponentSingleFile(dialogOverlay = new DialogOverlay + loadComponentSingleFile(accountCreation = new AccountCreationOverlay { Depth = -6, }, overlayContent.Add); - loadComponentSingleFile(accountCreation = new AccountCreationOverlay + loadComponentSingleFile(dialogOverlay = new DialogOverlay { Depth = -7, }, overlayContent.Add); + loadComponentSingleFile(externalLinkOpener = new ExternalLinkOpener + { + Depth = -8, + }, overlayContent.Add); + dependencies.Cache(idleTracker); dependencies.Cache(settings); dependencies.Cache(onscreenDisplay); @@ -426,8 +431,6 @@ namespace osu.Game dependencies.Cache(dialogOverlay); dependencies.Cache(accountCreation); - Add(externalLinkOpener = new ExternalLinkOpener()); - var singleDisplaySideOverlays = new OverlayContainer[] { settings, notifications }; overlays.AddRange(singleDisplaySideOverlays); From 0df9fa1e5905f8c976459d31b806518c7d0a21f6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Dec 2018 11:56:16 +0900 Subject: [PATCH 06/38] Remove pointless default size specification in OsuLogo --- osu.Game/Screens/Menu/OsuLogo.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index f858fded92..eafe44c0fc 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -79,8 +79,6 @@ namespace osu.Game.Screens.Menu private readonly Container impactContainer; - private const float default_size = 480; - private const double early_activation = 60; public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; @@ -89,8 +87,6 @@ namespace osu.Game.Screens.Menu { EarlyActivationMilliseconds = early_activation; - Size = new Vector2(default_size); - Origin = Anchor.Centre; AutoSizeAxes = Axes.Both; From e56f4cc8a5056c5cbadb9b7a3cb4793d12908de0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Dec 2018 11:58:09 +0900 Subject: [PATCH 07/38] Add remaining steps to registration screen --- .../Visual/TestCaseAccountCreationOverlay.cs | 13 ++ ...ground.cs => AccountCreationBackground.cs} | 3 + .../AccountCreation/AccountCreationScreen.cs | 28 +++ .../Overlays/AccountCreation/ScreenEntry.cs | 202 ++++++++++++++++++ .../Overlays/AccountCreation/ScreenWarning.cs | 95 ++++++++ .../Overlays/AccountCreation/ScreenWelcome.cs | 63 ++++++ osu.Game/Overlays/AccountCreationOverlay.cs | 177 +-------------- 7 files changed, 407 insertions(+), 174 deletions(-) rename osu.Game/Overlays/AccountCreation/{RegistrationBackground.cs => AccountCreationBackground.cs} (89%) create mode 100644 osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs create mode 100644 osu.Game/Overlays/AccountCreation/ScreenEntry.cs create mode 100644 osu.Game/Overlays/AccountCreation/ScreenWarning.cs create mode 100644 osu.Game/Overlays/AccountCreation/ScreenWelcome.cs diff --git a/osu.Game.Tests/Visual/TestCaseAccountCreationOverlay.cs b/osu.Game.Tests/Visual/TestCaseAccountCreationOverlay.cs index c8ee86e5fd..c54ac448dd 100644 --- a/osu.Game.Tests/Visual/TestCaseAccountCreationOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseAccountCreationOverlay.cs @@ -1,13 +1,26 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using System.Collections.Generic; using osu.Framework.Graphics.Containers; using osu.Game.Overlays; +using osu.Game.Overlays.AccountCreation; namespace osu.Game.Tests.Visual { public class TestCaseAccountCreationOverlay : OsuTestCase { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ErrorTextFlowContainer), + typeof(AccountCreationBackground), + typeof(ScreenEntry), + typeof(ScreenWarning), + typeof(ScreenWelcome), + typeof(AccountCreationScreen), + }; + public TestCaseAccountCreationOverlay() { var accountCreation = new AccountCreationOverlay(); diff --git a/osu.Game/Overlays/AccountCreation/RegistrationBackground.cs b/osu.Game/Overlays/AccountCreation/AccountCreationBackground.cs similarity index 89% rename from osu.Game/Overlays/AccountCreation/RegistrationBackground.cs rename to osu.Game/Overlays/AccountCreation/AccountCreationBackground.cs index 45c495d142..d1686912c5 100644 --- a/osu.Game/Overlays/AccountCreation/RegistrationBackground.cs +++ b/osu.Game/Overlays/AccountCreation/AccountCreationBackground.cs @@ -1,3 +1,6 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; diff --git a/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs b/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs new file mode 100644 index 0000000000..134db37afa --- /dev/null +++ b/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs @@ -0,0 +1,28 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Screens; + +namespace osu.Game.Overlays.AccountCreation +{ + public abstract class AccountCreationScreen : Screen + { + protected AccountCreationScreen() + { + ValidForResume = false; + } + + protected override void OnEntering(Screen last) + { + base.OnEntering(last); + Content.FadeOut().Delay(200).FadeIn(200); + } + + protected override void OnSuspending(Screen next) + { + base.OnSuspending(next); + Content.FadeOut(200); + } + } +} diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs new file mode 100644 index 0000000000..141e39be8f --- /dev/null +++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs @@ -0,0 +1,202 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.MathUtils; +using osu.Framework.Screens; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; +using osu.Game.Overlays.Settings; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Overlays.AccountCreation +{ + public class ScreenEntry : AccountCreationScreen + { + private ErrorTextFlowContainer usernameDescription; + private ErrorTextFlowContainer emailAddressDescription; + private ErrorTextFlowContainer passwordDescription; + + private OsuTextBox usernameTextBox; + private OsuTextBox emailTextBox; + private OsuPasswordTextBox passwordTextBox; + + private APIAccess api; + private ShakeContainer registerShake; + private IEnumerable characterCheckText; + + protected override void OnEntering(Screen last) + { + base.OnEntering(last); + + var nextTextbox = nextUnfilledTextbox(); + if (nextTextbox != null) + Schedule(() => GetContainingInputManager().ChangeFocus(nextTextbox)); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours, APIAccess api) + { + this.api = api; + + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Padding = new MarginPadding(20), + Spacing = new Vector2(0, 10), + Children = new Drawable[] + { + new OsuSpriteText + { + TextSize = 20, + Margin = new MarginPadding { Vertical = 10 }, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "Let's create an account!", + }, + usernameTextBox = new OsuTextBox + { + PlaceholderText = "username", + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this + }, + usernameDescription = new ErrorTextFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, + emailTextBox = new OsuTextBox + { + PlaceholderText = "email address", + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this + }, + emailAddressDescription = new ErrorTextFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, + passwordTextBox = new OsuPasswordTextBox + { + PlaceholderText = "password", + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + }, + passwordDescription = new ErrorTextFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + registerShake = new ShakeContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = new SettingsButton + { + Text = "Register", + Margin = new MarginPadding { Vertical = 20 }, + Action = performRegistration + } + } + } + }, + } + }; + + usernameDescription.AddText("This will be your public presence. No profanity, no impersonation. Avoid exposing your own personal details, too!"); + + emailAddressDescription.AddText("Will be used for notifications, account verification and in the case you forget your password. No spam, ever."); + emailAddressDescription.AddText(" Make sure to get it right!", cp => cp.Font = "Exo2.0-Bold"); + + passwordDescription.AddText("At least "); + characterCheckText = passwordDescription.AddText("8 characters long"); + passwordDescription.AddText(". Choose something long but also something you will remember, like a line from your favourite song."); + + passwordTextBox.Current.ValueChanged += text => { characterCheckText.ForEach(s => s.Colour = text.Length == 0 ? Color4.White : Interpolation.ValueAt(text.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In)); }; + } + + private void performRegistration() + { + var textbox = nextUnfilledTextbox(); + + if (textbox != null) + { + Schedule(() => GetContainingInputManager().ChangeFocus(textbox)); + registerShake.Shake(); + return; + } + + usernameDescription.ClearErrors(); + emailAddressDescription.ClearErrors(); + passwordDescription.ClearErrors(); + + Task.Run(() => + { + bool success; + RegistrationRequest.RegistrationRequestErrors errors = null; + + try + { + errors = api.CreateAccount(emailTextBox.Text, usernameTextBox.Text, passwordTextBox.Text); + success = errors == null; + } + catch (Exception) + { + success = false; + } + + Schedule(() => + { + if (!success) + { + if (errors != null) + { + usernameDescription.AddErrors(errors.User.Username); + emailAddressDescription.AddErrors(errors.User.Email); + passwordDescription.AddErrors(errors.User.Password); + } + else + { + passwordDescription.AddErrors(new[] { "Something happened... but we're not sure what." }); + } + + registerShake.Shake(); + return; + } + + api.Login(emailTextBox.Text, passwordTextBox.Text); + }); + }); + } + + private OsuTextBox nextUnfilledTextbox() + { + OsuTextBox textboxIfUsable(OsuTextBox textbox) + { + return !string.IsNullOrEmpty(textbox.Text) ? null : textbox; + } + + return textboxIfUsable(usernameTextBox) ?? textboxIfUsable(emailTextBox) ?? textboxIfUsable(passwordTextBox); + } + } +} diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs new file mode 100644 index 0000000000..6f887e23a2 --- /dev/null +++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs @@ -0,0 +1,95 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API; +using osu.Game.Overlays.Settings; +using osu.Game.Screens.Menu; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Overlays.AccountCreation +{ + public class ScreenWarning : AccountCreationScreen + { + private OsuTextFlowContainer multiAccountExplanationText; + private LinkFlowContainer furtherAssistance; + + private const string help_centre_url = "https://osu.ppy.sh/help/wiki/Help_Centre#login"; + + [BackgroundDependencyLoader(true)] + private void load(OsuColour colours, APIAccess api, OsuGame game) + { + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Padding = new MarginPadding(20), + Spacing = new Vector2(0, 5), + Children = new Drawable[] + { + new OsuLogo + { + Scale = new Vector2(0.1f), + Margin = new MarginPadding { Top = 500, Bottom = 300 }, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Triangles = false, + BeatMatching = false, + }, + new OsuSpriteText + { + TextSize = 28, + Font = "Exo2.0-Light", + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Colour = Color4.Red, + Text = "Warning! 注意!", + }, + multiAccountExplanationText = new OsuTextFlowContainer(cp => { cp.TextSize = 12; }) + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, + new SettingsButton + { + Text = "Help, I can't access my account!", + Margin = new MarginPadding { Top = 50 }, + Action = () => game?.OpenUrlExternally(help_centre_url) + }, + new DangerousSettingsButton + { + Text = "I understand. This account isn't for me.", + Action = () => Push(new ScreenEntry()) + }, + furtherAssistance = new LinkFlowContainer(cp => { cp.TextSize = 12; }) + { + Margin = new MarginPadding { Top = 20 }, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both + }, + } + }; + + multiAccountExplanationText.AddText("Are you "); + multiAccountExplanationText.AddText(api.ProvidedUsername, cp => cp.Colour = colours.BlueLight); + multiAccountExplanationText.AddText("? osu! has a policy of "); + multiAccountExplanationText.AddText("one account per person!", cp => cp.Colour = colours.Yellow); + multiAccountExplanationText.AddText(" Please be aware that creating more than one account per person may result in "); + multiAccountExplanationText.AddText("permanent deactivation of accounts", cp => cp.Colour = colours.Yellow); + multiAccountExplanationText.AddText("."); + + furtherAssistance.AddText("Need further assistance? Contact us via our "); + furtherAssistance.AddLink("support system", help_centre_url); + furtherAssistance.AddText("."); + } + } +} diff --git a/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs b/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs new file mode 100644 index 0000000000..0a4b35342e --- /dev/null +++ b/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs @@ -0,0 +1,63 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays.Settings; +using osu.Game.Screens.Menu; +using osuTK; + +namespace osu.Game.Overlays.AccountCreation +{ + public class ScreenWelcome : AccountCreationScreen + { + [BackgroundDependencyLoader] + private void load() + { + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Padding = new MarginPadding(20), + Spacing = new Vector2(0, 5), + Children = new Drawable[] + { + new OsuLogo + { + Scale = new Vector2(0.1f), + Margin = new MarginPadding { Vertical = 500 }, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Triangles = false, + BeatMatching = false, + }, + new OsuSpriteText + { + TextSize = 24, + Font = "Exo2.0-Light", + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "New Player Registration", + }, + new OsuSpriteText + { + TextSize = 12, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "let's get you started", + }, + new SettingsButton + { + Text = "Let's create an account!", + Margin = new MarginPadding { Vertical = 120 }, + Action = () => Push(new ScreenWarning()) + } + } + }; + } + } +} diff --git a/osu.Game/Overlays/AccountCreationOverlay.cs b/osu.Game/Overlays/AccountCreationOverlay.cs index ba54538d61..9f3470de21 100644 --- a/osu.Game/Overlays/AccountCreationOverlay.cs +++ b/osu.Game/Overlays/AccountCreationOverlay.cs @@ -1,43 +1,22 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; -using System.Collections.Generic; -using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; -using osuTK.Graphics; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.MathUtils; +using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Overlays.AccountCreation; -using osu.Game.Overlays.Settings; using osuTK; +using osuTK.Graphics; namespace osu.Game.Overlays { public class AccountCreationOverlay : OsuFocusedOverlayContainer, IOnlineComponent { - private ErrorTextFlowContainer usernameDescription; - private ErrorTextFlowContainer emailAddressDescription; - private ErrorTextFlowContainer passwordDescription; - - private OsuTextBox usernameTextBox; - private OsuTextBox emailTextBox; - private OsuPasswordTextBox passwordTextBox; - - private APIAccess api; - private ShakeContainer registerShake; - private IEnumerable characterCheckText; - private const float transition_time = 400; public AccountCreationOverlay() @@ -50,8 +29,6 @@ namespace osu.Game.Overlays [BackgroundDependencyLoader] private void load(OsuColour colours, APIAccess api) { - this.api = api; - api.Register(this); Children = new Drawable[] @@ -90,166 +67,18 @@ namespace osu.Game.Overlays Colour = Color4.Black, Alpha = 0.9f, }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Padding = new MarginPadding(20), - Spacing = new Vector2(0, 10), - Children = new Drawable[] - { - new OsuSpriteText - { - TextSize = 20, - Margin = new MarginPadding { Vertical = 10 }, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "Let's create an account!", - }, - usernameTextBox = new OsuTextBox - { - PlaceholderText = "username", - RelativeSizeAxes = Axes.X, - TabbableContentContainer = this - }, - usernameDescription = new ErrorTextFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y - }, - emailTextBox = new OsuTextBox - { - PlaceholderText = "email address", - RelativeSizeAxes = Axes.X, - Text = api.ProvidedUsername ?? string.Empty, - TabbableContentContainer = this - }, - emailAddressDescription = new ErrorTextFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y - }, - passwordTextBox = new OsuPasswordTextBox - { - PlaceholderText = "password", - RelativeSizeAxes = Axes.X, - TabbableContentContainer = this, - }, - passwordDescription = new ErrorTextFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y - }, - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - registerShake = new ShakeContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Child = new SettingsButton - { - Text = "Register", - Margin = new MarginPadding { Vertical = 20 }, - Action = performRegistration - } - } - } - }, - } - }, + new ScreenWelcome(), } } } } }; - - usernameDescription.AddText("This will be your public presence. No profanity, no impersonation. Avoid exposing your own personal details, too!"); - - emailAddressDescription.AddText("Will be used for notifications, account verification and in the case you forget your password. No spam, ever."); - emailAddressDescription.AddText(" Make sure to get it right!", cp => cp.Font = "Exo2.0-Bold"); - - passwordDescription.AddText("At least "); - characterCheckText = passwordDescription.AddText("8 characters long"); - passwordDescription.AddText(". Choose something long but also something you will remember, like a line from your favourite song."); - - passwordTextBox.Current.ValueChanged += text => { characterCheckText.ForEach(s => s.Colour = text.Length == 0 ? Color4.White : Interpolation.ValueAt(text.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In)); }; - } - - private void performRegistration() - { - var textbox = nextUnfilledTextbox(); - - if (textbox != null) - { - Schedule(() => GetContainingInputManager().ChangeFocus(textbox)); - registerShake.Shake(); - return; - } - - usernameDescription.ClearErrors(); - emailAddressDescription.ClearErrors(); - passwordDescription.ClearErrors(); - - Task.Run(() => - { - bool success; - RegistrationRequest.RegistrationRequestErrors errors = null; - - try - { - errors = api.CreateAccount(emailTextBox.Text, usernameTextBox.Text, passwordTextBox.Text); - success = errors == null; - } - catch (Exception) - { - success = false; - } - - Schedule(() => - { - if (!success) - { - if (errors != null) - { - usernameDescription.AddErrors(errors.User.Username); - emailAddressDescription.AddErrors(errors.User.Email); - passwordDescription.AddErrors(errors.User.Password); - } - else - { - passwordDescription.AddErrors(new[] { "Something happened... but we're not sure what." }); - } - - registerShake.Shake(); - return; - } - - api.Login(emailTextBox.Text, passwordTextBox.Text); - }); - }); - } - - private OsuTextBox nextUnfilledTextbox() - { - OsuTextBox textboxIfUsable(OsuTextBox textbox) => !string.IsNullOrEmpty(textbox.Text) ? null : textbox; - - return textboxIfUsable(usernameTextBox) ?? textboxIfUsable(emailTextBox) ?? textboxIfUsable(passwordTextBox); } protected override void PopIn() { base.PopIn(); this.FadeIn(transition_time, Easing.OutQuint); - - var nextTextbox = nextUnfilledTextbox(); - if (nextTextbox != null) - Schedule(() => GetContainingInputManager().ChangeFocus(nextTextbox)); } protected override void PopOut() From 966c2f65475e9149f3a65ca53566fde63b3e04de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Dec 2018 12:05:13 +0900 Subject: [PATCH 08/38] Update resources --- osu-resources | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-resources b/osu-resources index 694cb03f19..b622fe6d70 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit 694cb03f19c93106ed0f2593f3e506e835fb652a +Subproject commit b622fe6d700d3b8e4602ff6b7e5f8b516825aea5 From d3f5111fa108e2e1db762577be3a372d7e806d6b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Dec 2018 12:17:08 +0900 Subject: [PATCH 09/38] Use relative URL --- osu.Game/OsuGame.cs | 8 +++++++- osu.Game/OsuGameBase.cs | 12 +++++++----- osu.Game/Overlays/AccountCreation/ScreenWarning.cs | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e12723a61d..15f011e122 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -187,7 +187,13 @@ namespace osu.Game } private ExternalLinkOpener externalLinkOpener; - public void OpenUrlExternally(string url) => externalLinkOpener.OpenUrlExternally(url); + public void OpenUrlExternally(string url) + { + if (url.StartsWith("/")) + url = $"{API.Endpoint}{url}"; + + externalLinkOpener.OpenUrlExternally(url); + } private ScheduledDelegate scoreLoad; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 2729676504..0f1819d55b 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -60,6 +60,8 @@ namespace osu.Game protected RulesetConfigCache RulesetConfigCache; + protected APIAccess API; + protected MenuCursorContainer MenuCursorContainer; private Container content; @@ -146,14 +148,14 @@ namespace osu.Game dependencies.Cache(SkinManager = new SkinManager(Host.Storage, contextFactory, Host, Audio)); dependencies.CacheAs(SkinManager); - var api = new APIAccess(LocalConfig); + API = new APIAccess(LocalConfig); - dependencies.Cache(api); - dependencies.CacheAs(api); + dependencies.Cache(API); + dependencies.CacheAs(API); dependencies.Cache(RulesetStore = new RulesetStore(contextFactory)); dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage)); - dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory, RulesetStore, api, Audio, Host)); + dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory, RulesetStore, API, Audio, Host)); dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, BeatmapManager, Host.Storage, contextFactory, Host)); dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore)); dependencies.Cache(SettingsStore = new SettingsStore(contextFactory)); @@ -177,7 +179,7 @@ namespace osu.Game FileStore.Cleanup(); - AddInternal(api); + AddInternal(API); GlobalActionContainer globalBinding; diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs index 6f887e23a2..c1d5332ca7 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.AccountCreation private OsuTextFlowContainer multiAccountExplanationText; private LinkFlowContainer furtherAssistance; - private const string help_centre_url = "https://osu.ppy.sh/help/wiki/Help_Centre#login"; + private const string help_centre_url = "/help/wiki/Help_Centre#login"; [BackgroundDependencyLoader(true)] private void load(OsuColour colours, APIAccess api, OsuGame game) From 88052dcea1d2dc1e947e8d72c8812e05128c5cfe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Dec 2018 12:38:11 +0900 Subject: [PATCH 10/38] Reset to welcome screen on exiting mid-process --- .../Overlays/AccountCreation/AccountCreationScreen.cs | 11 ++++++----- osu.Game/Overlays/AccountCreationOverlay.cs | 7 ++++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs b/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs index 134db37afa..371428d988 100644 --- a/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs +++ b/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs @@ -8,17 +8,18 @@ namespace osu.Game.Overlays.AccountCreation { public abstract class AccountCreationScreen : Screen { - protected AccountCreationScreen() - { - ValidForResume = false; - } - protected override void OnEntering(Screen last) { base.OnEntering(last); Content.FadeOut().Delay(200).FadeIn(200); } + protected override void OnResuming(Screen last) + { + base.OnResuming(last); + Content.FadeIn(200); + } + protected override void OnSuspending(Screen next) { base.OnSuspending(next); diff --git a/osu.Game/Overlays/AccountCreationOverlay.cs b/osu.Game/Overlays/AccountCreationOverlay.cs index 9f3470de21..9bc4119716 100644 --- a/osu.Game/Overlays/AccountCreationOverlay.cs +++ b/osu.Game/Overlays/AccountCreationOverlay.cs @@ -19,6 +19,8 @@ namespace osu.Game.Overlays { private const float transition_time = 400; + private ScreenWelcome welcomeScreen; + public AccountCreationOverlay() { Size = new Vector2(620, 450); @@ -67,7 +69,7 @@ namespace osu.Game.Overlays Colour = Color4.Black, Alpha = 0.9f, }, - new ScreenWelcome(), + welcomeScreen = new ScreenWelcome(), } } } @@ -79,6 +81,9 @@ namespace osu.Game.Overlays { base.PopIn(); this.FadeIn(transition_time, Easing.OutQuint); + + if (welcomeScreen.ChildScreen != null) + welcomeScreen.MakeCurrent(); } protected override void PopOut() From cc3ccc4c40735fb08b46a549fe3d256a1ea60877 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Dec 2018 12:53:35 +0900 Subject: [PATCH 11/38] Affix logo in place better --- .../Overlays/AccountCreation/ScreenWarning.cs | 16 +++++++++------- .../Overlays/AccountCreation/ScreenWelcome.cs | 16 +++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs index c1d5332ca7..6bc22d29c4 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs @@ -35,14 +35,16 @@ namespace osu.Game.Overlays.AccountCreation Spacing = new Vector2(0, 5), Children = new Drawable[] { - new OsuLogo + new Container { - Scale = new Vector2(0.1f), - Margin = new MarginPadding { Top = 500, Bottom = 300 }, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Triangles = false, - BeatMatching = false, + RelativeSizeAxes = Axes.X, + Height = 150, + Child = new OsuLogo + { + Scale = new Vector2(0.1f), + Anchor = Anchor.Centre, + Triangles = false, + }, }, new OsuSpriteText { diff --git a/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs b/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs index 0a4b35342e..5b7dc21be8 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs @@ -26,14 +26,16 @@ namespace osu.Game.Overlays.AccountCreation Spacing = new Vector2(0, 5), Children = new Drawable[] { - new OsuLogo + new Container { - Scale = new Vector2(0.1f), - Margin = new MarginPadding { Vertical = 500 }, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Triangles = false, - BeatMatching = false, + RelativeSizeAxes = Axes.X, + Height = 150, + Child = new OsuLogo + { + Scale = new Vector2(0.1f), + Anchor = Anchor.Centre, + Triangles = false, + }, }, new OsuSpriteText { From d5de5d1cb7063198e8c8b68ef2eac791242b24ac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Dec 2018 14:57:00 +0900 Subject: [PATCH 12/38] Fix textbox focus issues --- .../Overlays/AccountCreation/ScreenEntry.cs | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs index 141e39be8f..7328372db2 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; @@ -10,7 +11,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.MathUtils; -using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -36,14 +36,7 @@ namespace osu.Game.Overlays.AccountCreation private ShakeContainer registerShake; private IEnumerable characterCheckText; - protected override void OnEntering(Screen last) - { - base.OnEntering(last); - - var nextTextbox = nextUnfilledTextbox(); - if (nextTextbox != null) - Schedule(() => GetContainingInputManager().ChangeFocus(nextTextbox)); - } + private OsuTextBox[] textboxes; [BackgroundDependencyLoader] private void load(OsuColour colours, APIAccess api) @@ -123,6 +116,8 @@ namespace osu.Game.Overlays.AccountCreation } }; + textboxes = new[] { usernameTextBox, emailTextBox, passwordTextBox }; + usernameDescription.AddText("This will be your public presence. No profanity, no impersonation. Avoid exposing your own personal details, too!"); emailAddressDescription.AddText("Will be used for notifications, account verification and in the case you forget your password. No spam, ever."); @@ -135,13 +130,18 @@ namespace osu.Game.Overlays.AccountCreation passwordTextBox.Current.ValueChanged += text => { characterCheckText.ForEach(s => s.Colour = text.Length == 0 ? Color4.White : Interpolation.ValueAt(text.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In)); }; } + protected override void Update() + { + base.Update(); + + if (!textboxes.Any(t => t.HasFocus)) + focusNextTextbox(); + } + private void performRegistration() { - var textbox = nextUnfilledTextbox(); - - if (textbox != null) + if (focusNextTextbox()) { - Schedule(() => GetContainingInputManager().ChangeFocus(textbox)); registerShake.Shake(); return; } @@ -189,14 +189,18 @@ namespace osu.Game.Overlays.AccountCreation }); } - private OsuTextBox nextUnfilledTextbox() + private bool focusNextTextbox() { - OsuTextBox textboxIfUsable(OsuTextBox textbox) + var nextTextbox = nextUnfilledTextbox(); + if (nextTextbox != null) { - return !string.IsNullOrEmpty(textbox.Text) ? null : textbox; + Schedule(() => GetContainingInputManager().ChangeFocus(nextTextbox)); + return true; } - return textboxIfUsable(usernameTextBox) ?? textboxIfUsable(emailTextBox) ?? textboxIfUsable(passwordTextBox); + return false; } + + private OsuTextBox nextUnfilledTextbox() => textboxes.FirstOrDefault(t => string.IsNullOrEmpty(t.Text)); } } From 09f985c721709a8b723ee22ca892f80f87111a4d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Dec 2018 15:49:06 +0900 Subject: [PATCH 13/38] Add warning lines --- .../Overlays/AccountCreation/ScreenWarning.cs | 115 ++++++++++-------- 1 file changed, 66 insertions(+), 49 deletions(-) diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs index 6bc22d29c4..9511f2f40c 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs @@ -4,6 +4,8 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -23,61 +25,76 @@ namespace osu.Game.Overlays.AccountCreation private const string help_centre_url = "/help/wiki/Help_Centre#login"; [BackgroundDependencyLoader(true)] - private void load(OsuColour colours, APIAccess api, OsuGame game) + private void load(OsuColour colours, APIAccess api, OsuGame game, TextureStore textures) { - Child = new FillFlowContainer + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Padding = new MarginPadding(20), - Spacing = new Vector2(0, 5), - Children = new Drawable[] + new Sprite { - new Container + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Texture = textures.Get(@"Menu/dev-build-footer"), + }, + new Sprite + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Texture = textures.Get(@"Menu/dev-build-footer"), + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Padding = new MarginPadding(20), + Spacing = new Vector2(0, 5), + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - Height = 150, - Child = new OsuLogo + new Container { - Scale = new Vector2(0.1f), - Anchor = Anchor.Centre, - Triangles = false, + RelativeSizeAxes = Axes.X, + Height = 150, + Child = new OsuLogo + { + Scale = new Vector2(0.1f), + Anchor = Anchor.Centre, + Triangles = false, + }, }, - }, - new OsuSpriteText - { - TextSize = 28, - Font = "Exo2.0-Light", - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Colour = Color4.Red, - Text = "Warning! 注意!", - }, - multiAccountExplanationText = new OsuTextFlowContainer(cp => { cp.TextSize = 12; }) - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y - }, - new SettingsButton - { - Text = "Help, I can't access my account!", - Margin = new MarginPadding { Top = 50 }, - Action = () => game?.OpenUrlExternally(help_centre_url) - }, - new DangerousSettingsButton - { - Text = "I understand. This account isn't for me.", - Action = () => Push(new ScreenEntry()) - }, - furtherAssistance = new LinkFlowContainer(cp => { cp.TextSize = 12; }) - { - Margin = new MarginPadding { Top = 20 }, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - AutoSizeAxes = Axes.Both - }, + new OsuSpriteText + { + TextSize = 28, + Font = "Exo2.0-Light", + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Colour = Color4.Red, + Text = "Warning! 注意!", + }, + multiAccountExplanationText = new OsuTextFlowContainer(cp => { cp.TextSize = 12; }) + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, + new SettingsButton + { + Text = "Help, I can't access my account!", + Margin = new MarginPadding { Top = 50 }, + Action = () => game?.OpenUrlExternally(help_centre_url) + }, + new DangerousSettingsButton + { + Text = "I understand. This account isn't for me.", + Action = () => Push(new ScreenEntry()) + }, + furtherAssistance = new LinkFlowContainer(cp => { cp.TextSize = 12; }) + { + Margin = new MarginPadding { Top = 20 }, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both + }, + } } }; From de8c5a6df0b441b6d6e1d8f2cab5d3e0684d5022 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Dec 2018 16:29:41 +0900 Subject: [PATCH 14/38] Block input and show loading when submitting registration --- .../UserInterface/LoadingAnimation.cs | 3 + .../UserInterface/ProcessingOverlay.cs | 56 +++++++ .../Overlays/AccountCreation/ScreenEntry.cs | 139 ++++++++++-------- 3 files changed, 136 insertions(+), 62 deletions(-) create mode 100644 osu.Game/Graphics/UserInterface/ProcessingOverlay.cs diff --git a/osu.Game/Graphics/UserInterface/LoadingAnimation.cs b/osu.Game/Graphics/UserInterface/LoadingAnimation.cs index e503436d47..292a9bd088 100644 --- a/osu.Game/Graphics/UserInterface/LoadingAnimation.cs +++ b/osu.Game/Graphics/UserInterface/LoadingAnimation.cs @@ -8,6 +8,9 @@ using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface { + /// + /// A loading spinner. + /// public class LoadingAnimation : VisibilityContainer { private readonly SpriteIcon spinner; diff --git a/osu.Game/Graphics/UserInterface/ProcessingOverlay.cs b/osu.Game/Graphics/UserInterface/ProcessingOverlay.cs new file mode 100644 index 0000000000..0161c17ba9 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/ProcessingOverlay.cs @@ -0,0 +1,56 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osuTK.Graphics; + +namespace osu.Game.Graphics.UserInterface +{ + /// + /// An overlay that will consume all available space and block input when required. + /// Useful for disabling all elements in a form and showing we are waiting on a response, for instance. + /// + public class ProcessingOverlay : VisibilityContainer + { + private const float transition_duration = 200; + + public ProcessingOverlay() + { + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + new Box + { + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, + Alpha = 0.9f, + }, + new LoadingAnimation { State = Visibility.Visible } + }; + } + + protected override bool Handle(UIEvent e) + { + return true; + } + + protected override void PopIn() + { + this.FadeIn(transition_duration * 2, Easing.OutQuint); + } + + protected override void PopOut() + { + this.FadeOut(transition_duration, Easing.OutQuint); + } + } +} diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs index 7328372db2..3d9a74ea2b 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.MathUtils; +using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -37,83 +38,88 @@ namespace osu.Game.Overlays.AccountCreation private IEnumerable characterCheckText; private OsuTextBox[] textboxes; + private ProcessingOverlay processingOverlay; [BackgroundDependencyLoader] private void load(OsuColour colours, APIAccess api) { this.api = api; - Child = new FillFlowContainer + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Padding = new MarginPadding(20), - Spacing = new Vector2(0, 10), - Children = new Drawable[] + new FillFlowContainer { - new OsuSpriteText + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Padding = new MarginPadding(20), + Spacing = new Vector2(0, 10), + Children = new Drawable[] { - TextSize = 20, - Margin = new MarginPadding { Vertical = 10 }, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "Let's create an account!", - }, - usernameTextBox = new OsuTextBox - { - PlaceholderText = "username", - RelativeSizeAxes = Axes.X, - TabbableContentContainer = this - }, - usernameDescription = new ErrorTextFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y - }, - emailTextBox = new OsuTextBox - { - PlaceholderText = "email address", - RelativeSizeAxes = Axes.X, - TabbableContentContainer = this - }, - emailAddressDescription = new ErrorTextFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y - }, - passwordTextBox = new OsuPasswordTextBox - { - PlaceholderText = "password", - RelativeSizeAxes = Axes.X, - TabbableContentContainer = this, - }, - passwordDescription = new ErrorTextFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y - }, - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] + new OsuSpriteText { - registerShake = new ShakeContainer + TextSize = 20, + Margin = new MarginPadding { Vertical = 10 }, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "Let's create an account!", + }, + usernameTextBox = new OsuTextBox + { + PlaceholderText = "username", + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this + }, + usernameDescription = new ErrorTextFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, + emailTextBox = new OsuTextBox + { + PlaceholderText = "email address", + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this + }, + emailAddressDescription = new ErrorTextFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, + passwordTextBox = new OsuPasswordTextBox + { + PlaceholderText = "password", + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + }, + passwordDescription = new ErrorTextFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Child = new SettingsButton + registerShake = new ShakeContainer { - Text = "Register", - Margin = new MarginPadding { Vertical = 20 }, - Action = performRegistration + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = new SettingsButton + { + Text = "Register", + Margin = new MarginPadding { Vertical = 20 }, + Action = performRegistration + } } } - } + }, }, - } + }, + processingOverlay = new ProcessingOverlay { Alpha = 0 } }; textboxes = new[] { usernameTextBox, emailTextBox, passwordTextBox }; @@ -138,6 +144,12 @@ namespace osu.Game.Overlays.AccountCreation focusNextTextbox(); } + protected override void OnEntering(Screen last) + { + base.OnEntering(last); + processingOverlay.Hide(); + } + private void performRegistration() { if (focusNextTextbox()) @@ -150,6 +162,8 @@ namespace osu.Game.Overlays.AccountCreation emailAddressDescription.ClearErrors(); passwordDescription.ClearErrors(); + processingOverlay.Show(); + Task.Run(() => { bool success; @@ -181,6 +195,7 @@ namespace osu.Game.Overlays.AccountCreation } registerShake.Shake(); + processingOverlay.Hide(); return; } From b0e2b56e8593d530edba2efaf83ade51a5fcf9d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Dec 2018 16:54:08 +0900 Subject: [PATCH 15/38] Don't show warning screen if no previous account is detected --- .../Overlays/AccountCreation/ScreenWarning.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs index 9511f2f40c..b6fffde621 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; +using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -21,12 +22,26 @@ namespace osu.Game.Overlays.AccountCreation { private OsuTextFlowContainer multiAccountExplanationText; private LinkFlowContainer furtherAssistance; + private APIAccess api; private const string help_centre_url = "/help/wiki/Help_Centre#login"; + protected override void OnEntering(Screen last) + { + if (string.IsNullOrEmpty(api.ProvidedUsername)) + { + Content.FadeOut(); + Push(new ScreenEntry()); + return; + } + + base.OnEntering(last); + } + [BackgroundDependencyLoader(true)] private void load(OsuColour colours, APIAccess api, OsuGame game, TextureStore textures) { + this.api = api; Children = new Drawable[] { new Sprite From f157628dcc5bf074101250eea4344e15a07a0637 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Dec 2018 17:06:22 +0900 Subject: [PATCH 16/38] Remove unnecessary csproj change --- osu.Game/osu.Game.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 78496830d8..85eabb0350 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -24,7 +24,4 @@ - - - From 6ebe555838fd458ec907a6254d84787935a8eb6b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Dec 2018 17:11:39 +0900 Subject: [PATCH 17/38] Fix incorrect filename --- .../Online/API/{RegsitrationRequest.cs => RegistrationRequest.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename osu.Game/Online/API/{RegsitrationRequest.cs => RegistrationRequest.cs} (100%) diff --git a/osu.Game/Online/API/RegsitrationRequest.cs b/osu.Game/Online/API/RegistrationRequest.cs similarity index 100% rename from osu.Game/Online/API/RegsitrationRequest.cs rename to osu.Game/Online/API/RegistrationRequest.cs From 13cabac386653da27ad6a4105847572792bf78fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Dec 2018 19:56:21 +0900 Subject: [PATCH 18/38] Update in line with framework changes --- osu.Game/Overlays/AccountCreation/ScreenEntry.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs index 3d9a74ea2b..bfc437f763 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs @@ -9,7 +9,6 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Framework.MathUtils; using osu.Framework.Screens; using osu.Game.Graphics; @@ -35,7 +34,7 @@ namespace osu.Game.Overlays.AccountCreation private APIAccess api; private ShakeContainer registerShake; - private IEnumerable characterCheckText; + private IEnumerable characterCheckText; private OsuTextBox[] textboxes; private ProcessingOverlay processingOverlay; From 3892454eccfd936dcb8de103b2d21167a881ce0e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 15 Dec 2018 16:34:48 +0900 Subject: [PATCH 19/38] Improve the way text search works at song select --- .../Screens/Select/Carousel/CarouselBeatmap.cs | 6 +++--- osu.Game/Screens/Select/FilterCriteria.cs | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index 272332f1ce..0f548bb667 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -26,10 +26,10 @@ namespace osu.Game.Screens.Select.Carousel bool match = criteria.Ruleset == null || Beatmap.RulesetID == criteria.Ruleset.ID || Beatmap.RulesetID == 0 && criteria.Ruleset.ID > 0 && criteria.AllowConvertedBeatmaps; - if (!string.IsNullOrEmpty(criteria.SearchText)) + foreach (var criteriaTerm in criteria.SearchTerms) match &= - Beatmap.Metadata.SearchableTerms.Any(term => term.IndexOf(criteria.SearchText, StringComparison.InvariantCultureIgnoreCase) >= 0) || - Beatmap.Version.IndexOf(criteria.SearchText, StringComparison.InvariantCultureIgnoreCase) >= 0; + Beatmap.Metadata.SearchableTerms.Any(term => term.IndexOf(criteriaTerm, StringComparison.InvariantCultureIgnoreCase) >= 0) || + Beatmap.Version.IndexOf(criteriaTerm, StringComparison.InvariantCultureIgnoreCase) >= 0; Filtered.Value = !match; } diff --git a/osu.Game/Screens/Select/FilterCriteria.cs b/osu.Game/Screens/Select/FilterCriteria.cs index bea806f00f..71cfedfdbf 100644 --- a/osu.Game/Screens/Select/FilterCriteria.cs +++ b/osu.Game/Screens/Select/FilterCriteria.cs @@ -1,6 +1,8 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using System.Linq; using osu.Game.Rulesets; using osu.Game.Screens.Select.Filter; @@ -10,8 +12,22 @@ namespace osu.Game.Screens.Select { public GroupMode Group; public SortMode Sort; - public string SearchText; + + public string[] SearchTerms = Array.Empty(); + public RulesetInfo Ruleset; public bool AllowConvertedBeatmaps; + + private string searchText; + + public string SearchText + { + get { return searchText; } + set + { + searchText = value; + SearchTerms = searchText.Split(',', ' ', '!').Where(s => !string.IsNullOrEmpty(s)).ToArray(); + } + } } } From eec5afa3828ac70ea639b39030f431d156e25eb4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 15 Dec 2018 16:37:37 +0900 Subject: [PATCH 20/38] Change inspection and add redundant parenthesis to appease codefactor --- osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs | 2 +- osu.sln.DotSettings | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index 0f548bb667..49779f5e11 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Select.Carousel { base.Filter(criteria); - bool match = criteria.Ruleset == null || Beatmap.RulesetID == criteria.Ruleset.ID || Beatmap.RulesetID == 0 && criteria.Ruleset.ID > 0 && criteria.AllowConvertedBeatmaps; + bool match = criteria.Ruleset == null || Beatmap.RulesetID == criteria.Ruleset.ID || (Beatmap.RulesetID == 0 && criteria.Ruleset.ID > 0 && criteria.AllowConvertedBeatmaps); foreach (var criteriaTerm in criteria.SearchTerms) match &= diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index d6882282e6..112efb37f0 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -8,7 +8,8 @@ SOLUTION HINT WARNING - WARNING + + True WARNING WARNING HINT From 81104f48036e2be94fe36095bdd06877c3b60567 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Dec 2018 17:54:12 +0900 Subject: [PATCH 21/38] Make standalone chat reuse more code from main chat overlay --- .../Visual/TestCaseStandAloneChatDisplay.cs | 12 +- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 142 ++++-------------- osu.Game/Overlays/Chat/ChatLine.cs | 123 +++++++-------- osu.Game/Overlays/Chat/DrawableChannel.cs | 22 +-- 4 files changed, 113 insertions(+), 186 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/TestCaseStandAloneChatDisplay.cs index 16ce720ab1..b5ce1f1eaf 100644 --- a/osu.Game.Tests/Visual/TestCaseStandAloneChatDisplay.cs +++ b/osu.Game.Tests/Visual/TestCaseStandAloneChatDisplay.cs @@ -68,31 +68,33 @@ namespace osu.Game.Tests.Visual chatDisplay.Channel.Value = testChannel; chatDisplay2.Channel.Value = testChannel; - AddStep("message from admin", () => testChannel.AddLocalEcho(new LocalEchoMessage + int sequence = 0; + + AddStep("message from admin", () => testChannel.AddNewMessages(new Message(sequence++) { Sender = admin, Content = "I am a wang!" })); - AddStep("message from team red", () => testChannel.AddLocalEcho(new LocalEchoMessage + AddStep("message from team red", () => testChannel.AddNewMessages(new Message(sequence++) { Sender = redUser, Content = "I am team red." })); - AddStep("message from team red", () => testChannel.AddLocalEcho(new LocalEchoMessage + AddStep("message from team red", () => testChannel.AddNewMessages(new Message(sequence++) { Sender = redUser, Content = "I plan to win!" })); - AddStep("message from team blue", () => testChannel.AddLocalEcho(new LocalEchoMessage + AddStep("message from team blue", () => testChannel.AddNewMessages(new Message(sequence++) { Sender = blueUser, Content = "Not on my watch. Prepare to eat saaaaaaaaaand. Lots and lots of saaaaaaand." })); - AddStep("message from admin", () => testChannel.AddLocalEcho(new LocalEchoMessage + AddStep("message from admin", () => testChannel.AddNewMessages(new Message(sequence++) { Sender = admin, Content = "Okay okay, calm down guys. Let's do this!" diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 332334a043..46c6873063 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -1,19 +1,15 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; -using System.Linq; +using System; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osuTK; +using osu.Game.Overlays.Chat; using osuTK.Graphics; namespace osu.Game.Online.Chat @@ -23,22 +19,27 @@ namespace osu.Game.Online.Chat /// public class StandAloneChatDisplay : CompositeDrawable { + private readonly bool postingTextbox; + public readonly Bindable Channel = new Bindable(); - private readonly FillFlowContainer messagesFlow; - - private Channel lastChannel; - private readonly FocusedTextBox textbox; protected ChannelManager ChannelManager; + private ScrollContainer scroll; + + private DrawableChannel drawableChannel; + + private const float textbox_height = 30; + /// /// Construct a new instance. /// /// Whether a textbox for posting new messages should be displayed. public StandAloneChatDisplay(bool postingTextbox = false) { + this.postingTextbox = postingTextbox; CornerRadius = 10; Masking = true; @@ -50,23 +51,11 @@ namespace osu.Game.Online.Chat Alpha = 0.8f, RelativeSizeAxes = Axes.Both }, - messagesFlow = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - LayoutEasing = Easing.Out, - LayoutDuration = 500, - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Direction = FillDirection.Vertical - } }; - const float textbox_height = 30; if (postingTextbox) { - messagesFlow.Y -= textbox_height; AddInternal(textbox = new FocusedTextBox { RelativeSizeAxes = Axes.X, @@ -117,112 +106,43 @@ namespace osu.Game.Online.Chat this.MoveToY(100, 500, Easing.In); } - protected virtual Drawable CreateMessage(Message message) - { - return new StandAloneMessage(message); - } + protected virtual ChatLine CreateMessage(Message message) => new StandAloneMessage(message); private void channelChanged(Channel channel) { - if (lastChannel != null) - lastChannel.NewMessagesArrived -= newMessages; - - lastChannel = channel; - messagesFlow.Clear(); + drawableChannel?.Expire(); if (channel == null) return; - channel.NewMessagesArrived += newMessages; - - newMessages(channel.Messages); + AddInternal(drawableChannel = new StandAloneDrawableChannel(channel) + { + CreateChatLineAction = CreateMessage, + Padding = new MarginPadding { Bottom = postingTextbox ? textbox_height : 0 } + }); } - private void newMessages(IEnumerable messages) + protected class StandAloneDrawableChannel : DrawableChannel { - var excessChildren = messagesFlow.Children.Count - 10; - if (excessChildren > 0) - foreach (var c in messagesFlow.Children.Take(excessChildren)) - c.Expire(); + public Func CreateChatLineAction; - foreach (var message in messages) + protected override ChatLine CreateChatLine(Message m) => CreateChatLineAction(m); + + public StandAloneDrawableChannel(Channel channel) + : base(channel) { - var formatted = MessageFormatter.FormatMessage(message); - var drawable = CreateMessage(formatted); - drawable.Y = messagesFlow.Height; - messagesFlow.Add(drawable); + ChatLineFlow.Padding = new MarginPadding { Horizontal = 0 }; } } - protected class StandAloneMessage : CompositeDrawable + protected class StandAloneMessage : ChatLine { - protected readonly Message Message; - protected OsuSpriteText SenderText; - protected Circle ColourBox; + protected override float TextSize => 15; - public StandAloneMessage(Message message) + protected override float HorizontalPadding => 10; + protected override float MessagePadding => 120; + + public StandAloneMessage(Message message) : base(message) { - Message = message; - } - - [BackgroundDependencyLoader] - private void load() - { - Margin = new MarginPadding(3); - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - - InternalChildren = new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.X, - Width = 0.2f, - Children = new Drawable[] - { - SenderText = new OsuSpriteText - { - Font = @"Exo2.0-Bold", - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Text = Message.Sender.ToString() - } - } - }, - new Container - { - Size = new Vector2(8, OsuSpriteText.FONT_SIZE), - Margin = new MarginPadding { Horizontal = 3 }, - Children = new Drawable[] - { - ColourBox = new Circle - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(8) - } - } - }, - new OsuTextFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Width = 0.5f, - Text = Message.DisplayContent - } - } - } - }; - - if (!string.IsNullOrEmpty(Message.Sender.Colour)) - SenderText.Colour = ColourBox.Colour = OsuColour.FromHex(Message.Sender.Colour); } } } diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index c11de48430..29579056bf 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -1,72 +1,38 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . +// Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; using System.Linq; -using osuTK; -using osuTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.Chat; using osu.Game.Users; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics.UserInterface; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Overlays.Chat { - public class ChatLine : Container + public class ChatLine : CompositeDrawable { - private static readonly Color4[] username_colours = - { - OsuColour.FromHex("588c7e"), - OsuColour.FromHex("b2a367"), - OsuColour.FromHex("c98f65"), - OsuColour.FromHex("bc5151"), - OsuColour.FromHex("5c8bd6"), - OsuColour.FromHex("7f6ab7"), - OsuColour.FromHex("a368ad"), - OsuColour.FromHex("aa6880"), + public const float LEFT_PADDING = default_message_padding + default_horizontal_padding * 2; - OsuColour.FromHex("6fad9b"), - OsuColour.FromHex("f2e394"), - OsuColour.FromHex("f2ae72"), - OsuColour.FromHex("f98f8a"), - OsuColour.FromHex("7daef4"), - OsuColour.FromHex("a691f2"), - OsuColour.FromHex("c894d3"), - OsuColour.FromHex("d895b0"), + private const float default_message_padding = 200; - OsuColour.FromHex("53c4a1"), - OsuColour.FromHex("eace5c"), - OsuColour.FromHex("ea8c47"), - OsuColour.FromHex("fc4f4f"), - OsuColour.FromHex("3d94ea"), - OsuColour.FromHex("7760ea"), - OsuColour.FromHex("af52c6"), - OsuColour.FromHex("e25696"), + protected virtual float MessagePadding => default_message_padding; - OsuColour.FromHex("677c66"), - OsuColour.FromHex("9b8732"), - OsuColour.FromHex("8c5129"), - OsuColour.FromHex("8c3030"), - OsuColour.FromHex("1f5d91"), - OsuColour.FromHex("4335a5"), - OsuColour.FromHex("812a96"), - OsuColour.FromHex("992861"), - }; + private const float default_horizontal_padding = 15; - public const float LEFT_PADDING = message_padding + padding * 2; + protected virtual float HorizontalPadding => default_horizontal_padding; - private const float padding = 15; - private const float message_padding = 200; - private const float action_padding = 3; - private const float text_size = 20; + protected virtual float TextSize => 20; private Color4 customUsernameColour; @@ -75,14 +41,13 @@ namespace osu.Game.Overlays.Chat public ChatLine(Message message) { Message = message; - + Padding = new MarginPadding { Left = HorizontalPadding, Right = HorizontalPadding }; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - - Padding = new MarginPadding { Left = padding, Right = padding }; } - private ChannelManager chatManager; + [Resolved(CanBeNull = true)] + private ChannelManager chatManager { get; set; } private Message message; private OsuSpriteText username; @@ -106,10 +71,9 @@ namespace osu.Game.Overlays.Chat } } - [BackgroundDependencyLoader(true)] - private void load(OsuColour colours, ChannelManager chatManager) + [BackgroundDependencyLoader] + private void load(OsuColour colours) { - this.chatManager = chatManager; customUsernameColour = colours.ChatBlue; } @@ -125,7 +89,7 @@ namespace osu.Game.Overlays.Chat { Font = @"Exo2.0-BoldItalic", Colour = hasBackground ? customUsernameColour : username_colours[message.Sender.Id % username_colours.Length], - TextSize = text_size, + TextSize = TextSize, }; if (hasBackground) @@ -163,11 +127,11 @@ namespace osu.Game.Overlays.Chat }; } - Children = new Drawable[] + InternalChildren = new Drawable[] { new Container { - Size = new Vector2(message_padding, text_size), + Size = new Vector2(MessagePadding, TextSize), Children = new Drawable[] { timestamp = new OsuSpriteText @@ -176,7 +140,7 @@ namespace osu.Game.Overlays.Chat Origin = Anchor.CentreLeft, Font = @"Exo2.0-SemiBold", FixedWidth = true, - TextSize = text_size * 0.75f, + TextSize = TextSize * 0.75f, }, new MessageSender(message.Sender) { @@ -191,7 +155,7 @@ namespace osu.Game.Overlays.Chat { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = message_padding + padding }, + Padding = new MarginPadding { Left = MessagePadding + HorizontalPadding }, Children = new Drawable[] { contentFlow = new LinkFlowContainer(t => @@ -204,7 +168,7 @@ namespace osu.Game.Overlays.Chat t.Colour = OsuColour.FromHex(message.Sender.Colour); } - t.TextSize = text_size; + t.TextSize = TextSize; }) { AutoSizeAxes = Axes.Y, @@ -257,5 +221,44 @@ namespace osu.Game.Overlays.Chat new OsuMenuItem("Start Chat", MenuItemType.Standard, startChatAction), }; } + + private static readonly Color4[] username_colours = + { + OsuColour.FromHex("588c7e"), + OsuColour.FromHex("b2a367"), + OsuColour.FromHex("c98f65"), + OsuColour.FromHex("bc5151"), + OsuColour.FromHex("5c8bd6"), + OsuColour.FromHex("7f6ab7"), + OsuColour.FromHex("a368ad"), + OsuColour.FromHex("aa6880"), + + OsuColour.FromHex("6fad9b"), + OsuColour.FromHex("f2e394"), + OsuColour.FromHex("f2ae72"), + OsuColour.FromHex("f98f8a"), + OsuColour.FromHex("7daef4"), + OsuColour.FromHex("a691f2"), + OsuColour.FromHex("c894d3"), + OsuColour.FromHex("d895b0"), + + OsuColour.FromHex("53c4a1"), + OsuColour.FromHex("eace5c"), + OsuColour.FromHex("ea8c47"), + OsuColour.FromHex("fc4f4f"), + OsuColour.FromHex("3d94ea"), + OsuColour.FromHex("7760ea"), + OsuColour.FromHex("af52c6"), + OsuColour.FromHex("e25696"), + + OsuColour.FromHex("677c66"), + OsuColour.FromHex("9b8732"), + OsuColour.FromHex("8c5129"), + OsuColour.FromHex("8c3030"), + OsuColour.FromHex("1f5d91"), + OsuColour.FromHex("4335a5"), + OsuColour.FromHex("812a96"), + OsuColour.FromHex("992861"), + }; } } diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 2418eda2b6..c8fc15a0bc 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Chat public class DrawableChannel : Container { public readonly Channel Channel; - private readonly ChatLineContainer flow; + protected readonly ChatLineContainer ChatLineFlow; private readonly ScrollContainer scroll; public DrawableChannel(Channel channel) @@ -38,7 +38,7 @@ namespace osu.Game.Overlays.Chat { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Child = flow = new ChatLineContainer + Child = ChatLineFlow = new ChatLineContainer { Padding = new MarginPadding { Left = 20, Right = 20 }, RelativeSizeAxes = Axes.X, @@ -72,17 +72,19 @@ namespace osu.Game.Overlays.Chat Channel.PendingMessageResolved -= pendingMessageResolved; } + protected virtual ChatLine CreateChatLine(Message m) => new ChatLine(m); + private void newMessagesArrived(IEnumerable newMessages) { // Add up to last Channel.MAX_HISTORY messages var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MaxHistory)); - flow.AddRange(displayMessages.Select(m => new ChatLine(m))); + ChatLineFlow.AddRange(displayMessages.Select(CreateChatLine)); - if (scroll.IsScrolledToEnd(10) || !flow.Children.Any() || newMessages.Any(m => m is LocalMessage)) + if (scroll.IsScrolledToEnd(10) || !ChatLineFlow.Children.Any() || newMessages.Any(m => m is LocalMessage)) scrollToEnd(); - var staleMessages = flow.Children.Where(c => c.LifetimeEnd == double.MaxValue).ToArray(); + var staleMessages = ChatLineFlow.Children.Where(c => c.LifetimeEnd == double.MaxValue).ToArray(); int count = staleMessages.Length - Channel.MaxHistory; for (int i = 0; i < count; i++) @@ -96,25 +98,25 @@ namespace osu.Game.Overlays.Chat private void pendingMessageResolved(Message existing, Message updated) { - var found = flow.Children.LastOrDefault(c => c.Message == existing); + var found = ChatLineFlow.Children.LastOrDefault(c => c.Message == existing); if (found != null) { Trace.Assert(updated.Id.HasValue, "An updated message was returned with no ID."); - flow.Remove(found); + ChatLineFlow.Remove(found); found.Message = updated; - flow.Add(found); + ChatLineFlow.Add(found); } } private void messageRemoved(Message removed) { - flow.Children.FirstOrDefault(c => c.Message == removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); + ChatLineFlow.Children.FirstOrDefault(c => c.Message == removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); } private void scrollToEnd() => ScheduleAfterChildren(() => scroll.ScrollToEnd()); - private class ChatLineContainer : FillFlowContainer + protected class ChatLineContainer : FillFlowContainer { protected override int Compare(Drawable x, Drawable y) { From 396caae0a90eace8b2b6da6bd91a516aadccc036 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Dec 2018 19:01:19 +0900 Subject: [PATCH 22/38] Remove redundant newline --- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 46c6873063..1ec138ab57 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -53,7 +53,6 @@ namespace osu.Game.Online.Chat }, }; - if (postingTextbox) { AddInternal(textbox = new FocusedTextBox From f0dfc75bb2024ed110871e2222089e940c1d9319 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Dec 2018 09:48:55 +0900 Subject: [PATCH 23/38] Change osu! default keys back to Z/X A/S was no better as far as keyboard layout agnostic-ness. And people are confused if we change the defaults. Need to take a step back and reassess. --- osu.Game.Rulesets.Osu/OsuRuleset.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index ecb0443f33..5cfc24bdde 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -31,8 +31,8 @@ namespace osu.Game.Rulesets.Osu public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] { - new KeyBinding(InputKey.A, OsuAction.LeftButton), - new KeyBinding(InputKey.S, OsuAction.RightButton), + new KeyBinding(InputKey.Z, OsuAction.LeftButton), + new KeyBinding(InputKey.X, OsuAction.RightButton), new KeyBinding(InputKey.MouseLeft, OsuAction.LeftButton), new KeyBinding(InputKey.MouseRight, OsuAction.RightButton), }; From 86ce0b551937f65f5b687430bf792d872a644ba1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 19 Dec 2018 12:44:51 +0900 Subject: [PATCH 24/38] Make DrawableDate adjustable --- osu.Game/Graphics/DrawableDate.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/DrawableDate.cs b/osu.Game/Graphics/DrawableDate.cs index 28f8bdf82f..639a549936 100644 --- a/osu.Game/Graphics/DrawableDate.cs +++ b/osu.Game/Graphics/DrawableDate.cs @@ -4,6 +4,7 @@ using System; using Humanizer; using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Graphics.Cursor; using osu.Game.Graphics.Sprites; @@ -11,13 +12,27 @@ namespace osu.Game.Graphics { public class DrawableDate : OsuSpriteText, IHasTooltip { - protected readonly DateTimeOffset Date; + private DateTimeOffset date; + + public DateTimeOffset Date + { + get => date; + set + { + if (date == value) + return; + date = value.ToLocalTime(); + + if (LoadState >= LoadState.Ready) + updateTime(); + } + } public DrawableDate(DateTimeOffset date) { Font = "Exo2.0-RegularItalic"; - Date = date.ToLocalTime(); + Date = date; } [BackgroundDependencyLoader] From d28c754256c7258d59f0c5cd0ad4289b8787ad58 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 19 Dec 2018 13:07:43 +0900 Subject: [PATCH 25/38] Fix negative dates, and time moving in opposite direction --- osu.Game/Graphics/DrawableDate.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/DrawableDate.cs b/osu.Game/Graphics/DrawableDate.cs index 639a549936..87711c72c7 100644 --- a/osu.Game/Graphics/DrawableDate.cs +++ b/osu.Game/Graphics/DrawableDate.cs @@ -54,14 +54,14 @@ namespace osu.Game.Graphics var diffToNow = DateTimeOffset.Now.Subtract(Date); double timeUntilNextUpdate = 1000; - if (diffToNow.TotalSeconds > 60) + if (Math.Abs(diffToNow.TotalSeconds) > 120) { timeUntilNextUpdate *= 60; - if (diffToNow.TotalMinutes > 60) + if (Math.Abs(diffToNow.TotalMinutes) > 120) { timeUntilNextUpdate *= 60; - if (diffToNow.TotalHours > 24) + if (Math.Abs(diffToNow.TotalHours) > 48) timeUntilNextUpdate *= 24; } } From 621480af0214f2e4e86199a0f667b70d431c895b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Dec 2018 14:21:21 +0900 Subject: [PATCH 26/38] Add simple (non-automated) test --- osu.Game.Tests/Visual/TestCaseDrawableDate.cs | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 osu.Game.Tests/Visual/TestCaseDrawableDate.cs diff --git a/osu.Game.Tests/Visual/TestCaseDrawableDate.cs b/osu.Game.Tests/Visual/TestCaseDrawableDate.cs new file mode 100644 index 0000000000..2e38f5eb28 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseDrawableDate.cs @@ -0,0 +1,67 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseDrawableDate : OsuTestCase + { + public TestCaseDrawableDate() + { + Child = new FillFlowContainer + { + Direction = FillDirection.Vertical, + AutoSizeAxes = Axes.Both, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Children = new Drawable[] + { + new PokeyDrawableDate(DateTimeOffset.Now.Subtract(TimeSpan.FromSeconds(60))), + new PokeyDrawableDate(DateTimeOffset.Now.Subtract(TimeSpan.FromSeconds(55))), + new PokeyDrawableDate(DateTimeOffset.Now.Subtract(TimeSpan.FromSeconds(50))), + new PokeyDrawableDate(DateTimeOffset.Now), + new PokeyDrawableDate(DateTimeOffset.Now.Add(TimeSpan.FromSeconds(60))), + new PokeyDrawableDate(DateTimeOffset.Now.Add(TimeSpan.FromSeconds(65))), + new PokeyDrawableDate(DateTimeOffset.Now.Add(TimeSpan.FromSeconds(70))), + } + }; + } + + private class PokeyDrawableDate : CompositeDrawable + { + public PokeyDrawableDate(DateTimeOffset date) + { + const float box_size = 10; + + DrawableDate drawableDate; + Box flash; + + AutoSizeAxes = Axes.Both; + InternalChildren = new Drawable[] + { + flash = new Box + { + Colour = Color4.Yellow, + Size = new Vector2(box_size), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Alpha = 0 + }, + drawableDate = new DrawableDate(date) + { + X = box_size + 2, + } + }; + + drawableDate.Current.ValueChanged += v => flash.FadeOutFromOne(500); + } + } + } +} From e657f13c1539fa6deace5405f61a4b1df12e4728 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Dec 2018 19:51:27 +0900 Subject: [PATCH 27/38] Separate out Leaderboard into BeatmapLeaderboard --- osu.Game.Tests/Visual/TestCaseLeaderboard.cs | 5 +- .../Online/API/Requests/GetScoresRequest.cs | 6 +- .../Leaderboards/DrawableRank.cs | 4 +- .../Leaderboards/Leaderboard.cs | 113 +++++------------- .../Leaderboards/LeaderboardScore.cs | 79 +++++++----- .../Leaderboards/MessagePlaceholder.cs | 2 +- .../Leaderboards/Placeholder.cs | 2 +- .../Leaderboards/PlaceholderState.cs | 2 +- .../RetrievalFailurePlaceholder.cs | 2 +- .../BeatmapSet/Scores/DrawableScore.cs | 2 +- .../BeatmapSet/Scores/DrawableTopScore.cs | 2 +- .../Sections/Ranks/DrawableProfileScore.cs | 2 +- .../Sections/Recent/DrawableRecentActivity.cs | 2 +- .../Screens/Ranking/ResultsPageRanking.cs | 2 +- osu.Game/Screens/Ranking/ResultsPageScore.cs | 2 +- osu.Game/Screens/Select/BeatmapDetailArea.cs | 6 +- .../Select/Leaderboards/BeatmapLeaderboard.cs | 87 ++++++++++++++ ...ardScope.cs => BeatmapLeaderboardScope.cs} | 2 +- .../Leaderboards/BeatmapLeaderboardScore.cs | 34 ++++++ 19 files changed, 224 insertions(+), 132 deletions(-) rename osu.Game/{Screens/Select => Online}/Leaderboards/DrawableRank.cs (96%) rename osu.Game/{Screens/Select => Online}/Leaderboards/Leaderboard.cs (76%) rename osu.Game/{Screens/Select => Online}/Leaderboards/LeaderboardScore.cs (87%) rename osu.Game/{Screens/Select => Online}/Leaderboards/MessagePlaceholder.cs (94%) rename osu.Game/{Screens/Select => Online}/Leaderboards/Placeholder.cs (94%) rename osu.Game/{Screens/Select => Online}/Leaderboards/PlaceholderState.cs (88%) rename osu.Game/{Screens/Select => Online}/Leaderboards/RetrievalFailurePlaceholder.cs (97%) create mode 100644 osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs rename osu.Game/Screens/Select/Leaderboards/{LeaderboardScope.cs => BeatmapLeaderboardScope.cs} (87%) create mode 100644 osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScore.cs diff --git a/osu.Game.Tests/Visual/TestCaseLeaderboard.cs b/osu.Game.Tests/Visual/TestCaseLeaderboard.cs index f7630f0902..10d7eaee8a 100644 --- a/osu.Game.Tests/Visual/TestCaseLeaderboard.cs +++ b/osu.Game.Tests/Visual/TestCaseLeaderboard.cs @@ -11,6 +11,7 @@ using osu.Framework.Allocation; using osuTK; using System.Linq; using osu.Game.Beatmaps; +using osu.Game.Online.Leaderboards; using osu.Game.Rulesets; using osu.Game.Scoring; @@ -36,7 +37,7 @@ namespace osu.Game.Tests.Visual Origin = Anchor.Centre, Anchor = Anchor.Centre, Size = new Vector2(550f, 450f), - Scope = LeaderboardScope.Global, + Scope = BeatmapLeaderboardScope.Global, }); AddStep(@"New Scores", newScores); @@ -275,7 +276,7 @@ namespace osu.Game.Tests.Visual }; } - private class FailableLeaderboard : Leaderboard + private class FailableLeaderboard : BeatmapLeaderboard { public void SetRetrievalState(PlaceholderState state) { diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index 2751dd956b..ae2c7dc269 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -13,15 +13,15 @@ namespace osu.Game.Online.API.Requests public class GetScoresRequest : APIRequest { private readonly BeatmapInfo beatmap; - private readonly LeaderboardScope scope; + private readonly BeatmapLeaderboardScope scope; private readonly RulesetInfo ruleset; - public GetScoresRequest(BeatmapInfo beatmap, RulesetInfo ruleset, LeaderboardScope scope = LeaderboardScope.Global) + public GetScoresRequest(BeatmapInfo beatmap, RulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global) { if (!beatmap.OnlineBeatmapID.HasValue) throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}."); - if (scope == LeaderboardScope.Local) + if (scope == BeatmapLeaderboardScope.Local) throw new InvalidOperationException("Should not attempt to request online scores for a local scoped leaderboard"); this.beatmap = beatmap; diff --git a/osu.Game/Screens/Select/Leaderboards/DrawableRank.cs b/osu.Game/Online/Leaderboards/DrawableRank.cs similarity index 96% rename from osu.Game/Screens/Select/Leaderboards/DrawableRank.cs rename to osu.Game/Online/Leaderboards/DrawableRank.cs index 3258a62adf..1c68c64180 100644 --- a/osu.Game/Screens/Select/Leaderboards/DrawableRank.cs +++ b/osu.Game/Online/Leaderboards/DrawableRank.cs @@ -2,14 +2,14 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; -using osu.Framework.Extensions; using osu.Game.Scoring; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Online.Leaderboards { public class DrawableRank : Container { diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs similarity index 76% rename from osu.Game/Screens/Select/Leaderboards/Leaderboard.cs rename to osu.Game/Online/Leaderboards/Leaderboard.cs index a65cc6f096..8e83c8ad5a 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -3,38 +3,30 @@ using System; using System.Collections.Generic; -using osuTK; -using osuTK.Graphics; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Threading; -using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; -using osu.Game.Online.API.Requests; -using System.Linq; -using osu.Framework.Configuration; -using osu.Game.Rulesets; -using osu.Game.Scoring; +using osu.Game.Screens.Select.Leaderboards; +using osuTK; +using osuTK.Graphics; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Online.Leaderboards { - public class Leaderboard : Container + public abstract class Leaderboard : Container { private const double fade_duration = 300; private readonly ScrollContainer scrollContainer; private readonly Container placeholderContainer; - private FillFlowContainer scrollFlow; - - private readonly IBindable ruleset = new Bindable(); - - public Action ScoreSelected; + private FillFlowContainer> scrollFlow; private readonly LoadingAnimation loading; @@ -42,9 +34,9 @@ namespace osu.Game.Screens.Select.Leaderboards private bool scoresLoadedOnce; - private IEnumerable scores; + private IEnumerable scores; - public IEnumerable Scores + public IEnumerable Scores { get { return scores; } set @@ -64,13 +56,13 @@ namespace osu.Game.Screens.Select.Leaderboards // ensure placeholder is hidden when displaying scores PlaceholderState = PlaceholderState.Successful; - var flow = scrollFlow = new FillFlowContainer + var flow = scrollFlow = new FillFlowContainer> { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Spacing = new Vector2(0f, 5f), Padding = new MarginPadding { Top = 10, Bottom = 5 }, - ChildrenEnumerable = scores.Select((s, index) => new LeaderboardScore(s, index + 1) { Action = () => ScoreSelected?.Invoke(s) }) + ChildrenEnumerable = scores.Select((s, index) => CreateScoreVisualiser(s, index + 1)) }; // schedule because we may not be loaded yet (LoadComponentAsync complains). @@ -96,18 +88,18 @@ namespace osu.Game.Screens.Select.Leaderboards } } - private LeaderboardScope scope; + private TScope scope; - public LeaderboardScope Scope + public TScope Scope { get { return scope; } set { - if (value == scope) + if (value.Equals(scope)) return; scope = value; - updateScores(); + UpdateScores(); } } @@ -137,7 +129,7 @@ namespace osu.Game.Screens.Select.Leaderboards case PlaceholderState.NetworkFailure: replacePlaceholder(new RetrievalFailurePlaceholder { - OnRetry = updateScores, + OnRetry = UpdateScores, }); break; case PlaceholderState.Unavailable: @@ -159,7 +151,7 @@ namespace osu.Game.Screens.Select.Leaderboards } } - public Leaderboard() + protected Leaderboard() { Children = new Drawable[] { @@ -177,36 +169,14 @@ namespace osu.Game.Screens.Select.Leaderboards } private APIAccess api; - private BeatmapInfo beatmap; - - [Resolved] - private ScoreManager scoreManager { get; set; } private ScheduledDelegate pendingUpdateScores; - public BeatmapInfo Beatmap - { - get { return beatmap; } - set - { - if (beatmap == value) - return; - - beatmap = value; - Scores = null; - - updateScores(); - } - } - - [BackgroundDependencyLoader(permitNulls: true)] - private void load(APIAccess api, IBindable parentRuleset) + [BackgroundDependencyLoader(true)] + private void load(APIAccess api) { this.api = api; - ruleset.BindTo(parentRuleset); - ruleset.ValueChanged += _ => updateScores(); - if (api != null) api.OnStateChange += handleApiStateChange; } @@ -219,21 +189,17 @@ namespace osu.Game.Screens.Select.Leaderboards api.OnStateChange -= handleApiStateChange; } - public void RefreshScores() => updateScores(); + public void RefreshScores() => UpdateScores(); - private GetScoresRequest getScoresRequest; + private APIRequest getScoresRequest; private void handleApiStateChange(APIState oldState, APIState newState) { - if (Scope == LeaderboardScope.Local) - // No need to respond to API state change while current scope is local - return; - if (newState == APIState.Online) - updateScores(); + UpdateScores(); } - private void updateScores() + protected void UpdateScores() { // don't display any scores or placeholder until the first Scores_Set has been called. // this avoids scope changes flickering a "no scores" placeholder before initialisation of song select is finished. @@ -245,40 +211,23 @@ namespace osu.Game.Screens.Select.Leaderboards pendingUpdateScores?.Cancel(); pendingUpdateScores = Schedule(() => { - if (Scope == LeaderboardScope.Local) - { - Scores = scoreManager.QueryScores(s => s.Beatmap.ID == Beatmap.ID).ToArray(); - PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores; - return; - } - - if (Beatmap?.OnlineBeatmapID == null) - { - PlaceholderState = PlaceholderState.Unavailable; - return; - } - if (api?.IsLoggedIn != true) { PlaceholderState = PlaceholderState.NotLoggedIn; return; } - if (Scope != LeaderboardScope.Global && !api.LocalUser.Value.IsSupporter) - { - PlaceholderState = PlaceholderState.NotSupporter; - return; - } - PlaceholderState = PlaceholderState.Retrieving; loading.Show(); - getScoresRequest = new GetScoresRequest(Beatmap, ruleset.Value ?? Beatmap.Ruleset, Scope); - getScoresRequest.Success += r => Schedule(() => + getScoresRequest = FetchScores(scores => Schedule(() => { - Scores = r.Scores; + Scores = scores; PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores; - }); + })); + + if (getScoresRequest == null) + return; getScoresRequest.Failure += e => Schedule(() => { @@ -292,6 +241,8 @@ namespace osu.Game.Screens.Select.Leaderboards }); } + protected abstract APIRequest FetchScores(Action> scoresCallback); + private Placeholder currentPlaceholder; private void replacePlaceholder(Placeholder placeholder) @@ -344,5 +295,7 @@ namespace osu.Game.Screens.Select.Leaderboards } } } + + protected abstract LeaderboardScore CreateScoreVisualiser(TScoreModel model, int index); } } diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs similarity index 87% rename from osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs rename to osu.Game/Online/Leaderboards/LeaderboardScore.cs index 1ba529c0bf..63352754a8 100644 --- a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -1,9 +1,8 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using System.Linq; -using osuTK; -using osuTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -14,47 +13,60 @@ using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using osu.Game.Scoring; using osu.Game.Users; +using osuTK; +using osuTK.Graphics; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Online.Leaderboards { - public class LeaderboardScore : OsuClickableContainer + public static class LeaderboardScore { - public static readonly float HEIGHT = 60; + public const float HEIGHT = 60; + } + public abstract class LeaderboardScore : OsuClickableContainer + { public readonly int RankPosition; - public readonly ScoreInfo Score; private const float corner_radius = 5; private const float edge_margin = 5; private const float background_alpha = 0.25f; private const float rank_width = 30; + protected Container RankContainer { get; private set; } + + private readonly TScoreModel score; + private Box background; private Container content; private Drawable avatar; - private DrawableRank scoreRank; + private Drawable scoreRank; private OsuSpriteText nameLabel; private GlowingSpriteText scoreLabel; - private ScoreComponentLabel maxCombo; - private ScoreComponentLabel accuracy; private Container flagBadgeContainer; private FillFlowContainer modsContainer; - public LeaderboardScore(ScoreInfo score, int rank) + private List statisticsLabels; + + protected LeaderboardScore(TScoreModel score, int rank) { - Score = score; + this.score = score; RankPosition = rank; RelativeSizeAxes = Axes.X; - Height = HEIGHT; + Height = LeaderboardScore.HEIGHT; } [BackgroundDependencyLoader] private void load() { + var user = GetUser(score); + + statisticsLabels = GetStatistics(score).Select(s => new ScoreComponentLabel(s.icon, s.value, s.name)).ToList(); + Children = new Drawable[] { new Container @@ -102,7 +114,7 @@ namespace osu.Game.Screens.Select.Leaderboards Children = new[] { avatar = new DelayedLoadWrapper( - new Avatar(Score.User) + new Avatar(user) { RelativeSizeAxes = Axes.Both, CornerRadius = corner_radius, @@ -117,18 +129,18 @@ namespace osu.Game.Screens.Select.Leaderboards }) { RelativeSizeAxes = Axes.None, - Size = new Vector2(HEIGHT - edge_margin * 2, HEIGHT - edge_margin * 2), + Size = new Vector2(LeaderboardScore.HEIGHT - edge_margin * 2, LeaderboardScore.HEIGHT - edge_margin * 2), }, new Container { RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, - Position = new Vector2(HEIGHT - edge_margin, 0f), + Position = new Vector2(LeaderboardScore.HEIGHT - edge_margin, 0f), Children = new Drawable[] { nameLabel = new OsuSpriteText { - Text = Score.User.Username, + Text = user.Username, Font = @"Exo2.0-BoldItalic", TextSize = 23, }, @@ -149,7 +161,7 @@ namespace osu.Game.Screens.Select.Leaderboards Masking = true, Children = new Drawable[] { - new DrawableFlag(Score.User?.Country) + new DrawableFlag(user.Country) { Width = 30, RelativeSizeAxes = Axes.Y, @@ -164,11 +176,7 @@ namespace osu.Game.Screens.Select.Leaderboards Direction = FillDirection.Horizontal, Spacing = new Vector2(10f, 0f), Margin = new MarginPadding { Left = edge_margin }, - Children = new Drawable[] - { - maxCombo = new ScoreComponentLabel(FontAwesome.fa_link, Score.MaxCombo.ToString(), "Max Combo"), - accuracy = new ScoreComponentLabel(FontAwesome.fa_crosshairs, string.Format(Score.Accuracy % 1 == 0 ? @"{0:P0}" : @"{0:P2}", Score.Accuracy), "Accuracy"), - }, + Children = statisticsLabels }, }, }, @@ -183,17 +191,17 @@ namespace osu.Game.Screens.Select.Leaderboards Spacing = new Vector2(5f, 0f), Children = new Drawable[] { - scoreLabel = new GlowingSpriteText(Score.TotalScore.ToString(@"N0"), @"Venera", 23, Color4.White, OsuColour.FromHex(@"83ccfa")), - new Container + scoreLabel = new GlowingSpriteText(GetTotalScore(score).ToString(@"N0"), @"Venera", 23, Color4.White, OsuColour.FromHex(@"83ccfa")), + RankContainer = new Container { Size = new Vector2(40f, 20f), Children = new[] { - scoreRank = new DrawableRank(Score.Rank) + scoreRank = new DrawableRank(GetRank(score)) { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(40f), + Size = new Vector2(40f) }, }, }, @@ -205,7 +213,7 @@ namespace osu.Game.Screens.Select.Leaderboards Origin = Anchor.BottomRight, AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, - ChildrenEnumerable = Score.Mods.Select(mod => new ModIcon(mod) { Scale = new Vector2(0.375f) }) + ChildrenEnumerable = GetMods(score).Select(mod => new ModIcon(mod) { Scale = new Vector2(0.375f) }) }, }, }, @@ -216,7 +224,7 @@ namespace osu.Game.Screens.Select.Leaderboards public override void Show() { - foreach (var d in new[] { avatar, nameLabel, scoreLabel, scoreRank, flagBadgeContainer, maxCombo, accuracy, modsContainer }) + foreach (var d in new[] { avatar, nameLabel, scoreLabel, scoreRank, flagBadgeContainer, modsContainer }.Concat(statisticsLabels)) d.FadeOut(); Alpha = 0; @@ -243,7 +251,7 @@ namespace osu.Game.Screens.Select.Leaderboards using (BeginDelayedSequence(50, true)) { - var drawables = new Drawable[] { flagBadgeContainer, maxCombo, accuracy, modsContainer, }; + var drawables = new Drawable[] { flagBadgeContainer, modsContainer }.Concat(statisticsLabels).ToArray(); for (int i = 0; i < drawables.Length; i++) drawables[i].FadeIn(100 + i * 50); } @@ -263,6 +271,16 @@ namespace osu.Game.Screens.Select.Leaderboards base.OnHoverLost(e); } + protected abstract User GetUser(TScoreModel model); + + protected abstract IEnumerable GetMods(TScoreModel model); + + protected abstract IEnumerable<(FontAwesome icon, string value, string name)> GetStatistics(TScoreModel model); + + protected abstract int GetTotalScore(TScoreModel model); + + protected abstract ScoreRank GetRank(TScoreModel model); + private class GlowingSpriteText : Container { public GlowingSpriteText(string text, string font, int textSize, Color4 textColour, Color4 glowColour) @@ -324,8 +342,7 @@ namespace osu.Game.Screens.Select.Leaderboards public ScoreComponentLabel(FontAwesome icon, string value, string name) { this.name = name; - AutoSizeAxes = Axes.Y; - Width = 60; + AutoSizeAxes = Axes.Both; Child = content = new FillFlowContainer { diff --git a/osu.Game/Screens/Select/Leaderboards/MessagePlaceholder.cs b/osu.Game/Online/Leaderboards/MessagePlaceholder.cs similarity index 94% rename from osu.Game/Screens/Select/Leaderboards/MessagePlaceholder.cs rename to osu.Game/Online/Leaderboards/MessagePlaceholder.cs index f01a55b662..ea92836e6e 100644 --- a/osu.Game/Screens/Select/Leaderboards/MessagePlaceholder.cs +++ b/osu.Game/Online/Leaderboards/MessagePlaceholder.cs @@ -4,7 +4,7 @@ using osu.Framework.Graphics; using osu.Game.Graphics; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Online.Leaderboards { public class MessagePlaceholder : Placeholder { diff --git a/osu.Game/Screens/Select/Leaderboards/Placeholder.cs b/osu.Game/Online/Leaderboards/Placeholder.cs similarity index 94% rename from osu.Game/Screens/Select/Leaderboards/Placeholder.cs rename to osu.Game/Online/Leaderboards/Placeholder.cs index 468b43e54f..4994ce0e99 100644 --- a/osu.Game/Screens/Select/Leaderboards/Placeholder.cs +++ b/osu.Game/Online/Leaderboards/Placeholder.cs @@ -5,7 +5,7 @@ using System; using osu.Framework.Graphics; using osu.Game.Graphics.Containers; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Online.Leaderboards { public abstract class Placeholder : OsuTextFlowContainer, IEquatable { diff --git a/osu.Game/Screens/Select/Leaderboards/PlaceholderState.cs b/osu.Game/Online/Leaderboards/PlaceholderState.cs similarity index 88% rename from osu.Game/Screens/Select/Leaderboards/PlaceholderState.cs rename to osu.Game/Online/Leaderboards/PlaceholderState.cs index 33a56540f3..504b03432f 100644 --- a/osu.Game/Screens/Select/Leaderboards/PlaceholderState.cs +++ b/osu.Game/Online/Leaderboards/PlaceholderState.cs @@ -1,7 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Online.Leaderboards { public enum PlaceholderState { diff --git a/osu.Game/Screens/Select/Leaderboards/RetrievalFailurePlaceholder.cs b/osu.Game/Online/Leaderboards/RetrievalFailurePlaceholder.cs similarity index 97% rename from osu.Game/Screens/Select/Leaderboards/RetrievalFailurePlaceholder.cs rename to osu.Game/Online/Leaderboards/RetrievalFailurePlaceholder.cs index 66a7793f7c..7fed40ed1a 100644 --- a/osu.Game/Screens/Select/Leaderboards/RetrievalFailurePlaceholder.cs +++ b/osu.Game/Online/Leaderboards/RetrievalFailurePlaceholder.cs @@ -8,7 +8,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osuTK; -namespace osu.Game.Screens.Select.Leaderboards +namespace osu.Game.Online.Leaderboards { public class RetrievalFailurePlaceholder : Placeholder { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs index f643e130aa..89416c1098 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs @@ -10,11 +10,11 @@ using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Leaderboards; using osu.Game.Overlays.Profile.Sections.Ranks; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Users; namespace osu.Game.Overlays.BeatmapSet.Scores diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs index 643839fa88..6259d85bee 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs @@ -12,12 +12,12 @@ using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Leaderboards; using osu.Game.Overlays.Profile.Sections.Ranks; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Users; namespace osu.Game.Overlays.BeatmapSet.Scores diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs index 1c39cb309c..18aa684664 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs @@ -6,8 +6,8 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Online.Leaderboards; using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Rulesets.UI; using osu.Game.Scoring; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index fefb289d17..8b4fb1a229 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -10,7 +10,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; -using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Online.Leaderboards; namespace osu.Game.Overlays.Profile.Sections.Recent { diff --git a/osu.Game/Screens/Ranking/ResultsPageRanking.cs b/osu.Game/Screens/Ranking/ResultsPageRanking.cs index c5a5cc6ad9..3a75daaf60 100644 --- a/osu.Game/Screens/Ranking/ResultsPageRanking.cs +++ b/osu.Game/Screens/Ranking/ResultsPageRanking.cs @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Ranking Colour = colours.GrayE, RelativeSizeAxes = Axes.Both, }, - new Leaderboard + new BeatmapLeaderboard { Origin = Anchor.Centre, Anchor = Anchor.Centre, diff --git a/osu.Game/Screens/Ranking/ResultsPageScore.cs b/osu.Game/Screens/Ranking/ResultsPageScore.cs index 62103314e1..0774a63e98 100644 --- a/osu.Game/Screens/Ranking/ResultsPageScore.cs +++ b/osu.Game/Screens/Ranking/ResultsPageScore.cs @@ -19,11 +19,11 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play; -using osu.Game.Screens.Select.Leaderboards; using osu.Game.Users; using osu.Framework.Graphics.Shapes; using osu.Framework.Extensions; using osu.Framework.Localisation; +using osu.Game.Online.Leaderboards; using osu.Game.Scoring; namespace osu.Game.Screens.Ranking diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs index a6fbd201d0..c5c4960ed4 100644 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.Select protected override Container Content => content; public readonly BeatmapDetails Details; - public readonly Leaderboard Leaderboard; + public readonly BeatmapLeaderboard Leaderboard; private WorkingBeatmap beatmap; public WorkingBeatmap Beatmap @@ -52,7 +52,7 @@ namespace osu.Game.Screens.Select default: Details.Hide(); - Leaderboard.Scope = (LeaderboardScope)tab - 1; + Leaderboard.Scope = (BeatmapLeaderboardScope)tab - 1; Leaderboard.Show(); break; } @@ -73,7 +73,7 @@ namespace osu.Game.Screens.Select Alpha = 0, Margin = new MarginPadding { Top = details_padding }, }, - Leaderboard = new Leaderboard + Leaderboard = new BeatmapLeaderboard { RelativeSizeAxes = Axes.Both, } diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs new file mode 100644 index 0000000000..b0cfad314c --- /dev/null +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -0,0 +1,87 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Game.Beatmaps; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.Leaderboards; +using osu.Game.Rulesets; +using osu.Game.Scoring; + +namespace osu.Game.Screens.Select.Leaderboards +{ + public class BeatmapLeaderboard : Leaderboard + { + public Action ScoreSelected; + + private BeatmapInfo beatmap; + + public BeatmapInfo Beatmap + { + get { return beatmap; } + set + { + if (beatmap == value) + return; + + beatmap = value; + Scores = null; + + UpdateScores(); + } + } + + [Resolved] + private ScoreManager scoreManager { get; set; } + + [Resolved] + private IBindable ruleset { get; set; } + + [Resolved] + private APIAccess api { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + ruleset.ValueChanged += _ => UpdateScores(); + } + + protected override APIRequest FetchScores(Action> scoresCallback) + { + if (Scope == BeatmapLeaderboardScope.Local) + { + Scores = scoreManager.QueryScores(s => s.Beatmap.ID == Beatmap.ID).ToArray(); + PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores; + return null; + } + + if (Beatmap?.OnlineBeatmapID == null) + { + PlaceholderState = PlaceholderState.Unavailable; + return null; + } + + if (Scope != BeatmapLeaderboardScope.Global && !api.LocalUser.Value.IsSupporter) + { + PlaceholderState = PlaceholderState.NotSupporter; + return null; + } + + var req = new GetScoresRequest(Beatmap, ruleset.Value ?? Beatmap.Ruleset, Scope); + + req.Success += r => scoresCallback?.Invoke(r.Scores); + + return req; + } + + protected override LeaderboardScore CreateScoreVisualiser(ScoreInfo model, int index) => new BeatmapLeaderboardScore(model, index) + { + Action = () => ScoreSelected?.Invoke(model) + }; + } +} diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScope.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs similarity index 87% rename from osu.Game/Screens/Select/Leaderboards/LeaderboardScope.cs rename to osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs index 761f53a5e8..39d9580792 100644 --- a/osu.Game/Screens/Select/Leaderboards/LeaderboardScope.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs @@ -3,7 +3,7 @@ namespace osu.Game.Screens.Select.Leaderboards { - public enum LeaderboardScope + public enum BeatmapLeaderboardScope { Local, Country, diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScore.cs new file mode 100644 index 0000000000..098fff4052 --- /dev/null +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScore.cs @@ -0,0 +1,34 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using osu.Game.Graphics; +using osu.Game.Online.Leaderboards; +using osu.Game.Rulesets.Mods; +using osu.Game.Scoring; +using osu.Game.Users; + +namespace osu.Game.Screens.Select.Leaderboards +{ + public class BeatmapLeaderboardScore : LeaderboardScore + { + public BeatmapLeaderboardScore(ScoreInfo score, int rank) + : base(score, rank) + { + } + + protected override User GetUser(ScoreInfo model) => model.User; + + protected override IEnumerable GetMods(ScoreInfo model) => model.Mods; + + protected override IEnumerable<(FontAwesome icon, string value, string name)> GetStatistics(ScoreInfo model) => new[] + { + (FontAwesome.fa_link, model.MaxCombo.ToString(), "Max Combo"), + (FontAwesome.fa_crosshairs, string.Format(model.Accuracy % 1 == 0 ? @"{0:P0}" : @"{0:P2}", model.Accuracy), "Accuracy") + }; + + protected override int GetTotalScore(ScoreInfo model) => model.TotalScore; + + protected override ScoreRank GetRank(ScoreInfo model) => model.Rank; + } +} From 23259b295cb5044be6923961d2e024d5b98fc895 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Dec 2018 14:45:35 +0900 Subject: [PATCH 28/38] Remove unnecessary using --- osu.Game/Online/Leaderboards/Leaderboard.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 8e83c8ad5a..83cc289bc1 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -13,7 +13,6 @@ using osu.Framework.Threading; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; -using osu.Game.Screens.Select.Leaderboards; using osuTK; using osuTK.Graphics; From 787e65c3c58bc8788c373de8e5ca5a4cd6007993 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Dec 2018 15:20:35 +0900 Subject: [PATCH 29/38] Reduce generic-ness --- osu.Game/Online/Leaderboards/Leaderboard.cs | 16 ++--- .../Online/Leaderboards/LeaderboardScore.cs | 68 ++++++++++--------- .../Select/Leaderboards/BeatmapLeaderboard.cs | 2 +- .../Leaderboards/BeatmapLeaderboardScore.cs | 34 ---------- 4 files changed, 46 insertions(+), 74 deletions(-) delete mode 100644 osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScore.cs diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 83cc289bc1..d9d78245bb 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -18,14 +18,14 @@ using osuTK.Graphics; namespace osu.Game.Online.Leaderboards { - public abstract class Leaderboard : Container + public abstract class Leaderboard : Container { private const double fade_duration = 300; private readonly ScrollContainer scrollContainer; private readonly Container placeholderContainer; - private FillFlowContainer> scrollFlow; + private FillFlowContainer scrollFlow; private readonly LoadingAnimation loading; @@ -33,9 +33,9 @@ namespace osu.Game.Online.Leaderboards private bool scoresLoadedOnce; - private IEnumerable scores; + private IEnumerable scores; - public IEnumerable Scores + public IEnumerable Scores { get { return scores; } set @@ -55,13 +55,13 @@ namespace osu.Game.Online.Leaderboards // ensure placeholder is hidden when displaying scores PlaceholderState = PlaceholderState.Successful; - var flow = scrollFlow = new FillFlowContainer> + var flow = scrollFlow = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Spacing = new Vector2(0f, 5f), Padding = new MarginPadding { Top = 10, Bottom = 5 }, - ChildrenEnumerable = scores.Select((s, index) => CreateScoreVisualiser(s, index + 1)) + ChildrenEnumerable = scores.Select((s, index) => CreateDrawableScore(s, index + 1)) }; // schedule because we may not be loaded yet (LoadComponentAsync complains). @@ -240,7 +240,7 @@ namespace osu.Game.Online.Leaderboards }); } - protected abstract APIRequest FetchScores(Action> scoresCallback); + protected abstract APIRequest FetchScores(Action> scoresCallback); private Placeholder currentPlaceholder; @@ -295,6 +295,6 @@ namespace osu.Game.Online.Leaderboards } } - protected abstract LeaderboardScore CreateScoreVisualiser(TScoreModel model, int index); + protected abstract LeaderboardScore CreateDrawableScore(ScoreInfo model, int index); } } diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index 63352754a8..8269e02847 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -13,7 +13,6 @@ using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using osu.Game.Scoring; using osu.Game.Users; @@ -22,15 +21,12 @@ using osuTK.Graphics; namespace osu.Game.Online.Leaderboards { - public static class LeaderboardScore - { - public const float HEIGHT = 60; - } - - public abstract class LeaderboardScore : OsuClickableContainer + public class LeaderboardScore : OsuClickableContainer { public readonly int RankPosition; + public const float HEIGHT = 60; + private const float corner_radius = 5; private const float edge_margin = 5; private const float background_alpha = 0.25f; @@ -38,7 +34,7 @@ namespace osu.Game.Online.Leaderboards protected Container RankContainer { get; private set; } - private readonly TScoreModel score; + private readonly ScoreInfo score; private Box background; private Container content; @@ -51,21 +47,27 @@ namespace osu.Game.Online.Leaderboards private List statisticsLabels; - protected LeaderboardScore(TScoreModel score, int rank) + public LeaderboardScore(ScoreInfo score, int rank) { this.score = score; RankPosition = rank; RelativeSizeAxes = Axes.X; - Height = LeaderboardScore.HEIGHT; + Height = HEIGHT; } + protected virtual IEnumerable GetStatistics(ScoreInfo model) => new[] + { + new LeaderboardScoreStatistic(FontAwesome.fa_link, "Max Combo", model.MaxCombo.ToString()), + new LeaderboardScoreStatistic(FontAwesome.fa_crosshairs, "Accuracy", string.Format(model.Accuracy % 1 == 0 ? @"{0:P0}" : @"{0:P2}", model.Accuracy)) + }; + [BackgroundDependencyLoader] private void load() { - var user = GetUser(score); + var user = score.User; - statisticsLabels = GetStatistics(score).Select(s => new ScoreComponentLabel(s.icon, s.value, s.name)).ToList(); + statisticsLabels = GetStatistics(score).Select(s => new ScoreComponentLabel(s)).ToList(); Children = new Drawable[] { @@ -129,13 +131,13 @@ namespace osu.Game.Online.Leaderboards }) { RelativeSizeAxes = Axes.None, - Size = new Vector2(LeaderboardScore.HEIGHT - edge_margin * 2, LeaderboardScore.HEIGHT - edge_margin * 2), + Size = new Vector2(HEIGHT - edge_margin * 2, HEIGHT - edge_margin * 2), }, new Container { RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, - Position = new Vector2(LeaderboardScore.HEIGHT - edge_margin, 0f), + Position = new Vector2(HEIGHT - edge_margin, 0f), Children = new Drawable[] { nameLabel = new OsuSpriteText @@ -191,13 +193,13 @@ namespace osu.Game.Online.Leaderboards Spacing = new Vector2(5f, 0f), Children = new Drawable[] { - scoreLabel = new GlowingSpriteText(GetTotalScore(score).ToString(@"N0"), @"Venera", 23, Color4.White, OsuColour.FromHex(@"83ccfa")), + scoreLabel = new GlowingSpriteText(score.TotalScore.ToString(@"N0"), @"Venera", 23, Color4.White, OsuColour.FromHex(@"83ccfa")), RankContainer = new Container { Size = new Vector2(40f, 20f), Children = new[] { - scoreRank = new DrawableRank(GetRank(score)) + scoreRank = new DrawableRank(score.Rank) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -213,7 +215,7 @@ namespace osu.Game.Online.Leaderboards Origin = Anchor.BottomRight, AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, - ChildrenEnumerable = GetMods(score).Select(mod => new ModIcon(mod) { Scale = new Vector2(0.375f) }) + ChildrenEnumerable = score.Mods.Select(mod => new ModIcon(mod) { Scale = new Vector2(0.375f) }) }, }, }, @@ -271,16 +273,6 @@ namespace osu.Game.Online.Leaderboards base.OnHoverLost(e); } - protected abstract User GetUser(TScoreModel model); - - protected abstract IEnumerable GetMods(TScoreModel model); - - protected abstract IEnumerable<(FontAwesome icon, string value, string name)> GetStatistics(TScoreModel model); - - protected abstract int GetTotalScore(TScoreModel model); - - protected abstract ScoreRank GetRank(TScoreModel model); - private class GlowingSpriteText : Container { public GlowingSpriteText(string text, string font, int textSize, Color4 textColour, Color4 glowColour) @@ -339,9 +331,9 @@ namespace osu.Game.Online.Leaderboards public string TooltipText => name; - public ScoreComponentLabel(FontAwesome icon, string value, string name) + public ScoreComponentLabel(LeaderboardScoreStatistic statistic) { - this.name = name; + name = statistic.Name; AutoSizeAxes = Axes.Both; Child = content = new FillFlowContainer @@ -373,11 +365,11 @@ namespace osu.Game.Online.Leaderboards Origin = Anchor.Centre, Size = new Vector2(icon_size - 6), Colour = OsuColour.FromHex(@"a4edff"), - Icon = icon, + Icon = statistic.Icon, }, }, }, - new GlowingSpriteText(value, @"Exo2.0-Bold", 17, Color4.White, OsuColour.FromHex(@"83ccfa")) + new GlowingSpriteText(statistic.Value, @"Exo2.0-Bold", 17, Color4.White, OsuColour.FromHex(@"83ccfa")) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, @@ -386,5 +378,19 @@ namespace osu.Game.Online.Leaderboards }; } } + + public class LeaderboardScoreStatistic + { + public FontAwesome Icon; + public string Value; + public string Name; + + public LeaderboardScoreStatistic(FontAwesome icon, string name, string value) + { + Icon = icon; + Name = name; + Value = value; + } + } } } diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index b0cfad314c..9f8726c86a 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -79,7 +79,7 @@ namespace osu.Game.Screens.Select.Leaderboards return req; } - protected override LeaderboardScore CreateScoreVisualiser(ScoreInfo model, int index) => new BeatmapLeaderboardScore(model, index) + protected override LeaderboardScore CreateDrawableScore(ScoreInfo model, int index) => new LeaderboardScore(model, index) { Action = () => ScoreSelected?.Invoke(model) }; diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScore.cs deleted file mode 100644 index 098fff4052..0000000000 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScore.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.Collections.Generic; -using osu.Game.Graphics; -using osu.Game.Online.Leaderboards; -using osu.Game.Rulesets.Mods; -using osu.Game.Scoring; -using osu.Game.Users; - -namespace osu.Game.Screens.Select.Leaderboards -{ - public class BeatmapLeaderboardScore : LeaderboardScore - { - public BeatmapLeaderboardScore(ScoreInfo score, int rank) - : base(score, rank) - { - } - - protected override User GetUser(ScoreInfo model) => model.User; - - protected override IEnumerable GetMods(ScoreInfo model) => model.Mods; - - protected override IEnumerable<(FontAwesome icon, string value, string name)> GetStatistics(ScoreInfo model) => new[] - { - (FontAwesome.fa_link, model.MaxCombo.ToString(), "Max Combo"), - (FontAwesome.fa_crosshairs, string.Format(model.Accuracy % 1 == 0 ? @"{0:P0}" : @"{0:P2}", model.Accuracy), "Accuracy") - }; - - protected override int GetTotalScore(ScoreInfo model) => model.TotalScore; - - protected override ScoreRank GetRank(ScoreInfo model) => model.Rank; - } -} From 52c6d5bfd418dbc3f6ab1e203f98b9b04d2edeb4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Dec 2018 15:23:32 +0900 Subject: [PATCH 30/38] Move protected method down --- osu.Game/Online/Leaderboards/LeaderboardScore.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index 8269e02847..0c64105d5c 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -56,12 +56,6 @@ namespace osu.Game.Online.Leaderboards Height = HEIGHT; } - protected virtual IEnumerable GetStatistics(ScoreInfo model) => new[] - { - new LeaderboardScoreStatistic(FontAwesome.fa_link, "Max Combo", model.MaxCombo.ToString()), - new LeaderboardScoreStatistic(FontAwesome.fa_crosshairs, "Accuracy", string.Format(model.Accuracy % 1 == 0 ? @"{0:P0}" : @"{0:P2}", model.Accuracy)) - }; - [BackgroundDependencyLoader] private void load() { @@ -261,6 +255,12 @@ namespace osu.Game.Online.Leaderboards } } + protected virtual IEnumerable GetStatistics(ScoreInfo model) => new[] + { + new LeaderboardScoreStatistic(FontAwesome.fa_link, "Max Combo", model.MaxCombo.ToString()), + new LeaderboardScoreStatistic(FontAwesome.fa_crosshairs, "Accuracy", string.Format(model.Accuracy % 1 == 0 ? @"{0:P0}" : @"{0:P2}", model.Accuracy)) + }; + protected override bool OnHover(HoverEvent e) { background.FadeTo(0.5f, 300, Easing.OutQuint); From daa6292e087366f2cdde87c804e641dad09fb6f3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 21 Dec 2018 16:28:33 +0900 Subject: [PATCH 31/38] Split results screen to allow for extensibility --- osu.Game.Tests/Visual/TestCaseResults.cs | 8 ++-- osu.Game/Screens/Play/Player.cs | 3 +- osu.Game/Screens/Play/SoloResults.cs | 24 +++++++++++ .../RankingResultsPage.cs} | 11 ++--- .../Ranking/{ => Pages}/ResultsPage.cs | 2 +- .../ScoreResultsPage.cs} | 23 +++++----- osu.Game/Screens/Ranking/ResultMode.cs | 12 ------ osu.Game/Screens/Ranking/ResultModeButton.cs | 19 +++----- .../Screens/Ranking/ResultModeTabControl.cs | 7 +-- osu.Game/Screens/Ranking/Results.cs | 43 ++++++++----------- osu.Game/Screens/Ranking/Types/IResultType.cs | 15 +++++++ .../Ranking/Types/RankingResultType.cs | 26 +++++++++++ .../Screens/Ranking/Types/ScoreResultType.cs | 26 +++++++++++ osu.Game/Screens/Select/SongSelect.cs | 4 +- 14 files changed, 147 insertions(+), 76 deletions(-) create mode 100644 osu.Game/Screens/Play/SoloResults.cs rename osu.Game/Screens/Ranking/{ResultsPageRanking.cs => Pages/RankingResultsPage.cs} (83%) rename osu.Game/Screens/Ranking/{ => Pages}/ResultsPage.cs (98%) rename osu.Game/Screens/Ranking/{ResultsPageScore.cs => Pages/ScoreResultsPage.cs} (98%) delete mode 100644 osu.Game/Screens/Ranking/ResultMode.cs create mode 100644 osu.Game/Screens/Ranking/Types/IResultType.cs create mode 100644 osu.Game/Screens/Ranking/Types/RankingResultType.cs create mode 100644 osu.Game/Screens/Ranking/Types/ScoreResultType.cs diff --git a/osu.Game.Tests/Visual/TestCaseResults.cs b/osu.Game.Tests/Visual/TestCaseResults.cs index 6a20a808b6..a954c6c57c 100644 --- a/osu.Game.Tests/Visual/TestCaseResults.cs +++ b/osu.Game.Tests/Visual/TestCaseResults.cs @@ -8,7 +8,9 @@ using osu.Framework.Allocation; using osu.Game.Beatmaps; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; +using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; +using osu.Game.Screens.Ranking.Pages; using osu.Game.Users; namespace osu.Game.Tests.Visual @@ -23,8 +25,8 @@ namespace osu.Game.Tests.Visual typeof(ScoreInfo), typeof(Results), typeof(ResultsPage), - typeof(ResultsPageScore), - typeof(ResultsPageRanking) + typeof(ScoreResultsPage), + typeof(RankingResultsPage) }; [BackgroundDependencyLoader] @@ -41,7 +43,7 @@ namespace osu.Game.Tests.Visual if (beatmapInfo != null) Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo); - Add(new Results(new ScoreInfo + Add(new SoloResults(new ScoreInfo { TotalScore = 2845370, Accuracy = 0.98, diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 19b49b099c..1429675ddd 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -28,7 +28,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; -using osu.Game.Screens.Ranking; using osu.Game.Skinning; using osu.Game.Storyboards.Drawables; @@ -288,7 +287,7 @@ namespace osu.Game.Screens.Play if (RulesetContainer.Replay == null) scoreManager.Import(score, true); - Push(new Results(score)); + Push(new SoloResults(score)); onCompletionEvent = null; }); diff --git a/osu.Game/Screens/Play/SoloResults.cs b/osu.Game/Screens/Play/SoloResults.cs new file mode 100644 index 0000000000..717efd118e --- /dev/null +++ b/osu.Game/Screens/Play/SoloResults.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using osu.Game.Scoring; +using osu.Game.Screens.Ranking; +using osu.Game.Screens.Ranking.Types; + +namespace osu.Game.Screens.Play +{ + public class SoloResults : Results + { + public SoloResults(ScoreInfo score) + : base(score) + { + } + + protected override IEnumerable CreateResultTypes() => new IResultType[] + { + new ScoreResultType(Score, Beatmap), + new RankingResultType(Score, Beatmap) + }; + } +} diff --git a/osu.Game/Screens/Ranking/ResultsPageRanking.cs b/osu.Game/Screens/Ranking/Pages/RankingResultsPage.cs similarity index 83% rename from osu.Game/Screens/Ranking/ResultsPageRanking.cs rename to osu.Game/Screens/Ranking/Pages/RankingResultsPage.cs index 3a75daaf60..4c98e476c4 100644 --- a/osu.Game/Screens/Ranking/ResultsPageRanking.cs +++ b/osu.Game/Screens/Ranking/Pages/RankingResultsPage.cs @@ -3,18 +3,19 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Scoring; using osu.Game.Screens.Select.Leaderboards; using osuTK; -using osu.Framework.Graphics.Shapes; -using osu.Game.Scoring; -namespace osu.Game.Screens.Ranking +namespace osu.Game.Screens.Ranking.Pages { - public class ResultsPageRanking : ResultsPage + public class RankingResultsPage : ResultsPage { - public ResultsPageRanking(ScoreInfo score, WorkingBeatmap beatmap = null) : base(score, beatmap) + public RankingResultsPage(ScoreInfo score, WorkingBeatmap beatmap = null) + : base(score, beatmap) { } diff --git a/osu.Game/Screens/Ranking/ResultsPage.cs b/osu.Game/Screens/Ranking/Pages/ResultsPage.cs similarity index 98% rename from osu.Game/Screens/Ranking/ResultsPage.cs rename to osu.Game/Screens/Ranking/Pages/ResultsPage.cs index 5f68623e54..2e379d0a76 100644 --- a/osu.Game/Screens/Ranking/ResultsPage.cs +++ b/osu.Game/Screens/Ranking/Pages/ResultsPage.cs @@ -12,7 +12,7 @@ using osu.Game.Scoring; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.Ranking +namespace osu.Game.Screens.Ranking.Pages { public class ResultsPage : Container { diff --git a/osu.Game/Screens/Ranking/ResultsPageScore.cs b/osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs similarity index 98% rename from osu.Game/Screens/Ranking/ResultsPageScore.cs rename to osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs index 0774a63e98..8f5b21a7cb 100644 --- a/osu.Game/Screens/Ranking/ResultsPageScore.cs +++ b/osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs @@ -4,36 +4,39 @@ using System; using System.Collections.Generic; using System.Linq; -using osuTK; -using osuTK.Graphics; using osu.Framework.Allocation; +using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Leaderboards; using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Users; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Extensions; -using osu.Framework.Localisation; -using osu.Game.Online.Leaderboards; -using osu.Game.Scoring; +using osuTK; +using osuTK.Graphics; -namespace osu.Game.Screens.Ranking +namespace osu.Game.Screens.Ranking.Pages { - public class ResultsPageScore : ResultsPage + public class ScoreResultsPage : ResultsPage { private Container scoreContainer; private ScoreCounter scoreCounter; - public ResultsPageScore(ScoreInfo score, WorkingBeatmap beatmap) : base(score, beatmap) { } + public ScoreResultsPage(ScoreInfo score, WorkingBeatmap beatmap) + : base(score, beatmap) + { + } private FillFlowContainer statisticsContainer; diff --git a/osu.Game/Screens/Ranking/ResultMode.cs b/osu.Game/Screens/Ranking/ResultMode.cs deleted file mode 100644 index 4742864b83..0000000000 --- a/osu.Game/Screens/Ranking/ResultMode.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -namespace osu.Game.Screens.Ranking -{ - public enum ResultMode - { - Summary, - Ranking, - Share - } -} diff --git a/osu.Game/Screens/Ranking/ResultModeButton.cs b/osu.Game/Screens/Ranking/ResultModeButton.cs index 5df3ff3afb..da0eb3dfcc 100644 --- a/osu.Game/Screens/Ranking/ResultModeButton.cs +++ b/osu.Game/Screens/Ranking/ResultModeButton.cs @@ -10,30 +10,21 @@ using osu.Game.Graphics; using osuTK; using osuTK.Graphics; using osu.Framework.Graphics.Shapes; +using osu.Game.Screens.Ranking.Types; namespace osu.Game.Screens.Ranking { - public class ResultModeButton : TabItem + public class ResultModeButton : TabItem { private readonly FontAwesome icon; private Color4 activeColour; private Color4 inactiveColour; private CircularContainer colouredPart; - public ResultModeButton(ResultMode mode) : base(mode) + public ResultModeButton(IResultType mode) + : base(mode) { - switch (mode) - { - case ResultMode.Summary: - icon = FontAwesome.fa_asterisk; - break; - case ResultMode.Ranking: - icon = FontAwesome.fa_list; - break; - case ResultMode.Share: - icon = FontAwesome.fa_camera; - break; - } + icon = mode.Icon; } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/Ranking/ResultModeTabControl.cs b/osu.Game/Screens/Ranking/ResultModeTabControl.cs index e5c6115085..cc1f7bc6b2 100644 --- a/osu.Game/Screens/Ranking/ResultModeTabControl.cs +++ b/osu.Game/Screens/Ranking/ResultModeTabControl.cs @@ -3,11 +3,12 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; +using osu.Game.Screens.Ranking.Types; using osuTK; namespace osu.Game.Screens.Ranking { - public class ResultModeTabControl : TabControl + public class ResultModeTabControl : TabControl { public ResultModeTabControl() { @@ -19,9 +20,9 @@ namespace osu.Game.Screens.Ranking TabContainer.Padding = new MarginPadding(5); } - protected override Dropdown CreateDropdown() => null; + protected override Dropdown CreateDropdown() => null; - protected override TabItem CreateTabItem(ResultMode value) => new ResultModeButton(value) + protected override TabItem CreateTabItem(IResultType value) => new ResultModeButton(value) { Anchor = TabContainer.Anchor, Origin = TabContainer.Origin diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 1ff5fc7bfd..e7340b2c33 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.IEnumerableExtensions; @@ -18,12 +19,12 @@ using osu.Game.Graphics.UserInterface; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Sprites; using osu.Game.Scoring; +using osu.Game.Screens.Ranking.Types; namespace osu.Game.Screens.Ranking { - public class Results : OsuScreen + public abstract class Results : OsuScreen { - private readonly ScoreInfo score; private Container circleOuterBackground; private Container circleOuter; private Container circleInner; @@ -34,6 +35,8 @@ namespace osu.Game.Screens.Ranking public override bool AllowBeatmapRulesetChange => false; + protected readonly ScoreInfo Score; + private Container currentPage; private static readonly Vector2 background_blur = new Vector2(20); @@ -44,9 +47,9 @@ namespace osu.Game.Screens.Ranking private const float circle_outer_scale = 0.96f; - public Results(ScoreInfo score) + protected Results(ScoreInfo score) { - this.score = score; + Score = score; } private const float transition_time = 800; @@ -67,7 +70,7 @@ namespace osu.Game.Screens.Ranking backgroundParallax.FadeOut(); modeChangeButtons.FadeOut(); - currentPage.FadeOut(); + currentPage?.FadeOut(); circleOuterBackground .FadeIn(transition_time, Easing.OutQuint) @@ -90,7 +93,7 @@ namespace osu.Game.Screens.Ranking using (BeginDelayedSequence(transition_time * 0.4f, true)) { modeChangeButtons.FadeIn(transition_time, Easing.OutQuint); - currentPage.FadeIn(transition_time, Easing.OutQuint); + currentPage?.FadeIn(transition_time, Easing.OutQuint); } } } @@ -188,7 +191,7 @@ namespace osu.Game.Screens.Ranking }, new OsuSpriteText { - Text = $"{score.MaxCombo}x", + Text = $"{Score.MaxCombo}x", TextSize = 40, RelativePositionAxes = Axes.X, Font = @"Exo2.0-Bold", @@ -209,7 +212,7 @@ namespace osu.Game.Screens.Ranking }, new OsuSpriteText { - Text = $"{score.Accuracy:P2}", + Text = $"{Score.Accuracy:P2}", TextSize = 40, RelativePositionAxes = Axes.X, Font = @"Exo2.0-Bold", @@ -262,30 +265,22 @@ namespace osu.Game.Screens.Ranking }, }; - modeChangeButtons.AddItem(ResultMode.Summary); - modeChangeButtons.AddItem(ResultMode.Ranking); - //modeChangeButtons.AddItem(ResultMode.Share); + foreach (var t in CreateResultTypes()) + modeChangeButtons.AddItem(t); + modeChangeButtons.Current.Value = modeChangeButtons.Items.FirstOrDefault(); - modeChangeButtons.Current.ValueChanged += mode => + modeChangeButtons.Current.BindValueChanged(m => { currentPage?.FadeOut(); currentPage?.Expire(); - switch (mode) - { - case ResultMode.Summary: - currentPage = new ResultsPageScore(score, Beatmap.Value); - break; - case ResultMode.Ranking: - currentPage = new ResultsPageRanking(score, Beatmap.Value); - break; - } + currentPage = m?.CreatePage(); if (currentPage != null) circleInner.Add(currentPage); - }; - - modeChangeButtons.Current.TriggerChange(); + }, true); } + + protected abstract IEnumerable CreateResultTypes(); } } diff --git a/osu.Game/Screens/Ranking/Types/IResultType.cs b/osu.Game/Screens/Ranking/Types/IResultType.cs new file mode 100644 index 0000000000..df574e99f1 --- /dev/null +++ b/osu.Game/Screens/Ranking/Types/IResultType.cs @@ -0,0 +1,15 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Graphics; +using osu.Game.Screens.Ranking.Pages; + +namespace osu.Game.Screens.Ranking.Types +{ + public interface IResultType + { + FontAwesome Icon { get; } + + ResultsPage CreatePage(); + } +} diff --git a/osu.Game/Screens/Ranking/Types/RankingResultType.cs b/osu.Game/Screens/Ranking/Types/RankingResultType.cs new file mode 100644 index 0000000000..a11732d324 --- /dev/null +++ b/osu.Game/Screens/Ranking/Types/RankingResultType.cs @@ -0,0 +1,26 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Scoring; +using osu.Game.Screens.Ranking.Pages; + +namespace osu.Game.Screens.Ranking.Types +{ + public class RankingResultType : IResultType + { + private readonly ScoreInfo score; + private readonly WorkingBeatmap beatmap; + + public RankingResultType(ScoreInfo score, WorkingBeatmap beatmap) + { + this.score = score; + this.beatmap = beatmap; + } + + public FontAwesome Icon => FontAwesome.fa_list; + + public ResultsPage CreatePage() => new RankingResultsPage(score, beatmap); + } +} diff --git a/osu.Game/Screens/Ranking/Types/ScoreResultType.cs b/osu.Game/Screens/Ranking/Types/ScoreResultType.cs new file mode 100644 index 0000000000..0841365528 --- /dev/null +++ b/osu.Game/Screens/Ranking/Types/ScoreResultType.cs @@ -0,0 +1,26 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Scoring; +using osu.Game.Screens.Ranking.Pages; + +namespace osu.Game.Screens.Ranking.Types +{ + public class ScoreResultType : IResultType + { + private readonly ScoreInfo score; + private readonly WorkingBeatmap beatmap; + + public ScoreResultType(ScoreInfo score, WorkingBeatmap beatmap) + { + this.score = score; + this.beatmap = beatmap; + } + + public FontAwesome Icon => FontAwesome.fa_asterisk; + + public ResultsPage CreatePage() => new ScoreResultsPage(score, beatmap); + } +} diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 71b63c8e5b..f65cc0e49d 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -28,7 +28,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; using osu.Game.Screens.Menu; -using osu.Game.Screens.Ranking; +using osu.Game.Screens.Play; using osu.Game.Screens.Select.Options; using osu.Game.Skinning; @@ -210,7 +210,7 @@ namespace osu.Game.Screens.Select }); } - BeatmapDetails.Leaderboard.ScoreSelected += s => Push(new Results(s)); + BeatmapDetails.Leaderboard.ScoreSelected += s => Push(new SoloResults(s)); } [BackgroundDependencyLoader(true)] From e404a0bc201d4a6e93b8ae47566998e78f5744f0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Dec 2018 15:51:00 +0900 Subject: [PATCH 32/38] Clean-ups and renames --- osu.Game/Screens/Play/SoloResults.cs | 6 +++--- osu.Game/Screens/Ranking/{Types => }/IResultType.cs | 7 ++++--- osu.Game/Screens/Ranking/ResultModeButton.cs | 5 ++--- osu.Game/Screens/Ranking/ResultModeTabControl.cs | 7 +++---- osu.Game/Screens/Ranking/Results.cs | 3 +-- osu.Game/Screens/Ranking/{Pages => }/ResultsPage.cs | 6 +++--- ...{RankingResultType.cs => BeatmapLeaderboardPageInfo.cs} | 6 ++++-- .../Types/{ScoreResultType.cs => ScoreOverviewPageInfo.cs} | 6 ++++-- 8 files changed, 24 insertions(+), 22 deletions(-) rename osu.Game/Screens/Ranking/{Types => }/IResultType.cs (70%) rename osu.Game/Screens/Ranking/{Pages => }/ResultsPage.cs (94%) rename osu.Game/Screens/Ranking/Types/{RankingResultType.cs => BeatmapLeaderboardPageInfo.cs} (76%) rename osu.Game/Screens/Ranking/Types/{ScoreResultType.cs => ScoreOverviewPageInfo.cs} (77%) diff --git a/osu.Game/Screens/Play/SoloResults.cs b/osu.Game/Screens/Play/SoloResults.cs index 717efd118e..2828c758e0 100644 --- a/osu.Game/Screens/Play/SoloResults.cs +++ b/osu.Game/Screens/Play/SoloResults.cs @@ -15,10 +15,10 @@ namespace osu.Game.Screens.Play { } - protected override IEnumerable CreateResultTypes() => new IResultType[] + protected override IEnumerable CreateResultTypes() => new IResultPageInfo[] { - new ScoreResultType(Score, Beatmap), - new RankingResultType(Score, Beatmap) + new ScoreOverviewPageInfo(Score, Beatmap), + new BeatmapLeaderboardPageInfo(Score, Beatmap) }; } } diff --git a/osu.Game/Screens/Ranking/Types/IResultType.cs b/osu.Game/Screens/Ranking/IResultType.cs similarity index 70% rename from osu.Game/Screens/Ranking/Types/IResultType.cs rename to osu.Game/Screens/Ranking/IResultType.cs index df574e99f1..5c6d08d883 100644 --- a/osu.Game/Screens/Ranking/Types/IResultType.cs +++ b/osu.Game/Screens/Ranking/IResultType.cs @@ -2,14 +2,15 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Game.Graphics; -using osu.Game.Screens.Ranking.Pages; -namespace osu.Game.Screens.Ranking.Types +namespace osu.Game.Screens.Ranking { - public interface IResultType + public interface IResultPageInfo { FontAwesome Icon { get; } + string Name { get; } + ResultsPage CreatePage(); } } diff --git a/osu.Game/Screens/Ranking/ResultModeButton.cs b/osu.Game/Screens/Ranking/ResultModeButton.cs index da0eb3dfcc..34a93236bd 100644 --- a/osu.Game/Screens/Ranking/ResultModeButton.cs +++ b/osu.Game/Screens/Ranking/ResultModeButton.cs @@ -10,18 +10,17 @@ using osu.Game.Graphics; using osuTK; using osuTK.Graphics; using osu.Framework.Graphics.Shapes; -using osu.Game.Screens.Ranking.Types; namespace osu.Game.Screens.Ranking { - public class ResultModeButton : TabItem + public class ResultModeButton : TabItem { private readonly FontAwesome icon; private Color4 activeColour; private Color4 inactiveColour; private CircularContainer colouredPart; - public ResultModeButton(IResultType mode) + public ResultModeButton(IResultPageInfo mode) : base(mode) { icon = mode.Icon; diff --git a/osu.Game/Screens/Ranking/ResultModeTabControl.cs b/osu.Game/Screens/Ranking/ResultModeTabControl.cs index cc1f7bc6b2..e87749d8dd 100644 --- a/osu.Game/Screens/Ranking/ResultModeTabControl.cs +++ b/osu.Game/Screens/Ranking/ResultModeTabControl.cs @@ -3,12 +3,11 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; -using osu.Game.Screens.Ranking.Types; using osuTK; namespace osu.Game.Screens.Ranking { - public class ResultModeTabControl : TabControl + public class ResultModeTabControl : TabControl { public ResultModeTabControl() { @@ -20,9 +19,9 @@ namespace osu.Game.Screens.Ranking TabContainer.Padding = new MarginPadding(5); } - protected override Dropdown CreateDropdown() => null; + protected override Dropdown CreateDropdown() => null; - protected override TabItem CreateTabItem(IResultType value) => new ResultModeButton(value) + protected override TabItem CreateTabItem(IResultPageInfo value) => new ResultModeButton(value) { Anchor = TabContainer.Anchor, Origin = TabContainer.Origin diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index e7340b2c33..86067d8cc5 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -19,7 +19,6 @@ using osu.Game.Graphics.UserInterface; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Sprites; using osu.Game.Scoring; -using osu.Game.Screens.Ranking.Types; namespace osu.Game.Screens.Ranking { @@ -281,6 +280,6 @@ namespace osu.Game.Screens.Ranking }, true); } - protected abstract IEnumerable CreateResultTypes(); + protected abstract IEnumerable CreateResultTypes(); } } diff --git a/osu.Game/Screens/Ranking/Pages/ResultsPage.cs b/osu.Game/Screens/Ranking/ResultsPage.cs similarity index 94% rename from osu.Game/Screens/Ranking/Pages/ResultsPage.cs rename to osu.Game/Screens/Ranking/ResultsPage.cs index 2e379d0a76..08c6155557 100644 --- a/osu.Game/Screens/Ranking/Pages/ResultsPage.cs +++ b/osu.Game/Screens/Ranking/ResultsPage.cs @@ -12,9 +12,9 @@ using osu.Game.Scoring; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.Ranking.Pages +namespace osu.Game.Screens.Ranking { - public class ResultsPage : Container + public abstract class ResultsPage : Container { protected readonly ScoreInfo Score; protected readonly WorkingBeatmap Beatmap; @@ -23,7 +23,7 @@ namespace osu.Game.Screens.Ranking.Pages protected override Container Content => content; - public ResultsPage(ScoreInfo score, WorkingBeatmap beatmap) + protected ResultsPage(ScoreInfo score, WorkingBeatmap beatmap) { Score = score; Beatmap = beatmap; diff --git a/osu.Game/Screens/Ranking/Types/RankingResultType.cs b/osu.Game/Screens/Ranking/Types/BeatmapLeaderboardPageInfo.cs similarity index 76% rename from osu.Game/Screens/Ranking/Types/RankingResultType.cs rename to osu.Game/Screens/Ranking/Types/BeatmapLeaderboardPageInfo.cs index a11732d324..2b192d4bcd 100644 --- a/osu.Game/Screens/Ranking/Types/RankingResultType.cs +++ b/osu.Game/Screens/Ranking/Types/BeatmapLeaderboardPageInfo.cs @@ -8,12 +8,12 @@ using osu.Game.Screens.Ranking.Pages; namespace osu.Game.Screens.Ranking.Types { - public class RankingResultType : IResultType + public class BeatmapLeaderboardPageInfo : IResultPageInfo { private readonly ScoreInfo score; private readonly WorkingBeatmap beatmap; - public RankingResultType(ScoreInfo score, WorkingBeatmap beatmap) + public BeatmapLeaderboardPageInfo(ScoreInfo score, WorkingBeatmap beatmap) { this.score = score; this.beatmap = beatmap; @@ -21,6 +21,8 @@ namespace osu.Game.Screens.Ranking.Types public FontAwesome Icon => FontAwesome.fa_list; + public string Name => @"Beatmap Leaderboard"; + public ResultsPage CreatePage() => new RankingResultsPage(score, beatmap); } } diff --git a/osu.Game/Screens/Ranking/Types/ScoreResultType.cs b/osu.Game/Screens/Ranking/Types/ScoreOverviewPageInfo.cs similarity index 77% rename from osu.Game/Screens/Ranking/Types/ScoreResultType.cs rename to osu.Game/Screens/Ranking/Types/ScoreOverviewPageInfo.cs index 0841365528..13930fe689 100644 --- a/osu.Game/Screens/Ranking/Types/ScoreResultType.cs +++ b/osu.Game/Screens/Ranking/Types/ScoreOverviewPageInfo.cs @@ -8,18 +8,20 @@ using osu.Game.Screens.Ranking.Pages; namespace osu.Game.Screens.Ranking.Types { - public class ScoreResultType : IResultType + public class ScoreOverviewPageInfo : IResultPageInfo { private readonly ScoreInfo score; private readonly WorkingBeatmap beatmap; - public ScoreResultType(ScoreInfo score, WorkingBeatmap beatmap) + public ScoreOverviewPageInfo(ScoreInfo score, WorkingBeatmap beatmap) { this.score = score; this.beatmap = beatmap; } public FontAwesome Icon => FontAwesome.fa_asterisk; + + public string Name => "Overview"; public ResultsPage CreatePage() => new ScoreResultsPage(score, beatmap); } From e7508cbd5efe7f1a74d6e1fbbccc33725697af04 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Dec 2018 15:55:10 +0900 Subject: [PATCH 33/38] Fix CI issues --- .../Ranking/{IResultType.cs => IResultPageInfo.cs} | 0 .../Screens/Ranking/Types/ScoreOverviewPageInfo.cs | 12 +++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) rename osu.Game/Screens/Ranking/{IResultType.cs => IResultPageInfo.cs} (100%) diff --git a/osu.Game/Screens/Ranking/IResultType.cs b/osu.Game/Screens/Ranking/IResultPageInfo.cs similarity index 100% rename from osu.Game/Screens/Ranking/IResultType.cs rename to osu.Game/Screens/Ranking/IResultPageInfo.cs diff --git a/osu.Game/Screens/Ranking/Types/ScoreOverviewPageInfo.cs b/osu.Game/Screens/Ranking/Types/ScoreOverviewPageInfo.cs index 13930fe689..03998d2840 100644 --- a/osu.Game/Screens/Ranking/Types/ScoreOverviewPageInfo.cs +++ b/osu.Game/Screens/Ranking/Types/ScoreOverviewPageInfo.cs @@ -10,6 +10,9 @@ namespace osu.Game.Screens.Ranking.Types { public class ScoreOverviewPageInfo : IResultPageInfo { + public FontAwesome Icon => FontAwesome.fa_asterisk; + + public string Name => "Overview"; private readonly ScoreInfo score; private readonly WorkingBeatmap beatmap; @@ -19,10 +22,9 @@ namespace osu.Game.Screens.Ranking.Types this.beatmap = beatmap; } - public FontAwesome Icon => FontAwesome.fa_asterisk; - - public string Name => "Overview"; - - public ResultsPage CreatePage() => new ScoreResultsPage(score, beatmap); + public ResultsPage CreatePage() + { + return new ScoreResultsPage(score, beatmap); + } } } From a35d9178f05bb58ae1aac22e5d6849da55894d68 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Dec 2018 16:20:29 +0900 Subject: [PATCH 34/38] Quick rename --- osu.Game/Screens/Play/SoloResults.cs | 2 +- osu.Game/Screens/Ranking/Results.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/SoloResults.cs b/osu.Game/Screens/Play/SoloResults.cs index 2828c758e0..5e318e95d1 100644 --- a/osu.Game/Screens/Play/SoloResults.cs +++ b/osu.Game/Screens/Play/SoloResults.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Play { } - protected override IEnumerable CreateResultTypes() => new IResultPageInfo[] + protected override IEnumerable CreateResultPages() => new IResultPageInfo[] { new ScoreOverviewPageInfo(Score, Beatmap), new BeatmapLeaderboardPageInfo(Score, Beatmap) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 86067d8cc5..bf9e3bcd27 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -264,7 +264,7 @@ namespace osu.Game.Screens.Ranking }, }; - foreach (var t in CreateResultTypes()) + foreach (var t in CreateResultPages()) modeChangeButtons.AddItem(t); modeChangeButtons.Current.Value = modeChangeButtons.Items.FirstOrDefault(); @@ -280,6 +280,6 @@ namespace osu.Game.Screens.Ranking }, true); } - protected abstract IEnumerable CreateResultTypes(); + protected abstract IEnumerable CreateResultPages(); } } From 005c6ff40c6212da2c4a279cb976a8f3edbcb747 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Dec 2018 16:30:06 +0900 Subject: [PATCH 35/38] Add tooltip text to results screen pages --- osu.Game/Screens/Ranking/ResultModeButton.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/ResultModeButton.cs b/osu.Game/Screens/Ranking/ResultModeButton.cs index 34a93236bd..f6a886418c 100644 --- a/osu.Game/Screens/Ranking/ResultModeButton.cs +++ b/osu.Game/Screens/Ranking/ResultModeButton.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osuTK; @@ -13,7 +14,7 @@ using osu.Framework.Graphics.Shapes; namespace osu.Game.Screens.Ranking { - public class ResultModeButton : TabItem + public class ResultModeButton : TabItem, IHasTooltip { private readonly FontAwesome icon; private Color4 activeColour; @@ -24,6 +25,7 @@ namespace osu.Game.Screens.Ranking : base(mode) { icon = mode.Icon; + TooltipText = mode.Name; } [BackgroundDependencyLoader] @@ -85,5 +87,7 @@ namespace osu.Game.Screens.Ranking protected override void OnActivated() => colouredPart.FadeColour(activeColour, 200, Easing.OutQuint); protected override void OnDeactivated() => colouredPart.FadeColour(inactiveColour, 200, Easing.OutQuint); + + public string TooltipText { get; private set; } } } From 0757beb3b87db23fc58829cef951ec1b6e55792f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 22 Dec 2018 17:54:04 +0900 Subject: [PATCH 36/38] Test for null before loading --- osu.Game/Overlays/AccountCreation/ScreenWarning.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs index b6fffde621..082eb8a51f 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs @@ -42,6 +42,10 @@ namespace osu.Game.Overlays.AccountCreation private void load(OsuColour colours, APIAccess api, OsuGame game, TextureStore textures) { this.api = api; + + if (string.IsNullOrEmpty(api.ProvidedUsername)) + return; + Children = new Drawable[] { new Sprite From 30dbc36fce3284f292701ee0f1bc4264abcf9cfc Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 22 Dec 2018 17:54:19 +0900 Subject: [PATCH 37/38] Don't clear username on logout --- osu.Game/Online/API/APIAccess.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index a3719d624c..8038c1fc1f 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -161,7 +161,7 @@ namespace osu.Game.Online.API //hard bail if we can't get a valid access token. if (authentication.RequestAccessToken() == null) { - Logout(false); + Logout(); continue; } @@ -293,7 +293,7 @@ namespace osu.Game.Online.API switch (statusCode) { case HttpStatusCode.Unauthorized: - Logout(false); + Logout(); return true; case HttpStatusCode.RequestTimeout: failureCount++; @@ -342,10 +342,9 @@ namespace osu.Game.Online.API } } - public void Logout(bool clearUsername = true) + public void Logout() { flushQueue(); - if (clearUsername) ProvidedUsername = null; password = null; authentication.Clear(); LocalUser.Value = createGuestUser(); From 40db23ff4c6d3583b01ad158bcd30f0ab1d46750 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 22 Dec 2018 19:30:52 +0900 Subject: [PATCH 38/38] Disable avatar clicks in chat tabs --- osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs index e04d7891f8..804ddeabb4 100644 --- a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs @@ -52,6 +52,7 @@ namespace osu.Game.Overlays.Chat.Tabs Child = new DelayedLoadWrapper(new Avatar(value.Users.First()) { RelativeSizeAxes = Axes.Both, + OpenOnClick = { Value = false }, OnLoadComplete = d => d.FadeInFromZero(300, Easing.OutQuint), }) {