From 1a974f64ded87e5f1fa575a5b6c8e291cdba5982 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 4 Dec 2018 20:33:29 +0900 Subject: [PATCH 01/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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 0757beb3b87db23fc58829cef951ec1b6e55792f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 22 Dec 2018 17:54:04 +0900 Subject: [PATCH 19/20] 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 20/20] 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();