Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New song select footer design implementation #21491

Merged
merged 28 commits into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
18b4317
Create Basic V2 footer and test
mk56-spn Dec 1, 2022
774eb17
Add basic button design and footer button addition flow
mk56-spn Dec 1, 2022
1530495
Add button "accent" colour, bottom bar, icon, text
mk56-spn Dec 1, 2022
d7cea51
Add functionality of Random button
mk56-spn Dec 1, 2022
55a21a7
Add hover lightening
mk56-spn Dec 1, 2022
ea882f6
Add disabled button dimming.
mk56-spn Dec 1, 2022
c5bad81
Add button colouring whilst corresponding overlay is present
mk56-spn Dec 2, 2022
7373d79
Use OsuColour instead of hex for button accent colour
mk56-spn Dec 2, 2022
407b0a0
Address issues from Joehuu review
mk56-spn Dec 19, 2022
878e2f2
Merge branch 'master' into footer_V2_implementation
mk56-spn Dec 19, 2022
626f4b0
fix test failures, improve button logic
mk56-spn Dec 19, 2022
680646d
Make offsetting of bottom bar more readable
mk56-spn Dec 29, 2022
92a755c
adjust colourbar to position itself in a more simple fashion
mk56-spn Jan 17, 2023
bc94f1b
add free mods button to test
mk56-spn Jan 23, 2023
41f5e51
Remove ```onclick``` and ```mousedown``` override
mk56-spn Jan 30, 2023
f5d5791
Remove free mods button
mk56-spn Jan 30, 2023
80fd1a0
Remove leftover comment regarding X axis offsets
mk56-spn Feb 2, 2023
a1200b8
Adjust footer button colour handling to read better and take into acc…
peppy Feb 3, 2023
4248453
Use `FinishTransforms` rather than manual duplication of background c…
peppy Feb 3, 2023
48f7e01
Adjust comments and formatting of comments
peppy Feb 3, 2023
4ec46c7
Merge branch 'master' into footer_V2_implementation
peppy Feb 3, 2023
6e6421c
Change FooterV2.cs colour to use `ColourProvider` instead of `OsuColo…
mk56-spn Feb 13, 2023
61584ba
Fix corner_radius missing in some parts of `FooterButtonV2.cs`.
mk56-spn Feb 13, 2023
be52d0a
Add note explaining shadow opacity
mk56-spn Feb 13, 2023
ae9a17d
Add offset to `FooterButtonV2.cs` shadow
mk56-spn Feb 13, 2023
5006dbe
Update osu.Game/Screens/Select/FooterV2/FooterButtonV2.cs
mk56-spn Feb 13, 2023
f0ebb92
Make `Action`s nullable
peppy Feb 14, 2023
51d4ae5
Merge branch 'master' into footer_V2_implementation
peppy Feb 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooterV2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// 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.Overlays;
using osu.Game.Overlays.Mods;
using osu.Game.Screens.Select.FooterV2;
using osuTK;
using osuTK.Input;

namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneSongSelectFooterV2 : OsuManualInputManagerTestScene
{
private FooterButtonRandomV2 randomButton = null!;
private FooterButtonModsV2 modsButton = null!;

private bool nextRandomCalled;
private bool previousRandomCalled;

private DummyOverlay overlay = null!;

[SetUp]
public void SetUp() => Schedule(() =>
{
nextRandomCalled = false;
previousRandomCalled = false;

FooterV2 footer;

Children = new Drawable[]
{
footer = new FooterV2
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
},
overlay = new DummyOverlay()
};

footer.AddButton(modsButton = new FooterButtonModsV2(), overlay);
footer.AddButton(randomButton = new FooterButtonRandomV2
{
NextRandom = () => nextRandomCalled = true,
PreviousRandom = () => previousRandomCalled = true
});
footer.AddButton(new FooterButtonOptionsV2());

InputManager.MoveMouseTo(Vector2.Zero);

overlay.Hide();
});

[Test]
public void TestState()
{
AddRepeatStep("toggle options state", () => this.ChildrenOfType<FooterButtonV2>().Last().Enabled.Toggle(), 20);
}

[Test]
public void TestFooterRandom()
{
AddStep("press F2", () => InputManager.Key(Key.F2));
AddAssert("next random invoked", () => nextRandomCalled && !previousRandomCalled);
}

[Test]
public void TestFooterRandomViaMouse()
{
AddStep("click button", () =>
{
InputManager.MoveMouseTo(randomButton);
InputManager.Click(MouseButton.Left);
});
AddAssert("next random invoked", () => nextRandomCalled && !previousRandomCalled);
}

[Test]
public void TestFooterRewind()
{
AddStep("press Shift+F2", () =>
{
InputManager.PressKey(Key.LShift);
InputManager.PressKey(Key.F2);
InputManager.ReleaseKey(Key.F2);
InputManager.ReleaseKey(Key.LShift);
});
AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled);
}

[Test]
public void TestFooterRewindViaShiftMouseLeft()
{
AddStep("shift + click button", () =>
{
InputManager.PressKey(Key.LShift);
InputManager.MoveMouseTo(randomButton);
InputManager.Click(MouseButton.Left);
InputManager.ReleaseKey(Key.LShift);
});
AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled);
}

[Test]
public void TestFooterRewindViaMouseRight()
{
AddStep("right click button", () =>
{
InputManager.MoveMouseTo(randomButton);
InputManager.Click(MouseButton.Right);
});
AddAssert("previous random invoked", () => previousRandomCalled && !nextRandomCalled);
}

[Test]
public void TestOverlayPresent()
{
AddStep("Press F1", () =>
{
InputManager.MoveMouseTo(modsButton);
InputManager.Click(MouseButton.Left);
});
AddAssert("Overlay visible", () => overlay.State.Value == Visibility.Visible);
AddStep("Hide", () => overlay.Hide());
}

private partial class DummyOverlay : ShearedOverlayContainer
{
public DummyOverlay()
: base(OverlayColourScheme.Green)
{
}

[BackgroundDependencyLoader]
private void load()
{
Header.Title = "An overlay";
}
}
}
}
21 changes: 21 additions & 0 deletions osu.Game/Screens/Select/FooterV2/FooterButtonFreeModsV2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// 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.Graphics.Sprites;
using osu.Game.Graphics;

namespace osu.Game.Screens.Select.FooterV2
{
public partial class FooterButtonFreeModsV2 : FooterButtonV2
mk56-spn marked this conversation as resolved.
Show resolved Hide resolved
{
[BackgroundDependencyLoader]
private void load(OsuColour colour)
{
//No design exists for this button!
Icon = FontAwesome.Solid.ExpandArrowsAlt;
Text = "Freemods";
AccentColour = colour.Yellow;
}
}
}
20 changes: 20 additions & 0 deletions osu.Game/Screens/Select/FooterV2/FooterButtonModsV2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// 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.Graphics.Sprites;
using osu.Game.Graphics;

namespace osu.Game.Screens.Select.FooterV2
{
public partial class FooterButtonModsV2 : FooterButtonV2
{
[BackgroundDependencyLoader]
private void load(OsuColour colour)
{
Text = "Mods";
Icon = FontAwesome.Solid.ExchangeAlt;
AccentColour = colour.Lime1;
}
}
}
22 changes: 22 additions & 0 deletions osu.Game/Screens/Select/FooterV2/FooterButtonOptionsV2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Input.Bindings;

namespace osu.Game.Screens.Select.FooterV2
{
public partial class FooterButtonOptionsV2 : FooterButtonV2
{
[BackgroundDependencyLoader]
private void load(OsuColour colour)
{
Text = "Options";
Icon = FontAwesome.Solid.Cog;
AccentColour = colour.Purple1;
Hotkey = GlobalAction.ToggleBeatmapOptions;
}
}
}
161 changes: 161 additions & 0 deletions osu.Game/Screens/Select/FooterV2/FooterButtonRandomV2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// 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;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Input.Bindings;
using osuTK;
using osuTK.Input;

namespace osu.Game.Screens.Select.FooterV2
{
public partial class FooterButtonRandomV2 : FooterButtonV2
{
public Action NextRandom { get; set; } = null!;
public Action PreviousRandom { get; set; } = null!;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally we always make Actions Action? and support nullability, as a pattern.


private Container persistentText = null!;
private OsuSpriteText randomSpriteText = null!;
private OsuSpriteText rewindSpriteText = null!;
private bool rewindSearch;

[BackgroundDependencyLoader]
private void load(OsuColour colour)
{
//TODO: use https://fontawesome.com/icons/shuffle?s=solid&f=classic when local Fontawesome is updated
Icon = FontAwesome.Solid.Random;
AccentColour = colour.Blue1;
TextContainer.Add(persistentText = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AlwaysPresent = true,
AutoSizeAxes = Axes.Both,
Children = new[]
{
randomSpriteText = new OsuSpriteText
{
Font = OsuFont.TorusAlternate.With(size: 19),
AlwaysPresent = true,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = "Random",
},
rewindSpriteText = new OsuSpriteText
{
Font = OsuFont.TorusAlternate.With(size: 19),
AlwaysPresent = true,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = "Rewind",
Alpha = 0f,
}
}
});

Action = () =>
{
if (rewindSearch)
{
const double fade_time = 500;

OsuSpriteText fallingRewind;

TextContainer.Add(fallingRewind = new OsuSpriteText
{
Alpha = 0,
Text = rewindSpriteText.Text,
AlwaysPresent = true, // make sure the button is sized large enough to always show this
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Font = OsuFont.TorusAlternate.With(size: 19),
});

fallingRewind.FadeOutFromOne(fade_time, Easing.In);
fallingRewind.MoveTo(Vector2.Zero).MoveTo(new Vector2(0, 10), fade_time, Easing.In);
fallingRewind.Expire();

persistentText.FadeInFromZero(fade_time, Easing.In);

PreviousRandom.Invoke();
}
else
{
NextRandom.Invoke();
}
};
}

protected override bool OnKeyDown(KeyDownEvent e)
{
updateText(e.ShiftPressed);
return base.OnKeyDown(e);
}

protected override void OnKeyUp(KeyUpEvent e)
{
updateText(e.ShiftPressed);
base.OnKeyUp(e);
}

protected override bool OnClick(ClickEvent e)
{
try
{
// this uses OR to handle rewinding when clicks are triggered by other sources (i.e. right button in OnMouseUp).
rewindSearch |= e.ShiftPressed;
return base.OnClick(e);
}
finally
{
rewindSearch = false;
}
}

protected override void OnMouseUp(MouseUpEvent e)
{
if (e.Button == MouseButton.Right)
{
rewindSearch = true;
TriggerClick();
return;
}

base.OnMouseUp(e);
}

public override bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
{
rewindSearch = e.Action == GlobalAction.SelectPreviousRandom;

if (e.Action != GlobalAction.SelectNextRandom && e.Action != GlobalAction.SelectPreviousRandom)
{
return false;
}

if (!e.Repeat)
TriggerClick();
return true;
}

public override void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
{
if (e.Action == GlobalAction.SelectPreviousRandom)
{
rewindSearch = false;
}
}

private void updateText(bool rewind = false)
{
randomSpriteText.Alpha = rewind ? 0 : 1;
rewindSpriteText.Alpha = rewind ? 1 : 0;
}
}
}
Loading