1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-21 15:27:24 +08:00

Merge pull request #23331 from letsgoawaydev/ui-login-spacing-fix

Update login overlay appearance to match new designs
This commit is contained in:
Dean Herbert 2023-06-26 14:11:57 +09:00 committed by GitHub
commit e085a36aac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 221 additions and 250 deletions

View File

@ -0,0 +1,89 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Overlays;
using osu.Game.Users.Drawables;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Menus
{
[TestFixture]
public partial class TestSceneLoginOverlay : OsuManualInputManagerTestScene
{
private LoginOverlay loginOverlay = null!;
[BackgroundDependencyLoader]
private void load()
{
Child = loginOverlay = new LoginOverlay
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
};
}
[SetUpSteps]
public void SetUpSteps()
{
AddStep("show login overlay", () => loginOverlay.Show());
}
[Test]
public void TestLoginSuccess()
{
AddStep("logout", () => API.Logout());
AddStep("enter password", () => loginOverlay.ChildrenOfType<OsuPasswordTextBox>().First().Text = "password");
AddStep("submit", () => loginOverlay.ChildrenOfType<OsuButton>().First(b => b.Text.ToString() == "Sign in").TriggerClick());
}
[Test]
public void TestLoginFailure()
{
AddStep("logout", () =>
{
API.Logout();
((DummyAPIAccess)API).FailNextLogin();
});
AddStep("enter password", () => loginOverlay.ChildrenOfType<OsuPasswordTextBox>().First().Text = "password");
AddStep("submit", () => loginOverlay.ChildrenOfType<OsuButton>().First(b => b.Text.ToString() == "Sign in").TriggerClick());
}
[Test]
public void TestLoginConnecting()
{
AddStep("logout", () =>
{
API.Logout();
((DummyAPIAccess)API).PauseOnConnectingNextLogin();
});
AddStep("enter password", () => loginOverlay.ChildrenOfType<OsuPasswordTextBox>().First().Text = "password");
AddStep("submit", () => loginOverlay.ChildrenOfType<OsuButton>().First(b => b.Text.ToString() == "Sign in").TriggerClick());
}
[Test]
public void TestClickingOnFlagClosesOverlay()
{
AddStep("logout", () => API.Logout());
AddStep("enter password", () => loginOverlay.ChildrenOfType<OsuPasswordTextBox>().First().Text = "password");
AddStep("submit", () => loginOverlay.ChildrenOfType<OsuButton>().First(b => b.Text.ToString() == "Sign in").TriggerClick());
AddStep("click on flag", () =>
{
InputManager.MoveMouseTo(loginOverlay.ChildrenOfType<UpdateableFlag>().First());
InputManager.Click(MouseButton.Left);
});
AddAssert("login overlay is hidden", () => loginOverlay.State.Value == Visibility.Hidden);
}
}
}

View File

