From f1dd319fd99393c2a9ae2a6741f5621c6d47c77d Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Fri, 15 Apr 2022 15:38:47 +0100 Subject: [PATCH 01/74] Implement `ChannelList` for new chat design Reference design: https://www.figma.com/file/f8b2dHp9LJCMOqYP4mdrPZ/Client%2FChat?node-id=1%3A297 Adds new component `ChannelList` which makes up the sidebar channel selector of the new chat design. Contains two separate fill flows for public and private `ChannelItem` child components. Exposed bindable `SelectorActive` to indicate current state of the "Add more channels" button. Requires `Bindable` from parent component. Renames and updates the `TestSceneChannelListItem` to `TestSceneChannelList` to make use of new component and having both tests seemed redundant. --- .../Visual/Online/TestSceneChannelList.cs | 187 ++++++++++++++++++ .../Visual/Online/TestSceneChannelListItem.cs | 163 --------------- .../Overlays/Chat/ChannelList/ChannelList.cs | 174 ++++++++++++++++ .../Chat/ChannelList/ChannelListSelector.cs | 84 ++++++++ 4 files changed, 445 insertions(+), 163 deletions(-) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneChannelList.cs delete mode 100644 osu.Game.Tests/Visual/Online/TestSceneChannelListItem.cs create mode 100644 osu.Game/Overlays/Chat/ChannelList/ChannelList.cs create mode 100644 osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs new file mode 100644 index 0000000000..d6a1e71f0d --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs @@ -0,0 +1,187 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Framework.Utils; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Chat; +using osu.Game.Overlays; +using osu.Game.Overlays.Chat.ChannelList; + +namespace osu.Game.Tests.Visual.Online +{ + [TestFixture] + public class TestSceneChannelList : OsuTestScene + { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); + + [Cached] + private readonly Bindable selected = new Bindable(); + + private OsuSpriteText selectorText; + private OsuSpriteText selectedText; + private OsuSpriteText leaveText; + private ChannelList channelList; + + [SetUp] + public void SetUp() + { + Schedule(() => + { + Child = new GridContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Height = 0.7f, + RowDimensions = new[] + { + new Dimension(GridSizeMode.Absolute, 20), + new Dimension(GridSizeMode.Absolute, 20), + new Dimension(GridSizeMode.Absolute, 20), + new Dimension(), + }, + Content = new[] + { + new Drawable[] + { + selectorText = new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + }, + new Drawable[] + { + selectedText = new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + }, + new Drawable[] + { + leaveText = new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + }, + new Drawable[] + { + channelList = new ChannelList + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Y, + Width = 190, + }, + }, + }, + }; + + channelList.OnRequestSelect += channel => + { + channelList.SelectorActive.Value = false; + selected.Value = channel; + }; + + channelList.OnRequestLeave += channel => + { + leaveText.Text = $"OnRequestLeave: {channel.Name}"; + leaveText.FadeOutFromOne(1000, Easing.InQuint); + selected.Value = null; + channelList.RemoveChannel(channel); + }; + + channelList.SelectorActive.BindValueChanged(change => + { + selectorText.Text = $"Channel Selector Active: {change.NewValue}"; + }, true); + + selected.BindValueChanged(change => + { + selectedText.Text = $"Selected Channel: {change.NewValue?.Name ?? "[null]"}"; + }, true); + }); + } + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("Add Public Channels", () => + { + for (int i = 0; i < 10; i++) + channelList.AddChannel(createRandomPublicChannel()); + }); + + AddStep("Add Private Channels", () => + { + for (int i = 0; i < 10; i++) + channelList.AddChannel(createRandomPrivateChannel()); + }); + } + + [Test] + public void TestVisual() + { + AddStep("Unread Selected", () => + { + if (selected.Value != null) + channelList.GetItem(selected.Value).Unread.Value = true; + }); + + AddStep("Read Selected", () => + { + if (selected.Value != null) + channelList.GetItem(selected.Value).Unread.Value = false; + }); + + AddStep("Add Mention Selected", () => + { + if (selected.Value != null) + channelList.GetItem(selected.Value).Mentions.Value++; + }); + + AddStep("Add 98 Mentions Selected", () => + { + if (selected.Value != null) + channelList.GetItem(selected.Value).Mentions.Value += 98; + }); + + AddStep("Clear Mentions Selected", () => + { + if (selected.Value != null) + channelList.GetItem(selected.Value).Mentions.Value = 0; + }); + } + + private Channel createRandomPublicChannel() + { + int id = RNG.Next(0, 10000); + return new Channel + { + Name = $"#channel-{id}", + Type = ChannelType.Public, + Id = id, + }; + } + + private Channel createRandomPrivateChannel() + { + int id = RNG.Next(0, 10000); + return new Channel(new APIUser + { + Id = id, + Username = $"test user {id}", + }); + } + } +} diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelListItem.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelListItem.cs deleted file mode 100644 index af419c8b91..0000000000 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelListItem.cs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using NUnit.Framework; -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics.Sprites; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Online.Chat; -using osu.Game.Overlays; -using osu.Game.Overlays.Chat.ChannelList; -using osuTK; - -namespace osu.Game.Tests.Visual.Online -{ - [TestFixture] - public class TestSceneChannelListItem : OsuTestScene - { - [Cached] - private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); - - [Cached] - private readonly Bindable selected = new Bindable(); - - private static readonly List channels = new List - { - createPublicChannel("#public-channel"), - createPublicChannel("#public-channel-long-name"), - createPrivateChannel("test user", 2), - createPrivateChannel("test user long name", 3), - }; - - private readonly Dictionary channelMap = new Dictionary(); - - private FillFlowContainer flow; - private OsuSpriteText selectedText; - private OsuSpriteText leaveText; - - [SetUp] - public void SetUp() - { - Schedule(() => - { - foreach (var item in channelMap.Values) - item.Expire(); - - channelMap.Clear(); - - Child = new FillFlowContainer - { - Direction = FillDirection.Vertical, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Spacing = new Vector2(10), - Children = new Drawable[] - { - selectedText = new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - }, - leaveText = new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Height = 16, - AlwaysPresent = true, - }, - new Container - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - AutoSizeAxes = Axes.Y, - Width = 190, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background6, - }, - flow = new FillFlowContainer - { - Direction = FillDirection.Vertical, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }, - }, - }, - }, - }; - - selected.BindValueChanged(change => - { - selectedText.Text = $"Selected Channel: {change.NewValue?.Name ?? "[null]"}"; - }, true); - - foreach (var channel in channels) - { - var item = new ChannelListItem(channel); - flow.Add(item); - channelMap.Add(channel, item); - item.OnRequestSelect += c => selected.Value = c; - item.OnRequestLeave += leaveChannel; - } - }); - } - - [Test] - public void TestVisual() - { - AddStep("Select second item", () => selected.Value = channels.Skip(1).First()); - - AddStep("Unread Selected", () => - { - if (selected.Value != null) - channelMap[selected.Value].Unread.Value = true; - }); - - AddStep("Read Selected", () => - { - if (selected.Value != null) - channelMap[selected.Value].Unread.Value = false; - }); - - AddStep("Add Mention Selected", () => - { - if (selected.Value != null) - channelMap[selected.Value].Mentions.Value++; - }); - - AddStep("Add 98 Mentions Selected", () => - { - if (selected.Value != null) - channelMap[selected.Value].Mentions.Value += 98; - }); - - AddStep("Clear Mentions Selected", () => - { - if (selected.Value != null) - channelMap[selected.Value].Mentions.Value = 0; - }); - } - - private void leaveChannel(Channel channel) - { - leaveText.Text = $"OnRequestLeave: {channel.Name}"; - leaveText.FadeOutFromOne(1000, Easing.InQuint); - } - - private static Channel createPublicChannel(string name) => - new Channel { Name = name, Type = ChannelType.Public, Id = 1234 }; - - private static Channel createPrivateChannel(string username, int id) - => new Channel(new APIUser { Id = id, Username = username }); - } -} diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs new file mode 100644 index 0000000000..4ffb6be451 --- /dev/null +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -0,0 +1,174 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using System; +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Chat; +using osuTK; + +namespace osu.Game.Overlays.Chat.ChannelList +{ + public class ChannelList : Container + { + public Action? OnRequestSelect; + public Action? OnRequestLeave; + + public readonly BindableBool SelectorActive = new BindableBool(); + + private readonly Dictionary channelMap = new Dictionary(); + + private ChannelListItemFlow publicChannelFlow = null!; + private ChannelListItemFlow privateChannelFlow = null!; + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background6, + }, + new ChannelListScrollContainer + { + Padding = new MarginPadding { Vertical = 7 }, + RelativeSizeAxes = Axes.Both, + ScrollbarAnchor = Anchor.TopLeft, + ScrollDistance = 35f, + Child = new FillFlowContainer + { + Direction = FillDirection.Vertical, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + publicChannelFlow = new ChannelListItemFlow("CHANNELS"), + new ChannelListSelector + { + Margin = new MarginPadding { Bottom = 10 }, + SelectorActive = { BindTarget = SelectorActive }, + }, + privateChannelFlow = new ChannelListItemFlow("DIRECT MESSAGES"), + }, + }, + }, + }; + } + + public void AddChannel(Channel channel) + { + if (channelMap.ContainsKey(channel)) + return; + + ChannelListItem item = new ChannelListItem(channel); + item.OnRequestSelect += channel => this.OnRequestSelect?.Invoke(channel); + item.OnRequestLeave += channel => this.OnRequestLeave?.Invoke(channel); + + ChannelListItemFlow flow = getFlowForChannel(channel); + channelMap.Add(channel, item); + flow.Add(item); + } + + public void RemoveChannel(Channel channel) + { + if (!channelMap.ContainsKey(channel)) + return; + + ChannelListItem item = channelMap[channel]; + ChannelListItemFlow flow = getFlowForChannel(channel); + + channelMap.Remove(channel); + flow.Remove(item); + item.Expire(); + } + + public ChannelListItem GetItem(Channel channel) + { + if (!channelMap.ContainsKey(channel)) + throw new ArgumentOutOfRangeException(); + + return channelMap[channel]; + } + + private ChannelListItemFlow getFlowForChannel(Channel channel) + { + switch (channel.Type) + { + case ChannelType.Public: + return publicChannelFlow; + + case ChannelType.PM: + return privateChannelFlow; + + default: + throw new ArgumentOutOfRangeException(); + } + } + + private class ChannelListItemFlow : FillFlowContainer + { + public ChannelListItemFlow(string label) + { + Direction = FillDirection.Vertical; + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + Add(new OsuSpriteText + { + Text = label, + Margin = new MarginPadding { Left = 18, Bottom = 5 }, + Font = OsuFont.Torus.With(size: 12), + }); + } + } + + private class ChannelListScrollContainer : OsuScrollContainer + { + protected override bool OnHover(HoverEvent e) + { + ScrollbarVisible = true; + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + ScrollbarVisible = false; + base.OnHoverLost(e); + } + + protected override ScrollbarContainer CreateScrollbar(Direction direction) + => new ChannelListScrollBar(direction); + + protected class ChannelListScrollBar : OsuScrollbar + { + private const float BAR_SIZE = 4; + private const float BAR_MARGIN = 7; + + public ChannelListScrollBar(Direction scrollDir) : base(scrollDir) + { + Size = new Vector2(BAR_SIZE); + Margin = new MarginPadding { Left = BAR_MARGIN }; + CornerRadius = 2; + } + + public override void ResizeTo(float val, int duration = 0, Easing easing = Easing.None) + { + Vector2 size = new Vector2(BAR_SIZE, val); + this.ResizeTo(size, duration, easing); + } + } + } + } +} diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs new file mode 100644 index 0000000000..5bc9a01598 --- /dev/null +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs @@ -0,0 +1,84 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Overlays.Chat.ChannelList +{ + public class ChannelListSelector : OsuClickableContainer + { + public readonly BindableBool SelectorActive = new BindableBool(); + + private Box hoverBox = null!; + private Box selectBox = null!; + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Height = 30; + RelativeSizeAxes = Axes.X; + + Children = new Drawable[] + { + hoverBox = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background3, + Alpha = 0f, + }, + selectBox = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background4, + Alpha = 0f, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = 18, Right = 10 }, + Child = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = "Add More Channels", + Font = OsuFont.Torus.With(size: 17, weight: FontWeight.SemiBold), + Colour = colourProvider.Light3, + Margin = new MarginPadding { Bottom = 2 }, + RelativeSizeAxes = Axes.X, + Truncate = true, + }, + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + SelectorActive.BindValueChanged(selected => selectBox.FadeTo(selected.NewValue ? 1 : 0)); + Action = () => SelectorActive.Value = true; + } + + protected override bool OnHover(HoverEvent e) + { + hoverBox.FadeIn(300, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + hoverBox.FadeOut(200, Easing.OutQuint); + base.OnHoverLost(e); + } + } +} From a0a2f8118e520003c23993bb2074d5664803758f Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Fri, 15 Apr 2022 22:05:20 +0100 Subject: [PATCH 02/74] Code quality fixes --- osu.Game/Overlays/Chat/ChannelList/ChannelList.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index 4ffb6be451..9fcd675dc5 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -73,8 +73,8 @@ namespace osu.Game.Overlays.Chat.ChannelList return; ChannelListItem item = new ChannelListItem(channel); - item.OnRequestSelect += channel => this.OnRequestSelect?.Invoke(channel); - item.OnRequestLeave += channel => this.OnRequestLeave?.Invoke(channel); + item.OnRequestSelect += chan => OnRequestSelect?.Invoke(chan); + item.OnRequestLeave += chan => OnRequestLeave?.Invoke(chan); ChannelListItemFlow flow = getFlowForChannel(channel); channelMap.Add(channel, item); @@ -153,19 +153,19 @@ namespace osu.Game.Overlays.Chat.ChannelList protected class ChannelListScrollBar : OsuScrollbar { - private const float BAR_SIZE = 4; - private const float BAR_MARGIN = 7; + private const float bar_size = 4; + private const float bar_margin = 7; public ChannelListScrollBar(Direction scrollDir) : base(scrollDir) { - Size = new Vector2(BAR_SIZE); - Margin = new MarginPadding { Left = BAR_MARGIN }; + Size = new Vector2(bar_size); + Margin = new MarginPadding { Left = bar_margin }; CornerRadius = 2; } public override void ResizeTo(float val, int duration = 0, Easing easing = Easing.None) { - Vector2 size = new Vector2(BAR_SIZE, val); + Vector2 size = new Vector2(bar_size, val); this.ResizeTo(size, duration, easing); } } From b6631fb9f97e5add211cc4187fef2f03210b71fd Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Fri, 15 Apr 2022 22:22:20 +0100 Subject: [PATCH 03/74] Add newline for base class call --- osu.Game/Overlays/Chat/ChannelList/ChannelList.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index 9fcd675dc5..94c05770ab 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -156,7 +156,8 @@ namespace osu.Game.Overlays.Chat.ChannelList private const float bar_size = 4; private const float bar_margin = 7; - public ChannelListScrollBar(Direction scrollDir) : base(scrollDir) + public ChannelListScrollBar(Direction scrollDir) + : base(scrollDir) { Size = new Vector2(bar_size); Margin = new MarginPadding { Left = bar_margin }; From 4a0c5a07813fb94107e40acc9295f3f315abdf08 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sat, 16 Apr 2022 19:16:06 +0100 Subject: [PATCH 04/74] Remove hover override for `ChannelListScrollContainer` --- osu.Game/Overlays/Chat/ChannelList/ChannelList.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index 94c05770ab..ef2f132501 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -10,7 +10,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -136,18 +135,6 @@ namespace osu.Game.Overlays.Chat.ChannelList private class ChannelListScrollContainer : OsuScrollContainer { - protected override bool OnHover(HoverEvent e) - { - ScrollbarVisible = true; - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - ScrollbarVisible = false; - base.OnHoverLost(e); - } - protected override ScrollbarContainer CreateScrollbar(Direction direction) => new ChannelListScrollBar(direction); From 36aea9009e754ebd18872d259a137e2df8f52a88 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sat, 16 Apr 2022 19:19:18 +0100 Subject: [PATCH 05/74] Move `ChannelList` scrollbar to the right --- osu.Game/Overlays/Chat/ChannelList/ChannelList.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index ef2f132501..759242a779 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -44,7 +44,7 @@ namespace osu.Game.Overlays.Chat.ChannelList { Padding = new MarginPadding { Vertical = 7 }, RelativeSizeAxes = Axes.Both, - ScrollbarAnchor = Anchor.TopLeft, + ScrollbarAnchor = Anchor.TopRight, ScrollDistance = 35f, Child = new FillFlowContainer { @@ -147,7 +147,7 @@ namespace osu.Game.Overlays.Chat.ChannelList : base(scrollDir) { Size = new Vector2(bar_size); - Margin = new MarginPadding { Left = bar_margin }; + Margin = new MarginPadding { Horizontal = bar_margin }; CornerRadius = 2; } From 2f41cddb00124179b13ae5c69a633f00805dbec9 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sat, 16 Apr 2022 19:28:24 +0100 Subject: [PATCH 06/74] Remove redundant `Expire` call --- osu.Game/Overlays/Chat/ChannelList/ChannelList.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index 759242a779..250e0cdf21 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -90,7 +90,6 @@ namespace osu.Game.Overlays.Chat.ChannelList channelMap.Remove(channel); flow.Remove(item); - item.Expire(); } public ChannelListItem GetItem(Channel channel) From 47c8b8010f1580ee9c7e583d0340f85f4c791e1d Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sat, 16 Apr 2022 19:30:03 +0100 Subject: [PATCH 07/74] Use semibold font weight for `ChannelListItemFlow` label --- osu.Game/Overlays/Chat/ChannelList/ChannelList.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index 250e0cdf21..5c2a1ad89f 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -127,7 +127,7 @@ namespace osu.Game.Overlays.Chat.ChannelList { Text = label, Margin = new MarginPadding { Left = 18, Bottom = 5 }, - Font = OsuFont.Torus.With(size: 12), + Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold), }); } } From 67c44db8d5aad22d8eb381574fb7421495840c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 27 Mar 2022 22:55:52 +0200 Subject: [PATCH 08/74] Add extension points required for replacing old mod overlay --- osu.Game/Overlays/Mods/ModColumn.cs | 7 +- osu.Game/Overlays/Mods/ModSelectScreen.cs | 89 +++++++++++++++++------ 2 files changed, 71 insertions(+), 25 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index f84ae4ac8a..abd243e1f7 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -54,6 +54,8 @@ namespace osu.Game.Overlays.Mods public Bindable> SelectedMods = new Bindable>(Array.Empty()); + protected virtual ModPanel CreateModPanel(Mod mod) => new ModPanel(mod); + private readonly Key[]? toggleKeys; private readonly Bindable>> availableMods = new Bindable>>(); @@ -258,10 +260,7 @@ namespace osu.Game.Overlays.Mods cancellationTokenSource?.Cancel(); - var panels = newMods.Select(mod => new ModPanel(mod) - { - Shear = new Vector2(-ModPanel.SHEAR_X, 0) - }); + var panels = newMods.Select(mod => CreateModPanel(mod).With(panel => panel.Shear = new Vector2(-ModPanel.SHEAR_X, 0))); Task? loadTask; diff --git a/osu.Game/Overlays/Mods/ModSelectScreen.cs b/osu.Game/Overlays/Mods/ModSelectScreen.cs index 62080ec1b5..d174474076 100644 --- a/osu.Game/Overlays/Mods/ModSelectScreen.cs +++ b/osu.Game/Overlays/Mods/ModSelectScreen.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +#nullable enable + using System; using System.Collections.Generic; using System.Diagnostics; @@ -31,16 +33,43 @@ namespace osu.Game.Overlays.Mods protected override bool StartHidden => true; + private Func isValidMod = m => true; + + public Func IsValidMod + { + get => isValidMod; + set + { + isValidMod = value ?? throw new ArgumentNullException(nameof(value)); + + if (IsLoaded) + updateAvailableMods(); + } + } + + /// + /// Whether configurable s can be configured by the local user. + /// + protected virtual bool AllowConfiguration => true; + + /// + /// Whether the total score multiplier calculated from the current selected set of mods should be shown. + /// + protected virtual bool ShowTotalMultiplier => true; + + protected virtual ModColumn CreateModColumn(ModType modType, Key[]? toggleKeys = null) => new ModColumn(modType, false, toggleKeys); + private readonly BindableBool customisationVisible = new BindableBool(); - private DifficultyMultiplierDisplay multiplierDisplay; - private ModSettingsArea modSettingsArea; - private FillFlowContainer columnFlow; - private GridContainer grid; - private Container mainContent; + private DifficultyMultiplierDisplay? multiplierDisplay; + private ModSettingsArea modSettingsArea = null!; + private Container aboveColumnsContainer = null!; + private FillFlowContainer columnFlow = null!; + private GridContainer grid = null!; + private Container mainContent = null!; - private PopupScreenTitle header; - private Container footer; + private PopupScreenTitle header = null!; + private Container footer = null!; [BackgroundDependencyLoader] private void load() @@ -82,7 +111,7 @@ namespace osu.Game.Overlays.Mods }, new Drawable[] { - new Container + aboveColumnsContainer = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -94,11 +123,6 @@ namespace osu.Game.Overlays.Mods { Horizontal = 100, Vertical = 10 - }, - Child = multiplierDisplay = new DifficultyMultiplierDisplay - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre } } }, @@ -126,11 +150,11 @@ namespace osu.Game.Overlays.Mods Margin = new MarginPadding { Right = 70 }, Children = new[] { - new ModColumn(ModType.DifficultyReduction, false, new[] { Key.Q, Key.W, Key.E, Key.R, Key.T, Key.Y, Key.U, Key.I, Key.O, Key.P }), - new ModColumn(ModType.DifficultyIncrease, false, new[] { Key.A, Key.S, Key.D, Key.F, Key.G, Key.H, Key.J, Key.K, Key.L }), - new ModColumn(ModType.Automation, false, new[] { Key.Z, Key.X, Key.C, Key.V, Key.B, Key.N, Key.M }), - new ModColumn(ModType.Conversion, false), - new ModColumn(ModType.Fun, false) + CreateModColumn(ModType.DifficultyReduction, new[] { Key.Q, Key.W, Key.E, Key.R, Key.T, Key.Y, Key.U, Key.I, Key.O, Key.P }), + CreateModColumn(ModType.DifficultyIncrease, new[] { Key.A, Key.S, Key.D, Key.F, Key.G, Key.H, Key.J, Key.K, Key.L }), + CreateModColumn(ModType.Automation, new[] { Key.Z, Key.X, Key.C, Key.V, Key.B, Key.N, Key.M }), + CreateModColumn(ModType.Conversion), + CreateModColumn(ModType.Fun) } } } @@ -182,6 +206,15 @@ namespace osu.Game.Overlays.Mods } }; + if (ShowTotalMultiplier) + { + aboveColumnsContainer.Add(multiplierDisplay = new DifficultyMultiplierDisplay + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight + }); + } + columnFlow.Shear = new Vector2(ModPanel.SHEAR_X, 0); } @@ -204,10 +237,15 @@ namespace osu.Game.Overlays.Mods } customisationVisible.BindValueChanged(_ => updateCustomisationVisualState(), true); + + updateAvailableMods(); } private void updateMultiplier() { + if (multiplierDisplay == null) + return; + double multiplier = 1.0; foreach (var mod in SelectedMods.Value) @@ -216,8 +254,17 @@ namespace osu.Game.Overlays.Mods multiplierDisplay.Current.Value = multiplier; } + private void updateAvailableMods() + { + foreach (var column in columnFlow) + column.Filter = isValidMod; + } + private void updateCustomisation(ValueChangedEvent> valueChangedEvent) { + if (!AllowConfiguration) + return; + bool anyCustomisableMod = false; bool anyModWithRequiredCustomisationAdded = false; @@ -292,7 +339,7 @@ namespace osu.Game.Overlays.Mods header.MoveToY(0, fade_in_duration, Easing.OutQuint); footer.MoveToY(0, fade_in_duration, Easing.OutQuint); - multiplierDisplay + multiplierDisplay? .Delay(fade_in_duration * 0.65f) .FadeIn(fade_in_duration / 2, Easing.OutQuint) .ScaleTo(1, fade_in_duration, Easing.OutElastic); @@ -313,7 +360,7 @@ namespace osu.Game.Overlays.Mods base.PopOut(); this.FadeOut(fade_out_duration, Easing.OutQuint); - multiplierDisplay + multiplierDisplay? .FadeOut(fade_out_duration / 2, Easing.OutQuint) .ScaleTo(0.75f, fade_out_duration, Easing.OutQuint); @@ -368,7 +415,7 @@ namespace osu.Game.Overlays.Mods { public BindableBool HandleMouse { get; } = new BindableBool(); - public Action OnClicked { get; set; } + public Action? OnClicked { get; set; } protected override bool Handle(UIEvent e) { From 7eebc2012465f58c95b6ff3bc2bb452f30d1a314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 27 Mar 2022 23:07:52 +0200 Subject: [PATCH 09/74] Add replacements for mod overlays used by game --- osu.Game/Overlays/Mods/UserModSelectScreen.cs | 24 +++++++++++++++ .../Screens/OnlinePlay/FreeModSelectScreen.cs | 29 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 osu.Game/Overlays/Mods/UserModSelectScreen.cs create mode 100644 osu.Game/Screens/OnlinePlay/FreeModSelectScreen.cs diff --git a/osu.Game/Overlays/Mods/UserModSelectScreen.cs b/osu.Game/Overlays/Mods/UserModSelectScreen.cs new file mode 100644 index 0000000000..81943da514 --- /dev/null +++ b/osu.Game/Overlays/Mods/UserModSelectScreen.cs @@ -0,0 +1,24 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using JetBrains.Annotations; +using osu.Game.Rulesets.Mods; +using osuTK.Input; + +namespace osu.Game.Overlays.Mods +{ + public class UserModSelectScreen : ModSelectScreen + { + protected override ModColumn CreateModColumn(ModType modType, Key[] toggleKeys = null) => new UserModColumn(modType, false, toggleKeys); + + private class UserModColumn : ModColumn + { + public UserModColumn(ModType modType, bool allowBulkSelection, [CanBeNull] Key[] toggleKeys = null) + : base(modType, allowBulkSelection, toggleKeys) + { + } + + protected override ModPanel CreateModPanel(Mod mod) => new IncompatibilityDisplayingModPanel(mod); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/FreeModSelectScreen.cs b/osu.Game/Screens/OnlinePlay/FreeModSelectScreen.cs new file mode 100644 index 0000000000..438b334e0b --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/FreeModSelectScreen.cs @@ -0,0 +1,29 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Game.Overlays.Mods; +using osu.Game.Rulesets.Mods; +using osuTK.Input; + +namespace osu.Game.Screens.OnlinePlay +{ + public class FreeModSelectScreen : ModSelectScreen + { + protected override bool AllowConfiguration => false; + protected override bool ShowTotalMultiplier => false; + + public new Func IsValidMod + { + get => base.IsValidMod; + set => base.IsValidMod = m => m.HasImplementation && m.UserPlayable && value.Invoke(m); + } + + public FreeModSelectScreen() + { + IsValidMod = _ => true; + } + + protected override ModColumn CreateModColumn(ModType modType, Key[] toggleKeys = null) => new ModColumn(modType, true, toggleKeys); + } +} From 20c17b8c98448f7ad1a93b53ebb259b8961765db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 3 Apr 2022 19:42:52 +0200 Subject: [PATCH 10/74] Make base mod select screen abstract --- .../Visual/UserInterface/TestSceneModSelectScreen.cs | 4 ++-- osu.Game/Overlays/Mods/ModSelectScreen.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectScreen.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectScreen.cs index 34d9ddcc4e..4a738cb29d 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectScreen.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectScreen.cs @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.UserInterface [Resolved] private RulesetStore rulesetStore { get; set; } - private ModSelectScreen modSelectScreen; + private UserModSelectScreen modSelectScreen; [SetUpSteps] public void SetUpSteps() @@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual.UserInterface private void createScreen() { - AddStep("create screen", () => Child = modSelectScreen = new ModSelectScreen + AddStep("create screen", () => Child = modSelectScreen = new UserModSelectScreen { RelativeSizeAxes = Axes.Both, State = { Value = Visibility.Visible }, diff --git a/osu.Game/Overlays/Mods/ModSelectScreen.cs b/osu.Game/Overlays/Mods/ModSelectScreen.cs index d174474076..ad111cd5b9 100644 --- a/osu.Game/Overlays/Mods/ModSelectScreen.cs +++ b/osu.Game/Overlays/Mods/ModSelectScreen.cs @@ -23,7 +23,7 @@ using osuTK.Input; namespace osu.Game.Overlays.Mods { - public class ModSelectScreen : OsuFocusedOverlayContainer + public abstract class ModSelectScreen : OsuFocusedOverlayContainer { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); From 9942b0a9467cf51fb6284d157fbc67ea78107af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 3 Apr 2022 19:53:05 +0200 Subject: [PATCH 11/74] Add test scene for free mod select screen --- .../TestSceneFreeModSelectScreen.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectScreen.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectScreen.cs new file mode 100644 index 0000000000..974cd710f7 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectScreen.cs @@ -0,0 +1,28 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Graphics.Containers; +using osu.Game.Screens.OnlinePlay; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneFreeModSelectScreen : MultiplayerTestScene + { + [Test] + public void TestFreeModSelect() + { + FreeModSelectScreen freeModSelectScreen = null; + + AddStep("create free mod select screen", () => Child = freeModSelectScreen = new FreeModSelectScreen + { + State = { Value = Visibility.Visible } + }); + AddToggleStep("toggle visibility", visible => + { + if (freeModSelectScreen != null) + freeModSelectScreen.State.Value = visible ? Visibility.Visible : Visibility.Hidden; + }); + } + } +} From 4b6d42c7e890bcd797535fc6c5203e4fc70112aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 17 Apr 2022 16:54:30 +0200 Subject: [PATCH 12/74] Add assertion covering free mod selection mod validity filter --- .../Visual/Multiplayer/TestSceneFreeModSelectScreen.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectScreen.cs index 974cd710f7..0db05e3a6a 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectScreen.cs @@ -1,8 +1,11 @@ // Copyright (c) ppy Pty Ltd . 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.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Overlays.Mods; using osu.Game.Screens.OnlinePlay; namespace osu.Game.Tests.Visual.Multiplayer @@ -18,6 +21,12 @@ namespace osu.Game.Tests.Visual.Multiplayer { State = { Value = Visibility.Visible } }); + + AddAssert("all visible mods are playable", + () => this.ChildrenOfType() + .Where(panel => panel.IsPresent) + .All(panel => panel.Mod.HasImplementation && panel.Mod.UserPlayable)); + AddToggleStep("toggle visibility", visible => { if (freeModSelectScreen != null) From ffb5c1e86c71003c6d6f8cda6e173948936e64f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 17 Apr 2022 16:58:02 +0200 Subject: [PATCH 13/74] Tweak colours on incompatibility displaying mod panel --- osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs index 4b6759c209..6c6c36eec9 100644 --- a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs +++ b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs @@ -46,8 +46,8 @@ namespace osu.Game.Overlays.Mods if (incompatible.Value) { - Colour4 backgroundColour = ColourProvider.Background5; - Colour4 textBackgroundColour = ColourProvider.Background4; + Colour4 backgroundColour = ColourProvider.Background6; + Colour4 textBackgroundColour = ColourProvider.Background5; Content.TransformTo(nameof(BorderColour), ColourInfo.GradientVertical(backgroundColour, textBackgroundColour), TRANSITION_DURATION, Easing.OutQuint); Background.FadeColour(backgroundColour, TRANSITION_DURATION, Easing.OutQuint); From 8af865a1c5766d850743f2654b48a50a63aa3316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 17 Apr 2022 21:20:16 +0200 Subject: [PATCH 14/74] Fix incompatibility panel using reference equality --- osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs index 6c6c36eec9..38781455fa 100644 --- a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs +++ b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs @@ -37,7 +37,9 @@ namespace osu.Game.Overlays.Mods private void updateIncompatibility() { - incompatible.Value = selectedMods.Value.Count > 0 && !selectedMods.Value.Contains(Mod) && !ModUtils.CheckCompatibleSet(selectedMods.Value.Append(Mod)); + incompatible.Value = selectedMods.Value.Count > 0 + && selectedMods.Value.All(selected => selected.GetType() != Mod.GetType()) + && !ModUtils.CheckCompatibleSet(selectedMods.Value.Append(Mod)); } protected override void UpdateState() From 881df7663d8ee8fab93759c57651e78c4ddfcab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 17 Apr 2022 22:30:02 +0200 Subject: [PATCH 15/74] Fix filter not taking effect if applied before panel load completion --- osu.Game/Overlays/Mods/ModPanel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModPanel.cs b/osu.Game/Overlays/Mods/ModPanel.cs index 312171cf74..c9aaa1c6c0 100644 --- a/osu.Game/Overlays/Mods/ModPanel.cs +++ b/osu.Game/Overlays/Mods/ModPanel.cs @@ -159,7 +159,7 @@ namespace osu.Game.Overlays.Mods playStateChangeSamples(); UpdateState(); }); - Filtered.BindValueChanged(_ => updateFilterState()); + Filtered.BindValueChanged(_ => updateFilterState(), true); UpdateState(); FinishTransforms(true); From 0d5ce336f49cfe4a475c6b587fc9c1e3dc52f3bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 17 Apr 2022 23:26:25 +0200 Subject: [PATCH 16/74] Hide mod customisation toggle if customisation not permitted --- osu.Game/Overlays/Mods/ModSelectScreen.cs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectScreen.cs b/osu.Game/Overlays/Mods/ModSelectScreen.cs index ad111cd5b9..237af2a71d 100644 --- a/osu.Game/Overlays/Mods/ModSelectScreen.cs +++ b/osu.Game/Overlays/Mods/ModSelectScreen.cs @@ -180,14 +180,6 @@ namespace osu.Game.Overlays.Mods Origin = Anchor.BottomCentre, Colour = colourProvider.Background5 }, - new ShearedToggleButton(200) - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Margin = new MarginPadding { Vertical = 14, Left = 70 }, - Text = "Mod Customisation", - Active = { BindTarget = customisationVisible } - } } }, new ClickToReturnContainer @@ -206,6 +198,18 @@ namespace osu.Game.Overlays.Mods } }; + if (AllowConfiguration) + { + footer.Add(new ShearedToggleButton(200) + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Margin = new MarginPadding { Vertical = 14, Left = 70 }, + Text = "Mod Customisation", + Active = { BindTarget = customisationVisible } + }); + } + if (ShowTotalMultiplier) { aboveColumnsContainer.Add(multiplierDisplay = new DifficultyMultiplierDisplay From 338d94626e5cb5f86ce924c76e0cea3b16970a1f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 18 Apr 2022 06:42:06 +0300 Subject: [PATCH 17/74] Expose underlying skin of `EditorBeatmapSkin` --- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index 429df85904..243a994a7f 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -21,13 +21,18 @@ namespace osu.Game.Screens.Edit { public event Action BeatmapSkinChanged; + /// + /// The underlying beatmap skin. + /// + protected internal ISkin Skin => skin; + + private readonly Skin skin; + /// /// The combo colours of this skin. /// If empty, the default combo colours will be used. /// - public readonly BindableList ComboColours; - - private readonly Skin skin; + public BindableList ComboColours { get; } public EditorBeatmapSkin(Skin skin) { From 80cce7c3cb1d5c840ec6bbb599a3bcdf3baf1e17 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 18 Apr 2022 06:46:06 +0300 Subject: [PATCH 18/74] Add failing test case --- .../Visual/Editing/TestSceneComposeScreen.cs | 63 +++++++++++++------ 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs index d100fba8d6..30c8539d85 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs @@ -1,44 +1,71 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose; +using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Editing { [TestFixture] public class TestSceneComposeScreen : EditorClockTestScene { - [Cached(typeof(EditorBeatmap))] - [Cached(typeof(IBeatSnapProvider))] - private readonly EditorBeatmap editorBeatmap = - new EditorBeatmap(new OsuBeatmap - { - BeatmapInfo = - { - Ruleset = new OsuRuleset().RulesetInfo - } - }); + private EditorBeatmap editorBeatmap; [Cached] private EditorClipboard clipboard = new EditorClipboard(); - protected override void LoadComplete() + [SetUpSteps] + public void SetUpSteps() { - base.LoadComplete(); - - Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); - - Child = new ComposeScreen + AddStep("setup compose screen", () => { - State = { Value = Visibility.Visible }, - }; + var beatmap = new OsuBeatmap + { + BeatmapInfo = { Ruleset = new OsuRuleset().RulesetInfo } + }; + + editorBeatmap = new EditorBeatmap(beatmap, new LegacyBeatmapSkin(beatmap.BeatmapInfo, null)); + + Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); + + Child = new DependencyProvidingContainer + { + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] + { + (typeof(EditorBeatmap), editorBeatmap), + (typeof(IBeatSnapProvider), editorBeatmap), + }, + Child = new ComposeScreen { State = { Value = Visibility.Visible } }, + }; + }); + + AddUntilStep("wait for composer", () => this.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); + } + + /// + /// Ensures that the skin of the edited beatmap is properly wrapped in a . + /// + [Test] + public void TestLegacyBeatmapSkinHasTransformer() + { + AddAssert("legacy beatmap skin has transformer", () => + { + var sources = this.ChildrenOfType().First().AllSources; + return sources.OfType().Count(t => t.Skin == editorBeatmap.BeatmapSkin.AsNonNull().Skin) == 1; + }); } } } From 2cb217e06c04d63de4bc4151c7631b9abc448062 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 18 Apr 2022 06:59:44 +0300 Subject: [PATCH 19/74] Fix editor legacy beatmap skins not receiving transformer --- osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs b/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs index decfa879a8..694d0253e0 100644 --- a/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs +++ b/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.Edit private readonly EditorBeatmapSkin? beatmapSkin; public EditorSkinProvidingContainer(EditorBeatmap editorBeatmap) - : base(editorBeatmap.PlayableBeatmap.BeatmapInfo.Ruleset.CreateInstance(), editorBeatmap.PlayableBeatmap, editorBeatmap.BeatmapSkin) + : base(editorBeatmap.PlayableBeatmap.BeatmapInfo.Ruleset.CreateInstance(), editorBeatmap.PlayableBeatmap, editorBeatmap.BeatmapSkin?.Skin) { beatmapSkin = editorBeatmap.BeatmapSkin; } From 90093c1d9d3fab7757218cdb021f08c64cdd1fe7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 13:32:37 +0900 Subject: [PATCH 20/74] Combine `private` skin variable into exposed one --- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index 243a994a7f..f650ffa5a3 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -24,9 +24,7 @@ namespace osu.Game.Screens.Edit /// /// The underlying beatmap skin. /// - protected internal ISkin Skin => skin; - - private readonly Skin skin; + protected internal readonly Skin Skin; /// /// The combo colours of this skin. @@ -36,11 +34,11 @@ namespace osu.Game.Screens.Edit public EditorBeatmapSkin(Skin skin) { - this.skin = skin; + Skin = skin; ComboColours = new BindableList(); - if (skin.Configuration.ComboColours != null) - ComboColours.AddRange(skin.Configuration.ComboColours.Select(c => (Colour4)c)); + if (Skin.Configuration.ComboColours != null) + ComboColours.AddRange(Skin.Configuration.ComboColours.Select(c => (Colour4)c)); ComboColours.BindCollectionChanged((_, __) => updateColours()); } @@ -48,16 +46,16 @@ namespace osu.Game.Screens.Edit private void updateColours() { - skin.Configuration.CustomComboColours = ComboColours.Select(c => (Color4)c).ToList(); + Skin.Configuration.CustomComboColours = ComboColours.Select(c => (Color4)c).ToList(); invokeSkinChanged(); } #region Delegated ISkin implementation - public Drawable GetDrawableComponent(ISkinComponent component) => skin.GetDrawableComponent(component); - public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => skin.GetTexture(componentName, wrapModeS, wrapModeT); - public ISample GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo); - public IBindable GetConfig(TLookup lookup) => skin.GetConfig(lookup); + public Drawable GetDrawableComponent(ISkinComponent component) => Skin.GetDrawableComponent(component); + public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => Skin.GetTexture(componentName, wrapModeS, wrapModeT); + public ISample GetSample(ISampleInfo sampleInfo) => Skin.GetSample(sampleInfo); + public IBindable GetConfig(TLookup lookup) => Skin.GetConfig(lookup); #endregion } From 2202863e1a1caf323aa341dec967fdaaefd4a237 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 17:49:28 +0900 Subject: [PATCH 21/74] Split out `IPerformFromScreenRunner` to allow for easier testing --- osu.Game/OsuGame.cs | 8 +----- .../Dashboard/CurrentlyPlayingDisplay.cs | 5 ++-- .../Sections/DebugSettings/GeneralSettings.cs | 5 ++-- .../StableDirectoryLocationDialog.cs | 7 ++--- osu.Game/Screens/IPerformFromScreenRunner.cs | 26 +++++++++++++++++++ osu.Game/Screens/Menu/MainMenu.cs | 4 +-- .../Skinning/Editor/SkinEditorSceneLibrary.cs | 7 ++--- 7 files changed, 43 insertions(+), 19 deletions(-) create mode 100644 osu.Game/Screens/IPerformFromScreenRunner.cs diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 73121f6e7d..76ccbe0a08 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -63,7 +63,7 @@ namespace osu.Game /// The full osu! experience. Builds on top of to add menus and binding logic /// for initial components that are generally retrieved via DI. /// - public class OsuGame : OsuGameBase, IKeyBindingHandler, ILocalUserPlayInfo + public class OsuGame : OsuGameBase, IKeyBindingHandler, ILocalUserPlayInfo, IPerformFromScreenRunner { /// /// The amount of global offset to apply when a left/right anchored overlay is displayed (ie. settings or notifications). @@ -586,12 +586,6 @@ namespace osu.Game private PerformFromMenuRunner performFromMainMenuTask; - /// - /// Perform an action only after returning to a specific screen as indicated by . - /// Eagerly tries to exit the current screen until it succeeds. - /// - /// The action to perform once we are in the correct state. - /// An optional collection of valid screen types. If any of these screens are already current we can perform the action immediately, else the first valid parent will be made current before performing the action. is used if not specified. public void PerformFromScreen(Action action, IEnumerable validScreens = null) { performFromMainMenuTask?.Cancel(); diff --git a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs index 117de88166..786401b7a8 100644 --- a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs +++ b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs @@ -14,6 +14,7 @@ using osu.Game.Database; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Spectator; +using osu.Game.Screens; using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.Play; using osu.Game.Users; @@ -106,7 +107,7 @@ namespace osu.Game.Overlays.Dashboard public readonly APIUser User; [Resolved(canBeNull: true)] - private OsuGame game { get; set; } + private IPerformFromScreenRunner performer { get; set; } public PlayingUserPanel(APIUser user) { @@ -140,7 +141,7 @@ namespace osu.Game.Overlays.Dashboard Text = "Watch", Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Action = () => game?.PerformFromScreen(s => s.Push(new SoloSpectator(User))), + Action = () => performer?.PerformFromScreen(s => s.Push(new SoloSpectator(User))), Enabled = { Value = User.Id != api.LocalUser.Value.Id } } } diff --git a/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs index 60540a089e..8833420523 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Framework.Screens; using osu.Game.Localisation; +using osu.Game.Screens; using osu.Game.Screens.Import; namespace osu.Game.Overlays.Settings.Sections.DebugSettings @@ -16,7 +17,7 @@ namespace osu.Game.Overlays.Settings.Sections.DebugSettings protected override LocalisableString Header => DebugSettingsStrings.GeneralHeader; [BackgroundDependencyLoader(true)] - private void load(FrameworkDebugConfigManager config, FrameworkConfigManager frameworkConfig, OsuGame game) + private void load(FrameworkDebugConfigManager config, FrameworkConfigManager frameworkConfig, IPerformFromScreenRunner performer) { Children = new Drawable[] { @@ -34,7 +35,7 @@ namespace osu.Game.Overlays.Settings.Sections.DebugSettings Add(new SettingsButton { Text = DebugSettingsStrings.ImportFiles, - Action = () => game?.PerformFromScreen(menu => menu.Push(new FileImportScreen())) + Action = () => performer?.PerformFromScreen(menu => menu.Push(new FileImportScreen())) }); } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs index 904c9deaae..4e81cd63b8 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs @@ -6,13 +6,14 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using osu.Framework.Screens; using osu.Game.Overlays.Dialog; +using osu.Game.Screens; namespace osu.Game.Overlays.Settings.Sections.Maintenance { public class StableDirectoryLocationDialog : PopupDialog { - [Resolved] - private OsuGame game { get; set; } + [Resolved(canBeNull: true)] + private IPerformFromScreenRunner performer { get; set; } public StableDirectoryLocationDialog(TaskCompletionSource taskCompletionSource) { @@ -25,7 +26,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance new PopupDialogOkButton { Text = "Sure! I know where it is located!", - Action = () => Schedule(() => game.PerformFromScreen(screen => screen.Push(new StableDirectorySelectScreen(taskCompletionSource)))) + Action = () => Schedule(() => performer.PerformFromScreen(screen => screen.Push(new StableDirectorySelectScreen(taskCompletionSource)))) }, new PopupDialogCancelButton { diff --git a/osu.Game/Screens/IPerformFromScreenRunner.cs b/osu.Game/Screens/IPerformFromScreenRunner.cs new file mode 100644 index 0000000000..655bebdeb0 --- /dev/null +++ b/osu.Game/Screens/IPerformFromScreenRunner.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Screens; +using osu.Game.Screens.Menu; + +namespace osu.Game.Screens +{ + /// + /// Manages a global screen stack to allow nested components a guarantee of where work is executed. + /// + [Cached] + public interface IPerformFromScreenRunner + { + /// + /// Perform an action only after returning to a specific screen as indicated by . + /// Eagerly tries to exit the current screen until it succeeds. + /// + /// The action to perform once we are in the correct state. + /// An optional collection of valid screen types. If any of these screens are already current we can perform the action immediately, else the first valid parent will be made current before performing the action. is used if not specified. + void PerformFromScreen(Action action, IEnumerable validScreens = null); + } +} diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index e2d79b4015..442a536cf9 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -148,14 +148,14 @@ namespace osu.Game.Screens.Menu } [Resolved(canBeNull: true)] - private OsuGame game { get; set; } + private IPerformFromScreenRunner performer { get; set; } private void confirmAndExit() { if (exitConfirmed) return; exitConfirmed = true; - game?.PerformFromScreen(menu => menu.Exit()); + performer?.PerformFromScreen(menu => menu.Exit()); } private void preloadSongSelect() diff --git a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs index 0808cd157f..4507526806 100644 --- a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs @@ -15,6 +15,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; +using osu.Game.Screens; using osu.Game.Screens.Play; using osu.Game.Screens.Select; using osuTK; @@ -28,7 +29,7 @@ namespace osu.Game.Skinning.Editor private const float padding = 10; [Resolved(canBeNull: true)] - private OsuGame game { get; set; } + private IPerformFromScreenRunner performer { get; set; } [Resolved] private IBindable ruleset { get; set; } @@ -75,7 +76,7 @@ namespace osu.Game.Skinning.Editor Text = "Song Select", Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Action = () => game?.PerformFromScreen(screen => + Action = () => performer?.PerformFromScreen(screen => { if (screen is SongSelect) return; @@ -88,7 +89,7 @@ namespace osu.Game.Skinning.Editor Text = "Gameplay", Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Action = () => game?.PerformFromScreen(screen => + Action = () => performer?.PerformFromScreen(screen => { if (screen is Player) return; From e3153132666a911dc2ac47d759d6a7654b128f59 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 18:09:14 +0900 Subject: [PATCH 22/74] Split out `IDialogOverlay` to allow for easier testing --- .../TestSceneManageCollectionsDialog.cs | 2 +- .../Visual/Navigation/TestSceneOsuGame.cs | 2 +- .../Navigation/TestScenePerformFromScreen.cs | 11 ++++--- .../Navigation/TestSceneScreenNavigation.cs | 13 ++++---- .../TestSceneDeleteLocalScore.cs | 2 +- .../UserInterface/TestSceneDialogOverlay.cs | 2 +- .../Collections/DrawableCollectionListItem.cs | 2 +- osu.Game/Database/LegacyImportManager.cs | 2 +- osu.Game/Online/Chat/ExternalLinkOpener.cs | 2 +- .../Online/Leaderboards/LeaderboardScore.cs | 2 +- osu.Game/Overlays/Dialog/PopupDialog.cs | 2 +- osu.Game/Overlays/DialogOverlay.cs | 2 +- osu.Game/Overlays/IDialogOverlay.cs | 31 +++++++++++++++++++ .../Sections/Maintenance/GeneralSettings.cs | 2 +- .../Maintenance/MigrationSelectScreen.cs | 2 +- osu.Game/PerformFromMenuRunner.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/Menu/MainMenu.cs | 2 +- osu.Game/Screens/Menu/StorageErrorDialog.cs | 2 +- .../Multiplayer/MultiplayerMatchSubScreen.cs | 2 +- .../Carousel/DrawableCarouselBeatmapSet.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 4 +-- osu.Game/Tests/Visual/EditorTestScene.cs | 2 +- osu.Game/Tests/Visual/ScreenTestScene.cs | 2 +- 24 files changed, 66 insertions(+), 33 deletions(-) create mode 100644 osu.Game/Overlays/IDialogOverlay.cs diff --git a/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs b/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs index e40dd58663..51ca55f37f 100644 --- a/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs +++ b/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs @@ -50,7 +50,7 @@ namespace osu.Game.Tests.Visual.Collections }); Dependencies.Cache(manager); - Dependencies.Cache(dialogOverlay); + Dependencies.CacheAs(dialogOverlay); } [SetUp] diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs index b8d1636ea0..921d088fc7 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs @@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Navigation typeof(LoginOverlay), typeof(MusicController), typeof(AccountCreationOverlay), - typeof(DialogOverlay), + typeof(IDialogOverlay), typeof(ScreenshotManager) }; diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs index f045e3a3e8..c4099b55c7 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs @@ -5,6 +5,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Framework.Testing; @@ -113,12 +114,12 @@ namespace osu.Game.Tests.Visual.Navigation AddAssert("did not perform", () => !actionPerformed); AddAssert("only one exit attempt", () => blocker.ExitAttempts == 1); - AddUntilStep("wait for dialog display", () => Game.Dependencies.Get().IsLoaded); + AddUntilStep("wait for dialog display", () => ((Drawable)Game.Dependencies.Get()).IsLoaded); if (confirmed) { AddStep("accept dialog", () => InputManager.Key(Key.Number1)); - AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get().CurrentDialog == null); + AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get().CurrentDialog == null); AddUntilStep("did perform", () => actionPerformed); } else @@ -145,7 +146,7 @@ namespace osu.Game.Tests.Visual.Navigation AddWaitStep("wait a bit", 10); - AddUntilStep("wait for dialog display", () => Game.Dependencies.Get().IsLoaded); + AddUntilStep("wait for dialog display", () => ((Drawable)Game.Dependencies.Get()).IsLoaded); AddAssert("screen didn't change", () => Game.ScreenStack.CurrentScreen == blocker2); AddAssert("did not perform", () => !actionPerformed); @@ -187,7 +188,7 @@ namespace osu.Game.Tests.Visual.Navigation AddWaitStep("wait a bit", 10); - AddUntilStep("wait for dialog display", () => Game.Dependencies.Get().IsLoaded); + AddUntilStep("wait for dialog display", () => ((Drawable)Game.Dependencies.Get()).IsLoaded); AddAssert("screen didn't change", () => Game.ScreenStack.CurrentScreen == screenWithNestedStack); AddAssert("nested screen didn't change", () => screenWithNestedStack.SubScreenStack.CurrentScreen == screenWithNestedStack.Blocker); @@ -221,7 +222,7 @@ namespace osu.Game.Tests.Visual.Navigation public class DialogBlockingScreen : OsuScreen { [Resolved] - private DialogOverlay dialogOverlay { get; set; } + private IDialogOverlay dialogOverlay { get; set; } private int dialogDisplayCount; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 394976eb43..0b7242eee0 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -6,6 +6,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Screens; @@ -200,10 +201,10 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("choose clear all scores", () => InputManager.Key(Key.Number4)); - AddUntilStep("wait for dialog display", () => Game.Dependencies.Get().IsLoaded); - AddUntilStep("wait for dialog", () => Game.Dependencies.Get().CurrentDialog != null); + AddUntilStep("wait for dialog display", () => ((Drawable)Game.Dependencies.Get()).IsLoaded); + AddUntilStep("wait for dialog", () => Game.Dependencies.Get().CurrentDialog != null); AddStep("confirm deletion", () => InputManager.Key(Key.Number1)); - AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get().CurrentDialog == null); + AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get().CurrentDialog == null); AddUntilStep("ensure score is pending deletion", () => Game.Realm.Run(r => r.Find(score.ID)?.DeletePending == true)); @@ -246,10 +247,10 @@ namespace osu.Game.Tests.Visual.Navigation InputManager.Click(MouseButton.Left); }); - AddUntilStep("wait for dialog display", () => Game.Dependencies.Get().IsLoaded); - AddUntilStep("wait for dialog", () => Game.Dependencies.Get().CurrentDialog != null); + AddUntilStep("wait for dialog display", () => ((Drawable)Game.Dependencies.Get()).IsLoaded); + AddUntilStep("wait for dialog", () => Game.Dependencies.Get().CurrentDialog != null); AddStep("confirm deletion", () => InputManager.Key(Key.Number1)); - AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get().CurrentDialog == null); + AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get().CurrentDialog == null); AddUntilStep("ensure score is pending deletion", () => Game.Realm.Run(r => r.Find(score.ID)?.DeletePending == true)); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index 72dfc53c01..1350052ae6 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.UserInterface private BeatmapInfo beatmapInfo; - [Cached] + [Cached(typeof(IDialogOverlay))] private readonly DialogOverlay dialogOverlay; public TestSceneDeleteLocalScore() diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs index 405461eec8..17234f4022 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs @@ -11,7 +11,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneDialogOverlay : OsuTestScene + public class TestSceneIDialogOverlay : OsuTestScene { private DialogOverlay overlay; diff --git a/osu.Game/Collections/DrawableCollectionListItem.cs b/osu.Game/Collections/DrawableCollectionListItem.cs index c4cb040b52..5a20b7e7bd 100644 --- a/osu.Game/Collections/DrawableCollectionListItem.cs +++ b/osu.Game/Collections/DrawableCollectionListItem.cs @@ -158,7 +158,7 @@ namespace osu.Game.Collections public Func IsTextBoxHovered; [Resolved(CanBeNull = true)] - private DialogOverlay dialogOverlay { get; set; } + private IDialogOverlay dialogOverlay { get; set; } [Resolved(CanBeNull = true)] private CollectionManager collectionManager { get; set; } diff --git a/osu.Game/Database/LegacyImportManager.cs b/osu.Game/Database/LegacyImportManager.cs index 4dc26b18bb..59394c2952 100644 --- a/osu.Game/Database/LegacyImportManager.cs +++ b/osu.Game/Database/LegacyImportManager.cs @@ -40,7 +40,7 @@ namespace osu.Game.Database private OsuGame game { get; set; } [Resolved] - private DialogOverlay dialogOverlay { get; set; } + private IDialogOverlay dialogOverlay { get; set; } [Resolved(CanBeNull = true)] private DesktopGameHost desktopGameHost { get; set; } diff --git a/osu.Game/Online/Chat/ExternalLinkOpener.cs b/osu.Game/Online/Chat/ExternalLinkOpener.cs index 328b43c4e8..20d8459132 100644 --- a/osu.Game/Online/Chat/ExternalLinkOpener.cs +++ b/osu.Game/Online/Chat/ExternalLinkOpener.cs @@ -17,7 +17,7 @@ namespace osu.Game.Online.Chat private GameHost host { get; set; } [Resolved(CanBeNull = true)] - private DialogOverlay dialogOverlay { get; set; } + private IDialogOverlay dialogOverlay { get; set; } private Bindable externalLinkWarning; diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index ddd9d9a2b2..eecb7ff6b3 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -64,7 +64,7 @@ namespace osu.Game.Online.Leaderboards private List statisticsLabels; [Resolved(CanBeNull = true)] - private DialogOverlay dialogOverlay { get; set; } + private IDialogOverlay dialogOverlay { get; set; } [Resolved(CanBeNull = true)] private SongSelect songSelect { get; set; } diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 6159ab59f0..9fd1a32e84 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -216,7 +216,7 @@ namespace osu.Game.Overlays.Dialog }; // It's important we start in a visible state so our state fires on hide, even before load. - // This is used by the DialogOverlay to know when the dialog was dismissed. + // This is used by the IDialogOverlay to know when the dialog was dismissed. Show(); } diff --git a/osu.Game/Overlays/DialogOverlay.cs b/osu.Game/Overlays/DialogOverlay.cs index 9dea1ca00a..15d89a561a 100644 --- a/osu.Game/Overlays/DialogOverlay.cs +++ b/osu.Game/Overlays/DialogOverlay.cs @@ -14,7 +14,7 @@ using osu.Game.Audio.Effects; namespace osu.Game.Overlays { - public class DialogOverlay : OsuFocusedOverlayContainer + public class DialogOverlay : OsuFocusedOverlayContainer, IDialogOverlay { private readonly Container dialogContainer; diff --git a/osu.Game/Overlays/IDialogOverlay.cs b/osu.Game/Overlays/IDialogOverlay.cs new file mode 100644 index 0000000000..07f28a7204 --- /dev/null +++ b/osu.Game/Overlays/IDialogOverlay.cs @@ -0,0 +1,31 @@ +#nullable enable +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Game.Overlays.Dialog; + +namespace osu.Game.Overlays +{ + /// + /// A global overlay that can show popup dialogs. + /// + [Cached] + public interface IDialogOverlay + { + /// + /// Push a new dialog for display. + /// + /// + /// This will immediate dismiss any already displayed dialog (cancelling the action). + /// If the dialog instance provided is already displayed, it will be a noop. + /// + /// The dialog to be presented. + void Push(PopupDialog dialog); + + /// + /// The currently displayed dialog, if any. + /// + PopupDialog? CurrentDialog { get; } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index aa02d086f4..be4b0decd9 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -30,7 +30,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private SettingsButton undeleteButton; [BackgroundDependencyLoader(permitNulls: true)] - private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, [CanBeNull] CollectionManager collectionManager, [CanBeNull] LegacyImportManager legacyImportManager, DialogOverlay dialogOverlay) + private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, [CanBeNull] CollectionManager collectionManager, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay) { if (legacyImportManager?.SupportsImportFromStable == true) { diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs index 0304a4291a..3cb5521e51 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs @@ -23,7 +23,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private OsuGameBase game { get; set; } [Resolved(canBeNull: true)] - private DialogOverlay dialogOverlay { get; set; } + private IDialogOverlay dialogOverlay { get; set; } protected override DirectoryInfo InitialPath => new DirectoryInfo(storage.GetFullPath(string.Empty)).Parent; diff --git a/osu.Game/PerformFromMenuRunner.cs b/osu.Game/PerformFromMenuRunner.cs index 528470768c..7039d5379c 100644 --- a/osu.Game/PerformFromMenuRunner.cs +++ b/osu.Game/PerformFromMenuRunner.cs @@ -26,7 +26,7 @@ namespace osu.Game private NotificationOverlay notifications { get; set; } [Resolved] - private DialogOverlay dialogOverlay { get; set; } + private IDialogOverlay dialogOverlay { get; set; } [Resolved(canBeNull: true)] private OsuGame game { get; set; } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 57f7429e06..255571dfdb 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -84,7 +84,7 @@ namespace osu.Game.Screens.Edit private Storage storage { get; set; } [Resolved(canBeNull: true)] - private DialogOverlay dialogOverlay { get; set; } + private IDialogOverlay dialogOverlay { get; set; } [Resolved(canBeNull: true)] private NotificationOverlay notifications { get; set; } diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index e2d79b4015..9e6af860fc 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -60,7 +60,7 @@ namespace osu.Game.Screens.Menu private IAPIProvider api { get; set; } [Resolved(canBeNull: true)] - private DialogOverlay dialogOverlay { get; set; } + private IDialogOverlay dialogOverlay { get; set; } private BackgroundScreenDefault background; diff --git a/osu.Game/Screens/Menu/StorageErrorDialog.cs b/osu.Game/Screens/Menu/StorageErrorDialog.cs index 250623ec68..f4c77d5d8f 100644 --- a/osu.Game/Screens/Menu/StorageErrorDialog.cs +++ b/osu.Game/Screens/Menu/StorageErrorDialog.cs @@ -13,7 +13,7 @@ namespace osu.Game.Screens.Menu public class StorageErrorDialog : PopupDialog { [Resolved] - private DialogOverlay dialogOverlay { get; set; } + private IDialogOverlay dialogOverlay { get; set; } public StorageErrorDialog(OsuStorage storage, OsuStorageError error) { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 7ef0bb5923..0dbf73fc5b 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -238,7 +238,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer } [Resolved(canBeNull: true)] - private DialogOverlay dialogOverlay { get; set; } + private IDialogOverlay dialogOverlay { get; set; } private bool exitConfirmed; diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 618c5cf5ec..2d70b1aecb 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Select.Carousel private Action viewDetails; [Resolved(CanBeNull = true)] - private DialogOverlay dialogOverlay { get; set; } + private IDialogOverlay dialogOverlay { get; set; } [Resolved(CanBeNull = true)] private CollectionManager collectionManager { get; set; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 2d1a2bce4e..dc505063d1 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -87,7 +87,7 @@ namespace osu.Game.Screens.Select protected Container LeftArea { get; private set; } private BeatmapInfoWedge beatmapInfoWedge; - private DialogOverlay dialogOverlay; + private IDialogOverlay dialogOverlay; [Resolved] private BeatmapManager beatmaps { get; set; } @@ -114,7 +114,7 @@ namespace osu.Game.Screens.Select private MusicController music { get; set; } [BackgroundDependencyLoader(true)] - private void load(AudioManager audio, DialogOverlay dialog, OsuColour colours, ManageCollectionsDialog manageCollectionsDialog, DifficultyRecommender recommender) + private void load(AudioManager audio, IDialogOverlay dialog, OsuColour colours, ManageCollectionsDialog manageCollectionsDialog, DifficultyRecommender recommender) { // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). transferRulesetValue(); diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 51221cb8fe..ca12bc73fe 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual { [Resolved(canBeNull: true)] [CanBeNull] - private DialogOverlay dialogOverlay { get; set; } + private IDialogOverlay dialogOverlay { get; set; } public new void Undo() => base.Undo(); diff --git a/osu.Game/Tests/Visual/ScreenTestScene.cs b/osu.Game/Tests/Visual/ScreenTestScene.cs index b6f6ca6daa..e9069d8c9c 100644 --- a/osu.Game/Tests/Visual/ScreenTestScene.cs +++ b/osu.Game/Tests/Visual/ScreenTestScene.cs @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual protected override Container Content => content; - [Cached] + [Cached(typeof(IDialogOverlay))] protected DialogOverlay DialogOverlay { get; private set; } protected ScreenTestScene() From 25f1f772f3d6cad2a0bb9728057e106588555bd0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 18:36:22 +0900 Subject: [PATCH 23/74] Allow caching via `loadComponentSingleFile` with interface specification --- 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 73121f6e7d..f8bc32431c 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -825,7 +825,7 @@ namespace osu.Game }, rightFloatingOverlayContent.Add, true); loadComponentSingleFile(new AccountCreationOverlay(), topMostOverlayContent.Add, true); - loadComponentSingleFile(new DialogOverlay(), topMostOverlayContent.Add, true); + loadComponentSingleFile(new DialogOverlay(), topMostOverlayContent.Add, true); loadComponentSingleFile(CreateHighPerformanceSession(), Add); @@ -982,12 +982,15 @@ namespace osu.Game /// The component to load. /// An action to invoke on load completion (generally to add the component to the hierarchy). /// Whether to cache the component as type into the game dependencies before any scheduling. - private T loadComponentSingleFile(T component, Action loadCompleteAction, bool cache = false) - where T : Drawable + private T loadComponentSingleFile(T component, Action loadCompleteAction, bool cache = false) + where T : class { if (cache) dependencies.CacheAs(component); + var drawableComponent = component as Drawable; + Debug.Assert(drawableComponent != null); + if (component is OsuFocusedOverlayContainer overlay) focusedOverlays.Add(overlay); @@ -1011,7 +1014,7 @@ namespace osu.Game // Since this is running in a separate thread, it is possible for OsuGame to be disposed after LoadComponentAsync has been called // throwing an exception. To avoid this, the call is scheduled on the update thread, which does not run if IsDisposed = true Task task = null; - var del = new ScheduledDelegate(() => task = LoadComponentAsync(component, loadCompleteAction)); + var del = new ScheduledDelegate(() => task = LoadComponentAsync(drawableComponent, loadCompleteAction)); Scheduler.Add(del); // The delegate won't complete if OsuGame has been disposed in the meantime From fea4632e839207ae1b183878aff42a437e271fa6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 20:04:19 +0900 Subject: [PATCH 24/74] Convert assert to hard throw --- osu.Game/OsuGame.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index f8bc32431c..e10da39055 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -988,8 +988,7 @@ namespace osu.Game if (cache) dependencies.CacheAs(component); - var drawableComponent = component as Drawable; - Debug.Assert(drawableComponent != null); + var drawableComponent = component as Drawable ?? throw new ArgumentException($"Component must be a {nameof(Drawable)}", nameof(component)); if (component is OsuFocusedOverlayContainer overlay) focusedOverlays.Add(overlay); From d86e3abf2c5d4857062cf23d680fa40f94006a0e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 20:04:38 +0900 Subject: [PATCH 25/74] Fix invalid rename --- osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs index 17234f4022..405461eec8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs @@ -11,7 +11,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneIDialogOverlay : OsuTestScene + public class TestSceneDialogOverlay : OsuTestScene { private DialogOverlay overlay; From 72a33c0926dde589b5dc1c2ffabdcf5184bdb474 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 20:06:08 +0900 Subject: [PATCH 26/74] Split out step for dialog overlay load wait --- .../Visual/Navigation/TestScenePerformFromScreen.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs index c4099b55c7..559e6ddd89 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs @@ -114,7 +114,7 @@ namespace osu.Game.Tests.Visual.Navigation AddAssert("did not perform", () => !actionPerformed); AddAssert("only one exit attempt", () => blocker.ExitAttempts == 1); - AddUntilStep("wait for dialog display", () => ((Drawable)Game.Dependencies.Get()).IsLoaded); + waitForDialogOverlayLoad(); if (confirmed) { @@ -146,7 +146,7 @@ namespace osu.Game.Tests.Visual.Navigation AddWaitStep("wait a bit", 10); - AddUntilStep("wait for dialog display", () => ((Drawable)Game.Dependencies.Get()).IsLoaded); + waitForDialogOverlayLoad(); AddAssert("screen didn't change", () => Game.ScreenStack.CurrentScreen == blocker2); AddAssert("did not perform", () => !actionPerformed); @@ -188,7 +188,7 @@ namespace osu.Game.Tests.Visual.Navigation AddWaitStep("wait a bit", 10); - AddUntilStep("wait for dialog display", () => ((Drawable)Game.Dependencies.Get()).IsLoaded); + waitForDialogOverlayLoad(); AddAssert("screen didn't change", () => Game.ScreenStack.CurrentScreen == screenWithNestedStack); AddAssert("nested screen didn't change", () => screenWithNestedStack.SubScreenStack.CurrentScreen == screenWithNestedStack.Blocker); @@ -212,6 +212,8 @@ namespace osu.Game.Tests.Visual.Navigation } } + private void waitForDialogOverlayLoad() => AddUntilStep("wait for dialog overlay loaded", () => ((Drawable)Game.Dependencies.Get()).IsLoaded); + private void importAndWaitForSongSelect() { AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely()); From 043599081bc29f81fa6888d48d214d1cc505edb3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 19:59:57 +0900 Subject: [PATCH 27/74] Split out `INotificationOverlay` to allow for easier testing --- .../Security/ElevatedPrivilegesChecker.cs | 2 +- osu.Desktop/Updater/SquirrelUpdateManager.cs | 2 +- osu.Game.Tests/Visual/Menus/IntroTestScene.cs | 2 +- .../Visual/Navigation/TestSceneOsuGame.cs | 2 +- .../Visual/Online/TestSceneMessageNotifier.cs | 2 +- osu.Game/Database/EFToRealmMigrator.cs | 2 +- osu.Game/Graphics/ScreenshotManager.cs | 2 +- osu.Game/Online/Chat/MessageNotifier.cs | 4 +-- osu.Game/OsuGame.cs | 2 +- .../BeatmapSet/Buttons/FavouriteButton.cs | 2 +- osu.Game/Overlays/INotificationOverlay.cs | 26 +++++++++++++++++++ osu.Game/Overlays/NotificationOverlay.cs | 6 +---- .../Sections/General/UpdateSettings.cs | 2 +- .../Maintenance/MigrationRunScreen.cs | 2 +- osu.Game/PerformFromMenuRunner.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/Menu/ButtonSystem.cs | 2 +- osu.Game/Screens/Menu/IntroScreen.cs | 2 +- osu.Game/Screens/Play/HUDOverlay.cs | 2 +- osu.Game/Screens/Play/PlayerLoader.cs | 4 +-- osu.Game/Screens/Select/PlaySongSelect.cs | 2 +- osu.Game/Updater/UpdateManager.cs | 4 +-- 22 files changed, 50 insertions(+), 28 deletions(-) create mode 100644 osu.Game/Overlays/INotificationOverlay.cs diff --git a/osu.Desktop/Security/ElevatedPrivilegesChecker.cs b/osu.Desktop/Security/ElevatedPrivilegesChecker.cs index 8f3ad853dc..ba37a14442 100644 --- a/osu.Desktop/Security/ElevatedPrivilegesChecker.cs +++ b/osu.Desktop/Security/ElevatedPrivilegesChecker.cs @@ -19,7 +19,7 @@ namespace osu.Desktop.Security public class ElevatedPrivilegesChecker : Component { [Resolved] - private NotificationOverlay notifications { get; set; } + private INotificationOverlay notifications { get; set; } private bool elevated; diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs index b307146b10..bae850fce1 100644 --- a/osu.Desktop/Updater/SquirrelUpdateManager.cs +++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs @@ -25,7 +25,7 @@ namespace osu.Desktop.Updater public class SquirrelUpdateManager : osu.Game.Updater.UpdateManager { private UpdateManager updateManager; - private NotificationOverlay notificationOverlay; + private INotificationOverlay notificationOverlay; public Task PrepareUpdateAsync() => UpdateManager.RestartAppWhenExited(); diff --git a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs index 82accceb23..c68cd39c65 100644 --- a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs +++ b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs @@ -26,7 +26,7 @@ namespace osu.Game.Tests.Visual.Menus private IntroScreen intro; - [Cached] + [Cached(typeof(INotificationOverlay))] private NotificationOverlay notifications; private ScheduledDelegate trackResetDelegate; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs index 921d088fc7..0f8337deb6 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs @@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Navigation typeof(OsuLogo), typeof(IdleTracker), typeof(OnScreenDisplay), - typeof(NotificationOverlay), + typeof(INotificationOverlay), typeof(BeatmapListingOverlay), typeof(DashboardOverlay), typeof(NewsOverlay), diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 2c253650d5..79f62a16e3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -200,7 +200,7 @@ namespace osu.Game.Tests.Visual.Online [Cached] public ChannelManager ChannelManager { get; } = new ChannelManager(); - [Cached] + [Cached(typeof(INotificationOverlay))] public NotificationOverlay NotificationOverlay { get; } = new NotificationOverlay { Anchor = Anchor.TopRight, diff --git a/osu.Game/Database/EFToRealmMigrator.cs b/osu.Game/Database/EFToRealmMigrator.cs index ae73e13b77..4e98b7d3d2 100644 --- a/osu.Game/Database/EFToRealmMigrator.cs +++ b/osu.Game/Database/EFToRealmMigrator.cs @@ -52,7 +52,7 @@ namespace osu.Game.Database private OsuConfigManager config { get; set; } = null!; [Resolved] - private NotificationOverlay notificationOverlay { get; set; } = null!; + private INotificationOverlay notificationOverlay { get; set; } = null!; [Resolved] private OsuGame game { get; set; } = null!; diff --git a/osu.Game/Graphics/ScreenshotManager.cs b/osu.Game/Graphics/ScreenshotManager.cs index b0f20de685..a2f1a3d7b9 100644 --- a/osu.Game/Graphics/ScreenshotManager.cs +++ b/osu.Game/Graphics/ScreenshotManager.cs @@ -43,7 +43,7 @@ namespace osu.Game.Graphics private Storage storage; [Resolved] - private NotificationOverlay notificationOverlay { get; set; } + private INotificationOverlay notificationOverlay { get; set; } private Sample shutter; diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 20c33db61f..ca6082e19b 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -24,7 +24,7 @@ namespace osu.Game.Online.Chat public class MessageNotifier : Component { [Resolved] - private NotificationOverlay notifications { get; set; } + private INotificationOverlay notifications { get; set; } [Resolved] private ChatOverlay chatOverlay { get; set; } @@ -170,7 +170,7 @@ namespace osu.Game.Online.Chat public override bool IsImportant => false; [BackgroundDependencyLoader] - private void load(OsuColour colours, ChatOverlay chatOverlay, NotificationOverlay notificationOverlay) + private void load(OsuColour colours, ChatOverlay chatOverlay, INotificationOverlay notificationOverlay) { IconBackground.Colour = colours.PurpleDark; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e10da39055..45d76cc15b 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -778,7 +778,7 @@ namespace osu.Game loadComponentSingleFile(onScreenDisplay, Add, true); - loadComponentSingleFile(Notifications.With(d => + loadComponentSingleFile(Notifications.With(d => { d.Anchor = Anchor.TopRight; d.Origin = Anchor.TopRight; diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs index 8fe7450873..28100e5fff 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs @@ -41,7 +41,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons } [BackgroundDependencyLoader(true)] - private void load(IAPIProvider api, NotificationOverlay notifications) + private void load(IAPIProvider api, INotificationOverlay notifications) { SpriteIcon icon; diff --git a/osu.Game/Overlays/INotificationOverlay.cs b/osu.Game/Overlays/INotificationOverlay.cs new file mode 100644 index 0000000000..432dd2be54 --- /dev/null +++ b/osu.Game/Overlays/INotificationOverlay.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Game.Overlays.Notifications; + +namespace osu.Game.Overlays +{ + /// + /// An overlay which is capable of showing notifications to the user. + /// + [Cached] + public interface INotificationOverlay + { + /// + /// Post a new notification for display. + /// + /// The notification to display. + void Post(Notification notification); + + /// + /// Hide the overlay, if it is currently visible. + /// + void Hide(); + } +} diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index e4e3931048..0e8fbc6680 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -19,7 +19,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays { - public class NotificationOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent + public class NotificationOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent, INotificationOverlay { public string IconTexture => "Icons/Hexacons/notification"; public LocalisableString Title => NotificationsStrings.HeaderTitle; @@ -111,10 +111,6 @@ namespace osu.Game.Overlays private double? lastSamplePlayback; - /// - /// Post a new notification for display. - /// - /// The notification to display. public void Post(Notification notification) => postScheduler.Add(() => { ++runningDepth; diff --git a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs index 0b4eca6379..5bc88b8692 100644 --- a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs @@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Settings.Sections.General private SettingsButton checkForUpdatesButton; [Resolved(CanBeNull = true)] - private NotificationOverlay notifications { get; set; } + private INotificationOverlay notifications { get; set; } [BackgroundDependencyLoader(true)] private void load(Storage storage, OsuConfigManager config, OsuGame game) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs index fb7ff0dbd1..10d6f0aef5 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs @@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private OsuGame game { get; set; } [Resolved] - private NotificationOverlay notifications { get; set; } + private INotificationOverlay notifications { get; set; } [Resolved] private Storage storage { get; set; } diff --git a/osu.Game/PerformFromMenuRunner.cs b/osu.Game/PerformFromMenuRunner.cs index 7039d5379c..ae9879fb5a 100644 --- a/osu.Game/PerformFromMenuRunner.cs +++ b/osu.Game/PerformFromMenuRunner.cs @@ -23,7 +23,7 @@ namespace osu.Game private readonly Func getCurrentScreen; [Resolved] - private NotificationOverlay notifications { get; set; } + private INotificationOverlay notifications { get; set; } [Resolved] private IDialogOverlay dialogOverlay { get; set; } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 255571dfdb..602b7563ac 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -87,7 +87,7 @@ namespace osu.Game.Screens.Edit private IDialogOverlay dialogOverlay { get; set; } [Resolved(canBeNull: true)] - private NotificationOverlay notifications { get; set; } + private INotificationOverlay notifications { get; set; } public readonly Bindable Mode = new Bindable(); diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 8eeb90a3fd..598c441042 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -118,7 +118,7 @@ namespace osu.Game.Screens.Menu private IAPIProvider api { get; set; } [Resolved(CanBeNull = true)] - private NotificationOverlay notifications { get; set; } + private INotificationOverlay notifications { get; set; } [Resolved(CanBeNull = true)] private LoginOverlay loginOverlay { get; set; } diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index e569b0e517..5575d3681f 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -171,7 +171,7 @@ namespace osu.Game.Screens.Menu } [Resolved] - private NotificationOverlay notifications { get; set; } + private INotificationOverlay notifications { get; set; } private void ensureEventuallyArrivingAtMenu() { diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 628452fbc8..676a08b434 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -119,7 +119,7 @@ namespace osu.Game.Screens.Play } [BackgroundDependencyLoader(true)] - private void load(OsuConfigManager config, NotificationOverlay notificationOverlay) + private void load(OsuConfigManager config, INotificationOverlay notificationOverlay) { if (drawableRuleset != null) { diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index ba720af2a1..b72ec373d7 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -515,7 +515,7 @@ namespace osu.Game.Screens.Play } [BackgroundDependencyLoader] - private void load(OsuColour colours, AudioManager audioManager, NotificationOverlay notificationOverlay, VolumeOverlay volumeOverlay) + private void load(OsuColour colours, AudioManager audioManager, INotificationOverlay notificationOverlay, VolumeOverlay volumeOverlay) { Icon = FontAwesome.Solid.VolumeMute; IconBackground.Colour = colours.RedDark; @@ -567,7 +567,7 @@ namespace osu.Game.Screens.Play } [BackgroundDependencyLoader] - private void load(OsuColour colours, NotificationOverlay notificationOverlay) + private void load(OsuColour colours, INotificationOverlay notificationOverlay) { Icon = FontAwesome.Solid.BatteryQuarter; IconBackground.Colour = colours.RedDark; diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 593436bbb7..4a991ffc66 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Select private OsuScreen playerLoader; [Resolved(CanBeNull = true)] - private NotificationOverlay notifications { get; set; } + private INotificationOverlay notifications { get; set; } public override bool AllowExternalScreenChange => true; diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs index 9b9f354d23..c17d8304b9 100644 --- a/osu.Game/Updater/UpdateManager.cs +++ b/osu.Game/Updater/UpdateManager.cs @@ -31,7 +31,7 @@ namespace osu.Game.Updater private OsuGameBase game { get; set; } [Resolved] - protected NotificationOverlay Notifications { get; private set; } + protected INotificationOverlay Notifications { get; private set; } protected override void LoadComplete() { @@ -94,7 +94,7 @@ namespace osu.Game.Updater } [BackgroundDependencyLoader] - private void load(OsuColour colours, ChangelogOverlay changelog, NotificationOverlay notificationOverlay) + private void load(OsuColour colours, ChangelogOverlay changelog, INotificationOverlay notificationOverlay) { Icon = FontAwesome.Solid.CheckSquare; IconBackground.Colour = colours.BlueDark; From d29312e0709eb11e63effe51fb6c806966e3689d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 21:47:47 +0900 Subject: [PATCH 28/74] Fix rider incompetency --- osu.Game/Overlays/IDialogOverlay.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/IDialogOverlay.cs b/osu.Game/Overlays/IDialogOverlay.cs index 07f28a7204..dedc164510 100644 --- a/osu.Game/Overlays/IDialogOverlay.cs +++ b/osu.Game/Overlays/IDialogOverlay.cs @@ -1,7 +1,8 @@ -#nullable enable // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +#nullable enable + using osu.Framework.Allocation; using osu.Game.Overlays.Dialog; From aaf5577e6a035606f19e3fd249b7a4f464f35a13 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 21:48:46 +0900 Subject: [PATCH 29/74] Remove unnecessary `canBeNull` specification --- .../Sections/Maintenance/StableDirectoryLocationDialog.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs index 4e81cd63b8..b16fd9a5a1 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public class StableDirectoryLocationDialog : PopupDialog { - [Resolved(canBeNull: true)] + [Resolved] private IPerformFromScreenRunner performer { get; set; } public StableDirectoryLocationDialog(TaskCompletionSource taskCompletionSource) From 5d5e46ede71bd05ac9846da73eb03119f96cad7b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 21:47:47 +0900 Subject: [PATCH 30/74] Fix rider incompetency --- osu.Game/Overlays/IDialogOverlay.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/IDialogOverlay.cs b/osu.Game/Overlays/IDialogOverlay.cs index 07f28a7204..dedc164510 100644 --- a/osu.Game/Overlays/IDialogOverlay.cs +++ b/osu.Game/Overlays/IDialogOverlay.cs @@ -1,7 +1,8 @@ -#nullable enable // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +#nullable enable + using osu.Framework.Allocation; using osu.Game.Overlays.Dialog; From 3cbc6cd29767a7d47ba624dc1680c22f4a02cedd Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 18 Apr 2022 21:04:22 +0300 Subject: [PATCH 31/74] Update further tests to cache using `IDialogOverlay` --- osu.Game.Tests/Visual/Online/TestSceneChatLink.cs | 2 +- osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs | 2 +- osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs | 2 +- .../Visual/SongSelect/TestSceneUserTopScoreContainer.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs index d077868175..6818147da4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs @@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Online Dependencies.Cache(chatManager); Dependencies.Cache(new ChatOverlay()); - Dependencies.Cache(dialogOverlay); + Dependencies.CacheAs(dialogOverlay); } [SetUp] diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs index f9c9b2a68b..2106043544 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs @@ -97,7 +97,7 @@ namespace osu.Game.Tests.Visual.Settings Depth = -1 }); - Dependencies.Cache(dialogOverlay); + Dependencies.CacheAs(dialogOverlay); } } } diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs index 1ed6648131..3b15ee9c45 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs @@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.SongSelect { private readonly FailableLeaderboard leaderboard; - [Cached] + [Cached(typeof(IDialogOverlay))] private readonly DialogOverlay dialogOverlay; private ScoreManager scoreManager; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs index dd7f9951bf..c71e54e9a8 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.SongSelect { public class TestSceneUserTopScoreContainer : OsuTestScene { - [Cached] + [Cached(typeof(IDialogOverlay))] private readonly DialogOverlay dialogOverlay; public TestSceneUserTopScoreContainer() From 16a0efc5621ba8a751f874bb8fef91218766efa2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 18 Apr 2022 21:06:27 +0300 Subject: [PATCH 32/74] Cache `IDialogOverlay` as its type in interface --- osu.Game/Overlays/IDialogOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/IDialogOverlay.cs b/osu.Game/Overlays/IDialogOverlay.cs index dedc164510..1c6a84cd64 100644 --- a/osu.Game/Overlays/IDialogOverlay.cs +++ b/osu.Game/Overlays/IDialogOverlay.cs @@ -11,7 +11,7 @@ namespace osu.Game.Overlays /// /// A global overlay that can show popup dialogs. /// - [Cached] + [Cached(typeof(IDialogOverlay))] public interface IDialogOverlay { /// From 1fc28552b54400ca6e49f40ad5e40f4c88d3bd6e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 18 Apr 2022 21:07:20 +0300 Subject: [PATCH 33/74] Minor reword inline comment --- osu.Game/Overlays/Dialog/PopupDialog.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 9fd1a32e84..d08b6b7beb 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -216,7 +216,7 @@ namespace osu.Game.Overlays.Dialog }; // It's important we start in a visible state so our state fires on hide, even before load. - // This is used by the IDialogOverlay to know when the dialog was dismissed. + // This is used by the dialog overlay to know when the dialog was dismissed. Show(); } From 9d59cd408fda8b931d77f9001ac38a31a4a91fb7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 18 Apr 2022 22:59:49 +0300 Subject: [PATCH 34/74] Add concept of "initial items count" in paginated API requests --- .../Online/API/Requests/GetUserBeatmapsRequest.cs | 4 ++-- .../API/Requests/GetUserKudosuHistoryRequest.cs | 4 ++-- .../Requests/GetUserMostPlayedBeatmapsRequest.cs | 4 ++-- .../API/Requests/GetUserRecentActivitiesRequest.cs | 4 ++-- .../Online/API/Requests/GetUserScoresRequest.cs | 4 ++-- osu.Game/Online/API/Requests/PaginatedAPIRequest.cs | 13 ++++++++++--- 6 files changed, 20 insertions(+), 13 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs index e2c0ed4301..b7681cb71b 100644 --- a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs @@ -13,8 +13,8 @@ namespace osu.Game.Online.API.Requests private readonly BeatmapSetType type; - public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int page = 0, int itemsPerPage = 6) - : base(page, itemsPerPage) + public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int page, int itemsPerPage, int initialItems) + : base(page, itemsPerPage, initialItems) { this.userId = userId; this.type = type; diff --git a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs index e90e297672..d2102d7697 100644 --- a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs @@ -10,8 +10,8 @@ namespace osu.Game.Online.API.Requests { private readonly long userId; - public GetUserKudosuHistoryRequest(long userId, int page = 0, int itemsPerPage = 5) - : base(page, itemsPerPage) + public GetUserKudosuHistoryRequest(long userId, int page, int itemsPerPage, int initialItems) + : base(page, itemsPerPage, initialItems) { this.userId = userId; } diff --git a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs index 9f094e51c4..a9b6dd7edc 100644 --- a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs @@ -10,8 +10,8 @@ namespace osu.Game.Online.API.Requests { private readonly long userId; - public GetUserMostPlayedBeatmapsRequest(long userId, int page = 0, int itemsPerPage = 5) - : base(page, itemsPerPage) + public GetUserMostPlayedBeatmapsRequest(long userId, int page, int itemsPerPage, int initialItems) + : base(page, itemsPerPage, initialItems) { this.userId = userId; } diff --git a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs index f2fa51bde7..60acc27182 100644 --- a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs @@ -10,8 +10,8 @@ namespace osu.Game.Online.API.Requests { private readonly long userId; - public GetUserRecentActivitiesRequest(long userId, int page = 0, int itemsPerPage = 5) - : base(page, itemsPerPage) + public GetUserRecentActivitiesRequest(long userId, int page, int itemsPerPage, int initialItems) + : base(page, itemsPerPage, initialItems) { this.userId = userId; } diff --git a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs index 5d39799f6b..85b58fc596 100644 --- a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs @@ -14,8 +14,8 @@ namespace osu.Game.Online.API.Requests private readonly ScoreType type; private readonly RulesetInfo ruleset; - public GetUserScoresRequest(long userId, ScoreType type, int page = 0, int itemsPerPage = 5, RulesetInfo ruleset = null) - : base(page, itemsPerPage) + public GetUserScoresRequest(long userId, ScoreType type, int page, int itemsPerPage, int initialItems, RulesetInfo ruleset = null) + : base(page, itemsPerPage, initialItems) { this.userId = userId; this.type = type; diff --git a/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs b/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs index bddc34a0dc..ea59fcfc25 100644 --- a/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs +++ b/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs @@ -9,11 +9,13 @@ namespace osu.Game.Online.API.Requests public abstract class PaginatedAPIRequest : APIRequest where T : class { private readonly int page; + private readonly int initialItems; private readonly int itemsPerPage; - protected PaginatedAPIRequest(int page, int itemsPerPage) + protected PaginatedAPIRequest(int page, int itemsPerPage, int initialItems) { this.page = page; + this.initialItems = initialItems; this.itemsPerPage = itemsPerPage; } @@ -21,8 +23,13 @@ namespace osu.Game.Online.API.Requests { var req = base.CreateWebRequest(); - req.AddParameter("offset", (page * itemsPerPage).ToString(CultureInfo.InvariantCulture)); - req.AddParameter("limit", itemsPerPage.ToString(CultureInfo.InvariantCulture)); + if (page == 0) + req.AddParameter("limit", initialItems.ToString(CultureInfo.InvariantCulture)); + else + { + req.AddParameter("offset", (initialItems + (page - 1) * itemsPerPage).ToString(CultureInfo.InvariantCulture)); + req.AddParameter("limit", itemsPerPage.ToString(CultureInfo.InvariantCulture)); + } return req; } From f08449e432d11625ec3b3fa3ad5d95df1ef091c8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 18 Apr 2022 23:04:21 +0300 Subject: [PATCH 35/74] Update paginated profile subsections to display items inline with web --- .../Beatmaps/PaginatedBeatmapContainer.cs | 7 ++++--- .../PaginatedMostPlayedBeatmapContainer.cs | 5 ++--- .../Kudosu/PaginatedKudosuHistoryContainer.cs | 5 ++--- .../Sections/PaginatedProfileSubsection.cs | 19 +++++++++++++++---- .../Sections/Ranks/PaginatedScoreContainer.cs | 6 ++---- .../PaginatedRecentActivityContainer.cs | 5 ++--- 6 files changed, 27 insertions(+), 20 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index d39074bd49..deeb63b5bf 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -20,11 +20,12 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps private const float panel_padding = 10f; private readonly BeatmapSetType type; + protected override int InitialItemsCount => type == BeatmapSetType.Graveyard ? 2 : 6; + public PaginatedBeatmapContainer(BeatmapSetType type, Bindable user, LocalisableString headerText) : base(user, headerText) { this.type = type; - ItemsPerPage = 6; } [BackgroundDependencyLoader] @@ -57,8 +58,8 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps } } - protected override APIRequest> CreateRequest() => - new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); + protected override APIRequest> CreateRequest(int itemsPerPage, int initialItems) => + new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, itemsPerPage, initialItems); protected override Drawable CreateDrawableItem(APIBeatmapSet model) => model.OnlineID > 0 ? new BeatmapCardNormal(model) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs index ad1192a13a..ccd60fcd89 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs @@ -19,7 +19,6 @@ namespace osu.Game.Overlays.Profile.Sections.Historical public PaginatedMostPlayedBeatmapContainer(Bindable user) : base(user, UsersStrings.ShowExtraHistoricalMostPlayedTitle) { - ItemsPerPage = 5; } [BackgroundDependencyLoader] @@ -30,8 +29,8 @@ namespace osu.Game.Overlays.Profile.Sections.Historical protected override int GetCount(APIUser user) => user.BeatmapPlayCountsCount; - protected override APIRequest> CreateRequest() => - new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage); + protected override APIRequest> CreateRequest(int itemsPerPage, int initialItems) => + new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, itemsPerPage, initialItems); protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap mostPlayed) => new DrawableMostPlayedBeatmap(mostPlayed); diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs index c4837cc0e2..311a64a10d 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs @@ -17,11 +17,10 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu public PaginatedKudosuHistoryContainer(Bindable user) : base(user, missingText: UsersStrings.ShowExtraKudosuEntryEmpty) { - ItemsPerPage = 5; } - protected override APIRequest> CreateRequest() - => new GetUserKudosuHistoryRequest(User.Value.Id, VisiblePages++, ItemsPerPage); + protected override APIRequest> CreateRequest(int itemsPerPage, int initialItems) + => new GetUserKudosuHistoryRequest(User.Value.Id, VisiblePages++, itemsPerPage, initialItems); protected override Drawable CreateDrawableItem(APIKudosuHistory item) => new DrawableKudosuHistoryItem(item); } diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs index 9dcbf6142d..646c16fbd7 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs @@ -21,11 +21,20 @@ namespace osu.Game.Overlays.Profile.Sections { public abstract class PaginatedProfileSubsection : ProfileSubsection { + /// + /// The number of items displayed per page. + /// + protected virtual int ItemsPerPage => 50; + + /// + /// The number of items displayed initially. + /// + protected virtual int InitialItemsCount => 5; + [Resolved] private IAPIProvider api { get; set; } protected int VisiblePages; - protected int ItemsPerPage; protected ReverseChildIDFillFlowContainer ItemsContainer { get; private set; } @@ -101,7 +110,7 @@ namespace osu.Game.Overlays.Profile.Sections { loadCancellation = new CancellationTokenSource(); - retrievalRequest = CreateRequest(); + retrievalRequest = CreateRequest(ItemsPerPage, InitialItemsCount); retrievalRequest.Success += UpdateItems; api.Queue(retrievalRequest); @@ -125,7 +134,9 @@ namespace osu.Game.Overlays.Profile.Sections LoadComponentsAsync(items.Select(CreateDrawableItem).Where(d => d != null), drawables => { missing.Hide(); - moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0); + + int maxCount = VisiblePages == 1 ? InitialItemsCount : ItemsPerPage; + moreButton.FadeTo(items.Count == maxCount ? 1 : 0); moreButton.IsLoading = false; ItemsContainer.AddRange(drawables); @@ -138,7 +149,7 @@ namespace osu.Game.Overlays.Profile.Sections { } - protected abstract APIRequest> CreateRequest(); + protected abstract APIRequest> CreateRequest(int itemsPerPage, int initialItems); protected abstract Drawable CreateDrawableItem(TModel model); diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index 5c67da1911..cc5952017d 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -23,8 +23,6 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks : base(user, headerText) { this.type = type; - - ItemsPerPage = 5; } [BackgroundDependencyLoader] @@ -62,8 +60,8 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks base.OnItemsReceived(items); } - protected override APIRequest> CreateRequest() => - new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); + protected override APIRequest> CreateRequest(int itemsPerPage, int initialItems) => + new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, itemsPerPage, initialItems); private int drawableItemIndex; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index c5ff896654..60cba95fda 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -19,7 +19,6 @@ namespace osu.Game.Overlays.Profile.Sections.Recent public PaginatedRecentActivityContainer(Bindable user) : base(user, missingText: EventsStrings.Empty) { - ItemsPerPage = 10; } [BackgroundDependencyLoader] @@ -28,8 +27,8 @@ namespace osu.Game.Overlays.Profile.Sections.Recent ItemsContainer.Spacing = new Vector2(0, 8); } - protected override APIRequest> CreateRequest() => - new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, ItemsPerPage); + protected override APIRequest> CreateRequest(int itemsPerPage, int initialItems) => + new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, itemsPerPage, initialItems); protected override Drawable CreateDrawableItem(APIRecentActivity model) => new DrawableRecentActivity(model); } From c4d89b8c3c446d6440b023c2fb5508da4c99add6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 05:57:03 +0900 Subject: [PATCH 36/74] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index a8952df329..8b22df418f 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 3246255815..0a102510e7 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 668d23f82e..2f0facea18 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From 94335c293848a5475aa0df3f8c71f6726a544ec8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 19 Apr 2022 00:18:10 +0300 Subject: [PATCH 37/74] Update further usages to cache/resolve via interface --- osu.Desktop/Updater/SquirrelUpdateManager.cs | 4 ++-- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 2 +- osu.Game.Tests/Visual/Settings/TestSceneMigrationScreens.cs | 2 +- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs index bae850fce1..c09cce1235 100644 --- a/osu.Desktop/Updater/SquirrelUpdateManager.cs +++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs @@ -39,9 +39,9 @@ namespace osu.Desktop.Updater private readonly SquirrelLogger squirrelLogger = new SquirrelLogger(); [BackgroundDependencyLoader] - private void load(NotificationOverlay notification) + private void load(INotificationOverlay notifications) { - notificationOverlay = notification; + notificationOverlay = notifications; SquirrelLocator.CurrentMutable.Register(() => squirrelLogger, typeof(ILogger)); } diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 958d617d63..950c755cc1 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Resolved] private SessionStatics sessionStatics { get; set; } - [Cached] + [Cached(typeof(INotificationOverlay))] private readonly NotificationOverlay notificationOverlay; [Cached] diff --git a/osu.Game.Tests/Visual/Settings/TestSceneMigrationScreens.cs b/osu.Game.Tests/Visual/Settings/TestSceneMigrationScreens.cs index a68090504d..ac0956502e 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneMigrationScreens.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneMigrationScreens.cs @@ -14,7 +14,7 @@ namespace osu.Game.Tests.Visual.Settings { public class TestSceneMigrationScreens : ScreenTestScene { - [Cached] + [Cached(typeof(INotificationOverlay))] private readonly NotificationOverlay notifications; public TestSceneMigrationScreens() diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index b72ec373d7..aea39bc8ff 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -124,7 +124,7 @@ namespace osu.Game.Screens.Play private EpilepsyWarning? epilepsyWarning; [Resolved(CanBeNull = true)] - private NotificationOverlay? notificationOverlay { get; set; } + private INotificationOverlay? notificationOverlay { get; set; } [Resolved(CanBeNull = true)] private VolumeOverlay? volumeOverlay { get; set; } From 96d4369cc823d71370f1c2fa9f8faaecba66f828 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 19 Apr 2022 02:04:23 +0300 Subject: [PATCH 38/74] Introduce `Pagination` and simplify paginated API requests --- .../API/Requests/GetUserBeatmapsRequest.cs | 4 +- .../Requests/GetUserKudosuHistoryRequest.cs | 4 +- .../GetUserMostPlayedBeatmapsRequest.cs | 4 +- .../GetUserRecentActivitiesRequest.cs | 4 +- .../API/Requests/GetUserScoresRequest.cs | 4 +- .../API/Requests/PaginatedAPIRequest.cs | 19 +++------- osu.Game/Online/API/Requests/Pagination.cs | 38 +++++++++++++++++++ .../Beatmaps/PaginatedBeatmapContainer.cs | 4 +- .../PaginatedMostPlayedBeatmapContainer.cs | 4 +- .../Kudosu/PaginatedKudosuHistoryContainer.cs | 4 +- .../Sections/PaginatedProfileSubsection.cs | 16 ++++---- .../Sections/Ranks/PaginatedScoreContainer.cs | 6 +-- .../PaginatedRecentActivityContainer.cs | 4 +- 13 files changed, 73 insertions(+), 42 deletions(-) create mode 100644 osu.Game/Online/API/Requests/Pagination.cs diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs index b7681cb71b..019c805c9a 100644 --- a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs @@ -13,8 +13,8 @@ namespace osu.Game.Online.API.Requests private readonly BeatmapSetType type; - public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int page, int itemsPerPage, int initialItems) - : base(page, itemsPerPage, initialItems) + public GetUserBeatmapsRequest(long userId, BeatmapSetType type, Pagination pagination) + : base(pagination) { this.userId = userId; this.type = type; diff --git a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs index d2102d7697..3759c59722 100644 --- a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs @@ -10,8 +10,8 @@ namespace osu.Game.Online.API.Requests { private readonly long userId; - public GetUserKudosuHistoryRequest(long userId, int page, int itemsPerPage, int initialItems) - : base(page, itemsPerPage, initialItems) + public GetUserKudosuHistoryRequest(long userId, Pagination pagination) + : base(pagination) { this.userId = userId; } diff --git a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs index a9b6dd7edc..37359e2cd0 100644 --- a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs @@ -10,8 +10,8 @@ namespace osu.Game.Online.API.Requests { private readonly long userId; - public GetUserMostPlayedBeatmapsRequest(long userId, int page, int itemsPerPage, int initialItems) - : base(page, itemsPerPage, initialItems) + public GetUserMostPlayedBeatmapsRequest(long userId, Pagination pagination) + : base(pagination) { this.userId = userId; } diff --git a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs index 60acc27182..c16633c17a 100644 --- a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs @@ -10,8 +10,8 @@ namespace osu.Game.Online.API.Requests { private readonly long userId; - public GetUserRecentActivitiesRequest(long userId, int page, int itemsPerPage, int initialItems) - : base(page, itemsPerPage, initialItems) + public GetUserRecentActivitiesRequest(long userId, Pagination pagination) + : base(pagination) { this.userId = userId; } diff --git a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs index 85b58fc596..af01969a1a 100644 --- a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs @@ -14,8 +14,8 @@ namespace osu.Game.Online.API.Requests private readonly ScoreType type; private readonly RulesetInfo ruleset; - public GetUserScoresRequest(long userId, ScoreType type, int page, int itemsPerPage, int initialItems, RulesetInfo ruleset = null) - : base(page, itemsPerPage, initialItems) + public GetUserScoresRequest(long userId, ScoreType type, Pagination pagination, RulesetInfo ruleset = null) + : base(pagination) { this.userId = userId; this.type = type; diff --git a/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs b/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs index ea59fcfc25..ddc453bf17 100644 --- a/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs +++ b/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs @@ -8,28 +8,19 @@ namespace osu.Game.Online.API.Requests { public abstract class PaginatedAPIRequest : APIRequest where T : class { - private readonly int page; - private readonly int initialItems; - private readonly int itemsPerPage; + private readonly Pagination pagination; - protected PaginatedAPIRequest(int page, int itemsPerPage, int initialItems) + protected PaginatedAPIRequest(Pagination pagination) { - this.page = page; - this.initialItems = initialItems; - this.itemsPerPage = itemsPerPage; + this.pagination = pagination; } protected override WebRequest CreateWebRequest() { var req = base.CreateWebRequest(); - if (page == 0) - req.AddParameter("limit", initialItems.ToString(CultureInfo.InvariantCulture)); - else - { - req.AddParameter("offset", (initialItems + (page - 1) * itemsPerPage).ToString(CultureInfo.InvariantCulture)); - req.AddParameter("limit", itemsPerPage.ToString(CultureInfo.InvariantCulture)); - } + req.AddParameter("offset", pagination.Offset.ToString(CultureInfo.InvariantCulture)); + req.AddParameter("limit", pagination.Limit.ToString(CultureInfo.InvariantCulture)); return req; } diff --git a/osu.Game/Online/API/Requests/Pagination.cs b/osu.Game/Online/API/Requests/Pagination.cs new file mode 100644 index 0000000000..a1caac7592 --- /dev/null +++ b/osu.Game/Online/API/Requests/Pagination.cs @@ -0,0 +1,38 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Online.API.Requests +{ + /// + /// Represents a pagination data used for . + /// + public readonly struct Pagination + { + /// + /// The starting point of the request. + /// + public int Offset { get; } + + /// + /// The maximum number of items to return in this request. + /// + public int Limit { get; } + + public Pagination(int offset, int limit) + { + Offset = offset; + Limit = limit; + } + + public Pagination(int limit) + : this(0, limit) + { + } + + /// + /// Returns a of the next number of items defined by after this. + /// + /// The limit of the next pagination. + public Pagination TakeNext(int limit) => new Pagination(Offset + Limit, limit); + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index deeb63b5bf..f1c2b4bf7a 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -58,8 +58,8 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps } } - protected override APIRequest> CreateRequest(int itemsPerPage, int initialItems) => - new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, itemsPerPage, initialItems); + protected override APIRequest> CreateRequest(Pagination pagination) => + new GetUserBeatmapsRequest(User.Value.Id, type, pagination); protected override Drawable CreateDrawableItem(APIBeatmapSet model) => model.OnlineID > 0 ? new BeatmapCardNormal(model) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs index ccd60fcd89..281bcc3a03 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs @@ -29,8 +29,8 @@ namespace osu.Game.Overlays.Profile.Sections.Historical protected override int GetCount(APIUser user) => user.BeatmapPlayCountsCount; - protected override APIRequest> CreateRequest(int itemsPerPage, int initialItems) => - new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, itemsPerPage, initialItems); + protected override APIRequest> CreateRequest(Pagination pagination) => + new GetUserMostPlayedBeatmapsRequest(User.Value.Id, pagination); protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap mostPlayed) => new DrawableMostPlayedBeatmap(mostPlayed); diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs index 311a64a10d..5aada2b655 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs @@ -19,8 +19,8 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu { } - protected override APIRequest> CreateRequest(int itemsPerPage, int initialItems) - => new GetUserKudosuHistoryRequest(User.Value.Id, VisiblePages++, itemsPerPage, initialItems); + protected override APIRequest> CreateRequest(Pagination pagination) + => new GetUserKudosuHistoryRequest(User.Value.Id, pagination); protected override Drawable CreateDrawableItem(APIKudosuHistory item) => new DrawableKudosuHistoryItem(item); } diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs index 646c16fbd7..a1f9e7546a 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs @@ -14,6 +14,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Graphics.Containers; +using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osuTK; @@ -34,7 +35,7 @@ namespace osu.Game.Overlays.Profile.Sections [Resolved] private IAPIProvider api { get; set; } - protected int VisiblePages; + protected Pagination? CurrentPage { get; private set; } protected ReverseChildIDFillFlowContainer ItemsContainer { get; private set; } @@ -96,7 +97,7 @@ namespace osu.Game.Overlays.Profile.Sections loadCancellation?.Cancel(); retrievalRequest?.Cancel(); - VisiblePages = 0; + CurrentPage = null; ItemsContainer.Clear(); if (e.NewValue != null) @@ -110,7 +111,9 @@ namespace osu.Game.Overlays.Profile.Sections { loadCancellation = new CancellationTokenSource(); - retrievalRequest = CreateRequest(ItemsPerPage, InitialItemsCount); + CurrentPage = CurrentPage?.TakeNext(ItemsPerPage) ?? new Pagination(InitialItemsCount); + + retrievalRequest = CreateRequest(CurrentPage.Value); retrievalRequest.Success += UpdateItems; api.Queue(retrievalRequest); @@ -120,7 +123,7 @@ namespace osu.Game.Overlays.Profile.Sections { OnItemsReceived(items); - if (!items.Any() && VisiblePages == 1) + if (!items.Any() && CurrentPage?.Offset == 0) { moreButton.Hide(); moreButton.IsLoading = false; @@ -135,8 +138,7 @@ namespace osu.Game.Overlays.Profile.Sections { missing.Hide(); - int maxCount = VisiblePages == 1 ? InitialItemsCount : ItemsPerPage; - moreButton.FadeTo(items.Count == maxCount ? 1 : 0); + moreButton.FadeTo(items.Count == CurrentPage?.Limit ? 1 : 0); moreButton.IsLoading = false; ItemsContainer.AddRange(drawables); @@ -149,7 +151,7 @@ namespace osu.Game.Overlays.Profile.Sections { } - protected abstract APIRequest> CreateRequest(int itemsPerPage, int initialItems); + protected abstract APIRequest> CreateRequest(Pagination pagination); protected abstract Drawable CreateDrawableItem(TModel model); diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index cc5952017d..c3a5e3f8b8 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -54,14 +54,14 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks protected override void OnItemsReceived(List items) { - if (VisiblePages == 0) + if (CurrentPage == null || CurrentPage?.Offset == 0) drawableItemIndex = 0; base.OnItemsReceived(items); } - protected override APIRequest> CreateRequest(int itemsPerPage, int initialItems) => - new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, itemsPerPage, initialItems); + protected override APIRequest> CreateRequest(Pagination pagination) => + new GetUserScoresRequest(User.Value.Id, type, pagination); private int drawableItemIndex; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index 60cba95fda..e5118094ce 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -27,8 +27,8 @@ namespace osu.Game.Overlays.Profile.Sections.Recent ItemsContainer.Spacing = new Vector2(0, 8); } - protected override APIRequest> CreateRequest(int itemsPerPage, int initialItems) => - new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, itemsPerPage, initialItems); + protected override APIRequest> CreateRequest(Pagination pagination) => + new GetUserRecentActivitiesRequest(User.Value.Id, pagination); protected override Drawable CreateDrawableItem(APIRecentActivity model) => new DrawableRecentActivity(model); } From c858ec24833b2020a434180d9f63a8a472ec7173 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 19 Apr 2022 02:48:34 +0300 Subject: [PATCH 39/74] `Pagination` -> `PaginationParameters --- osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs | 2 +- .../Online/API/Requests/GetUserKudosuHistoryRequest.cs | 2 +- .../API/Requests/GetUserMostPlayedBeatmapsRequest.cs | 2 +- .../API/Requests/GetUserRecentActivitiesRequest.cs | 2 +- osu.Game/Online/API/Requests/GetUserScoresRequest.cs | 2 +- osu.Game/Online/API/Requests/PaginatedAPIRequest.cs | 4 ++-- .../{Pagination.cs => PaginationParameters.cs} | 10 +++++----- .../Sections/Beatmaps/PaginatedBeatmapContainer.cs | 2 +- .../Historical/PaginatedMostPlayedBeatmapContainer.cs | 2 +- .../Sections/Kudosu/PaginatedKudosuHistoryContainer.cs | 2 +- .../Profile/Sections/PaginatedProfileSubsection.cs | 6 +++--- .../Profile/Sections/Ranks/PaginatedScoreContainer.cs | 2 +- .../Recent/PaginatedRecentActivityContainer.cs | 2 +- 13 files changed, 20 insertions(+), 20 deletions(-) rename osu.Game/Online/API/Requests/{Pagination.cs => PaginationParameters.cs} (68%) diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs index 019c805c9a..ffb3a3be9b 100644 --- a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs @@ -13,7 +13,7 @@ namespace osu.Game.Online.API.Requests private readonly BeatmapSetType type; - public GetUserBeatmapsRequest(long userId, BeatmapSetType type, Pagination pagination) + public GetUserBeatmapsRequest(long userId, BeatmapSetType type, PaginationParameters pagination) : base(pagination) { this.userId = userId; diff --git a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs index 3759c59722..67d3ad26b0 100644 --- a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs @@ -10,7 +10,7 @@ namespace osu.Game.Online.API.Requests { private readonly long userId; - public GetUserKudosuHistoryRequest(long userId, Pagination pagination) + public GetUserKudosuHistoryRequest(long userId, PaginationParameters pagination) : base(pagination) { this.userId = userId; diff --git a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs index 37359e2cd0..bef3df42fb 100644 --- a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs @@ -10,7 +10,7 @@ namespace osu.Game.Online.API.Requests { private readonly long userId; - public GetUserMostPlayedBeatmapsRequest(long userId, Pagination pagination) + public GetUserMostPlayedBeatmapsRequest(long userId, PaginationParameters pagination) : base(pagination) { this.userId = userId; diff --git a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs index c16633c17a..79f0549d4a 100644 --- a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs @@ -10,7 +10,7 @@ namespace osu.Game.Online.API.Requests { private readonly long userId; - public GetUserRecentActivitiesRequest(long userId, Pagination pagination) + public GetUserRecentActivitiesRequest(long userId, PaginationParameters pagination) : base(pagination) { this.userId = userId; diff --git a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs index af01969a1a..7250929f11 100644 --- a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs @@ -14,7 +14,7 @@ namespace osu.Game.Online.API.Requests private readonly ScoreType type; private readonly RulesetInfo ruleset; - public GetUserScoresRequest(long userId, ScoreType type, Pagination pagination, RulesetInfo ruleset = null) + public GetUserScoresRequest(long userId, ScoreType type, PaginationParameters pagination, RulesetInfo ruleset = null) : base(pagination) { this.userId = userId; diff --git a/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs b/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs index ddc453bf17..3d719de958 100644 --- a/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs +++ b/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs @@ -8,9 +8,9 @@ namespace osu.Game.Online.API.Requests { public abstract class PaginatedAPIRequest : APIRequest where T : class { - private readonly Pagination pagination; + private readonly PaginationParameters pagination; - protected PaginatedAPIRequest(Pagination pagination) + protected PaginatedAPIRequest(PaginationParameters pagination) { this.pagination = pagination; } diff --git a/osu.Game/Online/API/Requests/Pagination.cs b/osu.Game/Online/API/Requests/PaginationParameters.cs similarity index 68% rename from osu.Game/Online/API/Requests/Pagination.cs rename to osu.Game/Online/API/Requests/PaginationParameters.cs index a1caac7592..3593a4fe83 100644 --- a/osu.Game/Online/API/Requests/Pagination.cs +++ b/osu.Game/Online/API/Requests/PaginationParameters.cs @@ -6,7 +6,7 @@ namespace osu.Game.Online.API.Requests /// /// Represents a pagination data used for . /// - public readonly struct Pagination + public readonly struct PaginationParameters { /// /// The starting point of the request. @@ -18,21 +18,21 @@ namespace osu.Game.Online.API.Requests /// public int Limit { get; } - public Pagination(int offset, int limit) + public PaginationParameters(int offset, int limit) { Offset = offset; Limit = limit; } - public Pagination(int limit) + public PaginationParameters(int limit) : this(0, limit) { } /// - /// Returns a of the next number of items defined by after this. + /// Returns a of the next number of items defined by after this. /// /// The limit of the next pagination. - public Pagination TakeNext(int limit) => new Pagination(Offset + Limit, limit); + public PaginationParameters TakeNext(int limit) => new PaginationParameters(Offset + Limit, limit); } } diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index f1c2b4bf7a..0424fe8bd9 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps } } - protected override APIRequest> CreateRequest(Pagination pagination) => + protected override APIRequest> CreateRequest(PaginationParameters pagination) => new GetUserBeatmapsRequest(User.Value.Id, type, pagination); protected override Drawable CreateDrawableItem(APIBeatmapSet model) => model.OnlineID > 0 diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs index 281bcc3a03..06de0f62dc 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs @@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical protected override int GetCount(APIUser user) => user.BeatmapPlayCountsCount; - protected override APIRequest> CreateRequest(Pagination pagination) => + protected override APIRequest> CreateRequest(PaginationParameters pagination) => new GetUserMostPlayedBeatmapsRequest(User.Value.Id, pagination); protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap mostPlayed) => diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs index 5aada2b655..9af854e6b9 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu { } - protected override APIRequest> CreateRequest(Pagination pagination) + protected override APIRequest> CreateRequest(PaginationParameters pagination) => new GetUserKudosuHistoryRequest(User.Value.Id, pagination); protected override Drawable CreateDrawableItem(APIKudosuHistory item) => new DrawableKudosuHistoryItem(item); diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs index a1f9e7546a..33bd155d71 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs @@ -35,7 +35,7 @@ namespace osu.Game.Overlays.Profile.Sections [Resolved] private IAPIProvider api { get; set; } - protected Pagination? CurrentPage { get; private set; } + protected PaginationParameters? CurrentPage { get; private set; } protected ReverseChildIDFillFlowContainer ItemsContainer { get; private set; } @@ -111,7 +111,7 @@ namespace osu.Game.Overlays.Profile.Sections { loadCancellation = new CancellationTokenSource(); - CurrentPage = CurrentPage?.TakeNext(ItemsPerPage) ?? new Pagination(InitialItemsCount); + CurrentPage = CurrentPage?.TakeNext(ItemsPerPage) ?? new PaginationParameters(InitialItemsCount); retrievalRequest = CreateRequest(CurrentPage.Value); retrievalRequest.Success += UpdateItems; @@ -151,7 +151,7 @@ namespace osu.Game.Overlays.Profile.Sections { } - protected abstract APIRequest> CreateRequest(Pagination pagination); + protected abstract APIRequest> CreateRequest(PaginationParameters pagination); protected abstract Drawable CreateDrawableItem(TModel model); diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index c3a5e3f8b8..ef9f4b5ff3 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -60,7 +60,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks base.OnItemsReceived(items); } - protected override APIRequest> CreateRequest(Pagination pagination) => + protected override APIRequest> CreateRequest(PaginationParameters pagination) => new GetUserScoresRequest(User.Value.Id, type, pagination); private int drawableItemIndex; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index e5118094ce..77008d5f34 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent ItemsContainer.Spacing = new Vector2(0, 8); } - protected override APIRequest> CreateRequest(Pagination pagination) => + protected override APIRequest> CreateRequest(PaginationParameters pagination) => new GetUserRecentActivitiesRequest(User.Value.Id, pagination); protected override Drawable CreateDrawableItem(APIRecentActivity model) => new DrawableRecentActivity(model); From 83e89b3e80c737b626fe1962d2652a64a381058e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 11:10:11 +0900 Subject: [PATCH 40/74] Add unread count to `INotificationOverlay` and fix toolbar button DI logic --- .../Visual/Menus/TestSceneToolbar.cs | 18 +++++++++++++----- osu.Game/Overlays/INotificationOverlay.cs | 6 ++++++ osu.Game/Overlays/NotificationOverlay.cs | 6 ++++-- .../Toolbar/ToolbarNotificationButton.cs | 8 ++++---- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs b/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs index c65595d82e..dbc7e54b5e 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; +using Moq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -22,6 +23,17 @@ namespace osu.Game.Tests.Visual.Menus [Resolved] private IRulesetStore rulesets { get; set; } + private readonly Mock notifications = new Mock(); + + private readonly BindableInt unreadNotificationCount = new BindableInt(); + + [BackgroundDependencyLoader] + private void load() + { + Dependencies.CacheAs(notifications.Object); + notifications.SetupGet(n => n.UnreadCount).Returns(unreadNotificationCount); + } + [SetUp] public void SetUp() => Schedule(() => { @@ -31,10 +43,6 @@ namespace osu.Game.Tests.Visual.Menus [Test] public void TestNotificationCounter() { - ToolbarNotificationButton notificationButton = null; - - AddStep("retrieve notification button", () => notificationButton = toolbar.ChildrenOfType().Single()); - setNotifications(1); setNotifications(2); setNotifications(3); @@ -43,7 +51,7 @@ namespace osu.Game.Tests.Visual.Menus void setNotifications(int count) => AddStep($"set notification count to {count}", - () => notificationButton.NotificationCount.Value = count); + () => unreadNotificationCount.Value = count); } [TestCase(false)] diff --git a/osu.Game/Overlays/INotificationOverlay.cs b/osu.Game/Overlays/INotificationOverlay.cs index 432dd2be54..1d8e33ea3a 100644 --- a/osu.Game/Overlays/INotificationOverlay.cs +++ b/osu.Game/Overlays/INotificationOverlay.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Game.Overlays.Notifications; namespace osu.Game.Overlays @@ -22,5 +23,10 @@ namespace osu.Game.Overlays /// Hide the overlay, if it is currently visible. /// void Hide(); + + /// + /// Current number of unread notifications. + /// + IBindable UnreadCount { get; } } } diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 0e8fbc6680..2b5909f45a 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -99,7 +99,9 @@ namespace osu.Game.Overlays OverlayActivationMode.BindValueChanged(_ => updateProcessingMode(), true); } - public readonly BindableInt UnreadCount = new BindableInt(); + public IBindable UnreadCount => unreadCount; + + private readonly BindableInt unreadCount = new BindableInt(); private int runningDepth; @@ -180,7 +182,7 @@ namespace osu.Game.Overlays private void updateCounts() { - UnreadCount.Value = sections.Select(c => c.UnreadCount).Sum(); + unreadCount.Value = sections.Select(c => c.UnreadCount).Sum(); } private void markAllRead() diff --git a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs index 79d0fc74c1..313a2bc3f4 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs @@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Toolbar { protected override Anchor TooltipAnchor => Anchor.TopRight; - public BindableInt NotificationCount = new BindableInt(); + public IBindable NotificationCount = new BindableInt(); private readonly CountCircle countDisplay; @@ -36,10 +36,10 @@ namespace osu.Game.Overlays.Toolbar }); } - [BackgroundDependencyLoader(true)] - private void load(NotificationOverlay notificationOverlay) + [BackgroundDependencyLoader] + private void load(INotificationOverlay notificationOverlay) { - StateContainer = notificationOverlay; + StateContainer = notificationOverlay as NotificationOverlay; if (notificationOverlay != null) NotificationCount.BindTo(notificationOverlay.UnreadCount); From 8d0dd3961e056b2670f67412a48cfdf000ec1694 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 19 Apr 2022 03:25:18 +0300 Subject: [PATCH 41/74] Add failing test cases --- .../LegacyMainCirclePieceTest.cs | 133 ++++++++++++++++++ .../Skinning/Legacy/LegacyMainCirclePiece.cs | 19 ++- 2 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs diff --git a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs new file mode 100644 index 0000000000..200dd2f593 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs @@ -0,0 +1,133 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.Testing; +using osu.Game.Audio; +using osu.Game.Rulesets.Osu.Skinning.Legacy; +using osu.Game.Skinning; +using osu.Game.Tests.Visual; + +#nullable enable + +namespace osu.Game.Rulesets.Osu.Tests +{ + [HeadlessTest] + public class LegacyMainCirclePieceTest : OsuTestScene + { + private static readonly object?[][] texture_priority_cases = + { + // default priority lookup + new object?[] + { + // available textures + new[] { @"hitcircle", @"hitcircleoverlay" }, + // priority lookup + @"", + // expected circle and overlay + @"hitcircle", @"hitcircleoverlay", + }, + // custom priority lookup + new object?[] + { + new[] { @"hitcircle", @"hitcircleoverlay", @"sliderstartcircle", @"sliderstartcircleoverlay" }, + @"sliderstartcircle", + @"sliderstartcircle", @"sliderstartcircleoverlay", + }, + // when no sprites are available for the specified prefix, fall back to "hitcircle"/"hitcircleoverlay". + new object?[] + { + new[] { @"hitcircle", @"hitcircleoverlay" }, + @"sliderstartcircle", + @"hitcircle", @"hitcircleoverlay", + }, + // when a circle is available for the specified prefix but no overlay exists, no overlay is displayed. + new object?[] + { + new[] { @"hitcircle", @"hitcircleoverlay", @"sliderstartcircle" }, + @"sliderstartcircle", + @"sliderstartcircle", null + }, + // when no circle is available for the specified prefix but an overlay exists, the overlay is ignored. + new object?[] + { + new[] { @"hitcircle", @"hitcircleoverlay", @"sliderstartcircleoverlay" }, + @"sliderstartcircle", + @"hitcircle", @"hitcircleoverlay", + } + }; + + [TestCaseSource(nameof(texture_priority_cases))] + public void TestTexturePriorities(string[] textureFilenames, string priorityLookup, string? expectedCircle, string? expectedOverlay) + { + Sprite? circleSprite = null; + Sprite? overlaySprite = null; + + AddStep("load circle piece", () => + { + Child = new DependencyProvidingContainer + { + CachedDependencies = new (Type, object)[] + { + (typeof(ISkinSource), new TestSkin(textureFilenames)) + }, + Child = new LegacyMainCirclePiece(priorityLookup, false), + }; + + var sprites = this.ChildrenOfType().Where(s => s.Texture.AssetName != null).DistinctBy(s => s.Texture.AssetName).ToArray(); + Debug.Assert(sprites.Length <= 2); + + circleSprite = sprites.ElementAtOrDefault(0); + overlaySprite = sprites.ElementAtOrDefault(1); + }); + + AddAssert("check circle sprite", () => circleSprite?.Texture?.AssetName == expectedCircle); + AddAssert("check overlay sprite", () => overlaySprite?.Texture?.AssetName == expectedOverlay); + } + + private class TestSkin : ISkinSource + { + private readonly string[] textureFilenames; + + public TestSkin(string[] textureFilenames) + { + this.textureFilenames = textureFilenames; + } + + public Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) + { + if (textureFilenames.Contains(componentName)) + return new Texture(1, 1) { AssetName = componentName }; + + return null; + } + + public event Action SourceChanged + { + add { } + remove { } + } + + public IEnumerable AllSources { get; } = Enumerable.Empty(); + public Drawable? GetDrawableComponent(ISkinComponent component) => null; + public ISample? GetSample(ISampleInfo sampleInfo) => null; + + public IBindable? GetConfig(TLookup lookup) + where TLookup : notnull + where TValue : notnull + => null; + + public ISkin? FindProvider(Func lookupFunction) => lookupFunction(this) ? this : null; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index c6007885be..829dbb02f1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -43,7 +44,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private readonly Bindable accentColour = new Bindable(); private readonly IBindable indexInCurrentCombo = new Bindable(); - [Resolved] + [Resolved(canBeNull: true)] + [CanBeNull] private DrawableHitObject drawableObject { get; set; } [Resolved] @@ -107,8 +109,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy if (overlayAboveNumber) OverlayLayer.ChangeChildDepth(hitCircleOverlay, float.MinValue); - accentColour.BindTo(drawableObject.AccentColour); - indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); + if (drawableOsuObject != null) + { + accentColour.BindTo(drawableOsuObject.AccentColour); + indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); + } Texture getTextureWithFallback(string name) { @@ -149,15 +154,17 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy if (hasNumber) indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true); - drawableObject.ApplyCustomUpdateState += updateStateTransforms; - updateStateTransforms(drawableObject, drawableObject.State.Value); + if (drawableObject != null) + drawableObject.ApplyCustomUpdateState += updateStateTransforms; + + updateStateTransforms(drawableObject, drawableObject?.State.Value ?? ArmedState.Idle); } private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) { const double legacy_fade_duration = 240; - using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) + using (BeginAbsoluteSequence(drawableObject?.HitStateUpdateTime ?? 0)) { switch (state) { From ec7bb876b5f76416255fa04e71876f6f39980465 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 19 Apr 2022 07:12:05 +0300 Subject: [PATCH 42/74] Improve legacy circle texture lookup to match 1:1 with stable --- .../Skinning/Legacy/LegacyMainCirclePiece.cs | 49 +++++-------------- 1 file changed, 12 insertions(+), 37 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index 829dbb02f1..5fe4a4b5df 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -23,9 +23,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public override bool RemoveCompletedTransforms => false; - private readonly string priorityLookup; private readonly bool hasNumber; + private string priorityLookup; + public LegacyMainCirclePiece(string priorityLookup = null, bool hasNumber = true) { this.priorityLookup = priorityLookup; @@ -56,21 +57,19 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { var drawableOsuObject = (DrawableOsuHitObject)drawableObject; - bool allowFallback = false; - // attempt lookup using priority specification - Texture baseTexture = getTextureWithFallback(string.Empty); + Texture baseTexture = getTexture(string.Empty); - // if the base texture was not found without a fallback, switch on fallback mode and re-perform the lookup. + // if the base texture was not found using the priority specification, nullify the specification and fall back to "hitcircle". if (baseTexture == null) { - allowFallback = true; - baseTexture = getTextureWithFallback(string.Empty); + priorityLookup = null; + baseTexture = getTexture(string.Empty); } // at this point, any further texture fetches should be correctly using the priority source if the base texture was retrieved using it. // the flow above handles the case where a sliderendcircle.png is retrieved from the skin, but sliderendcircleoverlay.png doesn't exist. - // expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png (potentially from the default/fall-through skin). + // expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png. InternalChildren = new[] { @@ -83,7 +82,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Child = hitCircleOverlay = new KiaiFlashingDrawable(() => getAnimationWithFallback(@"overlay", 1000 / 2d)) + Child = hitCircleOverlay = new KiaiFlashingDrawable(() => getAnimation(@"overlay", 1000 / 2d)) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -115,35 +114,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); } - Texture getTextureWithFallback(string name) - { - Texture tex = null; + Texture getTexture(string name) + => skin.GetTexture($"{priorityLookup ?? @"hitcircle"}{name}"); - if (!string.IsNullOrEmpty(priorityLookup)) - { - tex = skin.GetTexture($"{priorityLookup}{name}"); - - if (!allowFallback) - return tex; - } - - return tex ?? skin.GetTexture($"hitcircle{name}"); - } - - Drawable getAnimationWithFallback(string name, double frameLength) - { - Drawable animation = null; - - if (!string.IsNullOrEmpty(priorityLookup)) - { - animation = skin.GetAnimation($"{priorityLookup}{name}", true, true, frameLength: frameLength); - - if (!allowFallback) - return animation; - } - - return animation ?? skin.GetAnimation($"hitcircle{name}", true, true, frameLength: frameLength); - } + Drawable getAnimation(string name, double frameLength) + => skin.GetAnimation($"{priorityLookup ?? @"hitcircle"}{name}", true, true, frameLength: frameLength); } protected override void LoadComplete() From f92a41b6c3758027e315347fafb01abbac7aa678 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 19 Apr 2022 08:03:50 +0300 Subject: [PATCH 43/74] Replace local `TestSkin` implementation with simplified Moq setups --- .../LegacyMainCirclePieceTest.cs | 56 ++++--------------- 1 file changed, 10 insertions(+), 46 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs index 200dd2f593..766db25d71 100644 --- a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs @@ -1,25 +1,21 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +#nullable enable + using System; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using Moq; using NUnit.Framework; -using osu.Framework.Audio.Sample; -using osu.Framework.Bindables; -using osu.Framework.Graphics; using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Testing; -using osu.Game.Audio; using osu.Game.Rulesets.Osu.Skinning.Legacy; using osu.Game.Skinning; using osu.Game.Tests.Visual; -#nullable enable - namespace osu.Game.Rulesets.Osu.Tests { [HeadlessTest] @@ -75,12 +71,15 @@ namespace osu.Game.Rulesets.Osu.Tests AddStep("load circle piece", () => { + var skin = new Mock(); + + skin.Setup(s => s.GetTexture(It.IsAny())).CallBase(); + skin.Setup(s => s.GetTexture(It.IsIn(textureFilenames), It.IsAny(), It.IsAny())) + .Returns((string componentName, WrapMode _, WrapMode __) => new Texture(1, 1) { AssetName = componentName }); + Child = new DependencyProvidingContainer { - CachedDependencies = new (Type, object)[] - { - (typeof(ISkinSource), new TestSkin(textureFilenames)) - }, + CachedDependencies = new (Type, object)[] { (typeof(ISkinSource), skin.Object) }, Child = new LegacyMainCirclePiece(priorityLookup, false), }; @@ -94,40 +93,5 @@ namespace osu.Game.Rulesets.Osu.Tests AddAssert("check circle sprite", () => circleSprite?.Texture?.AssetName == expectedCircle); AddAssert("check overlay sprite", () => overlaySprite?.Texture?.AssetName == expectedOverlay); } - - private class TestSkin : ISkinSource - { - private readonly string[] textureFilenames; - - public TestSkin(string[] textureFilenames) - { - this.textureFilenames = textureFilenames; - } - - public Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) - { - if (textureFilenames.Contains(componentName)) - return new Texture(1, 1) { AssetName = componentName }; - - return null; - } - - public event Action SourceChanged - { - add { } - remove { } - } - - public IEnumerable AllSources { get; } = Enumerable.Empty(); - public Drawable? GetDrawableComponent(ISkinComponent component) => null; - public ISample? GetSample(ISampleInfo sampleInfo) => null; - - public IBindable? GetConfig(TLookup lookup) - where TLookup : notnull - where TValue : notnull - => null; - - public ISkin? FindProvider(Func lookupFunction) => lookupFunction(this) ? this : null; - } } } From fd113953ace591b867081da881821f15dd356511 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 19 Apr 2022 08:06:39 +0300 Subject: [PATCH 44/74] Rename `prioritiyLookup` and add xmldoc --- .../Skinning/Legacy/LegacyMainCirclePiece.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index 5fe4a4b5df..82bb4dcf2d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -25,11 +25,18 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private readonly bool hasNumber; - private string priorityLookup; + /// + /// A prioritised prefix to perform texture lookups with. + /// + /// + /// If the "circle" texture could not be found with this prefix, + /// then it is nullified and the default prefix "hitcircle" is used instead. + /// + private string priorityLookupPrefix; - public LegacyMainCirclePiece(string priorityLookup = null, bool hasNumber = true) + public LegacyMainCirclePiece(string priorityLookupPrefix = null, bool hasNumber = true) { - this.priorityLookup = priorityLookup; + this.priorityLookupPrefix = priorityLookupPrefix; this.hasNumber = hasNumber; Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); @@ -63,7 +70,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy // if the base texture was not found using the priority specification, nullify the specification and fall back to "hitcircle". if (baseTexture == null) { - priorityLookup = null; + priorityLookupPrefix = null; baseTexture = getTexture(string.Empty); } @@ -115,10 +122,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy } Texture getTexture(string name) - => skin.GetTexture($"{priorityLookup ?? @"hitcircle"}{name}"); + => skin.GetTexture($"{priorityLookupPrefix ?? @"hitcircle"}{name}"); Drawable getAnimation(string name, double frameLength) - => skin.GetAnimation($"{priorityLookup ?? @"hitcircle"}{name}", true, true, frameLength: frameLength); + => skin.GetAnimation($"{priorityLookupPrefix ?? @"hitcircle"}{name}", true, true, frameLength: frameLength); } protected override void LoadComplete() From b067924adacb6ecdc38d3d9ccdf52a30b44458f7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 19 Apr 2022 08:08:02 +0300 Subject: [PATCH 45/74] Avoid applying state transforms when no object is present --- .../Skinning/Legacy/LegacyMainCirclePiece.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index 82bb4dcf2d..9d14041dd8 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -4,6 +4,7 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -137,16 +138,17 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true); if (drawableObject != null) + { drawableObject.ApplyCustomUpdateState += updateStateTransforms; - - updateStateTransforms(drawableObject, drawableObject?.State.Value ?? ArmedState.Idle); + updateStateTransforms(drawableObject, drawableObject.State.Value); + } } private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) { const double legacy_fade_duration = 240; - using (BeginAbsoluteSequence(drawableObject?.HitStateUpdateTime ?? 0)) + using (BeginAbsoluteSequence(drawableObject.AsNonNull().HitStateUpdateTime)) { switch (state) { From feeff1647697ef1c45156091cce88da20464caee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 14:30:45 +0900 Subject: [PATCH 46/74] Add debug language to help with localisation efforts The idea is to allow a developer to immediately see which text on a component or screen has already got localisation support. It can be a bit of a challenge to see this when creating a new component that doesn't yet have any translations populated. Curious to hear thoughts on this. I could see it working very well as a visual tests checkbox (implemented at o!f side), potentially in addition to having this at the game level, or replacing this PR. --- .../Localisation/DebugLocalisationStore.cs | 30 +++++++++++++++++++ osu.Game/Localisation/Language.cs | 7 ++++- osu.Game/OsuGame.cs | 8 +++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Localisation/DebugLocalisationStore.cs diff --git a/osu.Game/Localisation/DebugLocalisationStore.cs b/osu.Game/Localisation/DebugLocalisationStore.cs new file mode 100644 index 0000000000..99dca6265e --- /dev/null +++ b/osu.Game/Localisation/DebugLocalisationStore.cs @@ -0,0 +1,30 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public class DebugLocalisationStore : ILocalisationStore + { + public string Get(string lookup) => $@"[[{lookup.Substring(lookup.LastIndexOf('.') + 1)}]]"; + + public Task GetAsync(string lookup, CancellationToken cancellationToken = default) => Task.FromResult(Get(lookup)); + + public Stream GetStream(string name) => throw new NotImplementedException(); + + public IEnumerable GetAvailableResources() => throw new NotImplementedException(); + + public CultureInfo EffectiveCulture { get; } = new CultureInfo(@"debug"); + + public void Dispose() + { + } + } +} diff --git a/osu.Game/Localisation/Language.cs b/osu.Game/Localisation/Language.cs index ab96d01c82..c98586457e 100644 --- a/osu.Game/Localisation/Language.cs +++ b/osu.Game/Localisation/Language.cs @@ -110,6 +110,11 @@ namespace osu.Game.Localisation // zh_hk, [Description(@"繁體中文(台灣)")] - zh_hant + zh_hant, + +#if DEBUG + [Description(@"Debug (show raw keys)")] + DebugLocalisation +#endif } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index eee86de7ff..b591b09584 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -628,6 +628,14 @@ namespace osu.Game foreach (var language in Enum.GetValues(typeof(Language)).OfType()) { +#if DEBUG + if (language == Language.DebugLocalisation) + { + Localisation.AddLanguage(Language.DebugLocalisation.ToString(), new DebugLocalisationStore()); + continue; + } +#endif + string cultureCode = language.ToCultureCode(); try From a195d4f5aa5a132bf6860e23ab04f327cb84b8a8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 16:49:41 +0900 Subject: [PATCH 47/74] Use a culture name that doesn't cause everything to fall over --- osu.Game/Localisation/DebugLocalisationStore.cs | 2 +- osu.Game/Localisation/Language.cs | 2 +- osu.Game/OsuGame.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Localisation/DebugLocalisationStore.cs b/osu.Game/Localisation/DebugLocalisationStore.cs index 99dca6265e..2b114b1bd8 100644 --- a/osu.Game/Localisation/DebugLocalisationStore.cs +++ b/osu.Game/Localisation/DebugLocalisationStore.cs @@ -21,7 +21,7 @@ namespace osu.Game.Localisation public IEnumerable GetAvailableResources() => throw new NotImplementedException(); - public CultureInfo EffectiveCulture { get; } = new CultureInfo(@"debug"); + public CultureInfo EffectiveCulture { get; } = CultureInfo.CurrentCulture; public void Dispose() { diff --git a/osu.Game/Localisation/Language.cs b/osu.Game/Localisation/Language.cs index c98586457e..c13a1a10cb 100644 --- a/osu.Game/Localisation/Language.cs +++ b/osu.Game/Localisation/Language.cs @@ -114,7 +114,7 @@ namespace osu.Game.Localisation #if DEBUG [Description(@"Debug (show raw keys)")] - DebugLocalisation + debug #endif } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b591b09584..ea21954b9c 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -629,9 +629,9 @@ namespace osu.Game foreach (var language in Enum.GetValues(typeof(Language)).OfType()) { #if DEBUG - if (language == Language.DebugLocalisation) + if (language == Language.debug) { - Localisation.AddLanguage(Language.DebugLocalisation.ToString(), new DebugLocalisationStore()); + Localisation.AddLanguage(Language.debug.ToString(), new DebugLocalisationStore()); continue; } #endif From 2a3a0c1cd38dbe61d4941913b18785ed3a5732a6 Mon Sep 17 00:00:00 2001 From: chickensalt Date: Tue, 19 Apr 2022 18:44:20 +1000 Subject: [PATCH 48/74] remove notification on trying to multi when logged out fixes #17877 --- osu.Game/Screens/Menu/ButtonSystem.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 598c441042..6d09b6de9f 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -161,17 +161,7 @@ namespace osu.Game.Screens.Menu { if (api.State.Value != APIState.Online) { - notifications?.Post(new SimpleNotification - { - Text = "You gotta be online to multi 'yo!", - Icon = FontAwesome.Solid.Globe, - Activated = () => - { - loginOverlay?.Show(); - return true; - } - }); - + loginOverlay?.Show(); return; } From 75a6e9fd7f7bbf82325051c89fe7eab3caa60dcc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 18:10:10 +0900 Subject: [PATCH 49/74] Convert to use `nullable` and rearrange fields --- .../Skinning/Legacy/LegacyMainCirclePiece.cs | 47 +++++++++---------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index 9d14041dd8..1fedc7daae 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -1,7 +1,7 @@ +#nullable enable // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; @@ -33,9 +33,25 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy /// If the "circle" texture could not be found with this prefix, /// then it is nullified and the default prefix "hitcircle" is used instead. /// - private string priorityLookupPrefix; + private string? priorityLookupPrefix; - public LegacyMainCirclePiece(string priorityLookupPrefix = null, bool hasNumber = true) + private Drawable hitCircleSprite = null!; + + protected Container OverlayLayer { get; private set; } = null!; + + private Drawable hitCircleOverlay = null!; + private SkinnableSpriteText hitCircleText = null!; + + private readonly Bindable accentColour = new Bindable(); + private readonly IBindable indexInCurrentCombo = new Bindable(); + + [Resolved(canBeNull: true)] + private DrawableHitObject? drawableObject { get; set; } + + [Resolved] + private ISkinSource skin { get; set; } = null!; + + public LegacyMainCirclePiece(string? priorityLookupPrefix = null, bool hasNumber = true) { this.priorityLookupPrefix = priorityLookupPrefix; this.hasNumber = hasNumber; @@ -43,30 +59,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); } - private Drawable hitCircleSprite; - - protected Container OverlayLayer { get; private set; } - - private Drawable hitCircleOverlay; - private SkinnableSpriteText hitCircleText; - - private readonly Bindable accentColour = new Bindable(); - private readonly IBindable indexInCurrentCombo = new Bindable(); - - [Resolved(canBeNull: true)] - [CanBeNull] - private DrawableHitObject drawableObject { get; set; } - - [Resolved] - private ISkinSource skin { get; set; } - [BackgroundDependencyLoader] private void load() { - var drawableOsuObject = (DrawableOsuHitObject)drawableObject; + var drawableOsuObject = (DrawableOsuHitObject?)drawableObject; // attempt lookup using priority specification - Texture baseTexture = getTexture(string.Empty); + Texture? baseTexture = getTexture(string.Empty); // if the base texture was not found using the priority specification, nullify the specification and fall back to "hitcircle". if (baseTexture == null) @@ -122,10 +121,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); } - Texture getTexture(string name) + Texture? getTexture(string name) => skin.GetTexture($"{priorityLookupPrefix ?? @"hitcircle"}{name}"); - Drawable getAnimation(string name, double frameLength) + Drawable? getAnimation(string name, double frameLength) => skin.GetAnimation($"{priorityLookupPrefix ?? @"hitcircle"}{name}", true, true, frameLength: frameLength); } From 44c822f34d7a332ba41381d871c42814e9a6daea Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Tue, 19 Apr 2022 16:56:55 +0100 Subject: [PATCH 50/74] Use normal `OsuScrollContainer` for `ChannelList` --- .../Overlays/Chat/ChannelList/ChannelList.cs | 28 +------------------ 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index 5c2a1ad89f..94c1a99a81 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -40,7 +40,7 @@ namespace osu.Game.Overlays.Chat.ChannelList RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background6, }, - new ChannelListScrollContainer + new OsuScrollContainer { Padding = new MarginPadding { Vertical = 7 }, RelativeSizeAxes = Axes.Both, @@ -131,31 +131,5 @@ namespace osu.Game.Overlays.Chat.ChannelList }); } } - - private class ChannelListScrollContainer : OsuScrollContainer - { - protected override ScrollbarContainer CreateScrollbar(Direction direction) - => new ChannelListScrollBar(direction); - - protected class ChannelListScrollBar : OsuScrollbar - { - private const float bar_size = 4; - private const float bar_margin = 7; - - public ChannelListScrollBar(Direction scrollDir) - : base(scrollDir) - { - Size = new Vector2(bar_size); - Margin = new MarginPadding { Horizontal = bar_margin }; - CornerRadius = 2; - } - - public override void ResizeTo(float val, int duration = 0, Easing easing = Easing.None) - { - Vector2 size = new Vector2(bar_size, val); - this.ResizeTo(size, duration, easing); - } - } - } } } From 033b556be58fe1b780d52d0b6c90b75eaea23f31 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 19 Apr 2022 19:39:06 +0300 Subject: [PATCH 51/74] Simplify texture lookup further --- .../Skinning/Legacy/LegacyMainCirclePiece.cs | 35 +++++-------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index 1fedc7daae..2107de61b6 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -8,7 +8,6 @@ using osu.Framework.Extensions.ObjectExtensions; 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.Sprites; using osu.Game.Rulesets.Objects.Drawables; @@ -24,16 +23,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public override bool RemoveCompletedTransforms => false; - private readonly bool hasNumber; - /// /// A prioritised prefix to perform texture lookups with. /// - /// - /// If the "circle" texture could not be found with this prefix, - /// then it is nullified and the default prefix "hitcircle" is used instead. - /// - private string? priorityLookupPrefix; + private readonly string? priorityLookupPrefix; + + private readonly bool hasNumber; private Drawable hitCircleSprite = null!; @@ -64,23 +59,17 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { var drawableOsuObject = (DrawableOsuHitObject?)drawableObject; - // attempt lookup using priority specification - Texture? baseTexture = getTexture(string.Empty); - - // if the base texture was not found using the priority specification, nullify the specification and fall back to "hitcircle". - if (baseTexture == null) - { - priorityLookupPrefix = null; - baseTexture = getTexture(string.Empty); - } + // if a base texture for the specified prefix exists, continue using it for subsequent lookups. + // otherwise fall back to the default prefix "hitcircle". + string circleName = (priorityLookupPrefix != null && skin.GetTexture(priorityLookupPrefix) != null) ? priorityLookupPrefix : @"hitcircle"; // at this point, any further texture fetches should be correctly using the priority source if the base texture was retrieved using it. - // the flow above handles the case where a sliderendcircle.png is retrieved from the skin, but sliderendcircleoverlay.png doesn't exist. + // the conditional above handles the case where a sliderendcircle.png is retrieved from the skin, but sliderendcircleoverlay.png doesn't exist. // expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png. InternalChildren = new[] { - hitCircleSprite = new KiaiFlashingDrawable(() => new Sprite { Texture = baseTexture }) + hitCircleSprite = new KiaiFlashingDrawable(() => new Sprite { Texture = skin.GetTexture(circleName) }) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -89,7 +78,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Child = hitCircleOverlay = new KiaiFlashingDrawable(() => getAnimation(@"overlay", 1000 / 2d)) + Child = hitCircleOverlay = new KiaiFlashingDrawable(() => skin.GetAnimation(@$"{circleName}overlay", true, true, frameLength: 1000 / 2d)) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -120,12 +109,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy accentColour.BindTo(drawableOsuObject.AccentColour); indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); } - - Texture? getTexture(string name) - => skin.GetTexture($"{priorityLookupPrefix ?? @"hitcircle"}{name}"); - - Drawable? getAnimation(string name, double frameLength) - => skin.GetAnimation($"{priorityLookupPrefix ?? @"hitcircle"}{name}", true, true, frameLength: frameLength); } protected override void LoadComplete() From 813dc2dd78fd0ba65bcae4caddd289be67447310 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 19 Apr 2022 19:46:29 +0300 Subject: [PATCH 52/74] Fix wrong prefix for default priority lookup in test --- osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs index 766db25d71..c9eeef3c01 100644 --- a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Tests // available textures new[] { @"hitcircle", @"hitcircleoverlay" }, // priority lookup - @"", + null, // expected circle and overlay @"hitcircle", @"hitcircleoverlay", }, From a96664295bfd6cec5adc4b9c222ca47707e5f207 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 19 Apr 2022 19:48:44 +0300 Subject: [PATCH 53/74] Fix nullability preprocessor placed over the copyright header --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index 2107de61b6..db4d643046 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -1,4 +1,3 @@ -#nullable enable // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. @@ -17,6 +16,8 @@ using osu.Game.Skinning; using osuTK; using osuTK.Graphics; +#nullable enable + namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class LegacyMainCirclePiece : CompositeDrawable From fd20c2bdcd7c174b27efded6d8e371ec2233ba1f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 20 Apr 2022 00:24:18 +0300 Subject: [PATCH 54/74] Change circle/overlay sprite fields to `protected` for better test assertion --- .../LegacyMainCirclePieceTest.cs | 25 ++++++++++++------- .../Skinning/Legacy/LegacyMainCirclePiece.cs | 20 +++++++-------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs index c9eeef3c01..fd5b6fd752 100644 --- a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Tests { // available textures new[] { @"hitcircle", @"hitcircleoverlay" }, - // priority lookup + // priority lookup prefix null, // expected circle and overlay @"hitcircle", @"hitcircleoverlay", @@ -66,8 +66,7 @@ namespace osu.Game.Rulesets.Osu.Tests [TestCaseSource(nameof(texture_priority_cases))] public void TestTexturePriorities(string[] textureFilenames, string priorityLookup, string? expectedCircle, string? expectedOverlay) { - Sprite? circleSprite = null; - Sprite? overlaySprite = null; + TestLegacyMainCirclePiece piece = null!; AddStep("load circle piece", () => { @@ -80,18 +79,26 @@ namespace osu.Game.Rulesets.Osu.Tests Child = new DependencyProvidingContainer { CachedDependencies = new (Type, object)[] { (typeof(ISkinSource), skin.Object) }, - Child = new LegacyMainCirclePiece(priorityLookup, false), + Child = piece = new TestLegacyMainCirclePiece(priorityLookup), }; var sprites = this.ChildrenOfType().Where(s => s.Texture.AssetName != null).DistinctBy(s => s.Texture.AssetName).ToArray(); Debug.Assert(sprites.Length <= 2); - - circleSprite = sprites.ElementAtOrDefault(0); - overlaySprite = sprites.ElementAtOrDefault(1); }); - AddAssert("check circle sprite", () => circleSprite?.Texture?.AssetName == expectedCircle); - AddAssert("check overlay sprite", () => overlaySprite?.Texture?.AssetName == expectedOverlay); + AddAssert("check circle sprite", () => piece.CircleSprite?.Texture?.AssetName == expectedCircle); + AddAssert("check overlay sprite", () => piece.OverlaySprite?.Texture?.AssetName == expectedOverlay); + } + + private class TestLegacyMainCirclePiece : LegacyMainCirclePiece + { + public new Sprite? CircleSprite => base.CircleSprite.ChildrenOfType().DistinctBy(s => s.Texture.AssetName).SingleOrDefault(); + public new Sprite? OverlaySprite => base.OverlaySprite.ChildrenOfType().DistinctBy(s => s.Texture.AssetName).SingleOrDefault(); + + public TestLegacyMainCirclePiece(string? priorityLookupPrefix) + : base(priorityLookupPrefix, false) + { + } } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index db4d643046..391147648f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -31,11 +31,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private readonly bool hasNumber; - private Drawable hitCircleSprite = null!; + protected Drawable CircleSprite = null!; + protected Drawable OverlaySprite = null!; protected Container OverlayLayer { get; private set; } = null!; - private Drawable hitCircleOverlay = null!; private SkinnableSpriteText hitCircleText = null!; private readonly Bindable accentColour = new Bindable(); @@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy InternalChildren = new[] { - hitCircleSprite = new KiaiFlashingDrawable(() => new Sprite { Texture = skin.GetTexture(circleName) }) + CircleSprite = new KiaiFlashingDrawable(() => new Sprite { Texture = skin.GetTexture(circleName) }) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Child = hitCircleOverlay = new KiaiFlashingDrawable(() => skin.GetAnimation(@$"{circleName}overlay", true, true, frameLength: 1000 / 2d)) + Child = OverlaySprite = new KiaiFlashingDrawable(() => skin.GetAnimation(@$"{circleName}overlay", true, true, frameLength: 1000 / 2d)) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy bool overlayAboveNumber = skin.GetConfig(OsuSkinConfiguration.HitCircleOverlayAboveNumber)?.Value ?? true; if (overlayAboveNumber) - OverlayLayer.ChangeChildDepth(hitCircleOverlay, float.MinValue); + OverlayLayer.ChangeChildDepth(OverlaySprite, float.MinValue); if (drawableOsuObject != null) { @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { base.LoadComplete(); - accentColour.BindValueChanged(colour => hitCircleSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true); + accentColour.BindValueChanged(colour => CircleSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true); if (hasNumber) indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true); @@ -136,11 +136,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy switch (state) { case ArmedState.Hit: - hitCircleSprite.FadeOut(legacy_fade_duration, Easing.Out); - hitCircleSprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); + CircleSprite.FadeOut(legacy_fade_duration, Easing.Out); + CircleSprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); - hitCircleOverlay.FadeOut(legacy_fade_duration, Easing.Out); - hitCircleOverlay.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); + OverlaySprite.FadeOut(legacy_fade_duration, Easing.Out); + OverlaySprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); if (hasNumber) { From 858c8f927f7baccc9328cb85847d0ea510d2b0a9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 20 Apr 2022 00:27:02 +0300 Subject: [PATCH 55/74] Attach comment explaining purpose of `CallBase` --- osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs index fd5b6fd752..d8c10b814d 100644 --- a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs @@ -72,7 +72,11 @@ namespace osu.Game.Rulesets.Osu.Tests { var skin = new Mock(); + // shouldn't be required as GetTexture(string) calls GetTexture(string, WrapMode, WrapMode) by default, + // but moq doesn't handle that well, therefore explicitly requiring to use `CallBase`: + // https://github.com/moq/moq4/issues/972 skin.Setup(s => s.GetTexture(It.IsAny())).CallBase(); + skin.Setup(s => s.GetTexture(It.IsIn(textureFilenames), It.IsAny(), It.IsAny())) .Returns((string componentName, WrapMode _, WrapMode __) => new Texture(1, 1) { AssetName = componentName }); From 4f8065160684cbc49e7a20cad355663e245a5578 Mon Sep 17 00:00:00 2001 From: chickensalt Date: Wed, 20 Apr 2022 10:33:06 +1000 Subject: [PATCH 56/74] implement 2a3a0c1 for playlists as well --- osu.Game/Screens/Menu/ButtonSystem.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 6d09b6de9f..6d9941ba87 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -172,17 +172,7 @@ namespace osu.Game.Screens.Menu { if (api.State.Value != APIState.Online) { - notifications?.Post(new SimpleNotification - { - Text = "You gotta be online to view playlists 'yo!", - Icon = FontAwesome.Solid.Globe, - Activated = () => - { - loginOverlay?.Show(); - return true; - } - }); - + loginOverlay?.Show(); return; } From f5863c20307b8e4ad8123fb25641b588a782dbd7 Mon Sep 17 00:00:00 2001 From: chickensalt Date: Wed, 20 Apr 2022 13:40:02 +1000 Subject: [PATCH 57/74] remove unused import --- osu.Game/Screens/Menu/ButtonSystem.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 6d9941ba87..b59e42551a 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -26,7 +26,6 @@ using osu.Game.Input.Bindings; using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Overlays; -using osu.Game.Overlays.Notifications; using osuTK; using osuTK.Graphics; using osuTK.Input; From d46329f55a4fc651b34ac654e963eb79a6e73f23 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Apr 2022 12:51:55 +0900 Subject: [PATCH 58/74] Remove unused dependency --- osu.Game/Screens/Menu/ButtonSystem.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index b59e42551a..2d18dce6da 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -116,9 +116,6 @@ namespace osu.Game.Screens.Menu [Resolved] private IAPIProvider api { get; set; } - [Resolved(CanBeNull = true)] - private INotificationOverlay notifications { get; set; } - [Resolved(CanBeNull = true)] private LoginOverlay loginOverlay { get; set; } From 8d31b0bc015461a5c05bb7e0ff9747823cdded5e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Apr 2022 15:05:07 +0900 Subject: [PATCH 59/74] Split out the base design of sheared overlay into its own abstract class This will allow for reuse with the first-run overlay. --- .../UserInterface/PopupScreenTitle.cs | 4 +- osu.Game/Overlays/Mods/ModSelectScreen.cs | 101 ++++--------- .../Overlays/Mods/ShearedOverlayContainer.cs | 136 ++++++++++++++++++ 3 files changed, 165 insertions(+), 76 deletions(-) create mode 100644 osu.Game/Overlays/Mods/ShearedOverlayContainer.cs diff --git a/osu.Game/Graphics/UserInterface/PopupScreenTitle.cs b/osu.Game/Graphics/UserInterface/PopupScreenTitle.cs index 5b7db09e77..2e5519726b 100644 --- a/osu.Game/Graphics/UserInterface/PopupScreenTitle.cs +++ b/osu.Game/Graphics/UserInterface/PopupScreenTitle.cs @@ -21,6 +21,8 @@ namespace osu.Game.Graphics.UserInterface { public class PopupScreenTitle : CompositeDrawable { + public const float HEIGHT = main_area_height + 2 * corner_radius; + public LocalisableString Title { set => titleSpriteText.Text = value; @@ -67,7 +69,7 @@ namespace osu.Game.Graphics.UserInterface underlayContainer = new Container { RelativeSizeAxes = Axes.X, - Height = main_area_height + 2 * corner_radius, + Height = HEIGHT, CornerRadius = corner_radius, Masking = true, BorderThickness = 2, diff --git a/osu.Game/Overlays/Mods/ModSelectScreen.cs b/osu.Game/Overlays/Mods/ModSelectScreen.cs index 62080ec1b5..6e8684478e 100644 --- a/osu.Game/Overlays/Mods/ModSelectScreen.cs +++ b/osu.Game/Overlays/Mods/ModSelectScreen.cs @@ -9,7 +9,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Framework.Layout; using osu.Game.Configuration; @@ -21,39 +20,27 @@ using osuTK.Input; namespace osu.Game.Overlays.Mods { - public class ModSelectScreen : OsuFocusedOverlayContainer + public class ModSelectScreen : ShearedOverlayContainer { - [Cached] - private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); + protected override OverlayColourScheme ColourScheme => OverlayColourScheme.Green; [Cached] public Bindable> SelectedMods { get; private set; } = new Bindable>(Array.Empty()); - protected override bool StartHidden => true; - private readonly BindableBool customisationVisible = new BindableBool(); private DifficultyMultiplierDisplay multiplierDisplay; private ModSettingsArea modSettingsArea; private FillFlowContainer columnFlow; private GridContainer grid; - private Container mainContent; - - private PopupScreenTitle header; - private Container footer; [BackgroundDependencyLoader] private void load() { - RelativeSizeAxes = Axes.Both; - RelativePositionAxes = Axes.Both; - - InternalChildren = new Drawable[] + MainAreaContent.AddRange(new Drawable[] { - mainContent = new Container + new Container { - Origin = Anchor.BottomCentre, - Anchor = Anchor.BottomCentre, RelativeSizeAxes = Axes.Both, Children = new Drawable[] { @@ -62,24 +49,11 @@ namespace osu.Game.Overlays.Mods RelativeSizeAxes = Axes.Both, RowDimensions = new[] { - new Dimension(GridSizeMode.AutoSize), new Dimension(GridSizeMode.AutoSize), new Dimension(), - new Dimension(GridSizeMode.Absolute, 75), }, Content = new[] { - new Drawable[] - { - header = new PopupScreenTitle - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Title = "Mod Select", - Description = "Mods provide different ways to enjoy gameplay. Some have an effect on the score you can achieve during ranked play. Others are just for fun.", - Close = Hide - } - }, new Drawable[] { new Container @@ -120,6 +94,7 @@ namespace osu.Game.Overlays.Mods Child = columnFlow = new ModColumnContainer { Direction = FillDirection.Horizontal, + Shear = new Vector2(ModPanel.SHEAR_X, 0), RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, Spacing = new Vector2(10, 0), @@ -137,52 +112,36 @@ namespace osu.Game.Overlays.Mods } } }, - new[] { Empty() } } }, - footer = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.X, - Height = 50, - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Colour = colourProvider.Background5 - }, - new ShearedToggleButton(200) - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Margin = new MarginPadding { Vertical = 14, Left = 70 }, - Text = "Mod Customisation", - Active = { BindTarget = customisationVisible } - } - } - }, - new ClickToReturnContainer - { - RelativeSizeAxes = Axes.Both, - HandleMouse = { BindTarget = customisationVisible }, - OnClicked = () => customisationVisible.Value = false - } } }, + }); + + Footer.Add(new ShearedToggleButton(200) + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Margin = new MarginPadding { Vertical = 14, Left = 70 }, + Text = "Mod Customisation", + Active = { BindTarget = customisationVisible } + }); + + AddRange(new Drawable[] + { + new ClickToReturnContainer + { + RelativeSizeAxes = Axes.Both, + HandleMouse = { BindTarget = customisationVisible }, + OnClicked = () => customisationVisible.Value = false + }, modSettingsArea = new ModSettingsArea { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, Height = 0 } - }; - - columnFlow.Shear = new Vector2(ModPanel.SHEAR_X, 0); + }); } protected override void LoadComplete() @@ -252,7 +211,7 @@ namespace osu.Game.Overlays.Mods float modAreaHeight = customisationVisible.Value ? ModSettingsArea.HEIGHT : 0; modSettingsArea.ResizeHeightTo(modAreaHeight, transition_duration, Easing.InOutCubic); - mainContent.TransformTo(nameof(Margin), new MarginPadding { Bottom = modAreaHeight }, transition_duration, Easing.InOutCubic); + TopLevelContent.MoveToY(-modAreaHeight, transition_duration, Easing.InOutCubic); } private bool selectionBindableSyncInProgress; @@ -287,10 +246,6 @@ namespace osu.Game.Overlays.Mods const double fade_in_duration = 400; base.PopIn(); - this.FadeIn(fade_in_duration, Easing.OutQuint); - - header.MoveToY(0, fade_in_duration, Easing.OutQuint); - footer.MoveToY(0, fade_in_duration, Easing.OutQuint); multiplierDisplay .Delay(fade_in_duration * 0.65f) @@ -311,15 +266,11 @@ namespace osu.Game.Overlays.Mods const double fade_out_duration = 500; base.PopOut(); - this.FadeOut(fade_out_duration, Easing.OutQuint); multiplierDisplay .FadeOut(fade_out_duration / 2, Easing.OutQuint) .ScaleTo(0.75f, fade_out_duration, Easing.OutQuint); - header.MoveToY(-header.DrawHeight, fade_out_duration, Easing.OutQuint); - footer.MoveToY(footer.DrawHeight, fade_out_duration, Easing.OutQuint); - for (int i = 0; i < columnFlow.Count; i++) { const float distance = 700; diff --git a/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs b/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs new file mode 100644 index 0000000000..46a3ad3c8d --- /dev/null +++ b/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs @@ -0,0 +1,136 @@ +// Copyright (c) ppy Pty Ltd . 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; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays.Mods +{ + /// + /// A sheared overlay which provides a header and footer and basic animations. + /// Exposes , and as valid targets for content. + /// + public abstract class ShearedOverlayContainer : OsuFocusedOverlayContainer + { + [Cached] + protected readonly OverlayColourProvider ColourProvider; + + /// + /// The overlay's header. + /// + protected PopupScreenTitle Header { get; private set; } + + /// + /// The overlay's footer. + /// + protected Container Footer { get; private set; } + + /// + /// A container containing all content, including the header and footer. + /// May be used for overlay-wide animations. + /// + protected Container TopLevelContent { get; private set; } + + /// + /// A container for content that is to be displayed between the header and footer. + /// + protected Container MainAreaContent { get; private set; } + + /// + /// A container for content that is to be displayed inside the footer. + /// + protected Container FooterContent { get; private set; } + + protected abstract OverlayColourScheme ColourScheme { get; } + + protected override bool StartHidden => true; + + protected override bool BlockNonPositionalInput => true; + + protected ShearedOverlayContainer() + { + RelativeSizeAxes = Axes.Both; + + ColourProvider = new OverlayColourProvider(ColourScheme); + } + + [BackgroundDependencyLoader] + private void load() + { + const float footer_height = 50; + + Child = TopLevelContent = new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + Header = new PopupScreenTitle + { + Anchor = Anchor.TopCentre, + Depth = float.MinValue, + Origin = Anchor.TopCentre, + Title = "Mod Select", + Description = "Mods provide different ways to enjoy gameplay. Some have an effect on the score you can achieve during ranked play. Others are just for fun.", + Close = Hide + }, + MainAreaContent = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding + { + Top = PopupScreenTitle.HEIGHT, + Bottom = footer_height, + } + }, + Footer = new Container + { + RelativeSizeAxes = Axes.X, + Depth = float.MinValue, + Height = footer_height, + Margin = new MarginPadding { Top = 10 }, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourProvider.Background5 + }, + FooterContent = new Container + { + RelativeSizeAxes = Axes.Both, + }, + } + } + } + }; + } + + protected override void PopIn() + { + const double fade_in_duration = 400; + + base.PopIn(); + this.FadeIn(fade_in_duration, Easing.OutQuint); + + Header.MoveToY(0, fade_in_duration, Easing.OutQuint); + Footer.MoveToY(0, fade_in_duration, Easing.OutQuint); + } + + protected override void PopOut() + { + const double fade_out_duration = 500; + + base.PopOut(); + this.FadeOut(fade_out_duration, Easing.OutQuint); + + Header.MoveToY(-Header.DrawHeight, fade_out_duration, Easing.OutQuint); + Footer.MoveToY(Footer.DrawHeight, fade_out_duration, Easing.OutQuint); + } + } +} From 1032dc235dae06d61460c0fd019472bb4994ad04 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Apr 2022 15:50:57 +0900 Subject: [PATCH 60/74] Rename `PopupScreenTitle` to `ShearedOverlayHeader` --- ...reenTitle.cs => TestSceneShearedOverlayHeader.cs} | 12 ++++++------ .../{PopupScreenTitle.cs => ShearedOverlayHeader.cs} | 4 ++-- osu.Game/Overlays/Mods/ShearedOverlayContainer.cs | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) rename osu.Game.Tests/Visual/UserInterface/{TestScenePopupScreenTitle.cs => TestSceneShearedOverlayHeader.cs} (76%) rename osu.Game/Graphics/UserInterface/{PopupScreenTitle.cs => ShearedOverlayHeader.cs} (98%) diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePopupScreenTitle.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedOverlayHeader.cs similarity index 76% rename from osu.Game.Tests/Visual/UserInterface/TestScenePopupScreenTitle.cs rename to osu.Game.Tests/Visual/UserInterface/TestSceneShearedOverlayHeader.cs index 22a8fa8a46..ef2b25cd92 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePopupScreenTitle.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedOverlayHeader.cs @@ -10,19 +10,19 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestScenePopupScreenTitle : OsuTestScene + public class TestSceneShearedOverlayHeader : OsuTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); [Test] - public void TestPopupScreenTitle() + public void TestShearedOverlayHeader() { AddStep("create content", () => { - Child = new PopupScreenTitle + Child = new ShearedOverlayHeader { - Title = "Popup Screen Title", + Title = "Sheared overlay header", Description = string.Join(" ", Enumerable.Repeat("This is a description.", 20)), Close = () => { } }; @@ -34,9 +34,9 @@ namespace osu.Game.Tests.Visual.UserInterface { AddStep("create content", () => { - Child = new PopupScreenTitle + Child = new ShearedOverlayHeader { - Title = "Popup Screen Title", + Title = "Sheared overlay header", Description = "This is a description." }; }); diff --git a/osu.Game/Graphics/UserInterface/PopupScreenTitle.cs b/osu.Game/Graphics/UserInterface/ShearedOverlayHeader.cs similarity index 98% rename from osu.Game/Graphics/UserInterface/PopupScreenTitle.cs rename to osu.Game/Graphics/UserInterface/ShearedOverlayHeader.cs index 2e5519726b..9ed7bb35de 100644 --- a/osu.Game/Graphics/UserInterface/PopupScreenTitle.cs +++ b/osu.Game/Graphics/UserInterface/ShearedOverlayHeader.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public class PopupScreenTitle : CompositeDrawable + public class ShearedOverlayHeader : CompositeDrawable { public const float HEIGHT = main_area_height + 2 * corner_radius; @@ -50,7 +50,7 @@ namespace osu.Game.Graphics.UserInterface private readonly OsuTextFlowContainer descriptionText; private readonly IconButton closeButton; - public PopupScreenTitle() + public ShearedOverlayHeader() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; diff --git a/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs b/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs index 46a3ad3c8d..b6f6cf1468 100644 --- a/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs +++ b/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs @@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Mods /// /// The overlay's header. /// - protected PopupScreenTitle Header { get; private set; } + protected ShearedOverlayHeader Header { get; private set; } /// /// The overlay's footer. @@ -68,7 +68,7 @@ namespace osu.Game.Overlays.Mods RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - Header = new PopupScreenTitle + Header = new ShearedOverlayHeader { Anchor = Anchor.TopCentre, Depth = float.MinValue, @@ -82,7 +82,7 @@ namespace osu.Game.Overlays.Mods RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { - Top = PopupScreenTitle.HEIGHT, + Top = ShearedOverlayHeader.HEIGHT, Bottom = footer_height, } }, From 2ee37aeceb5c30f1f36eaa94707a02484f4c217e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Apr 2022 15:57:45 +0900 Subject: [PATCH 61/74] Reduce nesting and usage of `GridContainer` --- osu.Game/Overlays/Mods/ModSelectScreen.cs | 159 +++++++++------------- 1 file changed, 67 insertions(+), 92 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectScreen.cs b/osu.Game/Overlays/Mods/ModSelectScreen.cs index 6e8684478e..452c6e32a6 100644 --- a/osu.Game/Overlays/Mods/ModSelectScreen.cs +++ b/osu.Game/Overlays/Mods/ModSelectScreen.cs @@ -32,101 +32,10 @@ namespace osu.Game.Overlays.Mods private DifficultyMultiplierDisplay multiplierDisplay; private ModSettingsArea modSettingsArea; private FillFlowContainer columnFlow; - private GridContainer grid; [BackgroundDependencyLoader] private void load() { - MainAreaContent.AddRange(new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - grid = new GridContainer - { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - }, - Content = new[] - { - new Drawable[] - { - new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.X, - RelativePositionAxes = Axes.X, - X = 0.3f, - Height = DifficultyMultiplierDisplay.HEIGHT, - Margin = new MarginPadding - { - Horizontal = 100, - Vertical = 10 - }, - Child = multiplierDisplay = new DifficultyMultiplierDisplay - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre - } - } - }, - new Drawable[] - { - new Container - { - Depth = float.MaxValue, - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Both, - Children = new Drawable[] - { - new OsuScrollContainer(Direction.Horizontal) - { - RelativeSizeAxes = Axes.Both, - Masking = false, - ClampExtension = 100, - ScrollbarOverlapsContent = false, - Child = columnFlow = new ModColumnContainer - { - Direction = FillDirection.Horizontal, - Shear = new Vector2(ModPanel.SHEAR_X, 0), - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Spacing = new Vector2(10, 0), - Margin = new MarginPadding { Right = 70 }, - Children = new[] - { - new ModColumn(ModType.DifficultyReduction, false, new[] { Key.Q, Key.W, Key.E, Key.R, Key.T, Key.Y, Key.U, Key.I, Key.O, Key.P }), - new ModColumn(ModType.DifficultyIncrease, false, new[] { Key.A, Key.S, Key.D, Key.F, Key.G, Key.H, Key.J, Key.K, Key.L }), - new ModColumn(ModType.Automation, false, new[] { Key.Z, Key.X, Key.C, Key.V, Key.B, Key.N, Key.M }), - new ModColumn(ModType.Conversion, false), - new ModColumn(ModType.Fun, false) - } - } - } - } - } - }, - } - }, - } - }, - }); - - Footer.Add(new ShearedToggleButton(200) - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Margin = new MarginPadding { Vertical = 14, Left = 70 }, - Text = "Mod Customisation", - Active = { BindTarget = customisationVisible } - }); - AddRange(new Drawable[] { new ClickToReturnContainer @@ -142,6 +51,72 @@ namespace osu.Game.Overlays.Mods Height = 0 } }); + + MainAreaContent.AddRange(new Drawable[] + { + new Container + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.X, + Height = DifficultyMultiplierDisplay.HEIGHT, + Margin = new MarginPadding + { + Horizontal = 100, + }, + Child = multiplierDisplay = new DifficultyMultiplierDisplay + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + } + }, + new Container + { + Margin = new MarginPadding + { + Vertical = DifficultyMultiplierDisplay.HEIGHT + 10, + }, + Depth = float.MaxValue, + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + Children = new Drawable[] + { + new OsuScrollContainer(Direction.Horizontal) + { + RelativeSizeAxes = Axes.Both, + Masking = false, + ClampExtension = 100, + ScrollbarOverlapsContent = false, + Child = columnFlow = new ModColumnContainer + { + Direction = FillDirection.Horizontal, + Shear = new Vector2(ModPanel.SHEAR_X, 0), + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Spacing = new Vector2(10, 0), + Margin = new MarginPadding { Right = 70 }, + Children = new[] + { + new ModColumn(ModType.DifficultyReduction, false, new[] { Key.Q, Key.W, Key.E, Key.R, Key.T, Key.Y, Key.U, Key.I, Key.O, Key.P }), + new ModColumn(ModType.DifficultyIncrease, false, new[] { Key.A, Key.S, Key.D, Key.F, Key.G, Key.H, Key.J, Key.K, Key.L }), + new ModColumn(ModType.Automation, false, new[] { Key.Z, Key.X, Key.C, Key.V, Key.B, Key.N, Key.M }), + new ModColumn(ModType.Conversion, false), + new ModColumn(ModType.Fun, false) + } + } + } + } + } + }); + + Footer.Add(new ShearedToggleButton(200) + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Margin = new MarginPadding { Vertical = 14, Left = 70 }, + Text = "Mod Customisation", + Active = { BindTarget = customisationVisible } + }); } protected override void LoadComplete() @@ -206,7 +181,7 @@ namespace osu.Game.Overlays.Mods { const double transition_duration = 300; - grid.FadeColour(customisationVisible.Value ? Colour4.Gray : Colour4.White, transition_duration, Easing.InOutCubic); + MainAreaContent.FadeColour(customisationVisible.Value ? Colour4.Gray : Colour4.White, transition_duration, Easing.InOutCubic); float modAreaHeight = customisationVisible.Value ? ModSettingsArea.HEIGHT : 0; From 5c7ff363ce406ca8ef4c6c21bc6f76eb7b42f58d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Apr 2022 16:08:00 +0900 Subject: [PATCH 62/74] Move title/description to correct class --- osu.Game/Overlays/Mods/ModSelectScreen.cs | 3 +++ osu.Game/Overlays/Mods/ShearedOverlayContainer.cs | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectScreen.cs b/osu.Game/Overlays/Mods/ModSelectScreen.cs index 452c6e32a6..7c857d5a90 100644 --- a/osu.Game/Overlays/Mods/ModSelectScreen.cs +++ b/osu.Game/Overlays/Mods/ModSelectScreen.cs @@ -36,6 +36,9 @@ namespace osu.Game.Overlays.Mods [BackgroundDependencyLoader] private void load() { + Header.Title = "Mod Select"; + Header.Description = "Mods provide different ways to enjoy gameplay. Some have an effect on the score you can achieve during ranked play. Others are just for fun."; + AddRange(new Drawable[] { new ClickToReturnContainer diff --git a/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs b/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs index b6f6cf1468..76a81421fa 100644 --- a/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs +++ b/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs @@ -73,8 +73,6 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.TopCentre, Depth = float.MinValue, Origin = Anchor.TopCentre, - Title = "Mod Select", - Description = "Mods provide different ways to enjoy gameplay. Some have an effect on the score you can achieve during ranked play. Others are just for fun.", Close = Hide }, MainAreaContent = new Container From e17f224793bc31ebf92b8ae5113f221d61d908b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Apr 2022 16:28:52 +0900 Subject: [PATCH 63/74] Fix padding mismatches --- osu.Game/Overlays/Mods/ModSelectScreen.cs | 6 +++--- osu.Game/Overlays/Mods/ShearedOverlayContainer.cs | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectScreen.cs b/osu.Game/Overlays/Mods/ModSelectScreen.cs index 7c857d5a90..a9992d70bc 100644 --- a/osu.Game/Overlays/Mods/ModSelectScreen.cs +++ b/osu.Game/Overlays/Mods/ModSelectScreen.cs @@ -75,9 +75,9 @@ namespace osu.Game.Overlays.Mods }, new Container { - Margin = new MarginPadding + Padding = new MarginPadding { - Vertical = DifficultyMultiplierDisplay.HEIGHT + 10, + Top = DifficultyMultiplierDisplay.HEIGHT + PADDING, }, Depth = float.MaxValue, RelativeSizeAxes = Axes.Both, @@ -116,7 +116,7 @@ namespace osu.Game.Overlays.Mods { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, - Margin = new MarginPadding { Vertical = 14, Left = 70 }, + Margin = new MarginPadding { Vertical = PADDING, Left = 70 }, Text = "Mod Customisation", Active = { BindTarget = customisationVisible } }); diff --git a/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs b/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs index 76a81421fa..0bdd4189a0 100644 --- a/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs +++ b/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs @@ -16,6 +16,8 @@ namespace osu.Game.Overlays.Mods /// public abstract class ShearedOverlayContainer : OsuFocusedOverlayContainer { + protected const float PADDING = 14; + [Cached] protected readonly OverlayColourProvider ColourProvider; @@ -81,7 +83,7 @@ namespace osu.Game.Overlays.Mods Padding = new MarginPadding { Top = ShearedOverlayHeader.HEIGHT, - Bottom = footer_height, + Bottom = footer_height + PADDING, } }, Footer = new Container @@ -89,7 +91,7 @@ namespace osu.Game.Overlays.Mods RelativeSizeAxes = Axes.X, Depth = float.MinValue, Height = footer_height, - Margin = new MarginPadding { Top = 10 }, + Margin = new MarginPadding { Top = PADDING }, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, Children = new Drawable[] From 65b2db5e71fc86dab1d1f2c7416123f002c83d93 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Apr 2022 16:30:58 +0900 Subject: [PATCH 64/74] Move shear constant to overlay (this is going to likely be used everywhere ever) --- osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs | 6 +++--- osu.Game/Overlays/Mods/ModColumn.cs | 8 ++++---- osu.Game/Overlays/Mods/ModPanel.cs | 11 +++++------ osu.Game/Overlays/Mods/ModSelectScreen.cs | 4 ++-- osu.Game/Overlays/Mods/ShearedOverlayContainer.cs | 2 ++ 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs index 248d4f288e..66fd6a202d 100644 --- a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs +++ b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Mods AutoSizeAxes = Axes.X, Masking = true, CornerRadius = ModPanel.CORNER_RADIUS, - Shear = new Vector2(ModPanel.SHEAR_X, 0), + Shear = new Vector2(ShearedOverlayContainer.SHEAR, 0), Children = new Drawable[] { underlayBackground = new Box @@ -98,7 +98,7 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.Centre, Origin = Anchor.Centre, Margin = new MarginPadding { Horizontal = 18 }, - Shear = new Vector2(-ModPanel.SHEAR_X, 0), + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), Text = "Difficulty Multiplier", Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold) } @@ -109,7 +109,7 @@ namespace osu.Game.Overlays.Mods AutoSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Shear = new Vector2(-ModPanel.SHEAR_X, 0), + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), Direction = FillDirection.Horizontal, Spacing = new Vector2(2, 0), Children = new Drawable[] diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index f84ae4ac8a..78b4e24a4e 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Mods Width = 320; RelativeSizeAxes = Axes.Y; - Shear = new Vector2(ModPanel.SHEAR_X, 0); + Shear = new Vector2(ShearedOverlayContainer.SHEAR, 0); Container controlContainer; InternalChildren = new Drawable[] @@ -113,7 +113,7 @@ namespace osu.Game.Overlays.Mods AutoSizeAxes = Axes.Y, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Shear = new Vector2(-ModPanel.SHEAR_X, 0), + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), Padding = new MarginPadding { Horizontal = 17, @@ -193,7 +193,7 @@ namespace osu.Game.Overlays.Mods Scale = new Vector2(0.8f), RelativeSizeAxes = Axes.X, LabelText = "Enable All", - Shear = new Vector2(-ModPanel.SHEAR_X, 0) + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0) }); panelFlow.Padding = new MarginPadding { @@ -260,7 +260,7 @@ namespace osu.Game.Overlays.Mods var panels = newMods.Select(mod => new ModPanel(mod) { - Shear = new Vector2(-ModPanel.SHEAR_X, 0) + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0) }); Task? loadTask; diff --git a/osu.Game/Overlays/Mods/ModPanel.cs b/osu.Game/Overlays/Mods/ModPanel.cs index 312171cf74..7c4f2dcb7e 100644 --- a/osu.Game/Overlays/Mods/ModPanel.cs +++ b/osu.Game/Overlays/Mods/ModPanel.cs @@ -42,7 +42,6 @@ namespace osu.Game.Overlays.Mods protected const double TRANSITION_DURATION = 150; - public const float SHEAR_X = 0.2f; public const float CORNER_RADIUS = 7; protected const float HEIGHT = 42; @@ -67,7 +66,7 @@ namespace osu.Game.Overlays.Mods Content.Masking = true; Content.CornerRadius = CORNER_RADIUS; Content.BorderThickness = 2; - Content.Shear = new Vector2(SHEAR_X, 0); + Content.Shear = new Vector2(ShearedOverlayContainer.SHEAR, 0); Children = new Drawable[] { @@ -83,7 +82,7 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.Centre, Origin = Anchor.Centre, Active = { BindTarget = Active }, - Shear = new Vector2(-SHEAR_X, 0), + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), Scale = new Vector2(HEIGHT / ModSwitchSmall.DEFAULT_SIZE) } }, @@ -116,10 +115,10 @@ namespace osu.Game.Overlays.Mods { Text = mod.Name, Font = OsuFont.TorusAlternate.With(size: 18, weight: FontWeight.SemiBold), - Shear = new Vector2(-SHEAR_X, 0), + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), Margin = new MarginPadding { - Left = -18 * SHEAR_X + Left = -18 * ShearedOverlayContainer.SHEAR } }, new OsuSpriteText @@ -128,7 +127,7 @@ namespace osu.Game.Overlays.Mods Font = OsuFont.Default.With(size: 12), RelativeSizeAxes = Axes.X, Truncate = true, - Shear = new Vector2(-SHEAR_X, 0) + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0) } } } diff --git a/osu.Game/Overlays/Mods/ModSelectScreen.cs b/osu.Game/Overlays/Mods/ModSelectScreen.cs index a9992d70bc..94f877a08c 100644 --- a/osu.Game/Overlays/Mods/ModSelectScreen.cs +++ b/osu.Game/Overlays/Mods/ModSelectScreen.cs @@ -93,7 +93,7 @@ namespace osu.Game.Overlays.Mods Child = columnFlow = new ModColumnContainer { Direction = FillDirection.Horizontal, - Shear = new Vector2(ModPanel.SHEAR_X, 0), + Shear = new Vector2(SHEAR, 0), RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, Spacing = new Vector2(10, 0), @@ -284,7 +284,7 @@ namespace osu.Game.Overlays.Mods { Padding = new MarginPadding { - Left = DrawHeight * ModPanel.SHEAR_X, + Left = DrawHeight * SHEAR, Bottom = 10 }; diff --git a/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs b/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs index 0bdd4189a0..62ed736dc2 100644 --- a/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs +++ b/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs @@ -18,6 +18,8 @@ namespace osu.Game.Overlays.Mods { protected const float PADDING = 14; + public const float SHEAR = 0.2f; + [Cached] protected readonly OverlayColourProvider ColourProvider; From 4466e15bfcf3a0b7c93ba3c9cfc1da87509a6393 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Apr 2022 23:17:29 +0900 Subject: [PATCH 65/74] Rename `AllowConfiguration` to `AllowCustomisation` and simplify drawable addition --- osu.Game/Overlays/Mods/ModSelectScreen.cs | 57 ++++++++++--------- .../Screens/OnlinePlay/FreeModSelectScreen.cs | 2 +- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectScreen.cs b/osu.Game/Overlays/Mods/ModSelectScreen.cs index 41cbfdafb3..693c85fafc 100644 --- a/osu.Game/Overlays/Mods/ModSelectScreen.cs +++ b/osu.Game/Overlays/Mods/ModSelectScreen.cs @@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Mods /// /// Whether configurable s can be configured by the local user. /// - protected virtual bool AllowConfiguration => true; + protected virtual bool AllowCustomisation => true; /// /// Whether the total score multiplier calculated from the current selected set of mods should be shown. @@ -85,29 +85,12 @@ namespace osu.Game.Overlays.Mods MainAreaContent.AddRange(new Drawable[] { - new Container - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.X, - Height = DifficultyMultiplierDisplay.HEIGHT, - Margin = new MarginPadding - { - Horizontal = 100, - }, - Child = multiplierDisplay = new DifficultyMultiplierDisplay - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre - } - }, new Container { Padding = new MarginPadding { - Top = DifficultyMultiplierDisplay.HEIGHT + PADDING, + Top = (ShowTotalMultiplier ? DifficultyMultiplierDisplay.HEIGHT : 0) + PADDING, }, - Depth = float.MaxValue, RelativeSizeAxes = Axes.Both, RelativePositionAxes = Axes.Both, Children = new Drawable[] @@ -140,14 +123,34 @@ namespace osu.Game.Overlays.Mods } }); - Footer.Add(new ShearedToggleButton(200) + if (ShowTotalMultiplier) { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Margin = new MarginPadding { Vertical = PADDING, Left = 70 }, - Text = "Mod Customisation", - Active = { BindTarget = customisationVisible } - }); + MainAreaContent.Add(new Container + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.X, + Height = DifficultyMultiplierDisplay.HEIGHT, + Margin = new MarginPadding { Horizontal = 100 }, + Child = multiplierDisplay = new DifficultyMultiplierDisplay + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }, + }); + } + + if (AllowCustomisation) + { + Footer.Add(new ShearedToggleButton(200) + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Margin = new MarginPadding { Vertical = PADDING, Left = 70 }, + Text = "Mod Customisation", + Active = { BindTarget = customisationVisible } + }); + } } protected override void LoadComplete() @@ -194,7 +197,7 @@ namespace osu.Game.Overlays.Mods private void updateCustomisation(ValueChangedEvent> valueChangedEvent) { - if (!AllowConfiguration) + if (!AllowCustomisation) return; bool anyCustomisableMod = false; diff --git a/osu.Game/Screens/OnlinePlay/FreeModSelectScreen.cs b/osu.Game/Screens/OnlinePlay/FreeModSelectScreen.cs index 438b334e0b..c85a4fc38b 100644 --- a/osu.Game/Screens/OnlinePlay/FreeModSelectScreen.cs +++ b/osu.Game/Screens/OnlinePlay/FreeModSelectScreen.cs @@ -10,7 +10,7 @@ namespace osu.Game.Screens.OnlinePlay { public class FreeModSelectScreen : ModSelectScreen { - protected override bool AllowConfiguration => false; + protected override bool AllowCustomisation => false; protected override bool ShowTotalMultiplier => false; public new Func IsValidMod From e596c9d1713f82f3000f1c5029ee20d4a96ebdb3 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Wed, 20 Apr 2022 19:12:43 +0100 Subject: [PATCH 66/74] Use `Bindable` to control selector active visibility --- .../Visual/Online/TestSceneChannelList.cs | 9 +++-- .../Overlays/Chat/ChannelList/ChannelList.cs | 8 +++- .../Chat/ChannelList/ChannelListItem.cs | 38 +++++++++++-------- .../Chat/ChannelList/ChannelListSelector.cs | 14 ++++++- 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs index d6a1e71f0d..2bfe42e6d4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs @@ -25,6 +25,9 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly Bindable selected = new Bindable(); + [Cached] + private readonly Bindable selector = new Bindable(); + private OsuSpriteText selectorText; private OsuSpriteText selectedText; private OsuSpriteText leaveText; @@ -89,7 +92,7 @@ namespace osu.Game.Tests.Visual.Online channelList.OnRequestSelect += channel => { - channelList.SelectorActive.Value = false; + selector.Value = ChannelSelectorState.Hidden; selected.Value = channel; }; @@ -101,9 +104,9 @@ namespace osu.Game.Tests.Visual.Online channelList.RemoveChannel(channel); }; - channelList.SelectorActive.BindValueChanged(change => + selector.BindValueChanged(change => { - selectorText.Text = $"Channel Selector Active: {change.NewValue}"; + selectorText.Text = $"Channel Selector State: {change.NewValue}"; }, true); selected.BindValueChanged(change => diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index 94c1a99a81..578ac2aa45 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -14,7 +14,6 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Online.Chat; -using osuTK; namespace osu.Game.Overlays.Chat.ChannelList { @@ -57,7 +56,6 @@ namespace osu.Game.Overlays.Chat.ChannelList new ChannelListSelector { Margin = new MarginPadding { Bottom = 10 }, - SelectorActive = { BindTarget = SelectorActive }, }, privateChannelFlow = new ChannelListItemFlow("DIRECT MESSAGES"), }, @@ -132,4 +130,10 @@ namespace osu.Game.Overlays.Chat.ChannelList } } } + + public enum ChannelSelectorState + { + Visibile, + Hidden, + } } diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs index 43574351ed..3d59d1dc4c 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs @@ -31,14 +31,17 @@ namespace osu.Game.Overlays.Chat.ChannelList private readonly Channel channel; - private Box? hoverBox; - private Box? selectBox; - private OsuSpriteText? text; - private ChannelListItemCloseButton? close; + private Box hoverBox = null!; + private Box selectBox = null!; + private OsuSpriteText text = null!; + private ChannelListItemCloseButton close = null!; [Resolved] private Bindable selectedChannel { get; set; } = null!; + [Resolved] + private Bindable selectorState { get; set; } = null!; + [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -124,31 +127,26 @@ namespace osu.Game.Overlays.Chat.ChannelList { base.LoadComplete(); - selectedChannel.BindValueChanged(change => - { - if (change.NewValue == channel) - selectBox?.FadeIn(300, Easing.OutQuint); - else - selectBox?.FadeOut(200, Easing.OutQuint); - }, true); + selectedChannel.BindValueChanged(_ => updateSelectState(), true); + selectorState.BindValueChanged(_ => updateSelectState(), true); Unread.BindValueChanged(change => { - text!.FadeColour(change.NewValue ? colourProvider.Content1 : colourProvider.Light3, 300, Easing.OutQuint); + text.FadeColour(change.NewValue ? colourProvider.Content1 : colourProvider.Light3, 300, Easing.OutQuint); }, true); } protected override bool OnHover(HoverEvent e) { - hoverBox?.FadeIn(300, Easing.OutQuint); - close?.FadeIn(300, Easing.OutQuint); + hoverBox.FadeIn(300, Easing.OutQuint); + close.FadeIn(300, Easing.OutQuint); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - hoverBox?.FadeOut(200, Easing.OutQuint); - close?.FadeOut(200, Easing.OutQuint); + hoverBox.FadeOut(200, Easing.OutQuint); + close.FadeOut(200, Easing.OutQuint); base.OnHoverLost(e); } @@ -167,5 +165,13 @@ namespace osu.Game.Overlays.Chat.ChannelList Masking = true, }; } + + private void updateSelectState() + { + if (selectedChannel.Value == channel && selectorState.Value == ChannelSelectorState.Hidden) + selectBox.FadeIn(300, Easing.OutQuint); + else + selectBox.FadeOut(200, Easing.OutQuint); + } } } diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs index 5bc9a01598..4529a34f84 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs @@ -22,6 +22,9 @@ namespace osu.Game.Overlays.Chat.ChannelList private Box hoverBox = null!; private Box selectBox = null!; + [Resolved] + private Bindable selectorState { get; set; } = null!; + [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { @@ -65,8 +68,15 @@ namespace osu.Game.Overlays.Chat.ChannelList { base.LoadComplete(); - SelectorActive.BindValueChanged(selected => selectBox.FadeTo(selected.NewValue ? 1 : 0)); - Action = () => SelectorActive.Value = true; + selectorState.BindValueChanged(selector => + { + if (selector.NewValue == ChannelSelectorState.Visibile) + selectBox.FadeIn(300, Easing.OutQuint); + else + selectBox.FadeOut(200, Easing.OutQuint); + }, true); + + Action = () => selectorState.Value = ChannelSelectorState.Visibile; } protected override bool OnHover(HoverEvent e) From 5319bce772d9e91857108628997c78a8284c79fc Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Wed, 20 Apr 2022 21:05:33 +0100 Subject: [PATCH 67/74] Revert DI usage of `ChannelSelectorState` in favour of directly binding `BindableBool` `SelectorActive` --- osu.Game.Tests/Visual/Online/TestSceneChannelList.cs | 9 +++------ osu.Game/Overlays/Chat/ChannelList/ChannelList.cs | 8 ++------ osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs | 9 ++++----- .../Overlays/Chat/ChannelList/ChannelListSelector.cs | 9 +++------ 4 files changed, 12 insertions(+), 23 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs index 2bfe42e6d4..d6a1e71f0d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs @@ -25,9 +25,6 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly Bindable selected = new Bindable(); - [Cached] - private readonly Bindable selector = new Bindable(); - private OsuSpriteText selectorText; private OsuSpriteText selectedText; private OsuSpriteText leaveText; @@ -92,7 +89,7 @@ namespace osu.Game.Tests.Visual.Online channelList.OnRequestSelect += channel => { - selector.Value = ChannelSelectorState.Hidden; + channelList.SelectorActive.Value = false; selected.Value = channel; }; @@ -104,9 +101,9 @@ namespace osu.Game.Tests.Visual.Online channelList.RemoveChannel(channel); }; - selector.BindValueChanged(change => + channelList.SelectorActive.BindValueChanged(change => { - selectorText.Text = $"Channel Selector State: {change.NewValue}"; + selectorText.Text = $"Channel Selector Active: {change.NewValue}"; }, true); selected.BindValueChanged(change => diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index 578ac2aa45..076dc5719e 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -56,6 +56,7 @@ namespace osu.Game.Overlays.Chat.ChannelList new ChannelListSelector { Margin = new MarginPadding { Bottom = 10 }, + SelectorActive = { BindTarget = SelectorActive }, }, privateChannelFlow = new ChannelListItemFlow("DIRECT MESSAGES"), }, @@ -72,6 +73,7 @@ namespace osu.Game.Overlays.Chat.ChannelList ChannelListItem item = new ChannelListItem(channel); item.OnRequestSelect += chan => OnRequestSelect?.Invoke(chan); item.OnRequestLeave += chan => OnRequestLeave?.Invoke(chan); + item.SelectorActive.BindTarget = SelectorActive; ChannelListItemFlow flow = getFlowForChannel(channel); channelMap.Add(channel, item); @@ -130,10 +132,4 @@ namespace osu.Game.Overlays.Chat.ChannelList } } } - - public enum ChannelSelectorState - { - Visibile, - Hidden, - } } diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs index 3d59d1dc4c..7c4a72559b 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs @@ -29,6 +29,8 @@ namespace osu.Game.Overlays.Chat.ChannelList public readonly BindableBool Unread = new BindableBool(); + public readonly BindableBool SelectorActive = new BindableBool(); + private readonly Channel channel; private Box hoverBox = null!; @@ -39,9 +41,6 @@ namespace osu.Game.Overlays.Chat.ChannelList [Resolved] private Bindable selectedChannel { get; set; } = null!; - [Resolved] - private Bindable selectorState { get; set; } = null!; - [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -128,7 +127,7 @@ namespace osu.Game.Overlays.Chat.ChannelList base.LoadComplete(); selectedChannel.BindValueChanged(_ => updateSelectState(), true); - selectorState.BindValueChanged(_ => updateSelectState(), true); + SelectorActive.BindValueChanged(_ => updateSelectState(), true); Unread.BindValueChanged(change => { @@ -168,7 +167,7 @@ namespace osu.Game.Overlays.Chat.ChannelList private void updateSelectState() { - if (selectedChannel.Value == channel && selectorState.Value == ChannelSelectorState.Hidden) + if (selectedChannel.Value == channel && !SelectorActive.Value) selectBox.FadeIn(300, Easing.OutQuint); else selectBox.FadeOut(200, Easing.OutQuint); diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs index 4529a34f84..57ab7584b5 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs @@ -22,9 +22,6 @@ namespace osu.Game.Overlays.Chat.ChannelList private Box hoverBox = null!; private Box selectBox = null!; - [Resolved] - private Bindable selectorState { get; set; } = null!; - [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { @@ -68,15 +65,15 @@ namespace osu.Game.Overlays.Chat.ChannelList { base.LoadComplete(); - selectorState.BindValueChanged(selector => + SelectorActive.BindValueChanged(selector => { - if (selector.NewValue == ChannelSelectorState.Visibile) + if (selector.NewValue) selectBox.FadeIn(300, Easing.OutQuint); else selectBox.FadeOut(200, Easing.OutQuint); }, true); - Action = () => selectorState.Value = ChannelSelectorState.Visibile; + Action = () => SelectorActive.Value = true; } protected override bool OnHover(HoverEvent e) From 5e5c8e78a6538b4bcda713375f59b1b2828ec9fa Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 27 Jan 2022 20:53:48 -0800 Subject: [PATCH 68/74] Use existing web localisation for most hardcoded strings --- osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmap.cs | 5 +++-- osu.Game/Beatmaps/BeatmapStatistic.cs | 3 ++- .../Drawables/BeatmapDownloadButton.cs | 3 ++- osu.Game/Graphics/UserInterface/OsuMenuItem.cs | 3 ++- .../UserInterface/PageSelector/PageSelector.cs | 5 +++-- .../PageSelector/PageSelectorPrevNextButton.cs | 6 ++++-- .../Graphics/UserInterface/SearchTextBox.cs | 3 ++- .../Graphics/UserInterface/ShowMoreButton.cs | 4 +++- .../Graphics/UserInterfaceV2/ColourDisplay.cs | 3 ++- osu.Game/Localisation/CommonStrings.cs | 10 ---------- .../API/Requests/Responses/APIPlayStyle.cs | 11 ++++++----- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 3 ++- .../Online/Leaderboards/LeaderboardScore.cs | 11 ++++++----- osu.Game/Online/Rooms/MatchType.cs | 7 ++++--- .../Overlays/AccountCreation/ScreenEntry.cs | 3 ++- .../Overlays/BeatmapSet/BeatmapAvailability.cs | 7 ++++--- .../Scores/NotSupporterPlaceholder.cs | 3 ++- osu.Game/Overlays/ChatOverlay.cs | 2 +- .../Comments/Buttons/LoadRepliesButton.cs | 3 ++- .../Comments/Buttons/ShowMoreRepliesButton.cs | 3 ++- .../Comments/CancellableCommentEditor.cs | 3 ++- .../Overlays/Comments/CommentsContainer.cs | 3 ++- osu.Game/Overlays/Comments/CommentsHeader.cs | 10 ++++++++-- .../Comments/CommentsShowMoreButton.cs | 6 +++++- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- .../Overlays/Comments/TotalCommentsCounter.cs | 3 ++- .../Dashboard/CurrentlyPlayingDisplay.cs | 3 ++- .../Dashboard/Home/DrawableBeatmapList.cs | 3 ++- .../Dashboard/Home/DrawableNewBeatmapList.cs | 4 +++- .../Home/DrawablePopularBeatmapList.cs | 4 +++- .../Dashboard/Home/News/ShowMoreNewsPanel.cs | 3 ++- osu.Game/Overlays/Dialog/ConfirmDialog.cs | 3 ++- osu.Game/Overlays/Login/LoginForm.cs | 7 ++++--- osu.Game/Overlays/Login/UserAction.cs | 3 +++ osu.Game/Overlays/Mods/ModSelectOverlay.cs | 3 ++- osu.Game/Overlays/NotificationOverlay.cs | 5 +++-- .../Notifications/NotificationSection.cs | 7 ++++--- .../Profile/Header/BottomHeaderContainer.cs | 18 ++++++++++++++---- .../Settings/Sections/Input/KeyBindingRow.cs | 6 +++--- osu.Game/Overlays/Toolbar/ToolbarUserButton.cs | 3 ++- .../Wiki/Markdown/WikiNoticeContainer.cs | 8 +++++--- osu.Game/Overlays/Wiki/WikiSidebar.cs | 4 +++- .../Compose/Components/SelectionHandler.cs | 3 ++- osu.Game/Screens/Edit/Editor.cs | 3 ++- .../Screens/Edit/Setup/DifficultySection.cs | 9 +++++---- osu.Game/Screens/Edit/Setup/MetadataSection.cs | 7 ++++--- .../OnlinePlay/Components/OverlinedHeader.cs | 3 ++- .../OnlinePlay/DrawableRoomPlaylistItem.cs | 3 ++- .../Match/Components/MatchLeaderboardScore.cs | 5 +++-- .../OnlinePlay/Match/DrawableMatchRoom.cs | 3 ++- .../Participants/ParticipantsListHeader.cs | 3 ++- .../Screens/Play/BeatmapMetadataDisplay.cs | 9 +++++---- osu.Game/Screens/Play/Break/BreakInfo.cs | 3 ++- osu.Game/Screens/Play/Break/BreakInfoLine.cs | 4 ++-- .../Play/HUD/PerformancePointsCounter.cs | 3 ++- .../Play/PlayerSettings/AudioSettings.cs | 3 ++- .../Play/PlayerSettings/VisualSettings.cs | 11 ++++++----- .../Contracted/ContractedPanelMiddleContent.cs | 8 +++++--- .../Expanded/Statistics/AccuracyStatistic.cs | 3 ++- .../Expanded/Statistics/ComboStatistic.cs | 3 ++- .../Expanded/Statistics/CounterStatistic.cs | 3 ++- .../Statistics/PerformanceStatistic.cs | 3 ++- .../Expanded/Statistics/StatisticDisplay.cs | 8 +++++--- osu.Game/Screens/Select/BeatmapDetails.cs | 3 ++- .../Select/Carousel/DrawableCarouselBeatmap.cs | 14 ++++---------- .../Screens/Select/Details/AdvancedStats.cs | 13 +++++++------ osu.Game/Screens/Select/Filter/SortMode.cs | 16 +++++++++------- osu.Game/Screens/Select/FilterControl.cs | 3 ++- .../Select/Options/BeatmapOptionsOverlay.cs | 3 ++- osu.Game/Users/UserStatus.cs | 10 ++++++---- 70 files changed, 224 insertions(+), 147 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmap.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmap.cs index 2d3cc3c103..a5282877ee 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmap.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmap.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using osu.Game.Beatmaps; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Beatmaps @@ -20,13 +21,13 @@ namespace osu.Game.Rulesets.Osu.Beatmaps { new BeatmapStatistic { - Name = @"Circle Count", + Name = BeatmapsetsStrings.ShowStatsCountCircles, Content = circles.ToString(), CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Circles), }, new BeatmapStatistic { - Name = @"Slider Count", + Name = BeatmapsetsStrings.ShowStatsCountSliders, Content = sliders.ToString(), CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders), }, diff --git a/osu.Game/Beatmaps/BeatmapStatistic.cs b/osu.Game/Beatmaps/BeatmapStatistic.cs index 7d7ba09fcf..94ebb56a5c 100644 --- a/osu.Game/Beatmaps/BeatmapStatistic.cs +++ b/osu.Game/Beatmaps/BeatmapStatistic.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Graphics; +using osu.Framework.Localisation; namespace osu.Game.Beatmaps { @@ -14,6 +15,6 @@ namespace osu.Game.Beatmaps public Func CreateIcon; public string Content; - public string Name; + public LocalisableString Name; } } diff --git a/osu.Game/Beatmaps/Drawables/BeatmapDownloadButton.cs b/osu.Game/Beatmaps/Drawables/BeatmapDownloadButton.cs index e2485e7a77..6ab92a2ba2 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapDownloadButton.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapDownloadButton.cs @@ -12,6 +12,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Beatmaps.Drawables { @@ -104,7 +105,7 @@ namespace osu.Game.Beatmaps.Drawables if ((beatmapSet as IBeatmapSetOnlineInfo)?.Availability.DownloadDisabled == true) { button.Enabled.Value = false; - button.TooltipText = "this beatmap is currently not available for download."; + button.TooltipText = BeatmapsetsStrings.AvailabilityDisabled; } break; diff --git a/osu.Game/Graphics/UserInterface/OsuMenuItem.cs b/osu.Game/Graphics/UserInterface/OsuMenuItem.cs index 0fe41937ce..1da60415ba 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenuItem.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Localisation; namespace osu.Game.Graphics.UserInterface { @@ -15,7 +16,7 @@ namespace osu.Game.Graphics.UserInterface { } - public OsuMenuItem(string text, MenuItemType type, Action action) + public OsuMenuItem(LocalisableString text, MenuItemType type, Action action) : base(text, action) { Type = type; diff --git a/osu.Game/Graphics/UserInterface/PageSelector/PageSelector.cs b/osu.Game/Graphics/UserInterface/PageSelector/PageSelector.cs index 005729580c..5c6d087279 100644 --- a/osu.Game/Graphics/UserInterface/PageSelector/PageSelector.cs +++ b/osu.Game/Graphics/UserInterface/PageSelector/PageSelector.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using osu.Framework.Bindables; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Graphics.UserInterface.PageSelector { @@ -29,7 +30,7 @@ namespace osu.Game.Graphics.UserInterface.PageSelector Direction = FillDirection.Horizontal, Children = new Drawable[] { - previousPageButton = new PageSelectorPrevNextButton(false, "prev") + previousPageButton = new PageSelectorPrevNextButton(false, CommonStrings.PaginationPrevious) { Action = () => CurrentPage.Value -= 1, }, @@ -38,7 +39,7 @@ namespace osu.Game.Graphics.UserInterface.PageSelector AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, }, - nextPageButton = new PageSelectorPrevNextButton(true, "next") + nextPageButton = new PageSelectorPrevNextButton(true, CommonStrings.PaginationNext) { Action = () => CurrentPage.Value += 1 } diff --git a/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorPrevNextButton.cs b/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorPrevNextButton.cs index 7503ab8135..889917c397 100644 --- a/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorPrevNextButton.cs +++ b/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorPrevNextButton.cs @@ -2,9 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Graphics.Sprites; using osuTK; @@ -13,12 +15,12 @@ namespace osu.Game.Graphics.UserInterface.PageSelector public class PageSelectorPrevNextButton : PageSelectorButton { private readonly bool rightAligned; - private readonly string text; + private readonly LocalisableString text; private SpriteIcon icon; private OsuSpriteText name; - public PageSelectorPrevNextButton(bool rightAligned, string text) + public PageSelectorPrevNextButton(bool rightAligned, LocalisableString text) { this.rightAligned = rightAligned; this.text = text; diff --git a/osu.Game/Graphics/UserInterface/SearchTextBox.cs b/osu.Game/Graphics/UserInterface/SearchTextBox.cs index 6937782be6..dd9ed7c9e9 100644 --- a/osu.Game/Graphics/UserInterface/SearchTextBox.cs +++ b/osu.Game/Graphics/UserInterface/SearchTextBox.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Framework.Input.Events; +using osu.Game.Resources.Localisation.Web; using osuTK; using osuTK.Input; @@ -27,7 +28,7 @@ namespace osu.Game.Graphics.UserInterface }); TextFlow.Padding = new MarginPadding { Right = 35 }; - PlaceholderText = "type to search"; + PlaceholderText = HomeStrings.SearchPlaceholder; } public override bool OnPressed(KeyBindingPressEvent e) diff --git a/osu.Game/Graphics/UserInterface/ShowMoreButton.cs b/osu.Game/Graphics/UserInterface/ShowMoreButton.cs index 615895074c..05dda324d4 100644 --- a/osu.Game/Graphics/UserInterface/ShowMoreButton.cs +++ b/osu.Game/Graphics/UserInterface/ShowMoreButton.cs @@ -11,7 +11,9 @@ using osu.Game.Graphics.Sprites; using osu.Game.Overlays; using osuTK; using System.Collections.Generic; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Graphics.UserInterface { @@ -80,7 +82,7 @@ namespace osu.Game.Graphics.UserInterface Anchor = Anchor.Centre, Origin = Anchor.Centre, Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold), - Text = "show more".ToUpper(), + Text = CommonStrings.ButtonsShowMore.ToUpper(), }, rightIcon = new ChevronIcon { diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs b/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs index 5240df74a2..cec319f28e 100644 --- a/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs +++ b/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs @@ -14,6 +14,7 @@ using osu.Framework.Localisation; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Resources.Localisation.Web; using osuTK; namespace osu.Game.Graphics.UserInterfaceV2 @@ -139,7 +140,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 public MenuItem[] ContextMenuItems => new MenuItem[] { - new OsuMenuItem("Delete", MenuItemType.Destructive, () => DeleteRequested?.Invoke()) + new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => DeleteRequested?.Invoke()) }; } } diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 3ea337c279..b717bb83dd 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -9,16 +9,6 @@ namespace osu.Game.Localisation { private const string prefix = @"osu.Game.Resources.Localisation.Common"; - /// - /// "Cancel" - /// - public static LocalisableString Cancel => new TranslatableString(getKey(@"cancel"), @"Cancel"); - - /// - /// "Clear" - /// - public static LocalisableString Clear => new TranslatableString(getKey(@"clear"), @"Clear"); - /// /// "Enabled" /// diff --git a/osu.Game/Online/API/Requests/Responses/APIPlayStyle.cs b/osu.Game/Online/API/Requests/Responses/APIPlayStyle.cs index 9573ae1825..a9d66f3d6a 100644 --- a/osu.Game/Online/API/Requests/Responses/APIPlayStyle.cs +++ b/osu.Game/Online/API/Requests/Responses/APIPlayStyle.cs @@ -1,22 +1,23 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.ComponentModel; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Online.API.Requests.Responses { public enum APIPlayStyle { - [Description("Keyboard")] + [LocalisableDescription(typeof(CommonStrings), nameof(CommonStrings.DeviceKeyboard))] Keyboard, - [Description("Mouse")] + [LocalisableDescription(typeof(CommonStrings), nameof(CommonStrings.DeviceMouse))] Mouse, - [Description("Tablet")] + [LocalisableDescription(typeof(CommonStrings), nameof(CommonStrings.DeviceTablet))] Tablet, - [Description("Touch Screen")] + [LocalisableDescription(typeof(CommonStrings), nameof(CommonStrings.DeviceTouch))] Touch, } } diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index f83bf4877e..6a7da52416 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -12,6 +12,7 @@ using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Chat; +using osu.Game.Resources.Localisation.Web; using osuTK.Graphics; namespace osu.Game.Online.Chat @@ -63,7 +64,7 @@ namespace osu.Game.Online.Chat { RelativeSizeAxes = Axes.X, Height = text_box_height, - PlaceholderText = "type your message", + PlaceholderText = ChatStrings.InputPlaceholder, CornerRadius = corner_radius, ReleaseFocusOnCommit = false, HoldFocus = true, diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index eecb7ff6b3..c75e98cdaa 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -30,6 +30,7 @@ using osu.Game.Users.Drawables; using osuTK; using osuTK.Graphics; using osu.Game.Online.API; +using osu.Game.Resources.Localisation.Web; using osu.Game.Utils; namespace osu.Game.Online.Leaderboards @@ -291,8 +292,8 @@ namespace osu.Game.Online.Leaderboards protected virtual IEnumerable GetStatistics(ScoreInfo model) => new[] { - new LeaderboardScoreStatistic(FontAwesome.Solid.Link, "Max Combo", model.MaxCombo.ToString()), - new LeaderboardScoreStatistic(FontAwesome.Solid.Crosshairs, "Accuracy", model.DisplayAccuracy) + new LeaderboardScoreStatistic(FontAwesome.Solid.Link, BeatmapsetsStrings.ShowScoreboardHeadersCombo, model.MaxCombo.ToString()), + new LeaderboardScoreStatistic(FontAwesome.Solid.Crosshairs, BeatmapsetsStrings.ShowScoreboardHeadersAccuracy, model.DisplayAccuracy) }; protected override bool OnHover(HoverEvent e) @@ -403,9 +404,9 @@ namespace osu.Game.Online.Leaderboards { public IconUsage Icon; public LocalisableString Value; - public string Name; + public LocalisableString Name; - public LeaderboardScoreStatistic(IconUsage icon, string name, LocalisableString value) + public LeaderboardScoreStatistic(IconUsage icon, LocalisableString name, LocalisableString value) { Icon = icon; Name = name; @@ -426,7 +427,7 @@ namespace osu.Game.Online.Leaderboards items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => new LegacyScoreExporter(storage).Export(Score))); if (!isOnlineScope) - items.Add(new OsuMenuItem("Delete", MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score)))); + items.Add(new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score)))); return items.ToArray(); } diff --git a/osu.Game/Online/Rooms/MatchType.cs b/osu.Game/Online/Rooms/MatchType.cs index 36f0dc0c81..278f0693eb 100644 --- a/osu.Game/Online/Rooms/MatchType.cs +++ b/osu.Game/Online/Rooms/MatchType.cs @@ -1,7 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.ComponentModel; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Online.Rooms { @@ -11,10 +12,10 @@ namespace osu.Game.Online.Rooms Playlists, - [Description("Head to head")] + [LocalisableDescription(typeof(MatchesStrings), nameof(MatchesStrings.MatchTeamTypesHeadToHead))] HeadToHead, - [Description("Team VS")] + [LocalisableDescription(typeof(MatchesStrings), nameof(MatchesStrings.MatchTeamTypesTeamVs))] TeamVersus, } } diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs index a2c04c6989..6cf3fb4267 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs @@ -16,6 +16,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Overlays.Settings; +using osu.Game.Resources.Localisation.Web; using osuTK; using osuTK.Graphics; @@ -68,7 +69,7 @@ namespace osu.Game.Overlays.AccountCreation }, usernameTextBox = new OsuTextBox { - PlaceholderText = "username", + PlaceholderText = UsersStrings.LoginUsername, RelativeSizeAxes = Axes.X, TabbableContentContainer = this }, diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapAvailability.cs b/osu.Game/Overlays/BeatmapSet/BeatmapAvailability.cs index dc46452dcb..b6e768d632 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapAvailability.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapAvailability.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Resources.Localisation.Web; using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapSet @@ -69,14 +70,14 @@ namespace osu.Game.Overlays.BeatmapSet { textContainer.Clear(); textContainer.AddParagraph(downloadDisabled - ? "This beatmap is currently not available for download." - : "Portions of this beatmap have been removed at the request of the creator or a third-party rights holder.", t => t.Colour = Color4.Orange); + ? BeatmapsetsStrings.AvailabilityDisabled + : BeatmapsetsStrings.AvailabilityPartsRemoved, t => t.Colour = Color4.Orange); if (hasExternalLink) { textContainer.NewParagraph(); textContainer.NewParagraph(); - textContainer.AddLink("Check here for more information.", BeatmapSet.Availability.ExternalLink, creationParameters: t => t.Font = OsuFont.GetFont(size: 10)); + textContainer.AddLink(BeatmapsetsStrings.AvailabilityMoreInfo, BeatmapSet.Availability.ExternalLink, creationParameters: t => t.Font = OsuFont.GetFont(size: 10)); } } } diff --git a/osu.Game/Overlays/BeatmapSet/Scores/NotSupporterPlaceholder.cs b/osu.Game/Overlays/BeatmapSet/Scores/NotSupporterPlaceholder.cs index b2c87a1477..d1a0960a08 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/NotSupporterPlaceholder.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/NotSupporterPlaceholder.cs @@ -7,6 +7,7 @@ using osu.Game.Graphics.Sprites; using osuTK; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapSet.Scores { @@ -28,7 +29,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = @"You need to be an osu!supporter to access the friend and country rankings!", + Text = BeatmapsetsStrings.ShowScoreboardSupporterOnly, Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), }, text = new LinkFlowContainer(t => t.Font = t.Font.With(size: 11)) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 64b972262b..034670cf37 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -160,7 +160,7 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.Both, Height = 1, - PlaceholderText = "type your message", + PlaceholderText = Resources.Localisation.Web.ChatStrings.InputPlaceholder, ReleaseFocusOnCommit = false, HoldFocus = true, } diff --git a/osu.Game/Overlays/Comments/Buttons/LoadRepliesButton.cs b/osu.Game/Overlays/Comments/Buttons/LoadRepliesButton.cs index 4998e5391e..4bb5b9d66d 100644 --- a/osu.Game/Overlays/Comments/Buttons/LoadRepliesButton.cs +++ b/osu.Game/Overlays/Comments/Buttons/LoadRepliesButton.cs @@ -3,6 +3,7 @@ using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments.Buttons { @@ -25,7 +26,7 @@ namespace osu.Game.Overlays.Comments.Buttons { public ButtonContent() { - Text = "load replies"; + Text = CommentsStrings.LoadReplies; } } } diff --git a/osu.Game/Overlays/Comments/Buttons/ShowMoreRepliesButton.cs b/osu.Game/Overlays/Comments/Buttons/ShowMoreRepliesButton.cs index c115a8bb8f..4908e29b7d 100644 --- a/osu.Game/Overlays/Comments/Buttons/ShowMoreRepliesButton.cs +++ b/osu.Game/Overlays/Comments/Buttons/ShowMoreRepliesButton.cs @@ -9,6 +9,7 @@ using osu.Game.Graphics.Sprites; using System.Collections.Generic; using osuTK; using osu.Framework.Allocation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments.Buttons { @@ -38,7 +39,7 @@ namespace osu.Game.Overlays.Comments.Buttons { AlwaysPresent = true, Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold), - Text = "show more" + Text = CommonStrings.ButtonsShowMore } }; diff --git a/osu.Game/Overlays/Comments/CancellableCommentEditor.cs b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs index c226b7f07f..74c221bd82 100644 --- a/osu.Game/Overlays/Comments/CancellableCommentEditor.cs +++ b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments { @@ -54,7 +55,7 @@ namespace osu.Game.Overlays.Comments Origin = Anchor.Centre, Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), Margin = new MarginPadding { Horizontal = 20 }, - Text = @"Cancel" + Text = CommonStrings.ButtonsCancel } } }; diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 6a5734b553..a28b13fc12 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -16,6 +16,7 @@ using osu.Framework.Threading; using System.Collections.Generic; using JetBrains.Annotations; using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Comments @@ -328,7 +329,7 @@ namespace osu.Game.Overlays.Comments Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Margin = new MarginPadding { Left = 50 }, - Text = @"No comments yet." + Text = CommentsStrings.Empty } }); } diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs index bf80655c3d..e7d9e72dcc 100644 --- a/osu.Game/Overlays/Comments/CommentsHeader.cs +++ b/osu.Game/Overlays/Comments/CommentsHeader.cs @@ -12,7 +12,9 @@ using osu.Game.Graphics; using osu.Framework.Graphics.Sprites; using osuTK; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments { @@ -91,7 +93,7 @@ namespace osu.Game.Overlays.Comments Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold), - Text = @"Show deleted" + Text = CommonStrings.ButtonsShowDeleted } }, }); @@ -126,9 +128,13 @@ namespace osu.Game.Overlays.Comments public enum CommentsSortCriteria { - [System.ComponentModel.Description(@"Recent")] + [LocalisableDescription(typeof(SortStrings), nameof(SortStrings.New))] New, + + [LocalisableDescription(typeof(SortStrings), nameof(SortStrings.Old))] Old, + + [LocalisableDescription(typeof(SortStrings), nameof(SortStrings.Top))] Top } } diff --git a/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs b/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs index adf64eabb1..b1ca39c3bf 100644 --- a/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs +++ b/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs @@ -2,7 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments { @@ -18,7 +21,8 @@ namespace osu.Game.Overlays.Comments private void onCurrentChanged(ValueChangedEvent count) { - Text = $@"Show More ({count.NewValue})".ToUpper(); + Text = new TranslatableString(@"_", "{0} ({1})", + CommonStrings.ButtonsShowMore.ToUpper(), count.NewValue); } } } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 3286b6c5c0..3ec91c8e63 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -150,7 +150,7 @@ namespace osu.Game.Overlays.Comments { Alpha = Comment.IsDeleted ? 1 : 0, Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), - Text = "deleted" + Text = CommentsStrings.Deleted } } }, diff --git a/osu.Game/Overlays/Comments/TotalCommentsCounter.cs b/osu.Game/Overlays/Comments/TotalCommentsCounter.cs index 1bb9b52689..221a745189 100644 --- a/osu.Game/Overlays/Comments/TotalCommentsCounter.cs +++ b/osu.Game/Overlays/Comments/TotalCommentsCounter.cs @@ -9,6 +9,7 @@ using osuTK; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments { @@ -39,7 +40,7 @@ namespace osu.Game.Overlays.Comments Origin = Anchor.CentreLeft, Font = OsuFont.GetFont(size: 20, italics: true), Colour = colourProvider.Light1, - Text = @"Comments" + Text = CommentsStrings.Title }, new CircularContainer { diff --git a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs index 786401b7a8..e036f1d304 100644 --- a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs +++ b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs @@ -14,6 +14,7 @@ using osu.Game.Database; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Spectator; +using osu.Game.Resources.Localisation.Web; using osu.Game.Screens; using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.Play; @@ -138,7 +139,7 @@ namespace osu.Game.Overlays.Dashboard new PurpleTriangleButton { RelativeSizeAxes = Axes.X, - Text = "Watch", + Text = CommonStrings.ButtonsWatchTo1, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Action = () => performer?.PerformFromScreen(s => s.Push(new SoloSpectator(User))), diff --git a/osu.Game/Overlays/Dashboard/Home/DrawableBeatmapList.cs b/osu.Game/Overlays/Dashboard/Home/DrawableBeatmapList.cs index c73cc828e2..382bc00b1d 100644 --- a/osu.Game/Overlays/Dashboard/Home/DrawableBeatmapList.cs +++ b/osu.Game/Overlays/Dashboard/Home/DrawableBeatmapList.cs @@ -6,6 +6,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; @@ -49,7 +50,7 @@ namespace osu.Game.Overlays.Dashboard.Home flow.AddRange(beatmapSets.Select(CreateBeatmapPanel)); } - protected abstract string Title { get; } + protected abstract LocalisableString Title { get; } protected abstract DashboardBeatmapPanel CreateBeatmapPanel(APIBeatmapSet beatmapSet); } diff --git a/osu.Game/Overlays/Dashboard/Home/DrawableNewBeatmapList.cs b/osu.Game/Overlays/Dashboard/Home/DrawableNewBeatmapList.cs index 714e07a7ed..331fff0aea 100644 --- a/osu.Game/Overlays/Dashboard/Home/DrawableNewBeatmapList.cs +++ b/osu.Game/Overlays/Dashboard/Home/DrawableNewBeatmapList.cs @@ -2,7 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using osu.Framework.Localisation; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Dashboard.Home { @@ -15,6 +17,6 @@ namespace osu.Game.Overlays.Dashboard.Home protected override DashboardBeatmapPanel CreateBeatmapPanel(APIBeatmapSet beatmapSet) => new DashboardNewBeatmapPanel(beatmapSet); - protected override string Title => "New Ranked Beatmaps"; + protected override LocalisableString Title => HomeStrings.UserBeatmapsNew; } } diff --git a/osu.Game/Overlays/Dashboard/Home/DrawablePopularBeatmapList.cs b/osu.Game/Overlays/Dashboard/Home/DrawablePopularBeatmapList.cs index 48b100b04e..154813dea1 100644 --- a/osu.Game/Overlays/Dashboard/Home/DrawablePopularBeatmapList.cs +++ b/osu.Game/Overlays/Dashboard/Home/DrawablePopularBeatmapList.cs @@ -2,7 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using osu.Framework.Localisation; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Dashboard.Home { @@ -15,6 +17,6 @@ namespace osu.Game.Overlays.Dashboard.Home protected override DashboardBeatmapPanel CreateBeatmapPanel(APIBeatmapSet beatmapSet) => new DashboardPopularBeatmapPanel(beatmapSet); - protected override string Title => "Popular Beatmaps"; + protected override LocalisableString Title => HomeStrings.UserBeatmapsPopular; } } diff --git a/osu.Game/Overlays/Dashboard/Home/News/ShowMoreNewsPanel.cs b/osu.Game/Overlays/Dashboard/Home/News/ShowMoreNewsPanel.cs index d25df6f189..f6e966957e 100644 --- a/osu.Game/Overlays/Dashboard/Home/News/ShowMoreNewsPanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/News/ShowMoreNewsPanel.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; using osuTK.Graphics; namespace osu.Game.Overlays.Dashboard.Home.News @@ -35,7 +36,7 @@ namespace osu.Game.Overlays.Dashboard.Home.News Anchor = Anchor.Centre, Origin = Anchor.Centre, Margin = new MarginPadding { Vertical = 20 }, - Text = "see more" + Text = CommonStrings.ButtonsSeeMore } }; diff --git a/osu.Game/Overlays/Dialog/ConfirmDialog.cs b/osu.Game/Overlays/Dialog/ConfirmDialog.cs index d1c0d746d1..58ce84e13a 100644 --- a/osu.Game/Overlays/Dialog/ConfirmDialog.cs +++ b/osu.Game/Overlays/Dialog/ConfirmDialog.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Dialog { @@ -33,7 +34,7 @@ namespace osu.Game.Overlays.Dialog }, new PopupDialogCancelButton { - Text = Localisation.CommonStrings.Cancel, + Text = CommonStrings.ButtonsCancel, Action = onCancel }, }; diff --git a/osu.Game/Overlays/Login/LoginForm.cs b/osu.Game/Overlays/Login/LoginForm.cs index f7842dcd30..c31416e078 100644 --- a/osu.Game/Overlays/Login/LoginForm.cs +++ b/osu.Game/Overlays/Login/LoginForm.cs @@ -13,6 +13,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Overlays.Settings; +using osu.Game.Resources.Localisation.Web; using osuTK; namespace osu.Game.Overlays.Login @@ -50,14 +51,14 @@ namespace osu.Game.Overlays.Login { username = new OsuTextBox { - PlaceholderText = "username", + PlaceholderText = UsersStrings.LoginUsername, RelativeSizeAxes = Axes.X, Text = api?.ProvidedUsername ?? string.Empty, TabbableContentContainer = this }, password = new OsuPasswordTextBox { - PlaceholderText = "password", + PlaceholderText = UsersStrings.LoginPassword, RelativeSizeAxes = Axes.X, TabbableContentContainer = this, }, @@ -88,7 +89,7 @@ namespace osu.Game.Overlays.Login AutoSizeAxes = Axes.Y, Child = new SettingsButton { - Text = "Sign in", + Text = UsersStrings.LoginButton, Action = performLogin }, } diff --git a/osu.Game/Overlays/Login/UserAction.cs b/osu.Game/Overlays/Login/UserAction.cs index 07b6b4bf7e..d216670a28 100644 --- a/osu.Game/Overlays/Login/UserAction.cs +++ b/osu.Game/Overlays/Login/UserAction.cs @@ -2,11 +2,14 @@ // See the LICENCE file in the repository root for full licence text. using System.ComponentModel; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Login { public enum UserAction { + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.StatusOnline))] Online, [Description(@"Do not disturb")] diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index ec7e49920c..9ce79c25f7 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -20,6 +20,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Mods; using osu.Game.Screens; using osu.Game.Utils; @@ -317,7 +318,7 @@ namespace osu.Game.Overlays.Mods CloseButton = new TriangleButton { Width = 180, - Text = "Close", + Text = CommonStrings.ButtonsClose, Action = Hide, Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 2b5909f45a..f1ed5c4ba6 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -15,7 +15,8 @@ using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Framework.Threading; using osu.Game.Graphics; -using osu.Game.Localisation; +using osu.Game.Resources.Localisation.Web; +using NotificationsStrings = osu.Game.Localisation.NotificationsStrings; namespace osu.Game.Overlays { @@ -61,7 +62,7 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.X, Children = new[] { - new NotificationSection(@"Notifications", @"Clear All") + new NotificationSection(AccountsStrings.NotificationsTitle, "Clear All") { AcceptTypes = new[] { typeof(SimpleNotification) } }, diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index a23ff07a64..a4851ab365 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; @@ -34,9 +35,9 @@ namespace osu.Game.Overlays.Notifications private readonly string clearButtonText; - private readonly string titleText; + private readonly LocalisableString titleText; - public NotificationSection(string title, string clearButtonText) + public NotificationSection(LocalisableString title, string clearButtonText) { this.clearButtonText = clearButtonText.ToUpperInvariant(); titleText = title; @@ -84,7 +85,7 @@ namespace osu.Game.Overlays.Notifications { new OsuSpriteText { - Text = titleText.ToUpperInvariant(), + Text = titleText.ToUpper(), Font = OsuFont.GetFont(weight: FontWeight.Bold) }, countDrawable = new OsuSpriteText diff --git a/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs index ea52cec2e1..a70d57661b 100644 --- a/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Linq; using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -11,10 +10,12 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Resources.Localisation.Web; using osuTK; using osuTK.Graphics; @@ -83,7 +84,7 @@ namespace osu.Game.Overlays.Profile.Header if (user == null) return; if (user.JoinDate.ToUniversalTime().Year < 2008) - topLinkContainer.AddText("Here since the beginning"); + topLinkContainer.AddText(UsersStrings.ShowFirstMembers); else { topLinkContainer.AddText("Joined "); @@ -94,7 +95,7 @@ namespace osu.Game.Overlays.Profile.Header if (user.IsOnline) { - topLinkContainer.AddText("Currently online"); + topLinkContainer.AddText(UsersStrings.ShowLastvisitOnline); addSpacer(topLinkContainer); } else if (user.LastVisit.HasValue) @@ -108,7 +109,16 @@ namespace osu.Game.Overlays.Profile.Header if (user.PlayStyles?.Length > 0) { topLinkContainer.AddText("Plays with "); - topLinkContainer.AddText(string.Join(", ", user.PlayStyles.Select(style => style.GetDescription())), embolden); + + LocalisableString playStylesString = user.PlayStyles[0].GetLocalisableDescription(); + + for (int i = 1; i < user.PlayStyles.Length; i++) + { + playStylesString = new TranslatableString(@"_", @"{0}{1}", playStylesString, CommonStrings.ArrayAndWordsConnector); + playStylesString = new TranslatableString(@"_", @"{0}{1}", playStylesString, user.PlayStyles[i].GetLocalisableDescription()); + } + + topLinkContainer.AddText(playStylesString, embolden); addSpacer(topLinkContainer); } diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index 2405618917..459405f57d 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -21,7 +21,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Input; using osu.Game.Input.Bindings; -using osu.Game.Localisation; +using osu.Game.Resources.Localisation.Web; using osuTK; using osuTK.Graphics; using osuTK.Input; @@ -402,7 +402,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input { public CancelButton() { - Text = CommonStrings.Cancel; + Text = CommonStrings.ButtonsCancel; Size = new Vector2(80, 20); } } @@ -411,7 +411,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input { public ClearButton() { - Text = CommonStrings.Clear; + Text = CommonStrings.ButtonsClear; Size = new Vector2(80, 20); } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index b0c9a04285..d8ba07dc3b 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Effects; using osu.Game.Graphics; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Resources.Localisation.Web; using osu.Game.Users.Drawables; using osuTK; using osuTK.Graphics; @@ -62,7 +63,7 @@ namespace osu.Game.Overlays.Toolbar switch (state.NewValue) { default: - Text = @"Guest"; + Text = UsersStrings.AnonymousUsername; avatar.User = new APIUser(); break; diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs index a22c18b0a4..11cab80a57 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs @@ -7,7 +7,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; using osu.Game.Graphics; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Wiki.Markdown { @@ -46,14 +48,14 @@ namespace osu.Game.Overlays.Wiki.Markdown { Add(new NoticeBox { - Text = "The content on this page is incomplete or outdated. If you are able to help out, please consider updating the article!", + Text = WikiStrings.ShowIncompleteOrOutdated, }); } else if (needsCleanup) { Add(new NoticeBox { - Text = "This page does not meet the standards of the osu! wiki and needs to be cleaned up or rewritten. If you are able to help out, please consider updating the article!", + Text = WikiStrings.ShowNeedsCleanupOrRewrite, }); } } @@ -63,7 +65,7 @@ namespace osu.Game.Overlays.Wiki.Markdown [Resolved] private IMarkdownTextFlowComponent parentFlowComponent { get; set; } - public string Text { get; set; } + public LocalisableString Text { get; set; } [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider, OsuColour colour) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index ee4e195f3f..da96885fb5 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -3,11 +3,13 @@ using Markdig.Syntax; using Markdig.Syntax.Inlines; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Wiki { @@ -24,7 +26,7 @@ namespace osu.Game.Overlays.Wiki { new OsuSpriteText { - Text = "CONTENTS", + Text = WikiStrings.ShowToc.ToUpper(), Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), Margin = new MarginPadding { Bottom = 5 }, }, diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 9d5d8013b7..78b98a3649 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -17,6 +17,7 @@ using osu.Framework.Input.Events; using osu.Framework.Utils; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Edit; using osuTK; using osuTK.Input; @@ -358,7 +359,7 @@ namespace osu.Game.Screens.Edit.Compose.Components if (SelectedBlueprints.Count == 1) items.AddRange(SelectedBlueprints[0].ContextMenuItems); - items.Add(new OsuMenuItem("Delete", MenuItemType.Destructive, DeleteSelected)); + items.Add(new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, DeleteSelected)); return items.ToArray(); } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 602b7563ac..30c57733ed 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -29,6 +29,7 @@ using osu.Game.Input.Bindings; using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit.Components; @@ -252,7 +253,7 @@ namespace osu.Game.Screens.Edit { Items = createFileMenuItems() }, - new MenuItem("Edit") + new MenuItem(CommonStrings.ButtonsEdit) { Items = new[] { diff --git a/osu.Game/Screens/Edit/Setup/DifficultySection.cs b/osu.Game/Screens/Edit/Setup/DifficultySection.cs index 75c6a89a66..e799081115 100644 --- a/osu.Game/Screens/Edit/Setup/DifficultySection.cs +++ b/osu.Game/Screens/Edit/Setup/DifficultySection.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Screens.Edit.Setup { @@ -27,7 +28,7 @@ namespace osu.Game.Screens.Edit.Setup { circleSizeSlider = new LabelledSliderBar { - Label = "Object Size", + Label = BeatmapsetsStrings.ShowStatsCs, FixedLabelWidth = LABEL_WIDTH, Description = "The size of all hit objects", Current = new BindableFloat(Beatmap.Difficulty.CircleSize) @@ -40,7 +41,7 @@ namespace osu.Game.Screens.Edit.Setup }, healthDrainSlider = new LabelledSliderBar { - Label = "Health Drain", + Label = BeatmapsetsStrings.ShowStatsDrain, FixedLabelWidth = LABEL_WIDTH, Description = "The rate of passive health drain throughout playable time", Current = new BindableFloat(Beatmap.Difficulty.DrainRate) @@ -53,7 +54,7 @@ namespace osu.Game.Screens.Edit.Setup }, approachRateSlider = new LabelledSliderBar { - Label = "Approach Rate", + Label = BeatmapsetsStrings.ShowStatsAr, FixedLabelWidth = LABEL_WIDTH, Description = "The speed at which objects are presented to the player", Current = new BindableFloat(Beatmap.Difficulty.ApproachRate) @@ -66,7 +67,7 @@ namespace osu.Game.Screens.Edit.Setup }, overallDifficultySlider = new LabelledSliderBar { - Label = "Overall Difficulty", + Label = BeatmapsetsStrings.ShowStatsAccuracy, FixedLabelWidth = LABEL_WIDTH, Description = "The harshness of hit windows and difficulty of special objects (ie. spinners)", Current = new BindableFloat(Beatmap.Difficulty.OverallDifficulty) diff --git a/osu.Game/Screens/Edit/Setup/MetadataSection.cs b/osu.Game/Screens/Edit/Setup/MetadataSection.cs index 571dfb3f6f..6262b4c18b 100644 --- a/osu.Game/Screens/Edit/Setup/MetadataSection.cs +++ b/osu.Game/Screens/Edit/Setup/MetadataSection.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Screens.Edit.Setup { @@ -48,15 +49,15 @@ namespace osu.Game.Screens.Edit.Setup creatorTextBox = createTextBox("Creator", metadata.Author.Username), difficultyTextBox = createTextBox("Difficulty Name", Beatmap.BeatmapInfo.DifficultyName), - sourceTextBox = createTextBox("Source", metadata.Source), - tagsTextBox = createTextBox("Tags", metadata.Tags) + sourceTextBox = createTextBox(BeatmapsetsStrings.ShowInfoSource, metadata.Source), + tagsTextBox = createTextBox(BeatmapsetsStrings.ShowInfoTags, metadata.Tags) }; foreach (var item in Children.OfType()) item.OnCommit += onCommit; } - private TTextBox createTextBox(string label, string initialValue) + private TTextBox createTextBox(LocalisableString label, string initialValue) where TTextBox : LabelledTextBox, new() => new TTextBox { diff --git a/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs b/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs index 08a0a3405e..f667a3c1d2 100644 --- a/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs @@ -6,6 +6,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osuTK; @@ -34,7 +35,7 @@ namespace osu.Game.Screens.OnlinePlay.Components private readonly Circle line; private readonly OsuSpriteText details; - public OverlinedHeader(string title) + public OverlinedHeader(LocalisableString title) { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 25b36e0774..459b861d96 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -26,6 +26,7 @@ using osu.Game.Online; using osu.Game.Online.Chat; using osu.Game.Online.Rooms; using osu.Game.Overlays.BeatmapSet; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play.HUD; @@ -449,7 +450,7 @@ namespace osu.Game.Screens.OnlinePlay Size = new Vector2(30, 30), Alpha = AllowEditing ? 1 : 0, Action = () => RequestEdit?.Invoke(Item), - TooltipText = "Edit" + TooltipText = CommonStrings.ButtonsEdit }, removeButton = new PlaylistRemoveButton { diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboardScore.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboardScore.cs index cf7e33fd63..799983342b 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboardScore.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboardScore.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Leaderboards; +using osu.Game.Resources.Localisation.Web; using osu.Game.Scoring; namespace osu.Game.Screens.OnlinePlay.Match.Components @@ -30,8 +31,8 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components protected override IEnumerable GetStatistics(ScoreInfo model) => new[] { - new LeaderboardScoreStatistic(FontAwesome.Solid.Crosshairs, "Accuracy", model.DisplayAccuracy), - new LeaderboardScoreStatistic(FontAwesome.Solid.Sync, "Total Attempts", score.TotalAttempts.ToString()), + new LeaderboardScoreStatistic(FontAwesome.Solid.Crosshairs, RankingsStrings.StatAccuracy, model.DisplayAccuracy), + new LeaderboardScoreStatistic(FontAwesome.Solid.Sync, RankingsStrings.StatPlayCount, score.TotalAttempts.ToString()), new LeaderboardScoreStatistic(FontAwesome.Solid.Check, "Completed Beatmaps", score.CompletedBeatmaps.ToString()), }; } diff --git a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs index cdd2ae0c9c..1828a072f8 100644 --- a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs @@ -10,6 +10,7 @@ using osu.Game.Beatmaps.Drawables; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; +using osu.Game.Resources.Localisation.Web; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match.Components; using osuTK; @@ -49,7 +50,7 @@ namespace osu.Game.Screens.OnlinePlay.Match { RelativeSizeAxes = Axes.Y, Size = new Vector2(100, 1), - Text = "Edit", + Text = CommonStrings.ButtonsEdit, Action = () => OnEdit?.Invoke() }); } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsListHeader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsListHeader.cs index 7e442c6568..ef84c4b4fa 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsListHeader.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsListHeader.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Game.Online.Multiplayer; +using osu.Game.Resources.Localisation.Web; using osu.Game.Screens.OnlinePlay.Components; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants @@ -13,7 +14,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants private MultiplayerClient client { get; set; } public ParticipantsListHeader() - : base("Participants") + : base(RankingsStrings.SpotlightParticipants) { } diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs index 0d759bacf0..4a0bab84fa 100644 --- a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -14,6 +14,7 @@ using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play.HUD; using osuTK; @@ -158,7 +159,7 @@ namespace osu.Game.Screens.Play { new Drawable[] { - new MetadataLineLabel("Source"), + new MetadataLineLabel(BeatmapsetsStrings.ShowInfoSource), new MetadataLineInfo(metadata.Source) }, new Drawable[] @@ -213,7 +214,7 @@ namespace osu.Game.Screens.Play private class MetadataLineLabel : OsuSpriteText { - public MetadataLineLabel(string text) + public MetadataLineLabel(LocalisableString text) { Anchor = Anchor.TopRight; Origin = Anchor.TopRight; @@ -225,10 +226,10 @@ namespace osu.Game.Screens.Play private class MetadataLineInfo : OsuSpriteText { - public MetadataLineInfo(string text) + public MetadataLineInfo(LocalisableString text) { Margin = new MarginPadding { Left = 5 }; - Text = string.IsNullOrEmpty(text) ? @"-" : text; + Text = string.IsNullOrEmpty(text.ToString()) ? @"-" : text; } } } diff --git a/osu.Game/Screens/Play/Break/BreakInfo.cs b/osu.Game/Screens/Play/Break/BreakInfo.cs index 6349ebd9a7..f95e949920 100644 --- a/osu.Game/Screens/Play/Break/BreakInfo.cs +++ b/osu.Game/Screens/Play/Break/BreakInfo.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; using osu.Game.Scoring; using osuTK; @@ -42,7 +43,7 @@ namespace osu.Game.Screens.Play.Break Direction = FillDirection.Vertical, Children = new Drawable[] { - AccuracyDisplay = new PercentageBreakInfoLine("Accuracy"), + AccuracyDisplay = new PercentageBreakInfoLine(BeatmapsetsStrings.ShowStatsAccuracy), // See https://github.com/ppy/osu/discussions/15185 // RankDisplay = new BreakInfoLine("Rank"), diff --git a/osu.Game/Screens/Play/Break/BreakInfoLine.cs b/osu.Game/Screens/Play/Break/BreakInfoLine.cs index 87f514ffd5..4cae90e50f 100644 --- a/osu.Game/Screens/Play/Break/BreakInfoLine.cs +++ b/osu.Game/Screens/Play/Break/BreakInfoLine.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.Play.Break private readonly string prefix; - public BreakInfoLine(string name, string prefix = @"") + public BreakInfoLine(LocalisableString name, string prefix = @"") { this.prefix = prefix; @@ -82,7 +82,7 @@ namespace osu.Game.Screens.Play.Break public class PercentageBreakInfoLine : BreakInfoLine { - public PercentageBreakInfoLine(string name, string prefix = "") + public PercentageBreakInfoLine(LocalisableString name, string prefix = "") : base(name, prefix) { } diff --git a/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs b/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs index 8b1e0ae83e..019a9f9730 100644 --- a/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs +++ b/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs @@ -19,6 +19,7 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Judgements; @@ -200,7 +201,7 @@ namespace osu.Game.Screens.Play.HUD { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, - Text = @"pp", + Text = BeatmapsetsStrings.ShowScoreboardHeaderspp, Font = OsuFont.Numeric.With(size: 8), Padding = new MarginPadding { Bottom = 1.5f }, // align baseline better } diff --git a/osu.Game/Screens/Play/PlayerSettings/AudioSettings.cs b/osu.Game/Screens/Play/PlayerSettings/AudioSettings.cs index 32de5333e1..90caf6f0f3 100644 --- a/osu.Game/Screens/Play/PlayerSettings/AudioSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/AudioSettings.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Configuration; +using osu.Game.Localisation; using osu.Game.Scoring; namespace osu.Game.Screens.Play.PlayerSettings @@ -20,7 +21,7 @@ namespace osu.Game.Screens.Play.PlayerSettings { Children = new Drawable[] { - beatmapHitsoundsToggle = new PlayerCheckbox { LabelText = "Beatmap hitsounds" }, + beatmapHitsoundsToggle = new PlayerCheckbox { LabelText = SkinSettingsStrings.BeatmapHitsounds }, new BeatmapOffsetControl { ReferenceScore = { BindTarget = ReferenceScore }, diff --git a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs index 81950efa9e..a999b32cb4 100644 --- a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Configuration; using osu.Game.Graphics.Sprites; +using osu.Game.Localisation; namespace osu.Game.Screens.Play.PlayerSettings { @@ -23,7 +24,7 @@ namespace osu.Game.Screens.Play.PlayerSettings { new OsuSpriteText { - Text = "Background dim:" + Text = GameplaySettingsStrings.BackgroundDim }, dimSliderBar = new PlayerSliderBar { @@ -31,7 +32,7 @@ namespace osu.Game.Screens.Play.PlayerSettings }, new OsuSpriteText { - Text = "Background blur:" + Text = GameplaySettingsStrings.BackgroundBlur }, blurSliderBar = new PlayerSliderBar { @@ -41,9 +42,9 @@ namespace osu.Game.Screens.Play.PlayerSettings { Text = "Toggles:" }, - showStoryboardToggle = new PlayerCheckbox { LabelText = "Storyboard / Video" }, - beatmapSkinsToggle = new PlayerCheckbox { LabelText = "Beatmap skins" }, - beatmapColorsToggle = new PlayerCheckbox { LabelText = "Beatmap colours" }, + showStoryboardToggle = new PlayerCheckbox { LabelText = GraphicsSettingsStrings.StoryboardVideo }, + beatmapSkinsToggle = new PlayerCheckbox { LabelText = SkinSettingsStrings.BeatmapSkins }, + beatmapColorsToggle = new PlayerCheckbox { LabelText = SkinSettingsStrings.BeatmapColours }, }; } diff --git a/osu.Game/Screens/Ranking/Contracted/ContractedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Contracted/ContractedPanelMiddleContent.cs index f9aff28bef..bb286f41c0 100644 --- a/osu.Game/Screens/Ranking/Contracted/ContractedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Contracted/ContractedPanelMiddleContent.cs @@ -9,9 +9,11 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.Leaderboards; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Play.HUD; @@ -127,8 +129,8 @@ namespace osu.Game.Screens.Ranking.Contracted Spacing = new Vector2(0, 5), Children = new[] { - createStatistic("Max Combo", $"x{score.MaxCombo}"), - createStatistic("Accuracy", $"{score.Accuracy.FormatAccuracy()}"), + createStatistic(BeatmapsetsStrings.ShowScoreboardHeadersCombo, $"x{score.MaxCombo}"), + createStatistic(BeatmapsetsStrings.ShowScoreboardHeadersAccuracy, $"{score.Accuracy.FormatAccuracy()}"), } }, new ModFlowDisplay @@ -200,7 +202,7 @@ namespace osu.Game.Screens.Ranking.Contracted private Drawable createStatistic(HitResultDisplayStatistic result) => createStatistic(result.DisplayName, result.MaxCount == null ? $"{result.Count}" : $"{result.Count}/{result.MaxCount}"); - private Drawable createStatistic(string key, string value) => new Container + private Drawable createStatistic(LocalisableString key, string value) => new Container { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs index 476c9fb42f..25a644d8d9 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs @@ -6,6 +6,7 @@ using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Resources.Localisation.Web; using osu.Game.Screens.Ranking.Expanded.Accuracy; using osu.Game.Utils; using osuTK; @@ -26,7 +27,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics /// /// The accuracy to display. public AccuracyStatistic(double accuracy) - : base("accuracy") + : base(BeatmapsetsStrings.ShowScoreboardHeadersAccuracy) { this.accuracy = accuracy; } diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs index 0e42ec026a..cb25736f6e 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; using osu.Game.Screens.Ranking.Expanded.Accuracy; using osuTK; @@ -27,7 +28,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics /// The combo to be displayed. /// The maximum value of . public ComboStatistic(int combo, int? maxCombo) - : base("combo", combo, maxCombo) + : base(BeatmapsetsStrings.ShowScoreboardHeadersCombo, combo, maxCombo) { isPerfect = combo == maxCombo; } diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs index d37f6c5e5f..b1c72173da 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs @@ -3,6 +3,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -26,7 +27,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics /// The name of the statistic. /// The value to display. /// The maximum value of . Not displayed if null. - public CounterStatistic(string header, int count, int? maxCount = null) + public CounterStatistic(LocalisableString header, int count, int? maxCount = null) : base(header) { this.count = count; diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/PerformanceStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/PerformanceStatistic.cs index 95f017d625..c681946a2f 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/PerformanceStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/PerformanceStatistic.cs @@ -8,6 +8,7 @@ using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; +using osu.Game.Resources.Localisation.Web; using osu.Game.Scoring; namespace osu.Game.Screens.Ranking.Expanded.Statistics @@ -23,7 +24,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics private RollingCounter counter; public PerformanceStatistic(ScoreInfo score) - : base("PP") + : base(BeatmapsetsStrings.ShowScoreboardHeaderspp) { this.score = score; } diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs index 9206c58bc9..c034abc916 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs @@ -3,10 +3,12 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -19,14 +21,14 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics { protected SpriteText HeaderText { get; private set; } - private readonly string header; + private readonly LocalisableString header; private Drawable content; /// /// Creates a new . /// /// The name of the statistic. - protected StatisticDisplay(string header) + protected StatisticDisplay(LocalisableString header) { this.header = header; RelativeSizeAxes = Axes.X; @@ -60,7 +62,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics Anchor = Anchor.Centre, Origin = Anchor.Centre, Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold), - Text = header.ToUpperInvariant(), + Text = header.ToUpper(), } } }, diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index bbe0a37d8e..9ff1574fe4 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -16,6 +16,7 @@ using osu.Game.Online; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.BeatmapSet; +using osu.Game.Resources.Localisation.Web; using osu.Game.Screens.Select.Details; using osuTK; using osuTK.Graphics; @@ -155,7 +156,7 @@ namespace osu.Game.Screens.Select { new OsuSpriteText { - Text = "Points of Failure", + Text = BeatmapsetsStrings.ShowInfoPointsOfFailure, Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 14), }, failRetryGraph = new FailRetryGraph diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index 3576b77ae8..c6037d1bd6 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -24,6 +24,7 @@ using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; +using osu.Game.Resources.Localisation.Web; using osuTK; using osuTK.Graphics; @@ -136,14 +137,7 @@ namespace osu.Game.Screens.Select.Carousel }, new OsuSpriteText { - Text = "mapped by", - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft - }, - new OsuSpriteText - { - Text = $"{beatmapInfo.Metadata.Author.Username}", - Font = OsuFont.GetFont(italics: true), + Text = BeatmapsetsStrings.ShowDetailsMappedBy(beatmapInfo.Metadata.Author.Username), Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft }, @@ -235,7 +229,7 @@ namespace osu.Game.Screens.Select.Carousel items.Add(new OsuMenuItem("Play", MenuItemType.Highlighted, () => startRequested(beatmapInfo))); if (editRequested != null) - items.Add(new OsuMenuItem("Edit", MenuItemType.Standard, () => editRequested(beatmapInfo))); + items.Add(new OsuMenuItem(CommonStrings.ButtonsEdit, MenuItemType.Standard, () => editRequested(beatmapInfo))); if (beatmapInfo.OnlineID > 0 && beatmapOverlay != null) items.Add(new OsuMenuItem("Details...", MenuItemType.Standard, () => beatmapOverlay.FetchAndShowBeatmap(beatmapInfo.OnlineID))); @@ -250,7 +244,7 @@ namespace osu.Game.Screens.Select.Carousel } if (hideRequested != null) - items.Add(new OsuMenuItem("Hide", MenuItemType.Destructive, () => hideRequested(beatmapInfo))); + items.Add(new OsuMenuItem(CommonStrings.ButtonsHide, MenuItemType.Destructive, () => hideRequested(beatmapInfo))); return items.ToArray(); } diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index adaaa6425c..a6f2520472 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -21,6 +21,7 @@ using osu.Framework.Localisation; using osu.Framework.Threading; using osu.Framework.Utils; using osu.Game.Configuration; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; namespace osu.Game.Screens.Select.Details @@ -63,10 +64,10 @@ namespace osu.Game.Screens.Select.Details Children = new[] { FirstValue = new StatisticRow(), // circle size/key amount - HpDrain = new StatisticRow { Title = "HP Drain" }, - Accuracy = new StatisticRow { Title = "Accuracy" }, - ApproachRate = new StatisticRow { Title = "Approach Rate" }, - starDifficulty = new StatisticRow(10, true) { Title = "Star Difficulty" }, + HpDrain = new StatisticRow { Title = BeatmapsetsStrings.ShowStatsDrain }, + Accuracy = new StatisticRow { Title = BeatmapsetsStrings.ShowStatsAccuracy }, + ApproachRate = new StatisticRow { Title = BeatmapsetsStrings.ShowStatsAr }, + starDifficulty = new StatisticRow(10, true) { Title = BeatmapsetsStrings.ShowStatsStars }, }, }; } @@ -120,12 +121,12 @@ namespace osu.Game.Screens.Select.Details case 3: // Account for mania differences locally for now // Eventually this should be handled in a more modular way, allowing rulesets to return arbitrary difficulty attributes - FirstValue.Title = "Key Count"; + FirstValue.Title = BeatmapsetsStrings.ShowStatsCsMania; FirstValue.Value = (baseDifficulty?.CircleSize ?? 0, null); break; default: - FirstValue.Title = "Circle Size"; + FirstValue.Title = BeatmapsetsStrings.ShowStatsCs; FirstValue.Value = (baseDifficulty?.CircleSize ?? 0, adjustedDifficulty?.CircleSize); break; } diff --git a/osu.Game/Screens/Select/Filter/SortMode.cs b/osu.Game/Screens/Select/Filter/SortMode.cs index 18c5d713e1..1ab54fa069 100644 --- a/osu.Game/Screens/Select/Filter/SortMode.cs +++ b/osu.Game/Screens/Select/Filter/SortMode.cs @@ -2,36 +2,38 @@ // See the LICENCE file in the repository root for full licence text. using System.ComponentModel; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Screens.Select.Filter { public enum SortMode { - [Description("Artist")] + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingArtist))] Artist, [Description("Author")] Author, - [Description("BPM")] + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowStatsBpm))] BPM, [Description("Date Added")] DateAdded, - [Description("Difficulty")] + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingDifficulty))] Difficulty, - [Description("Length")] + [LocalisableDescription(typeof(SortStrings), nameof(SortStrings.ArtistTracksLength))] Length, - [Description("Rank Achieved")] + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchFiltersRank))] RankAchieved, - [Description("Source")] + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowInfoSource))] Source, - [Description("Title")] + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingTitle))] Title, } } diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index b53d64260a..65dde146bb 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -14,6 +14,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; using osu.Game.Screens.Select.Filter; using osuTK; @@ -139,7 +140,7 @@ namespace osu.Game.Screens.Select }, new OsuSpriteText { - Text = "Sort by", + Text = SortStrings.Default, Font = OsuFont.GetFont(size: 14), Margin = new MarginPadding(5), Anchor = Anchor.BottomRight, diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs index b5fdbd225f..1a8b69d859 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs @@ -13,6 +13,7 @@ using osuTK.Input; using osu.Game.Graphics.Containers; using osu.Framework.Input.Events; using System.Linq; +using osu.Framework.Localisation; namespace osu.Game.Screens.Select.Options { @@ -63,7 +64,7 @@ namespace osu.Game.Screens.Select.Options /// Colour of the button. /// Icon of the button. /// Binding the button does. - public void AddButton(string firstLine, string secondLine, IconUsage icon, Color4 colour, Action action) + public void AddButton(LocalisableString firstLine, string secondLine, IconUsage icon, Color4 colour, Action action) { var button = new BeatmapOptionsButton { diff --git a/osu.Game/Users/UserStatus.cs b/osu.Game/Users/UserStatus.cs index 21c18413f4..7f275b3b2a 100644 --- a/osu.Game/Users/UserStatus.cs +++ b/osu.Game/Users/UserStatus.cs @@ -1,20 +1,22 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Localisation; using osuTK.Graphics; using osu.Game.Graphics; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Users { public abstract class UserStatus { - public abstract string Message { get; } + public abstract LocalisableString Message { get; } public abstract Color4 GetAppropriateColour(OsuColour colours); } public class UserStatusOnline : UserStatus { - public override string Message => @"Online"; + public override LocalisableString Message => UsersStrings.StatusOnline; public override Color4 GetAppropriateColour(OsuColour colours) => colours.GreenLight; } @@ -25,13 +27,13 @@ namespace osu.Game.Users public class UserStatusOffline : UserStatus { - public override string Message => @"Offline"; + public override LocalisableString Message => UsersStrings.StatusOffline; public override Color4 GetAppropriateColour(OsuColour colours) => Color4.Black; } public class UserStatusDoNotDisturb : UserStatus { - public override string Message => @"Do not disturb"; + public override LocalisableString Message => "Do not disturb"; public override Color4 GetAppropriateColour(OsuColour colours) => colours.RedDark; } } From 0146949ad60c45e788230e6336bfb29aaaa3491e Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 20 Apr 2022 16:52:24 -0700 Subject: [PATCH 69/74] Fix failing string comparison tests --- osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs index 7ceae0a69b..8af70df48a 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; @@ -55,7 +56,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("no mods selected", () => SelectedMods.Value = Array.Empty()); - AddAssert("first bar text is Circle Size", () => advancedStats.ChildrenOfType().First().Text == "Circle Size"); + AddAssert("first bar text is correct", () => advancedStats.ChildrenOfType().First().Text == BeatmapsetsStrings.ShowStatsCs); AddAssert("circle size bar is white", () => barIsWhite(advancedStats.FirstValue)); AddAssert("HP drain bar is white", () => barIsWhite(advancedStats.HpDrain)); AddAssert("accuracy bar is white", () => barIsWhite(advancedStats.Accuracy)); @@ -78,7 +79,7 @@ namespace osu.Game.Tests.Visual.SongSelect StarRating = 8 }); - AddAssert("first bar text is Key Count", () => advancedStats.ChildrenOfType().First().Text == "Key Count"); + AddAssert("first bar text is correct", () => advancedStats.ChildrenOfType().First().Text == BeatmapsetsStrings.ShowStatsCsMania); } [Test] From a9163727db6195bee3a4212ad6d4c3cf8b1d0804 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Apr 2022 13:44:14 +0900 Subject: [PATCH 70/74] Mark selected channel null in test when selector is activated --- osu.Game.Tests/Visual/Online/TestSceneChannelList.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs index d6a1e71f0d..a3bfbd47a3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs @@ -104,6 +104,7 @@ namespace osu.Game.Tests.Visual.Online channelList.SelectorActive.BindValueChanged(change => { selectorText.Text = $"Channel Selector Active: {change.NewValue}"; + selected.Value = null; }, true); selected.BindValueChanged(change => From 9f525ee26743ce70b1f200979c1664841fef0896 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Apr 2022 14:09:51 +0900 Subject: [PATCH 71/74] Revert localisation of spectate/watch button --- osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs index e036f1d304..9807a65250 100644 --- a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs +++ b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs @@ -139,7 +139,7 @@ namespace osu.Game.Overlays.Dashboard new PurpleTriangleButton { RelativeSizeAxes = Axes.X, - Text = CommonStrings.ButtonsWatchTo1, + Text = "Spectate", Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Action = () => performer?.PerformFromScreen(s => s.Push(new SoloSpectator(User))), From 848366416e7595b1dce036fa186e0f1369b66c5c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Apr 2022 14:10:58 +0900 Subject: [PATCH 72/74] Revert string type changes in `MetadataLineInfo` --- osu.Game/Screens/Play/BeatmapMetadataDisplay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs index 4a0bab84fa..e8021d4065 100644 --- a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -226,10 +226,10 @@ namespace osu.Game.Screens.Play private class MetadataLineInfo : OsuSpriteText { - public MetadataLineInfo(LocalisableString text) + public MetadataLineInfo(string text) { Margin = new MarginPadding { Left = 5 }; - Text = string.IsNullOrEmpty(text.ToString()) ? @"-" : text; + Text = string.IsNullOrEmpty(text) ? @"-" : text; } } } From b4c208be63db5babf41d3301de4f07f59379a7c9 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 21 Apr 2022 15:34:01 +0900 Subject: [PATCH 73/74] Move Code Quality check to top of checks list --- .github/workflows/ci.yml | 110 +++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e7f9628fc..f2066f27de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,6 +2,60 @@ on: [push, pull_request] name: Continuous Integration jobs: + inspect-code: + name: Code Quality + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + # FIXME: Tools won't run in .NET 6.0 unless you install 3.1.x LTS side by side. + # https://itnext.io/how-to-support-multiple-net-sdks-in-github-actions-workflows-b988daa884e + - name: Install .NET 3.1.x LTS + uses: actions/setup-dotnet@v1 + with: + dotnet-version: "3.1.x" + + - name: Install .NET 6.0.x + uses: actions/setup-dotnet@v1 + with: + dotnet-version: "6.0.x" + + - name: Restore Tools + run: dotnet tool restore + + - name: Restore Packages + run: dotnet restore + + - name: Restore inspectcode cache + uses: actions/cache@v3 + with: + path: ${{ github.workspace }}/inspectcode + key: inspectcode-${{ hashFiles('.config/dotnet-tools.json') }}-${{ hashFiles('.github/workflows/ci.yml' ) }} + + - name: CodeFileSanity + run: | + # TODO: Add ignore filters and GitHub Workflow Command Reporting in CFS. That way we don't have to do this workaround. + # FIXME: Suppress warnings from templates project + exit_code=0 + while read -r line; do + if [[ ! -z "$line" ]]; then + echo "::error::$line" + exit_code=1 + fi + done <<< $(dotnet codefilesanity) + exit $exit_code + + # Temporarily disabled due to test failures, but it won't work anyway until the tool is upgraded. + # - name: .NET Format (Dry Run) + # run: dotnet format --dry-run --check + + - name: InspectCode + run: dotnet jb inspectcode $(pwd)/osu.Desktop.slnf --no-build --output="inspectcodereport.xml" --caches-home="inspectcode" --verbosity=WARN + + - name: NVika + run: dotnet nvika parsereport "${{github.workspace}}/inspectcodereport.xml" --treatwarningsaserrors + test: name: Test runs-on: ${{matrix.os.fullname}} @@ -93,58 +147,4 @@ jobs: # cannot accept .sln(f) files as arguments. # Build just the main game for now. - name: Build - run: msbuild osu.iOS/osu.iOS.csproj /restore /p:Configuration=Debug - - inspect-code: - name: Code Quality - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - # FIXME: Tools won't run in .NET 6.0 unless you install 3.1.x LTS side by side. - # https://itnext.io/how-to-support-multiple-net-sdks-in-github-actions-workflows-b988daa884e - - name: Install .NET 3.1.x LTS - uses: actions/setup-dotnet@v1 - with: - dotnet-version: "3.1.x" - - - name: Install .NET 6.0.x - uses: actions/setup-dotnet@v1 - with: - dotnet-version: "6.0.x" - - - name: Restore Tools - run: dotnet tool restore - - - name: Restore Packages - run: dotnet restore - - - name: Restore inspectcode cache - uses: actions/cache@v3 - with: - path: ${{ github.workspace }}/inspectcode - key: inspectcode-${{ hashFiles('.config/dotnet-tools.json') }}-${{ hashFiles('.github/workflows/ci.yml' ) }} - - - name: CodeFileSanity - run: | - # TODO: Add ignore filters and GitHub Workflow Command Reporting in CFS. That way we don't have to do this workaround. - # FIXME: Suppress warnings from templates project - exit_code=0 - while read -r line; do - if [[ ! -z "$line" ]]; then - echo "::error::$line" - exit_code=1 - fi - done <<< $(dotnet codefilesanity) - exit $exit_code - - # Temporarily disabled due to test failures, but it won't work anyway until the tool is upgraded. - # - name: .NET Format (Dry Run) - # run: dotnet format --dry-run --check - - - name: InspectCode - run: dotnet jb inspectcode $(pwd)/osu.Desktop.slnf --no-build --output="inspectcodereport.xml" --caches-home="inspectcode" --verbosity=WARN - - - name: NVika - run: dotnet nvika parsereport "${{github.workspace}}/inspectcodereport.xml" --treatwarningsaserrors + run: msbuild osu.iOS/osu.iOS.csproj /restore /p:Configuration=Debug \ No newline at end of file From 54ca4b9d36f55bd9e3636b1c88eea0ef553753e6 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 21 Apr 2022 15:34:14 +0900 Subject: [PATCH 74/74] Remove unused using --- osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs index 9807a65250..a9312e9a3a 100644 --- a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs +++ b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs @@ -14,7 +14,6 @@ using osu.Game.Database; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Spectator; -using osu.Game.Resources.Localisation.Web; using osu.Game.Screens; using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.Play;