1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-13 16:13:34 +08:00

Various renaming and class updates to allow multiple menu banners

This commit is contained in:
Dean Herbert 2024-03-23 16:41:40 +08:00
parent 77660e57ea
commit ef2a16dd8f
No known key found for this signature in database
7 changed files with 169 additions and 80 deletions

View File

@ -13,30 +13,48 @@ namespace osu.Game.Tests.Visual.Menus
{
public partial class TestSceneMainMenu : OsuGameTestScene
{
private SystemTitle systemTitle => Game.ChildrenOfType<SystemTitle>().Single();
private OnlineMenuBanner onlineMenuBanner => Game.ChildrenOfType<OnlineMenuBanner>().Single();
[Test]
public void TestSystemTitle()
public void TestOnlineMenuBanner()
{
AddStep("set system title", () => systemTitle.Current.Value = new APISystemTitle
AddStep("set online content", () => onlineMenuBanner.Current.Value = new APIMenuContent
{
Image = @"https://assets.ppy.sh/main-menu/project-loved-2@2x.png",
Url = @"https://osu.ppy.sh/home/news/2023-12-21-project-loved-december-2023",
Images = new[]
{
new APIMenuImage
{
Image = @"https://assets.ppy.sh/main-menu/project-loved-2@2x.png",
Url = @"https://osu.ppy.sh/home/news/2023-12-21-project-loved-december-2023",
}
}
});
AddAssert("system title not visible", () => systemTitle.State.Value, () => Is.EqualTo(Visibility.Hidden));
AddAssert("system title not visible", () => onlineMenuBanner.State.Value, () => Is.EqualTo(Visibility.Hidden));
AddStep("enter menu", () => InputManager.Key(Key.Enter));
AddUntilStep("system title visible", () => systemTitle.State.Value, () => Is.EqualTo(Visibility.Visible));
AddStep("set another title", () => systemTitle.Current.Value = new APISystemTitle
AddUntilStep("system title visible", () => onlineMenuBanner.State.Value, () => Is.EqualTo(Visibility.Visible));
AddStep("set another title", () => onlineMenuBanner.Current.Value = new APIMenuContent
{
Image = @"https://assets.ppy.sh/main-menu/wf2023-vote@2x.png",
Url = @"https://osu.ppy.sh/community/contests/189",
Images = new[]
{
new APIMenuImage
{
Image = @"https://assets.ppy.sh/main-menu/wf2023-vote@2x.png",
Url = @"https://osu.ppy.sh/community/contests/189",
}
}
});
AddStep("set title with nonexistent image", () => systemTitle.Current.Value = new APISystemTitle
AddStep("set title with nonexistent image", () => onlineMenuBanner.Current.Value = new APIMenuContent
{
Image = @"https://test.invalid/@2x", // .invalid TLD reserved by https://datatracker.ietf.org/doc/html/rfc2606#section-2
Url = @"https://osu.ppy.sh/community/contests/189",
Images = new[]
{
new APIMenuImage
{
Image = @"https://test.invalid/@2x", // .invalid TLD reserved by https://datatracker.ietf.org/doc/html/rfc2606#section-2
Url = @"https://osu.ppy.sh/community/contests/189",
}
}
});
AddStep("unset system title", () => systemTitle.Current.Value = null);
AddStep("unset system title", () => onlineMenuBanner.Current.Value = new APIMenuContent());
}
}
}

View File

@ -5,9 +5,9 @@ using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
public class GetSystemTitleRequest : OsuJsonWebRequest<APISystemTitle>
public class GetMenuContentRequest : OsuJsonWebRequest<APIMenuContent>
{
public GetSystemTitleRequest()
public GetMenuContentRequest()
: base(@"https://assets.ppy.sh/lazer-status.json")
{
}

View File

@ -0,0 +1,42 @@
// 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 Newtonsoft.Json;
namespace osu.Game.Online.API.Requests.Responses
{
public class APIMenuContent : IEquatable<APIMenuContent>
{
/// <summary>
/// Images which should be displayed in rotation.
/// </summary>
[JsonProperty(@"images")]
public APIMenuImage[] Images { get; init; } = Array.Empty<APIMenuImage>();
public DateTimeOffset LastUpdated { get; init; }
public bool Equals(APIMenuContent? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return LastUpdated.Equals(other.LastUpdated);
}
public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((APIMenuContent)obj);
}
public override int GetHashCode()
{
return LastUpdated.GetHashCode();
}
}
}

View File

@ -0,0 +1,57 @@
// 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 Newtonsoft.Json;
namespace osu.Game.Online.API.Requests.Responses
{
public class APIMenuImage : IEquatable<APIMenuImage>
{
/// <summary>
/// A URL pointing to the image which should be displayed. Generally should be an @2x image filename.
/// </summary>
[JsonProperty(@"image")]
public string Image { get; init; } = string.Empty;
/// <summary>
/// A URL that should be opened on clicking the image.
/// </summary>
[JsonProperty(@"url")]
public string Url { get; init; } = string.Empty;
/// <summary>
/// The time at which this item should begin displaying. If <c>null</c>, will display immediately.
/// </summary>
[JsonProperty(@"begins")]
public DateTimeOffset? Begins { get; set; }
/// <summary>
/// The time at which this item should stop displaying. If <c>null</c>, will display indefinitely.
/// </summary>
[JsonProperty(@"expires")]
public DateTimeOffset? Expires { get; set; }
public bool Equals(APIMenuImage? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Image == other.Image && Url == other.Url;
}
public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((APIMenuImage)obj);
}
public override int GetHashCode()
{
return HashCode.Combine(Image, Url);
}
}
}

View File

@ -1,30 +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.
using System;
using Newtonsoft.Json;
namespace osu.Game.Online.API.Requests.Responses
{
public class APISystemTitle : IEquatable<APISystemTitle>
{
[JsonProperty(@"image")]
public string Image { get; set; } = string.Empty;
[JsonProperty(@"url")]
public string Url { get; set; } = string.Empty;
public bool Equals(APISystemTitle? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Image == other.Image && Url == other.Url;
}
public override bool Equals(object? obj) => obj is APISystemTitle other && Equals(other);
// ReSharper disable NonReadonlyMemberInGetHashCode
public override int GetHashCode() => HashCode.Combine(Image, Url);
}
}

View File

@ -98,7 +98,7 @@ namespace osu.Game.Screens.Menu
private ParallaxContainer buttonsContainer;
private SongTicker songTicker;
private Container logoTarget;
private SystemTitle systemTitle;
private OnlineMenuBanner onlineMenuBanner;
private MenuTip menuTip;
private FillFlowContainer bottomElementsFlow;
private SupporterDisplay supporterDisplay;
@ -178,7 +178,7 @@ namespace osu.Game.Screens.Menu
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
},
systemTitle = new SystemTitle
onlineMenuBanner = new OnlineMenuBanner
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
@ -201,12 +201,12 @@ namespace osu.Game.Screens.Menu
case ButtonSystemState.Initial:
case ButtonSystemState.Exit:
ApplyToBackground(b => b.FadeColour(Color4.White, 500, Easing.OutSine));
systemTitle.State.Value = Visibility.Hidden;
onlineMenuBanner.State.Value = Visibility.Hidden;
break;
default:
ApplyToBackground(b => b.FadeColour(OsuColour.Gray(0.8f), 500, Easing.OutSine));
systemTitle.State.Value = Visibility.Visible;
onlineMenuBanner.State.Value = Visibility.Visible;
break;
}
};

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Allocation;
@ -18,42 +19,28 @@ using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Screens.Menu
{
public partial class SystemTitle : VisibilityContainer
public partial class OnlineMenuBanner : VisibilityContainer
{
internal Bindable<APISystemTitle?> Current { get; } = new Bindable<APISystemTitle?>();
internal Bindable<APIMenuContent> Current { get; } = new Bindable<APIMenuContent>(new APIMenuContent());
private const float transition_duration = 500;
private Container content = null!;
private CancellationTokenSource? cancellationTokenSource;
private SystemTitleImage? currentImage;
private ScheduledDelegate? openUrlAction;
private MenuImage? currentImage;
[BackgroundDependencyLoader]
private void load(OsuGame? game)
private void load()
{
AutoSizeAxes = Axes.Both;
AutoSizeDuration = transition_duration;
AutoSizeEasing = Easing.OutQuint;
InternalChild = content = new OsuClickableContainer
InternalChild = content = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Action = () =>
{
currentImage?.Flash();
// Delay slightly to allow animation to play out.
openUrlAction?.Cancel();
openUrlAction = Scheduler.AddDelayed(() =>
{
if (!string.IsNullOrEmpty(Current.Value?.Url))
game?.HandleLink(Current.Value.Url);
}, 250);
}
};
}
@ -98,7 +85,7 @@ namespace osu.Game.Screens.Menu
private void checkForUpdates()
{
var request = new GetSystemTitleRequest();
var request = new GetMenuContentRequest();
Task.Run(() => request.Perform())
.ContinueWith(r =>
{
@ -121,12 +108,12 @@ namespace osu.Game.Screens.Menu
cancellationTokenSource = null;
currentImage?.FadeOut(500, Easing.OutQuint).Expire();
if (string.IsNullOrEmpty(Current.Value?.Image))
if (Current.Value.Images.Length == 0)
return;
LoadComponentAsync(new SystemTitleImage(Current.Value), loaded =>
LoadComponentAsync(new MenuImage(Current.Value.Images.First()), loaded =>
{
if (!loaded.SystemTitle.Equals(Current.Value))
if (!loaded.Image.Equals(Current.Value.Images.First()))
loaded.Dispose();
content.Add(currentImage = loaded);
@ -134,22 +121,24 @@ namespace osu.Game.Screens.Menu
}
[LongRunningLoad]
private partial class SystemTitleImage : CompositeDrawable
private partial class MenuImage : OsuClickableContainer
{
public readonly APISystemTitle SystemTitle;
public readonly APIMenuImage Image;
private Sprite flash = null!;
public SystemTitleImage(APISystemTitle systemTitle)
private ScheduledDelegate? openUrlAction;
public MenuImage(APIMenuImage image)
{
SystemTitle = systemTitle;
Image = image;
}
[BackgroundDependencyLoader]
private void load(LargeTextureStore textureStore)
private void load(LargeTextureStore textureStore, OsuGame game)
{
Texture? texture = textureStore.Get(SystemTitle.Image);
if (texture != null && SystemTitle.Image.Contains(@"@2x"))
Texture? texture = textureStore.Get(Image.Image);
if (texture != null && Image.Image.Contains(@"@2x"))
texture.ScaleAdjust *= 2;
AutoSizeAxes = Axes.Both;
@ -163,6 +152,19 @@ namespace osu.Game.Screens.Menu
Blending = BlendingParameters.Additive,
},
};
Action = () =>
{
Flash();
// Delay slightly to allow animation to play out.
openUrlAction?.Cancel();
openUrlAction = Scheduler.AddDelayed(() =>
{
if (!string.IsNullOrEmpty(Image.Url))
game?.HandleLink(Image.Url);
}, 250);
};
}
protected override void LoadComplete()