@ -1,78 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Overlays.Login;
using osu.Game.Users.Drawables;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Menus
{
[TestFixture]
public partial class TestSceneLoginPanel : OsuManualInputManagerTestScene
{
private LoginPanel loginPanel;
private int hideCount;
[SetUpSteps]
public void SetUpSteps()
{
AddStep("create login dialog", () =>
{
Add(loginPanel = new LoginPanel
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Width = 0.5f,
RequestHide = () => hideCount++,
});
});
}
[Test]
public void TestLoginSuccess()
{
AddStep("logout", () => API.Logout());
AddStep("enter password", () => loginPanel.ChildrenOfType<OsuPasswordTextBox>().First().Text = "password");
AddStep("submit", () => loginPanel.ChildrenOfType<OsuButton>().First(b => b.Text.ToString() == "Sign in").TriggerClick());
}
[Test]
public void TestLoginFailure()
{
AddStep("logout", () =>
{
API.Logout();
((DummyAPIAccess)API).FailNextLogin();
});
AddStep("enter password", () => loginPanel.ChildrenOfType<OsuPasswordTextBox>().First().Text = "password");
AddStep("submit", () => loginPanel.ChildrenOfType<OsuButton>().First(b => b.Text.ToString() == "Sign in").TriggerClick());
}
[Test]
public void TestClickingOnFlagClosesPanel()
{
AddStep("reset hide count", () => hideCount = 0);
AddStep("logout", () => API.Logout());
AddStep("enter password", () => loginPanel.ChildrenOfType<OsuPasswordTextBox>().First().Text = "password");
AddStep("submit", () => loginPanel.ChildrenOfType<OsuButton>().First(b => b.Text.ToString() == "Sign in").TriggerClick());
AddStep("click on flag", () =>
{
InputManager.MoveMouseTo(loginPanel.ChildrenOfType<UpdateableFlag>().First());
InputManager.Click(MouseButton.Left);
});
AddAssert("hide requested", () => hideCount == 1);
}
}
}

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Threading;
using System.Threading.Tasks;
@ -45,17 +43,18 @@ namespace osu.Game.Online.API
public int APIVersion => int.Parse(DateTime.Now.ToString("yyyyMMdd"));
public Exception LastLoginError { get; private set; }
public Exception? LastLoginError { get; private set; }
/// <summary>
/// Provide handling logic for an arbitrary API request.
/// Should return true is a request was handled. If null or false return, the request will be failed with a <see cref="NotSupportedException"/>.
/// </summary>
public Func<APIRequest, bool> HandleRequest;
public Func<APIRequest, bool>? HandleRequest;
private readonly Bindable<APIState> state = new Bindable<APIState>(APIState.Online);
private bool shouldFailNextLogin;
private bool stayConnectingNextLogin;
/// <summary>
/// The current connectivity state of the API.
@ -94,6 +93,12 @@ namespace osu.Game.Online.API
{
state.Value = APIState.Connecting;
if (stayConnectingNextLogin)
{
stayConnectingNextLogin = false;
return;
}
if (shouldFailNextLogin)
{
LastLoginError = new APIException("Not powerful enough to login.", new ArgumentException(nameof(shouldFailNextLogin)));
@ -121,11 +126,11 @@ namespace osu.Game.Online.API
LocalUser.Value = new GuestUser();
}
public IHubClientConnector GetHubConnector(string clientName, string endpoint, bool preferMessagePack) => null;
public IHubClientConnector? GetHubConnector(string clientName, string endpoint, bool preferMessagePack) => null;
public NotificationsClientConnector GetNotificationsConnector() => new PollingNotificationsClientConnector(this);
public RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, string username, string password)
public RegistrationRequest.RegistrationRequestErrors? CreateAccount(string email, string username, string password)
{
Thread.Sleep(200);
return null;
@ -137,8 +142,16 @@ namespace osu.Game.Online.API
IBindableList<APIUser> IAPIProvider.Friends => Friends;
IBindable<UserActivity> IAPIProvider.Activity => Activity;
/// <summary>
/// During the next simulated login, the process will fail immediately.
/// </summary>
public void FailNextLogin() => shouldFailNextLogin = true;
/// <summary>
/// During the next simulated login, the process will pause indefinitely at "connecting".
/// </summary>
public void PauseOnConnectingNextLogin() => stayConnectingNextLogin = true;
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);

View File

@ -11,6 +11,7 @@ using osu.Framework.Input.Events;
using osu.Game.Configuration;
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;
@ -42,33 +43,50 @@ namespace osu.Game.Overlays.Login
[BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuConfigManager config, AccountCreationOverlay accountCreation)
{
Direction = FillDirection.Vertical;
Spacing = new Vector2(0, 5);
AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Direction = FillDirection.Vertical;
Spacing = new Vector2(0, SettingsSection.ITEM_SPACING);
ErrorTextFlowContainer errorText;
LinkFlowContainer forgottenPasswordLink;
Children = new Drawable[]
{
username = new OsuTextBox
{
PlaceholderText = UsersStrings.LoginUsername.ToLower(),
RelativeSizeAxes = Axes.X,
Text = api.ProvidedUsername,
TabbableContentContainer = this
},
password = new OsuPasswordTextBox
{
PlaceholderText = UsersStrings.LoginPassword.ToLower(),
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
},
errorText = new ErrorTextFlowContainer
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS },
Direction = FillDirection.Vertical,
Spacing = new Vector2(0f, SettingsSection.ITEM_SPACING),
Children = new Drawable[]
{
new OsuSpriteText
{
Text = LoginPanelStrings.Account.ToUpper(),
Font = OsuFont.GetFont(weight: FontWeight.Bold),
},
username = new OsuTextBox
{
PlaceholderText = UsersStrings.LoginUsername.ToLower(),
RelativeSizeAxes = Axes.X,
Text = api.ProvidedUsername,
TabbableContentContainer = this
},
password = new OsuPasswordTextBox
{
PlaceholderText = UsersStrings.LoginPassword.ToLower(),
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
},
errorText = new ErrorTextFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Alpha = 0,
},
},
},
new SettingsCheckbox
{
@ -82,7 +100,7 @@ namespace osu.Game.Overlays.Login
},
forgottenPasswordLink = new LinkFlowContainer
{
Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS },
Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS },
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
},
@ -120,7 +138,10 @@ namespace osu.Game.Overlays.Login
password.OnCommit += (_, _) => performLogin();
if (api.LastLoginError?.Message is string error)
{
errorText.Alpha = 1;
errorText.AddErrors(new[] { error });
}
}
public override bool AcceptsFocus => true;

View File

@ -1,14 +1,13 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
@ -16,33 +15,33 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
using osu.Game.Online.API;
using osu.Game.Overlays.Settings;
using osu.Game.Users;
using osuTK;
using RectangleF = osu.Framework.Graphics.Primitives.RectangleF;
using Container = osu.Framework.Graphics.Containers.Container;
namespace osu.Game.Overlays.Login
{
public partial class LoginPanel : FillFlowContainer
public partial class LoginPanel : Container
{
private bool bounding = true;
private LoginForm form;
private LoginForm? form;
[Resolved]
private OsuColour colours { get; set; }
private OsuColour colours { get; set; } = null!;
private UserGridPanel panel;
private UserDropdown dropdown;
private UserGridPanel panel = null!;
private UserDropdown dropdown = null!;
/// <summary>
/// Called to request a hide of a parent displaying this container.
/// </summary>
public Action RequestHide;
public Action? RequestHide;
private readonly IBindable<APIState> apiState = new Bindable<APIState>();
[Resolved]
private IAPIProvider api { get; set; }
private IAPIProvider api { get; set; } = null!;
public override RectangleF BoundingBox => bounding ? base.BoundingBox : RectangleF.Empty;
@ -60,8 +59,6 @@ namespace osu.Game.Overlays.Login
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Direction = FillDirection.Vertical;
Spacing = new Vector2(0f, 5f);
}
[BackgroundDependencyLoader]
@ -78,18 +75,9 @@ namespace osu.Game.Overlays.Login
switch (state.NewValue)
{
case APIState.Offline:
Children = new Drawable[]
Child = form = new LoginForm
{
new OsuSpriteText
{
Text = LoginPanelStrings.Account.ToUpper(),
Margin = new MarginPadding { Bottom = 5 },
Font = OsuFont.GetFont(weight: FontWeight.Bold),
},
form = new LoginForm
{
RequestHide = RequestHide
}
RequestHide = RequestHide
};
break;
@ -97,22 +85,29 @@ namespace osu.Game.Overlays.Login
case APIState.Connecting:
LinkFlowContainer linkFlow;
Children = new Drawable[]
Child = new FillFlowContainer
{
new LoadingSpinner
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS },
Direction = FillDirection.Vertical,
Spacing = new Vector2(0f, SettingsSection.ITEM_SPACING),
Children = new Drawable[]
{
State = { Value = Visibility.Visible },
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
},
linkFlow = new LinkFlowContainer
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
TextAnchor = Anchor.TopCentre,
AutoSizeAxes = Axes.Both,
Text = state.NewValue == APIState.Failing ? ToolbarStrings.AttemptingToReconnect : ToolbarStrings.Connecting,
Margin = new MarginPadding { Top = 10, Bottom = 10 },
new LoadingSpinner
{
State = { Value = Visibility.Visible },
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
},
linkFlow = new LinkFlowContainer
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
TextAnchor = Anchor.TopCentre,
AutoSizeAxes = Axes.Both,
Text = state.NewValue == APIState.Failing ? ToolbarStrings.AttemptingToReconnect : ToolbarStrings.Connecting,
},
},
};
@ -120,40 +115,28 @@ namespace osu.Game.Overlays.Login
break;
case APIState.Online:
Children = new Drawable[]
Child = new FillFlowContainer
{
new FillFlowContainer
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS },
Direction = FillDirection.Vertical,
Spacing = new Vector2(0f, SettingsSection.ITEM_SPACING),
Children = new Drawable[]
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Left = 20, Right = 20 },
Direction = FillDirection.Vertical,
Spacing = new Vector2(0f, 10f),
Children = new Drawable[]
new OsuSpriteText
{
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new[]
{
new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = LoginPanelStrings.SignedIn,
Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold),
Margin = new MarginPadding { Top = 5, Bottom = 5 },
},
},
},
panel = new UserGridPanel(api.LocalUser.Value)
{
RelativeSizeAxes = Axes.X,
Action = RequestHide
},
dropdown = new UserDropdown { RelativeSizeAxes = Axes.X },
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = LoginPanelStrings.SignedIn,
Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold),
},
panel = new UserGridPanel(api.LocalUser.Value)
{
RelativeSizeAxes = Axes.X,
Action = RequestHide
},
dropdown = new UserDropdown { RelativeSizeAxes = Axes.X },
},
};

View File

@ -1,12 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Users.Drawables;
using osuTK;
@ -31,29 +27,6 @@ namespace osu.Game.Overlays.Login
protected partial class UserDropdownMenu : OsuDropdownMenu
{
public UserDropdownMenu()
{
Masking = true;
CornerRadius = 5;
Margin = new MarginPadding { Bottom = 5 };
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.25f),
Radius = 4,
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = colours.Gray3;
SelectionColour = colours.Gray4;
HoverColour = colours.Gray5;
}
protected override DrawableDropdownMenuItem CreateDrawableDropdownMenuItem(MenuItem item) => new DrawableUserDropdownMenuItem(item);
private partial class DrawableUserDropdownMenuItem : DrawableOsuDropdownMenuItem
@ -62,20 +35,12 @@ namespace osu.Game.Overlays.Login
: base(item)
{
Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 5 };
CornerRadius = 5;
}
protected override Drawable CreateContent() => new Content
{
Label = { Margin = new MarginPadding { Left = UserDropdownHeader.LABEL_LEFT_MARGIN - 11 } }
};
}
}
private partial class UserDropdownHeader : OsuDropdownHeader
{
public const float LABEL_LEFT_MARGIN = 20;
private readonly StatusIcon statusIcon;
public Color4 StatusColour
@ -85,20 +50,6 @@ namespace osu.Game.Overlays.Login
public UserDropdownHeader()
{
Foreground.Padding = new MarginPadding { Left = 10, Right = 10 };
Margin = new MarginPadding { Bottom = 5 };
Masking = true;
CornerRadius = 5;
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.25f),
Radius = 4,
};
Icon.Size = new Vector2(14);
Icon.Margin = new MarginPadding(0);
Foreground.Add(statusIcon = new StatusIcon
{
Anchor = Anchor.CentreLeft,
@ -106,14 +57,7 @@ namespace osu.Game.Overlays.Login
Size = new Vector2(14),
});
Text.Margin = new MarginPadding { Left = LABEL_LEFT_MARGIN };
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = colours.Gray3;
BackgroundColourHover = colours.Gray5;
Text.Margin = new MarginPadding { Left = 20 };
}
}
}

View File

@ -1,33 +1,43 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Framework.Graphics.Effects;
using osuTK.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Cursor;
using osu.Game.Overlays.Login;
using osu.Game.Overlays.Settings;
namespace osu.Game.Overlays
{
public partial class LoginOverlay : OsuFocusedOverlayContainer
{
private LoginPanel panel;
private LoginPanel panel = null!;
private const float transition_time = 400;
[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
public LoginOverlay()
{
AutoSizeAxes = Axes.Both;
Masking = true;
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black,
Type = EdgeEffectType.Shadow,
Radius = 10,
Hollow = true,
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load()
{
Children = new Drawable[]
{
@ -40,8 +50,7 @@ namespace osu.Game.Overlays
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
Alpha = 0.6f,
Colour = colourProvider.Background4,
},
new Container
{
@ -50,23 +59,11 @@ namespace osu.Game.Overlays
Masking = true,
AutoSizeDuration = transition_time,
AutoSizeEasing = Easing.OutQuint,
Children = new Drawable[]
Child = panel = new LoginPanel
{
panel = new LoginPanel
{
Padding = new MarginPadding(10),
RequestHide = Hide,
},
new Box
{
RelativeSizeAxes = Axes.X,
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Height = 3,
Colour = colours.Yellow,
Alpha = 1,
},
}
Padding = new MarginPadding { Vertical = SettingsSection.ITEM_SPACING },
RequestHide = Hide,
},
}
}
}
@ -77,6 +74,7 @@ namespace osu.Game.Overlays
{
panel.Bounding = true;
this.FadeIn(transition_time, Easing.OutQuint);
FadeEdgeEffectTo(WaveContainer.SHADOW_OPACITY, WaveContainer.APPEAR_DURATION, Easing.Out);
ScheduleAfterChildren(() => GetContainingInputManager().ChangeFocus(panel));
}
@ -87,6 +85,7 @@ namespace osu.Game.Overlays
panel.Bounding = false;
this.FadeOut(transition_time);
FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.In);
}
}
}