From 69351d2cdf9de1b4c01ef5740c73983cb3a94fe2 Mon Sep 17 00:00:00 2001 From: Noah M Date: Wed, 18 May 2022 01:09:58 -0500 Subject: [PATCH 001/103] Implement button to delete all beatmap videos --- osu.Game/Beatmaps/BeatmapManager.cs | 12 ++++++ .../MaintenanceSettingsStrings.cs | 5 +++ .../Sections/Maintenance/GeneralSettings.cs | 14 +++++++ .../MassDeleteConfirmationDialog.cs | 7 ++++ osu.Game/Stores/RealmArchiveModelManager.cs | 38 +++++++++++++++++++ 5 files changed, 76 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 5f7de0d762..2a5df9e206 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -319,6 +319,18 @@ namespace osu.Game.Beatmaps }); } + public void DeleteVideos(Expression>? filter = null, bool silent = false) + { + realm.Write(r => + { + var items = r.All().Where(s => !s.DeletePending && !s.Protected); + + if (filter != null) + items = items.Where(filter); + beatmapModelManager.DeleteVideos(items.ToList(), silent); + }); + } + public void UndeleteAll() { realm.Run(r => beatmapModelManager.Undelete(r.All().Where(s => s.DeletePending).ToList())); diff --git a/osu.Game/Localisation/MaintenanceSettingsStrings.cs b/osu.Game/Localisation/MaintenanceSettingsStrings.cs index a0e1a9ddab..7a04bcd1ca 100644 --- a/osu.Game/Localisation/MaintenanceSettingsStrings.cs +++ b/osu.Game/Localisation/MaintenanceSettingsStrings.cs @@ -29,6 +29,11 @@ namespace osu.Game.Localisation /// public static LocalisableString DeleteAllBeatmaps => new TranslatableString(getKey(@"delete_all_beatmaps"), @"Delete ALL beatmaps"); + /// + /// "Delete ALL beatmap videos" + /// + public static LocalisableString DeleteAllBeatmapVideos => new TranslatableString(getKey(@"delete_all_beatmap_videos"), @"Delete ALL beatmap videos"); + /// /// "Import scores from stable" /// diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index be4b0decd9..c2ebb59ecc 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -28,6 +28,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private SettingsButton deleteSkinsButton; private SettingsButton restoreButton; private SettingsButton undeleteButton; + private SettingsButton deleteBeatmapVideosButton; [BackgroundDependencyLoader(permitNulls: true)] private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, [CanBeNull] CollectionManager collectionManager, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay) @@ -58,6 +59,19 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance } }); + Add(deleteBeatmapVideosButton = new DangerousSettingsButton + { + Text = MaintenanceSettingsStrings.DeleteAllBeatmapVideos, + Action = () => + { + dialogOverlay?.Push(new MassVideoDeleteConfirmationDialog(() => + { + deleteBeatmapVideosButton.Enabled.Value = false; + Task.Run(() => beatmaps.DeleteVideos()).ContinueWith(t => Schedule(() => deleteBeatmapsButton.Enabled.Value = true)); + })); + } + }); + if (legacyImportManager?.SupportsImportFromStable == true) { Add(importScoresButton = new SettingsButton diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs index c481c80d82..274b1060ca 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs @@ -29,4 +29,11 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance }; } } + public class MassVideoDeleteConfirmationDialog : MassDeleteConfirmationDialog + { + public MassVideoDeleteConfirmationDialog(Action deleteAction) : base(deleteAction) + { + BodyText = "All beatmap videos? This cannot be undone!"; + } + } } diff --git a/osu.Game/Stores/RealmArchiveModelManager.cs b/osu.Game/Stores/RealmArchiveModelManager.cs index cc8229b436..f70aa41cfb 100644 --- a/osu.Game/Stores/RealmArchiveModelManager.cs +++ b/osu.Game/Stores/RealmArchiveModelManager.cs @@ -132,6 +132,44 @@ namespace osu.Game.Stores notification.State = ProgressNotificationState.Completed; } + /// + /// Delete videos from a list of items. + /// This will post notifications tracking progress. + /// + public void DeleteVideos(List items, bool silent = false) + { + if (items.Count == 0) return; + + var notification = new ProgressNotification + { + Progress = 0, + Text = $"Preparing to delete all {HumanisedModelName} videos...", + CompletionText = $"Deleted all {HumanisedModelName} videos!", + State = ProgressNotificationState.Active, + }; + if (!silent) + PostNotification?.Invoke(notification); + + int i = 0; + + foreach (var b in items) + { + if (notification.State == ProgressNotificationState.Cancelled) + // user requested abort + return; + + notification.Text = $"Deleting videos from {HumanisedModelName}s ({++i} of {items.Count})"; + + var video = b.Files.FirstOrDefault(f => f.Filename.EndsWith(".mp4") || f.Filename.EndsWith(".avi") || f.Filename.EndsWith(".mov") || f.Filename.EndsWith(".flv")); + if (video != null) + DeleteFile(b, video); + + notification.Progress = (float)i / items.Count; + } + + notification.State = ProgressNotificationState.Completed; + } + /// /// Restore multiple items that were previously deleted. /// This will post notifications tracking progress. From 617382a56f19d628122f5842d8e939efbf2ecbad Mon Sep 17 00:00:00 2001 From: Noah M Date: Wed, 18 May 2022 15:20:02 -0500 Subject: [PATCH 002/103] Split off MassVideoDeleteConfirmationDialog into its own file --- .../Maintenance/MassDeleteConfirmationDialog.cs | 7 ------- .../MassVideoDeleteConfirmationDialog.cs | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs index 274b1060ca..c481c80d82 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs @@ -29,11 +29,4 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance }; } } - public class MassVideoDeleteConfirmationDialog : MassDeleteConfirmationDialog - { - public MassVideoDeleteConfirmationDialog(Action deleteAction) : base(deleteAction) - { - BodyText = "All beatmap videos? This cannot be undone!"; - } - } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs new file mode 100644 index 0000000000..522177807c --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs @@ -0,0 +1,15 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; + +namespace osu.Game.Overlays.Settings.Sections.Maintenance +{ + public class MassVideoDeleteConfirmationDialog : MassDeleteConfirmationDialog + { + public MassVideoDeleteConfirmationDialog(Action deleteAction) : base(deleteAction) + { + BodyText = "All beatmap videos? This cannot be undone!"; + } + } +} From a93a2fcafba1b0f3af7e52ea6b36e72a592b9e51 Mon Sep 17 00:00:00 2001 From: Noah M Date: Wed, 18 May 2022 15:37:46 -0500 Subject: [PATCH 003/103] Move implementation of DeleteVideos to BeatmapModelManager --- osu.Game/Beatmaps/BeatmapModelManager.cs | 39 +++++++++++++++++++++ osu.Game/Stores/RealmArchiveModelManager.cs | 38 -------------------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapModelManager.cs b/osu.Game/Beatmaps/BeatmapModelManager.cs index 4c680bbcc9..3cd2e8c8bd 100644 --- a/osu.Game/Beatmaps/BeatmapModelManager.cs +++ b/osu.Game/Beatmaps/BeatmapModelManager.cs @@ -16,6 +16,7 @@ using osu.Game.Database; using osu.Game.Extensions; using osu.Game.Skinning; using osu.Game.Stores; +using osu.Game.Overlays.Notifications; #nullable enable @@ -114,5 +115,43 @@ namespace osu.Game.Beatmaps item.CopyChangesToRealm(existing); }); } + + /// + /// Delete videos from a list of beatmaps. + /// This will post notifications tracking progress. + /// + public void DeleteVideos(List items, bool silent = false) + { + if (items.Count == 0) return; + + var notification = new ProgressNotification + { + Progress = 0, + Text = $"Preparing to delete all {HumanisedModelName} videos...", + CompletionText = $"Deleted all {HumanisedModelName} videos!", + State = ProgressNotificationState.Active, + }; + if (!silent) + PostNotification?.Invoke(notification); + + int i = 0; + + foreach (var b in items) + { + if (notification.State == ProgressNotificationState.Cancelled) + // user requested abort + return; + + notification.Text = $"Deleting videos from {HumanisedModelName}s ({++i} of {items.Count})"; + + var video = b.Files.FirstOrDefault(f => f.Filename.EndsWith(".mp4") || f.Filename.EndsWith(".avi") || f.Filename.EndsWith(".mov") || f.Filename.EndsWith(".flv")); + if (video != null) + DeleteFile(b, video); + + notification.Progress = (float)i / items.Count; + } + + notification.State = ProgressNotificationState.Completed; + } } } diff --git a/osu.Game/Stores/RealmArchiveModelManager.cs b/osu.Game/Stores/RealmArchiveModelManager.cs index f70aa41cfb..cc8229b436 100644 --- a/osu.Game/Stores/RealmArchiveModelManager.cs +++ b/osu.Game/Stores/RealmArchiveModelManager.cs @@ -132,44 +132,6 @@ namespace osu.Game.Stores notification.State = ProgressNotificationState.Completed; } - /// - /// Delete videos from a list of items. - /// This will post notifications tracking progress. - /// - public void DeleteVideos(List items, bool silent = false) - { - if (items.Count == 0) return; - - var notification = new ProgressNotification - { - Progress = 0, - Text = $"Preparing to delete all {HumanisedModelName} videos...", - CompletionText = $"Deleted all {HumanisedModelName} videos!", - State = ProgressNotificationState.Active, - }; - if (!silent) - PostNotification?.Invoke(notification); - - int i = 0; - - foreach (var b in items) - { - if (notification.State == ProgressNotificationState.Cancelled) - // user requested abort - return; - - notification.Text = $"Deleting videos from {HumanisedModelName}s ({++i} of {items.Count})"; - - var video = b.Files.FirstOrDefault(f => f.Filename.EndsWith(".mp4") || f.Filename.EndsWith(".avi") || f.Filename.EndsWith(".mov") || f.Filename.EndsWith(".flv")); - if (video != null) - DeleteFile(b, video); - - notification.Progress = (float)i / items.Count; - } - - notification.State = ProgressNotificationState.Completed; - } - /// /// Restore multiple items that were previously deleted. /// This will post notifications tracking progress. From 60eb0ea69edd1c8e9a9b41c2db071d385536493e Mon Sep 17 00:00:00 2001 From: Noah M Date: Wed, 18 May 2022 15:40:46 -0500 Subject: [PATCH 004/103] Remove unnecessary parameters from DeleteVideos --- osu.Game/Beatmaps/BeatmapManager.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 2a5df9e206..92266924df 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -319,15 +319,12 @@ namespace osu.Game.Beatmaps }); } - public void DeleteVideos(Expression>? filter = null, bool silent = false) + public void DeleteVideos() { realm.Write(r => { var items = r.All().Where(s => !s.DeletePending && !s.Protected); - - if (filter != null) - items = items.Where(filter); - beatmapModelManager.DeleteVideos(items.ToList(), silent); + beatmapModelManager.DeleteVideos(items.ToList()); }); } From d1fcd73c87ca9fe93123ad66b0259521587d15a0 Mon Sep 17 00:00:00 2001 From: Noah M Date: Wed, 18 May 2022 16:25:10 -0500 Subject: [PATCH 005/103] Convert extension checking to checking against string array --- osu.Game/Beatmaps/BeatmapModelManager.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapModelManager.cs b/osu.Game/Beatmaps/BeatmapModelManager.cs index 3cd2e8c8bd..9d3ea7d192 100644 --- a/osu.Game/Beatmaps/BeatmapModelManager.cs +++ b/osu.Game/Beatmaps/BeatmapModelManager.cs @@ -34,6 +34,8 @@ namespace osu.Game.Beatmaps protected override string[] HashableFileTypes => new[] { ".osu" }; + private static readonly string[] video_extensions = { ".mp4", ".mov", ".avi", ".flv" }; + public BeatmapModelManager(RealmAccess realm, Storage storage, BeatmapOnlineLookupQueue? onlineLookupQueue = null) : base(realm, storage, onlineLookupQueue) { @@ -144,7 +146,7 @@ namespace osu.Game.Beatmaps notification.Text = $"Deleting videos from {HumanisedModelName}s ({++i} of {items.Count})"; - var video = b.Files.FirstOrDefault(f => f.Filename.EndsWith(".mp4") || f.Filename.EndsWith(".avi") || f.Filename.EndsWith(".mov") || f.Filename.EndsWith(".flv")); + var video = b.Files.FirstOrDefault(f => video_extensions.Any(ex => f.Filename.EndsWith(ex, StringComparison.Ordinal))); if (video != null) DeleteFile(b, video); From 0ef94067872805047679d948585ce6fb81d8a463 Mon Sep 17 00:00:00 2001 From: Noah M Date: Wed, 18 May 2022 16:35:14 -0500 Subject: [PATCH 006/103] Fix deleteBeatmapVideosButton not being reenabled My bad --- .../Overlays/Settings/Sections/Maintenance/GeneralSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index c2ebb59ecc..afc5cad893 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance dialogOverlay?.Push(new MassVideoDeleteConfirmationDialog(() => { deleteBeatmapVideosButton.Enabled.Value = false; - Task.Run(() => beatmaps.DeleteVideos()).ContinueWith(t => Schedule(() => deleteBeatmapsButton.Enabled.Value = true)); + Task.Run(() => beatmaps.DeleteVideos()).ContinueWith(t => Schedule(() => deleteBeatmapVideosButton.Enabled.Value = true)); })); } }); From b550cbc5a3e22421073401059c43c7b54095a623 Mon Sep 17 00:00:00 2001 From: Noah M Date: Wed, 25 May 2022 17:01:30 -0500 Subject: [PATCH 007/103] Fix failing code quality checks --- .../Overlays/Settings/Sections/Maintenance/GeneralSettings.cs | 2 +- .../Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index afc5cad893..37758875ea 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance dialogOverlay?.Push(new MassVideoDeleteConfirmationDialog(() => { deleteBeatmapVideosButton.Enabled.Value = false; - Task.Run(() => beatmaps.DeleteVideos()).ContinueWith(t => Schedule(() => deleteBeatmapVideosButton.Enabled.Value = true)); + Task.Run(beatmaps.DeleteVideos).ContinueWith(t => Schedule(() => deleteBeatmapVideosButton.Enabled.Value = true)); })); } }); diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs index 522177807c..fc8c9d497b 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs @@ -7,7 +7,8 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public class MassVideoDeleteConfirmationDialog : MassDeleteConfirmationDialog { - public MassVideoDeleteConfirmationDialog(Action deleteAction) : base(deleteAction) + public MassVideoDeleteConfirmationDialog(Action deleteAction) + : base(deleteAction) { BodyText = "All beatmap videos? This cannot be undone!"; } From 0349d92f8b0b6802423efc5304df52f6db5af81c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 28 May 2022 17:45:00 +0300 Subject: [PATCH 008/103] Add failing test case --- .../Visual/Editing/TestSceneTimelineZoom.cs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs new file mode 100644 index 0000000000..10f1f2fceb --- /dev/null +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs @@ -0,0 +1,48 @@ +// 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; +using osu.Framework.Utils; + +namespace osu.Game.Tests.Visual.Editing +{ + public class TestSceneTimelineZoom : TimelineTestScene + { + public override Drawable CreateTestComponent() => Empty(); + + [Test] + public void TestVisibleRangeViaZoom() + { + double initialVisibleRange = 0; + + AddStep("reset zoom", () => TimelineArea.Timeline.Zoom = 100); + AddStep("get initial range", () => initialVisibleRange = TimelineArea.Timeline.VisibleRange); + + AddStep("scale zoom", () => TimelineArea.Timeline.Zoom = 200); + AddAssert("range halved", () => Precision.AlmostEquals(TimelineArea.Timeline.VisibleRange, initialVisibleRange / 2, 1)); + AddStep("descale zoom", () => TimelineArea.Timeline.Zoom = 50); + AddAssert("range doubled", () => Precision.AlmostEquals(TimelineArea.Timeline.VisibleRange, initialVisibleRange * 2, 1)); + + AddStep("restore zoom", () => TimelineArea.Timeline.Zoom = 100); + AddAssert("range restored", () => Precision.AlmostEquals(TimelineArea.Timeline.VisibleRange, initialVisibleRange, 1)); + } + + [Test] + public void TestVisibleRangeViaTimelineSize() + { + double initialVisibleRange = 0; + + AddStep("reset timeline size", () => TimelineArea.Timeline.Width = 1); + AddStep("get initial range", () => initialVisibleRange = TimelineArea.Timeline.VisibleRange); + + AddStep("scale timeline size", () => TimelineArea.Timeline.Width = 2); + AddAssert("range doubled", () => TimelineArea.Timeline.VisibleRange == initialVisibleRange * 2); + AddStep("descale timeline size", () => TimelineArea.Timeline.Width = 0.5f); + AddAssert("range halved", () => TimelineArea.Timeline.VisibleRange == initialVisibleRange / 2); + + AddStep("restore timeline size", () => TimelineArea.Timeline.Width = 1); + AddAssert("range restored", () => TimelineArea.Timeline.VisibleRange == initialVisibleRange); + } + } +} From 02baf9a97abe0fb6e94af53b83708a15a508d437 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 28 May 2022 17:45:33 +0300 Subject: [PATCH 009/103] Fix timeline objects disappearing prematurely on wide-screens --- osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 6812bbb72d..2a6e8f5453 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -302,7 +302,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline /// /// The total amount of time visible on the timeline. /// - public double VisibleRange => track.Length / Zoom; + public double VisibleRange => (DisplayableContent / Content.DrawWidth) * track.Length; public SnapResult FindSnappedPositionAndTime(Vector2 screenSpacePosition, SnapType snapType = SnapType.All) => new SnapResult(screenSpacePosition, beatSnapProvider.SnapTime(getTimeFromPosition(Content.ToLocalSpace(screenSpacePosition)))); From d12f6ea2213da50789f48c9cf3f0e65a55e1ae93 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Jun 2022 18:53:35 +0900 Subject: [PATCH 010/103] Add basics of tap button --- .../Visual/Editing/TestSceneTapButton.cs | 48 +++++++ osu.Game/Screens/Edit/Timing/TapButton.cs | 122 ++++++++++++++++++ .../Screens/Edit/Timing/TapTimingControl.cs | 9 ++ 3 files changed, 179 insertions(+) create mode 100644 osu.Game.Tests/Visual/Editing/TestSceneTapButton.cs create mode 100644 osu.Game/Screens/Edit/Timing/TapButton.cs diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTapButton.cs b/osu.Game.Tests/Visual/Editing/TestSceneTapButton.cs new file mode 100644 index 0000000000..d8141619ab --- /dev/null +++ b/osu.Game.Tests/Visual/Editing/TestSceneTapButton.cs @@ -0,0 +1,48 @@ +// 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.Graphics; +using osu.Game.Overlays; +using osu.Game.Screens.Edit.Timing; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Editing +{ + public class TestSceneTapButton : OsuManualInputManagerTestScene + { + private TapButton tapButton; + + [Cached] + private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + + [Test] + public void TestBasic() + { + AddStep("create button", () => + { + Child = tapButton = new TapButton + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(4), + }; + }); + + bool pressed = false; + + AddRepeatStep("Press button", () => + { + InputManager.MoveMouseTo(tapButton); + if (!pressed) + InputManager.PressButton(MouseButton.Left); + else + InputManager.ReleaseButton(MouseButton.Left); + + pressed = !pressed; + }, 100); + } + } +} diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs new file mode 100644 index 0000000000..59ec966fe0 --- /dev/null +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -0,0 +1,122 @@ +// 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.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Game.Overlays; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.Edit.Timing +{ + internal class TapButton : CircularContainer + { + public const float SIZE = 100; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + + private Circle hoverLayer; + private CircularContainer innerCircle; + private Circle outerCircle; + + private Container scaleContainer; + + [BackgroundDependencyLoader] + private void load() + { + Size = new Vector2(SIZE); + + const float ring_width = 20; + const float light_padding = 3; + + InternalChild = scaleContainer = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + outerCircle = new Circle + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background3 + }, + new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Name = "outer masking", + Masking = true, + BorderThickness = light_padding, + BorderColour = colourProvider.Background3, + Children = new Drawable[] + { + new Box + { + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + }, + } + }, + innerCircle = new CircularContainer + { + Size = new Vector2(SIZE - ring_width + light_padding), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Masking = true, + BorderThickness = light_padding, + BorderColour = colourProvider.Background3, + Children = new Drawable[] + { + new Box + { + Colour = colourProvider.Background2, + RelativeSizeAxes = Axes.Both, + AlwaysPresent = true, + }, + } + }, + hoverLayer = new Circle + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White.Opacity(0.01f), + Blending = BlendingParameters.Additive, + Alpha = 0, + }, + } + }; + } + + protected override bool OnHover(HoverEvent e) + { + hoverLayer.FadeIn(500, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + hoverLayer.FadeOut(500, Easing.OutQuint); + base.OnHoverLost(e); + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + scaleContainer.ScaleTo(0.98f, 200, Easing.OutQuint); + innerCircle.ScaleTo(0.95f, 200, Easing.OutQuint); + return base.OnMouseDown(e); + } + + protected override void OnMouseUp(MouseUpEvent e) + { + scaleContainer.ScaleTo(1, 1200, Easing.OutQuint); + innerCircle.ScaleTo(1, 1200, Easing.OutQuint); + base.OnMouseUp(e); + } + } +} diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 990f8d2ce0..20d6c656ff 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -50,6 +50,7 @@ namespace osu.Game.Screens.Edit.Timing new Dimension(GridSizeMode.Absolute, 200), new Dimension(GridSizeMode.Absolute, 60), new Dimension(GridSizeMode.Absolute, 60), + new Dimension(GridSizeMode.Absolute, 120), }, Content = new[] { @@ -141,6 +142,14 @@ namespace osu.Game.Screens.Edit.Timing } } }, + }, + new Drawable[] + { + new TapButton + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } } } }, From c3ba7b2c3beef436f9a03b4210ff3181e9d79a4d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Jun 2022 19:45:11 +0900 Subject: [PATCH 011/103] Add lights --- osu.Game/Screens/Edit/Timing/TapButton.cs | 150 +++++++++++++++++++--- 1 file changed, 132 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index 59ec966fe0..3eb8e23bad 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -6,7 +6,10 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; using osu.Game.Overlays; using osuTK; using osuTK.Graphics; @@ -21,17 +24,23 @@ namespace osu.Game.Screens.Edit.Timing private OverlayColourProvider colourProvider { get; set; } private Circle hoverLayer; + private CircularContainer innerCircle; - private Circle outerCircle; + private Box innerCircleHighlight; + + private int currentLight; private Container scaleContainer; + private Container lights; + + private const int light_count = 6; [BackgroundDependencyLoader] private void load() { Size = new Vector2(SIZE); - const float ring_width = 20; + const float ring_width = 18; const float light_padding = 3; InternalChild = scaleContainer = new Container @@ -41,11 +50,15 @@ namespace osu.Game.Screens.Edit.Timing RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - outerCircle = new Circle + new Circle { RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background3 }, + lights = new Container + { + RelativeSizeAxes = Axes.Both, + }, new CircularContainer { RelativeSizeAxes = Axes.Both, @@ -64,35 +77,65 @@ namespace osu.Game.Screens.Edit.Timing }, } }, + new Circle + { + Size = new Vector2(SIZE - ring_width * 2 + light_padding * 2), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = colourProvider.Background3, + }, innerCircle = new CircularContainer { - Size = new Vector2(SIZE - ring_width + light_padding), + Size = new Vector2(SIZE - ring_width * 2), Anchor = Anchor.Centre, Origin = Anchor.Centre, Masking = true, - BorderThickness = light_padding, - BorderColour = colourProvider.Background3, Children = new Drawable[] { new Box { Colour = colourProvider.Background2, RelativeSizeAxes = Axes.Both, - AlwaysPresent = true, + }, + innerCircleHighlight = new Box + { + Colour = colourProvider.Colour3, + Blending = BlendingParameters.Additive, + RelativeSizeAxes = Axes.Both, + Alpha = 0, + }, + new OsuSpriteText + { + Font = OsuFont.Torus.With(size: 20), + Colour = colourProvider.Background1, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "Tap!" + }, + hoverLayer = new Circle + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background1.Opacity(0.3f), + Blending = BlendingParameters.Additive, + Alpha = 0, }, } }, - hoverLayer = new Circle - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White.Opacity(0.01f), - Blending = BlendingParameters.Additive, - Alpha = 0, - }, } }; + + for (int i = 0; i < light_count; i++) + { + lights.Add(new Light + { + Rotation = i * (360f / light_count) + }); + } } + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => + hoverLayer.ReceivePositionalInputAt(screenSpacePos); + protected override bool OnHover(HoverEvent e) { hoverLayer.FadeIn(500, Easing.OutQuint); @@ -107,16 +150,87 @@ namespace osu.Game.Screens.Edit.Timing protected override bool OnMouseDown(MouseDownEvent e) { - scaleContainer.ScaleTo(0.98f, 200, Easing.OutQuint); - innerCircle.ScaleTo(0.95f, 200, Easing.OutQuint); + const double in_duration = 100; + + scaleContainer.ScaleTo(0.99f, in_duration, Easing.OutQuint); + innerCircle.ScaleTo(0.96f, in_duration, Easing.OutQuint); + + innerCircleHighlight + .FadeIn(50, Easing.OutQuint) + .FlashColour(Color4.White, 1000, Easing.OutQuint); + + lights[currentLight % light_count].Hide(); + lights[(currentLight + light_count / 2) % light_count].Hide(); + + currentLight++; + + lights[currentLight % light_count].Show(); + lights[(currentLight + light_count / 2) % light_count].Show(); + return base.OnMouseDown(e); } protected override void OnMouseUp(MouseUpEvent e) { - scaleContainer.ScaleTo(1, 1200, Easing.OutQuint); - innerCircle.ScaleTo(1, 1200, Easing.OutQuint); + const double out_duration = 800; + + scaleContainer.ScaleTo(1, out_duration, Easing.OutQuint); + innerCircle.ScaleTo(1, out_duration, Easing.OutQuint); + innerCircleHighlight.FadeOut(out_duration, Easing.OutQuint); base.OnMouseUp(e); } + + private class Light : CompositeDrawable + { + private CircularProgress fill; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Both; + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + InternalChildren = new Drawable[] + { + new CircularProgress + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(0.99f), + Current = { Value = 1f / light_count - 0.01f }, + Colour = colourProvider.Background2, + }, + fill = new CircularProgress + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + Size = new Vector2(0.99f), + Current = { Value = 1f / light_count - 0.01f }, + Colour = colourProvider.Colour1, + Blending = BlendingParameters.Additive + }, + }; + } + + public override void Show() + { + fill + .FadeIn(50, Easing.OutQuint) + .FlashColour(Color4.White, 1000, Easing.OutQuint); + } + + public override void Hide() + { + fill + .FadeOut(300, Easing.OutQuint); + } + } } } From 3c7a04256fda8041f4e8e5b51a4a2ba8050cb345 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Jun 2022 20:04:44 +0900 Subject: [PATCH 012/103] Add glow --- osu.Game/Screens/Edit/Timing/TapButton.cs | 62 +++++++++++++++++------ 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index 3eb8e23bad..f7a5a0ca7b 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; @@ -32,6 +33,8 @@ namespace osu.Game.Screens.Edit.Timing private Container scaleContainer; private Container lights; + private Container lightsGlow; + private OsuSpriteText text; private const int light_count = 6; @@ -79,11 +82,16 @@ namespace osu.Game.Screens.Edit.Timing }, new Circle { + Name = "inner masking", Size = new Vector2(SIZE - ring_width * 2 + light_padding * 2), Anchor = Anchor.Centre, Origin = Anchor.Centre, Colour = colourProvider.Background3, }, + lightsGlow = new Container + { + RelativeSizeAxes = Axes.Both, + }, innerCircle = new CircularContainer { Size = new Vector2(SIZE - ring_width * 2), @@ -104,7 +112,7 @@ namespace osu.Game.Screens.Edit.Timing RelativeSizeAxes = Axes.Both, Alpha = 0, }, - new OsuSpriteText + text = new OsuSpriteText { Font = OsuFont.Torus.With(size: 20), Colour = colourProvider.Background1, @@ -126,10 +134,13 @@ namespace osu.Game.Screens.Edit.Timing for (int i = 0; i < light_count; i++) { - lights.Add(new Light + var light = new Light { Rotation = i * (360f / light_count) - }); + }; + + lights.Add(light); + lightsGlow.Add(light.Glow.CreateProxy()); } } @@ -152,6 +163,8 @@ namespace osu.Game.Screens.Edit.Timing { const double in_duration = 100; + text.FadeColour(colourProvider.Background4, in_duration, Easing.OutQuint); + scaleContainer.ScaleTo(0.99f, in_duration, Easing.OutQuint); innerCircle.ScaleTo(0.96f, in_duration, Easing.OutQuint); @@ -174,6 +187,8 @@ namespace osu.Game.Screens.Edit.Timing { const double out_duration = 800; + text.FadeColour(colourProvider.Background1, out_duration, Easing.OutQuint); + scaleContainer.ScaleTo(1, out_duration, Easing.OutQuint); innerCircle.ScaleTo(1, out_duration, Easing.OutQuint); innerCircleHighlight.FadeOut(out_duration, Easing.OutQuint); @@ -182,7 +197,9 @@ namespace osu.Game.Screens.Edit.Timing private class Light : CompositeDrawable { - private CircularProgress fill; + public Drawable Glow { get; private set; } + + private Container fillContent; [Resolved] private OverlayColourProvider colourProvider { get; set; } @@ -194,41 +211,56 @@ namespace osu.Game.Screens.Edit.Timing Anchor = Anchor.Centre; Origin = Anchor.Centre; + Size = new Vector2(0.98f); // Avoid bleed into masking edge. + InternalChildren = new Drawable[] { new CircularProgress { RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(0.99f), Current = { Value = 1f / light_count - 0.01f }, Colour = colourProvider.Background2, }, - fill = new CircularProgress + fillContent = new Container { RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, Alpha = 0, - Size = new Vector2(0.99f), - Current = { Value = 1f / light_count - 0.01f }, Colour = colourProvider.Colour1, - Blending = BlendingParameters.Additive + Children = new[] + { + new CircularProgress + { + RelativeSizeAxes = Axes.Both, + Current = { Value = 1f / light_count - 0.01f }, + Blending = BlendingParameters.Additive + }, + Glow = new CircularProgress + { + RelativeSizeAxes = Axes.Both, + Current = { Value = 1f / light_count - 0.01f }, + Blending = BlendingParameters.Additive + }.WithEffect(new GlowEffect + { + Colour = colourProvider.Colour1.Opacity(0.4f), + BlurSigma = new Vector2(9f), + Strength = 10, + PadExtent = true + }), + } }, }; } public override void Show() { - fill + fillContent .FadeIn(50, Easing.OutQuint) .FlashColour(Color4.White, 1000, Easing.OutQuint); } public override void Hide() { - fill + fillContent .FadeOut(300, Easing.OutQuint); } } From a2d177d7d258cba760086a59a413584367ff7efd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Jun 2022 20:37:02 +0900 Subject: [PATCH 013/103] Add BPM display and tracking --- osu.Game/Screens/Edit/Timing/TapButton.cs | 109 +++++++++++++++++++--- 1 file changed, 98 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index f7a5a0ca7b..9c6dde4ffe 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -1,14 +1,19 @@ // 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.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; +using osu.Framework.Threading; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; @@ -34,7 +39,12 @@ namespace osu.Game.Screens.Edit.Timing private Container scaleContainer; private Container lights; private Container lightsGlow; - private OsuSpriteText text; + private OsuSpriteText bpmText; + private Container textContainer; + + private bool grabbedMouseDown; + + private ScheduledDelegate resetDelegate; private const int light_count = 6; @@ -65,7 +75,7 @@ namespace osu.Game.Screens.Edit.Timing new CircularContainer { RelativeSizeAxes = Axes.Both, - Name = "outer masking", + Name = @"outer masking", Masking = true, BorderThickness = light_padding, BorderColour = colourProvider.Background3, @@ -82,7 +92,7 @@ namespace osu.Game.Screens.Edit.Timing }, new Circle { - Name = "inner masking", + Name = @"inner masking", Size = new Vector2(SIZE - ring_width * 2 + light_padding * 2), Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -112,13 +122,27 @@ namespace osu.Game.Screens.Edit.Timing RelativeSizeAxes = Axes.Both, Alpha = 0, }, - text = new OsuSpriteText + textContainer = new Container { - Font = OsuFont.Torus.With(size: 20), + RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background1, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "Tap!" + Children = new Drawable[] + { + new OsuSpriteText + { + Font = OsuFont.Torus.With(size: 20), + Anchor = Anchor.Centre, + Origin = Anchor.BottomCentre, + Y = 3, + Text = "Tap" + }, + bpmText = new OsuSpriteText + { + Font = OsuFont.Torus.With(size: 14), + Anchor = Anchor.Centre, + Origin = Anchor.TopCentre, + }, + } }, hoverLayer = new Circle { @@ -142,20 +166,38 @@ namespace osu.Game.Screens.Edit.Timing lights.Add(light); lightsGlow.Add(light.Glow.CreateProxy()); } + + reset(); } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => hoverLayer.ReceivePositionalInputAt(screenSpacePos); + private ColourInfo textColour + { + get + { + if (grabbedMouseDown) + return colourProvider.Background4; + + if (IsHovered) + return colourProvider.Content2; + + return colourProvider.Background1; + } + } + protected override bool OnHover(HoverEvent e) { hoverLayer.FadeIn(500, Easing.OutQuint); + textContainer.FadeColour(textColour, 500, Easing.OutQuint); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { hoverLayer.FadeOut(500, Easing.OutQuint); + textContainer.FadeColour(textColour, 500, Easing.OutQuint); base.OnHoverLost(e); } @@ -163,7 +205,14 @@ namespace osu.Game.Screens.Edit.Timing { const double in_duration = 100; - text.FadeColour(colourProvider.Background4, in_duration, Easing.OutQuint); + grabbedMouseDown = true; + + handleTap(); + + resetDelegate?.Cancel(); + resetDelegate = Scheduler.AddDelayed(reset, 1000); + + textContainer.FadeColour(textColour, in_duration, Easing.OutQuint); scaleContainer.ScaleTo(0.99f, in_duration, Easing.OutQuint); innerCircle.ScaleTo(0.96f, in_duration, Easing.OutQuint); @@ -180,14 +229,16 @@ namespace osu.Game.Screens.Edit.Timing lights[currentLight % light_count].Show(); lights[(currentLight + light_count / 2) % light_count].Show(); - return base.OnMouseDown(e); + return true; } protected override void OnMouseUp(MouseUpEvent e) { const double out_duration = 800; - text.FadeColour(colourProvider.Background1, out_duration, Easing.OutQuint); + grabbedMouseDown = false; + + textContainer.FadeColour(textColour, out_duration, Easing.OutQuint); scaleContainer.ScaleTo(1, out_duration, Easing.OutQuint); innerCircle.ScaleTo(1, out_duration, Easing.OutQuint); @@ -195,6 +246,42 @@ namespace osu.Game.Screens.Edit.Timing base.OnMouseUp(e); } + private readonly List tapTimings = new List(); + + private void reset() + { + bpmText.FadeOut(500, Easing.OutQuint); + + using (BeginDelayedSequence(tapTimings.Count > 0 ? 500 : 0)) + { + Schedule(() => bpmText.Text = "the beat!"); + bpmText.FadeIn(800, Easing.OutQuint); + } + + foreach (var light in lights) + light.Hide(); + + tapTimings.Clear(); + } + + private void handleTap() + { + tapTimings.Add(Clock.CurrentTime); + + if (tapTimings.Count > 8) + tapTimings.RemoveAt(0); + + if (tapTimings.Count < 5) + { + bpmText.Text = new string('.', tapTimings.Count); + return; + } + + double bpm = Math.Round(60000 / ((tapTimings.Last() - tapTimings.First()) / (tapTimings.Count - 1))); + + bpmText.Text = $"{bpm} BPM"; + } + private class Light : CompositeDrawable { public Drawable Glow { get; private set; } From d47a3bb8e4948aefff1d8d07e965eac729455cf6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Jun 2022 20:44:05 +0900 Subject: [PATCH 014/103] Use NRT and transfer BPM --- osu.Game/Screens/Edit/Timing/TapButton.cs | 41 ++++++++++++++++------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index 9c6dde4ffe..d85edb6cce 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -1,10 +1,13 @@ // 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.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -14,6 +17,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Threading; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; @@ -27,24 +31,27 @@ namespace osu.Game.Screens.Edit.Timing public const float SIZE = 100; [Resolved] - private OverlayColourProvider colourProvider { get; set; } + private OverlayColourProvider colourProvider { get; set; } = null!; - private Circle hoverLayer; + [Resolved(canBeNull: true)] + private Bindable? selectedGroup { get; set; } - private CircularContainer innerCircle; - private Box innerCircleHighlight; + private Circle hoverLayer = null!; + + private CircularContainer innerCircle = null!; + private Box innerCircleHighlight = null!; private int currentLight; - private Container scaleContainer; - private Container lights; - private Container lightsGlow; - private OsuSpriteText bpmText; - private Container textContainer; + private Container scaleContainer = null!; + private Container lights = null!; + private Container lightsGlow = null!; + private OsuSpriteText bpmText = null!; + private Container textContainer = null!; private bool grabbedMouseDown; - private ScheduledDelegate resetDelegate; + private ScheduledDelegate? resetDelegate; private const int light_count = 6; @@ -280,16 +287,24 @@ namespace osu.Game.Screens.Edit.Timing double bpm = Math.Round(60000 / ((tapTimings.Last() - tapTimings.First()) / (tapTimings.Count - 1))); bpmText.Text = $"{bpm} BPM"; + + var timingPoint = selectedGroup?.Value.ControlPoints.OfType().FirstOrDefault(); + + if (timingPoint != null) + { + // Intentionally use the rounded BPM here. + timingPoint.BeatLength = 60000 / bpm; + } } private class Light : CompositeDrawable { - public Drawable Glow { get; private set; } + public Drawable Glow { get; private set; } = null!; - private Container fillContent; + private Container fillContent = null!; [Resolved] - private OverlayColourProvider colourProvider { get; set; } + private OverlayColourProvider colourProvider { get; set; } = null!; [BackgroundDependencyLoader] private void load() From 96ccd29bdc9d2372abdca8fe1a8ba284e87ceb3c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Jun 2022 20:48:06 +0900 Subject: [PATCH 015/103] Don't play metronome click when tapping for timing --- osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs | 5 +++++ osu.Game/Screens/Edit/Timing/TapButton.cs | 4 ++++ osu.Game/Screens/Edit/Timing/TapTimingControl.cs | 12 +++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index 4143c5ea55..2ecd66a05f 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -38,6 +38,8 @@ namespace osu.Game.Screens.Edit.Timing [Resolved] private OverlayColourProvider overlayColourProvider { get; set; } + public bool EnableClicking { get; set; } = true; + [BackgroundDependencyLoader] private void load(AudioManager audio) { @@ -281,6 +283,9 @@ namespace osu.Game.Screens.Edit.Timing Schedule(() => { + if (!EnableClicking) + return; + var channel = clunk?.GetChannel(); if (channel != null) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index d85edb6cce..fb5580c6ac 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -30,6 +30,8 @@ namespace osu.Game.Screens.Edit.Timing { public const float SIZE = 100; + public readonly BindableBool IsHandlingTapping = new BindableBool(); + [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -213,6 +215,7 @@ namespace osu.Game.Screens.Edit.Timing const double in_duration = 100; grabbedMouseDown = true; + IsHandlingTapping.Value = true; handleTap(); @@ -269,6 +272,7 @@ namespace osu.Game.Screens.Edit.Timing light.Hide(); tapTimings.Clear(); + IsHandlingTapping.Value = false; } private void handleTap() diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 20d6c656ff..16e9f703c8 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -25,6 +25,10 @@ namespace osu.Game.Screens.Edit.Timing [Resolved] private Bindable selectedGroup { get; set; } + private readonly BindableBool isHandlingTapping = new BindableBool(); + + private MetronomeDisplay metronome; + [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider, OsuColour colours) { @@ -73,7 +77,7 @@ namespace osu.Game.Screens.Edit.Timing { new Drawable[] { - new MetronomeDisplay + metronome = new MetronomeDisplay { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, @@ -149,11 +153,17 @@ namespace osu.Game.Screens.Edit.Timing { Anchor = Anchor.Centre, Origin = Anchor.Centre, + IsHandlingTapping = { BindTarget = isHandlingTapping } } } } }, }; + + isHandlingTapping.BindValueChanged(handling => + { + metronome.EnableClicking = !handling.NewValue; + }, true); } private void adjustOffset(double adjust) From b88bce9b8baf47dc54b27e041d9a51c41e672dfc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Jun 2022 20:57:16 +0900 Subject: [PATCH 016/103] Restart track playback when tapping to time --- osu.Game/Screens/Edit/Timing/TapTimingControl.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 16e9f703c8..6640eeaa38 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -163,6 +163,12 @@ namespace osu.Game.Screens.Edit.Timing isHandlingTapping.BindValueChanged(handling => { metronome.EnableClicking = !handling.NewValue; + + if (handling.NewValue) + { + editorClock.Seek(selectedGroup.Value.Time); + editorClock.Start(); + } }, true); } From f3f7e28353d340b916a2d4ba7735e21de3c51c16 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Jun 2022 20:57:24 +0900 Subject: [PATCH 017/103] Ignore initial taps as they are generally inaccurate --- osu.Game/Screens/Edit/Timing/TapButton.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index fb5580c6ac..65f31f4396 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -275,20 +275,23 @@ namespace osu.Game.Screens.Edit.Timing IsHandlingTapping.Value = false; } + private const int initial_taps_to_ignore = 4; + private const int max_taps_to_consider = 8; + private void handleTap() { tapTimings.Add(Clock.CurrentTime); - if (tapTimings.Count > 8) + if (tapTimings.Count > initial_taps_to_ignore + max_taps_to_consider) tapTimings.RemoveAt(0); - if (tapTimings.Count < 5) + if (tapTimings.Count < initial_taps_to_ignore * 2) { bpmText.Text = new string('.', tapTimings.Count); return; } - double bpm = Math.Round(60000 / ((tapTimings.Last() - tapTimings.First()) / (tapTimings.Count - 1))); + double bpm = Math.Round(60000 / ((tapTimings.Last() - tapTimings.Skip(initial_taps_to_ignore).First()) / (tapTimings.Count - initial_taps_to_ignore - 1))); bpmText.Text = $"{bpm} BPM"; From d4e88441eceabfd2fce25cfb268836e896c5473d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Jun 2022 22:00:34 +0900 Subject: [PATCH 018/103] Adjust metrics to make timing section fit better in editor --- osu.Game/Screens/Edit/Timing/GroupSection.cs | 2 +- osu.Game/Screens/Edit/Timing/Section.cs | 2 +- osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/GroupSection.cs b/osu.Game/Screens/Edit/Timing/GroupSection.cs index bb2dd35a9c..f613488aae 100644 --- a/osu.Game/Screens/Edit/Timing/GroupSection.cs +++ b/osu.Game/Screens/Edit/Timing/GroupSection.cs @@ -37,7 +37,7 @@ namespace osu.Game.Screens.Edit.Timing RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Padding = new MarginPadding(10); + Padding = new MarginPadding(10) { Bottom = 0 }; InternalChildren = new Drawable[] { diff --git a/osu.Game/Screens/Edit/Timing/Section.cs b/osu.Game/Screens/Edit/Timing/Section.cs index 139abfb187..17147c21f4 100644 --- a/osu.Game/Screens/Edit/Timing/Section.cs +++ b/osu.Game/Screens/Edit/Timing/Section.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Edit.Timing { Flow = new FillFlowContainer { - Padding = new MarginPadding(20), + Padding = new MarginPadding(10) { Top = 0 }, Spacing = new Vector2(20), RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, diff --git a/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs b/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs index 9fc7e56a3d..eecd85fbca 100644 --- a/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs +++ b/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs @@ -187,7 +187,7 @@ namespace osu.Game.Screens.Edit.Timing Origin = direction, Font = OsuFont.Default.With(size: 10, weight: FontWeight.Bold), Text = $"{(index > 0 ? "+" : "-")}{Math.Abs(Multiplier * amount)}", - Padding = new MarginPadding(5), + Padding = new MarginPadding(2), Alpha = 0, } }; From 781a1527b10e8c5d846b335e2961d1749aa2c995 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Jun 2022 22:00:54 +0900 Subject: [PATCH 019/103] Adjust button metrics and move surrounding buttons to be more integrated --- osu.Game/Screens/Edit/Timing/TapButton.cs | 27 +-- .../Screens/Edit/Timing/TapTimingControl.cs | 159 +++++++++++++----- 2 files changed, 130 insertions(+), 56 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index 65f31f4396..d18f65c2eb 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Edit.Timing { internal class TapButton : CircularContainer { - public const float SIZE = 100; + public const float SIZE = 140; public readonly BindableBool IsHandlingTapping = new BindableBool(); @@ -62,7 +62,7 @@ namespace osu.Game.Screens.Edit.Timing { Size = new Vector2(SIZE); - const float ring_width = 18; + const float ring_width = 22; const float light_padding = 3; InternalChild = scaleContainer = new Container @@ -75,7 +75,7 @@ namespace osu.Game.Screens.Edit.Timing new Circle { RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background3 + Colour = colourProvider.Background4 }, lights = new Container { @@ -87,7 +87,7 @@ namespace osu.Game.Screens.Edit.Timing Name = @"outer masking", Masking = true, BorderThickness = light_padding, - BorderColour = colourProvider.Background3, + BorderColour = colourProvider.Background4, Children = new Drawable[] { new Box @@ -105,7 +105,7 @@ namespace osu.Game.Screens.Edit.Timing Size = new Vector2(SIZE - ring_width * 2 + light_padding * 2), Anchor = Anchor.Centre, Origin = Anchor.Centre, - Colour = colourProvider.Background3, + Colour = colourProvider.Background4, }, lightsGlow = new Container { @@ -139,17 +139,18 @@ namespace osu.Game.Screens.Edit.Timing { new OsuSpriteText { - Font = OsuFont.Torus.With(size: 20), + Font = OsuFont.Torus.With(size: 34, weight: FontWeight.SemiBold), Anchor = Anchor.Centre, Origin = Anchor.BottomCentre, - Y = 3, - Text = "Tap" + Y = 5, + Text = "Tap", }, bpmText = new OsuSpriteText { - Font = OsuFont.Torus.With(size: 14), + Font = OsuFont.Torus.With(size: 23, weight: FontWeight.Regular), Anchor = Anchor.Centre, Origin = Anchor.TopCentre, + Y = -1, }, } }, @@ -200,7 +201,7 @@ namespace osu.Game.Screens.Edit.Timing { hoverLayer.FadeIn(500, Easing.OutQuint); textContainer.FadeColour(textColour, 500, Easing.OutQuint); - return base.OnHover(e); + return true; } protected override void OnHoverLost(HoverLostEvent e) @@ -322,12 +323,14 @@ namespace osu.Game.Screens.Edit.Timing Size = new Vector2(0.98f); // Avoid bleed into masking edge. + const float angular_gap = 0.007f; + InternalChildren = new Drawable[] { new CircularProgress { RelativeSizeAxes = Axes.Both, - Current = { Value = 1f / light_count - 0.01f }, + Current = { Value = 1f / light_count - angular_gap }, Colour = colourProvider.Background2, }, fillContent = new Container @@ -340,7 +343,7 @@ namespace osu.Game.Screens.Edit.Timing new CircularProgress { RelativeSizeAxes = Axes.Both, - Current = { Value = 1f / light_count - 0.01f }, + Current = { Value = 1f / light_count - angular_gap }, Blending = BlendingParameters.Additive }, Glow = new CircularProgress diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 6640eeaa38..f8975c5b11 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -7,10 +7,14 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Overlays; +using osuTK; namespace osu.Game.Screens.Edit.Timing { @@ -32,6 +36,8 @@ namespace osu.Game.Screens.Edit.Timing [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider, OsuColour colours) { + const float padding = 10; + RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -52,9 +58,8 @@ namespace osu.Game.Screens.Edit.Timing RowDimensions = new[] { new Dimension(GridSizeMode.Absolute, 200), - new Dimension(GridSizeMode.Absolute, 60), - new Dimension(GridSizeMode.Absolute, 60), - new Dimension(GridSizeMode.Absolute, 120), + new Dimension(GridSizeMode.Absolute, 50), + new Dimension(GridSizeMode.Absolute, TapButton.SIZE + padding), }, Content = new[] { @@ -63,6 +68,7 @@ namespace osu.Game.Screens.Edit.Timing new Container { RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(padding), Children = new Drawable[] { new GridContainer @@ -94,15 +100,14 @@ namespace osu.Game.Screens.Edit.Timing new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(10), + Padding = new MarginPadding { Bottom = padding, Horizontal = padding }, Children = new Drawable[] { new TimingAdjustButton(1) { Text = "Offset", - RelativeSizeAxes = Axes.X, - Width = 0.48f, - Height = 50, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.48f, 1), Action = adjustOffset, }, new TimingAdjustButton(0.1) @@ -110,9 +115,8 @@ namespace osu.Game.Screens.Edit.Timing Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Text = "BPM", - RelativeSizeAxes = Axes.X, - Width = 0.48f, - Height = 50, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.48f, 1), Action = adjustBpm, } } @@ -123,39 +127,47 @@ namespace osu.Game.Screens.Edit.Timing new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(10), + Padding = new MarginPadding { Bottom = padding, Horizontal = padding }, Children = new Drawable[] { - new RoundedButton + new Container { - Text = "Reset", - BackgroundColour = colours.Pink, - RelativeSizeAxes = Axes.X, - Width = 0.3f, - Action = reset, + RelativeSizeAxes = Axes.Y, + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + Height = 0.98f, + Width = TapButton.SIZE / 1.3f, + Masking = true, + CornerRadius = 15, + Children = new Drawable[] + { + new LessRoundedButton(FontAwesome.Solid.Stop, Anchor.TopLeft) + { + BackgroundColour = colourProvider.Background1, + RelativeSizeAxes = Axes.Both, + Height = 0.49f, + Action = reset, + }, + new LessRoundedButton(FontAwesome.Solid.Play, Anchor.BottomLeft) + { + BackgroundColour = colourProvider.Background1, + RelativeSizeAxes = Axes.Both, + Height = 0.49f, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Action = start, + }, + }, }, - new RoundedButton + new TapButton { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Text = "Play from start", - RelativeSizeAxes = Axes.X, - BackgroundColour = colourProvider.Background1, - Width = 0.68f, - Action = tap, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + IsHandlingTapping = { BindTarget = isHandlingTapping } } } }, }, - new Drawable[] - { - new TapButton - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - IsHandlingTapping = { BindTarget = isHandlingTapping } - } - } } }, }; @@ -165,13 +177,78 @@ namespace osu.Game.Screens.Edit.Timing metronome.EnableClicking = !handling.NewValue; if (handling.NewValue) - { - editorClock.Seek(selectedGroup.Value.Time); - editorClock.Start(); - } + start(); }, true); } + private class LessRoundedButton : OsuButton + { + private readonly IconUsage icon; + private readonly Anchor anchor; + + private SpriteIcon spriteIcon; + + public LessRoundedButton(IconUsage icon, Anchor anchor) + { + this.icon = icon; + this.anchor = anchor; + } + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Content.CornerRadius = 0; + Content.Masking = false; + + BackgroundColour = colourProvider.Background2; + + Content.Add(new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(15), + Children = new Drawable[] + { + spriteIcon = new SpriteIcon + { + Icon = icon, + Size = new Vector2(22), + Anchor = anchor, + Origin = anchor, + Colour = colourProvider.Background1, + }, + } + }); + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + // scale looks bad so don't call base. + return false; + } + + protected override bool OnHover(HoverEvent e) + { + spriteIcon.FadeColour(colourProvider.Content2, 200, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + spriteIcon.FadeColour(colourProvider.Background1, 200, Easing.OutQuint); + base.OnHoverLost(e); + } + } + + private void start() + { + editorClock.Seek(selectedGroup.Value.Time); + editorClock.Start(); + } + private void adjustOffset(double adjust) { // VERY TEMPORARY @@ -201,12 +278,6 @@ namespace osu.Game.Screens.Edit.Timing timing.BeatLength = 60000 / (timing.BPM + adjust); } - private void tap() - { - editorClock.Seek(selectedGroup.Value.Time); - editorClock.Start(); - } - private void reset() { editorClock.Stop(); From 0c493dd3592f96abd63f3390bb1160f9a99ecf6d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 12:27:11 +0900 Subject: [PATCH 020/103] Add key binding for tap button --- .../Input/Bindings/GlobalActionContainer.cs | 4 +++ .../GlobalActionKeyBindingStrings.cs | 5 ++++ osu.Game/Screens/Edit/Timing/TapButton.cs | 25 +++++++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 69ea6b00ca..3da5f3212e 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -80,6 +80,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(new[] { InputKey.K }, GlobalAction.EditorNudgeRight), new KeyBinding(new[] { InputKey.G }, GlobalAction.EditorCycleGridDisplayMode), new KeyBinding(new[] { InputKey.F5 }, GlobalAction.EditorTestGameplay), + new KeyBinding(new[] { InputKey.T }, GlobalAction.EditorTapForBPM), new KeyBinding(new[] { InputKey.Control, InputKey.H }, GlobalAction.EditorFlipHorizontally), new KeyBinding(new[] { InputKey.Control, InputKey.J }, GlobalAction.EditorFlipVertically), new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.MouseWheelDown }, GlobalAction.EditorDecreaseDistanceSpacing), @@ -322,5 +323,8 @@ namespace osu.Game.Input.Bindings [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.DeselectAllMods))] DeselectAllMods, + + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorTapForBPM))] + EditorTapForBPM, } } diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index e392ae619f..586e29a432 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -174,6 +174,11 @@ namespace osu.Game.Localisation /// public static LocalisableString EditorTimingMode => new TranslatableString(getKey(@"editor_timing_mode"), @"Timing mode"); + /// + /// "Tap for BPM" + /// + public static LocalisableString EditorTapForBPM => new TranslatableString(getKey(@"editor_tap_for_bpm"), @"Tap for BPM"); + /// /// "Cycle grid display mode" /// diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index d18f65c2eb..614e7aecde 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -15,18 +15,21 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Threading; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Input.Bindings; using osu.Game.Overlays; using osuTK; using osuTK.Graphics; +using osuTK.Input; namespace osu.Game.Screens.Edit.Timing { - internal class TapButton : CircularContainer + internal class TapButton : CircularContainer, IKeyBindingHandler { public const float SIZE = 140; @@ -57,6 +60,8 @@ namespace osu.Game.Screens.Edit.Timing private const int light_count = 6; + private readonly List tapTimings = new List(); + [BackgroundDependencyLoader] private void load() { @@ -257,7 +262,23 @@ namespace osu.Game.Screens.Edit.Timing base.OnMouseUp(e); } - private readonly List tapTimings = new List(); + public bool OnPressed(KeyBindingPressEvent e) + { + if (e.Action == GlobalAction.EditorTapForBPM && !e.Repeat) + { + // Direct through mouse handling to achieve animation + OnMouseDown(new MouseDownEvent(e.CurrentState, MouseButton.Left)); + return true; + } + + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + if (e.Action == GlobalAction.EditorTapForBPM) + OnMouseUp(new MouseUpEvent(e.CurrentState, MouseButton.Left)); + } private void reset() { From 943e904c71f74feda0765075798140c2370ac46c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 12:55:03 +0900 Subject: [PATCH 021/103] Fix reset happening on mouse down instead of mouse up Also some reorganisation of file content for legibility --- osu.Game/Screens/Edit/Timing/TapButton.cs | 49 ++++++++++++----------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index 614e7aecde..7f913e386e 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -60,6 +60,10 @@ namespace osu.Game.Screens.Edit.Timing private const int light_count = 6; + private const int initial_taps_to_ignore = 4; + + private const int max_taps_to_consider = 8; + private readonly List tapTimings = new List(); [BackgroundDependencyLoader] @@ -223,10 +227,9 @@ namespace osu.Game.Screens.Edit.Timing grabbedMouseDown = true; IsHandlingTapping.Value = true; - handleTap(); - resetDelegate?.Cancel(); - resetDelegate = Scheduler.AddDelayed(reset, 1000); + + handleTap(); textContainer.FadeColour(textColour, in_duration, Easing.OutQuint); @@ -259,6 +262,9 @@ namespace osu.Game.Screens.Edit.Timing scaleContainer.ScaleTo(1, out_duration, Easing.OutQuint); innerCircle.ScaleTo(1, out_duration, Easing.OutQuint); innerCircleHighlight.FadeOut(out_duration, Easing.OutQuint); + + resetDelegate = Scheduler.AddDelayed(reset, 1000); + base.OnMouseUp(e); } @@ -280,26 +286,6 @@ namespace osu.Game.Screens.Edit.Timing OnMouseUp(new MouseUpEvent(e.CurrentState, MouseButton.Left)); } - private void reset() - { - bpmText.FadeOut(500, Easing.OutQuint); - - using (BeginDelayedSequence(tapTimings.Count > 0 ? 500 : 0)) - { - Schedule(() => bpmText.Text = "the beat!"); - bpmText.FadeIn(800, Easing.OutQuint); - } - - foreach (var light in lights) - light.Hide(); - - tapTimings.Clear(); - IsHandlingTapping.Value = false; - } - - private const int initial_taps_to_ignore = 4; - private const int max_taps_to_consider = 8; - private void handleTap() { tapTimings.Add(Clock.CurrentTime); @@ -326,6 +312,23 @@ namespace osu.Game.Screens.Edit.Timing } } + private void reset() + { + bpmText.FadeOut(500, Easing.OutQuint); + + using (BeginDelayedSequence(tapTimings.Count > 0 ? 500 : 0)) + { + Schedule(() => bpmText.Text = "the beat!"); + bpmText.FadeIn(800, Easing.OutQuint); + } + + foreach (var light in lights) + light.Hide(); + + tapTimings.Clear(); + IsHandlingTapping.Value = false; + } + private class Light : CompositeDrawable { public Drawable Glow { get; private set; } = null!; From d99d37c0a60c6eb95d43e920331210d4af315d6f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 13:06:18 +0900 Subject: [PATCH 022/103] Apply current track rate to calculated BPM --- osu.Game/Screens/Edit/Timing/TapButton.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index 7f913e386e..6b9ac7be5c 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -18,6 +18,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Threading; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -41,6 +42,9 @@ namespace osu.Game.Screens.Edit.Timing [Resolved(canBeNull: true)] private Bindable? selectedGroup { get; set; } + [Resolved(canBeNull: true)] + private IBeatSyncProvider? beatSyncSource { get; set; } + private Circle hoverLayer = null!; private CircularContainer innerCircle = null!; @@ -299,7 +303,10 @@ namespace osu.Game.Screens.Edit.Timing return; } - double bpm = Math.Round(60000 / ((tapTimings.Last() - tapTimings.Skip(initial_taps_to_ignore).First()) / (tapTimings.Count - initial_taps_to_ignore - 1))); + double averageBeatLength = (tapTimings.Last() - tapTimings.Skip(initial_taps_to_ignore).First()) / (tapTimings.Count - initial_taps_to_ignore - 1); + double clockRate = beatSyncSource?.Clock?.Rate ?? 1; + + double bpm = Math.Round(60000 / averageBeatLength / clockRate); bpmText.Text = $"{bpm} BPM"; From ac3793f340d14cd3a9d0a7b4dc738f3ee6c96f35 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 13:10:50 +0900 Subject: [PATCH 023/103] Move inline class to end and apply NRT --- .../Screens/Edit/Timing/TapTimingControl.cs | 108 +++++++++--------- 1 file changed, 55 insertions(+), 53 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index f8975c5b11..9b5574d3cb 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.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.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -21,17 +23,17 @@ namespace osu.Game.Screens.Edit.Timing public class TapTimingControl : CompositeDrawable { [Resolved] - private EditorClock editorClock { get; set; } + private EditorClock editorClock { get; set; } = null!; [Resolved] - private EditorBeatmap beatmap { get; set; } + private EditorBeatmap beatmap { get; set; } = null!; [Resolved] - private Bindable selectedGroup { get; set; } + private Bindable selectedGroup { get; set; } = null!; private readonly BindableBool isHandlingTapping = new BindableBool(); - private MetronomeDisplay metronome; + private MetronomeDisplay metronome = null!; [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider, OsuColour colours) @@ -141,14 +143,14 @@ namespace osu.Game.Screens.Edit.Timing CornerRadius = 15, Children = new Drawable[] { - new LessRoundedButton(FontAwesome.Solid.Stop, Anchor.TopLeft) + new InlineButton(FontAwesome.Solid.Stop, Anchor.TopLeft) { BackgroundColour = colourProvider.Background1, RelativeSizeAxes = Axes.Both, Height = 0.49f, Action = reset, }, - new LessRoundedButton(FontAwesome.Solid.Play, Anchor.BottomLeft) + new InlineButton(FontAwesome.Solid.Play, Anchor.BottomLeft) { BackgroundColour = colourProvider.Background1, RelativeSizeAxes = Axes.Both, @@ -181,22 +183,63 @@ namespace osu.Game.Screens.Edit.Timing }, true); } - private class LessRoundedButton : OsuButton + private void start() + { + editorClock.Seek(selectedGroup.Value.Time); + editorClock.Start(); + } + + private void reset() + { + editorClock.Stop(); + editorClock.Seek(selectedGroup.Value.Time); + } + + private void adjustOffset(double adjust) + { + // VERY TEMPORARY + var currentGroupItems = selectedGroup.Value.ControlPoints.ToArray(); + + beatmap.ControlPointInfo.RemoveGroup(selectedGroup.Value); + + double newOffset = selectedGroup.Value.Time + adjust; + + foreach (var cp in currentGroupItems) + beatmap.ControlPointInfo.Add(newOffset, cp); + + // the control point might not necessarily exist yet, if currentGroupItems was empty. + selectedGroup.Value = beatmap.ControlPointInfo.GroupAt(newOffset, true); + + if (!editorClock.IsRunning) + editorClock.Seek(newOffset); + } + + private void adjustBpm(double adjust) + { + var timing = selectedGroup.Value.ControlPoints.OfType().FirstOrDefault(); + + if (timing == null) + return; + + timing.BeatLength = 60000 / (timing.BPM + adjust); + } + + private class InlineButton : OsuButton { private readonly IconUsage icon; private readonly Anchor anchor; - private SpriteIcon spriteIcon; + private SpriteIcon spriteIcon = null!; - public LessRoundedButton(IconUsage icon, Anchor anchor) + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + public InlineButton(IconUsage icon, Anchor anchor) { this.icon = icon; this.anchor = anchor; } - [Resolved] - private OverlayColourProvider colourProvider { get; set; } - protected override void LoadComplete() { base.LoadComplete(); @@ -242,46 +285,5 @@ namespace osu.Game.Screens.Edit.Timing base.OnHoverLost(e); } } - - private void start() - { - editorClock.Seek(selectedGroup.Value.Time); - editorClock.Start(); - } - - private void adjustOffset(double adjust) - { - // VERY TEMPORARY - var currentGroupItems = selectedGroup.Value.ControlPoints.ToArray(); - - beatmap.ControlPointInfo.RemoveGroup(selectedGroup.Value); - - double newOffset = selectedGroup.Value.Time + adjust; - - foreach (var cp in currentGroupItems) - beatmap.ControlPointInfo.Add(newOffset, cp); - - // the control point might not necessarily exist yet, if currentGroupItems was empty. - selectedGroup.Value = beatmap.ControlPointInfo.GroupAt(newOffset, true); - - if (!editorClock.IsRunning) - editorClock.Seek(newOffset); - } - - private void adjustBpm(double adjust) - { - var timing = selectedGroup.Value.ControlPoints.OfType().FirstOrDefault(); - - if (timing == null) - return; - - timing.BeatLength = 60000 / (timing.BPM + adjust); - } - - private void reset() - { - editorClock.Stop(); - editorClock.Seek(selectedGroup.Value.Time); - } } } From 15f8d318eb05355d09fce8e457d0bbfb9660377a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 13:13:00 +0900 Subject: [PATCH 024/103] Add note about glow code (please look away) --- osu.Game/Screens/Edit/Timing/TapButton.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index 6b9ac7be5c..0cb2ac3d1a 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -377,6 +377,9 @@ namespace osu.Game.Screens.Edit.Timing Current = { Value = 1f / light_count - angular_gap }, Blending = BlendingParameters.Additive }, + // Please do not try and make sense of this. + // Getting the visual effect I was going for relies on what I can only imagine is broken implementation + // of `PadExtent`. If that's ever fixed in the future this will likely need to be adjusted. Glow = new CircularProgress { RelativeSizeAxes = Axes.Both, From 060372a129a4e42fc3d2f67a9118874e3aa13fb3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 13:16:31 +0900 Subject: [PATCH 025/103] Split out transition length constants --- osu.Game/Screens/Edit/Timing/TapButton.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index 0cb2ac3d1a..4eeb358066 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -68,6 +68,8 @@ namespace osu.Game.Screens.Edit.Timing private const int max_taps_to_consider = 8; + private const double transition_length = 500; + private readonly List tapTimings = new List(); [BackgroundDependencyLoader] @@ -212,15 +214,15 @@ namespace osu.Game.Screens.Edit.Timing protected override bool OnHover(HoverEvent e) { - hoverLayer.FadeIn(500, Easing.OutQuint); - textContainer.FadeColour(textColour, 500, Easing.OutQuint); + hoverLayer.FadeIn(transition_length, Easing.OutQuint); + textContainer.FadeColour(textColour, transition_length, Easing.OutQuint); return true; } protected override void OnHoverLost(HoverLostEvent e) { - hoverLayer.FadeOut(500, Easing.OutQuint); - textContainer.FadeColour(textColour, 500, Easing.OutQuint); + hoverLayer.FadeOut(transition_length, Easing.OutQuint); + textContainer.FadeColour(textColour, transition_length, Easing.OutQuint); base.OnHoverLost(e); } @@ -265,6 +267,7 @@ namespace osu.Game.Screens.Edit.Timing scaleContainer.ScaleTo(1, out_duration, Easing.OutQuint); innerCircle.ScaleTo(1, out_duration, Easing.OutQuint); + innerCircleHighlight.FadeOut(out_duration, Easing.OutQuint); resetDelegate = Scheduler.AddDelayed(reset, 1000); @@ -321,9 +324,9 @@ namespace osu.Game.Screens.Edit.Timing private void reset() { - bpmText.FadeOut(500, Easing.OutQuint); + bpmText.FadeOut(transition_length, Easing.OutQuint); - using (BeginDelayedSequence(tapTimings.Count > 0 ? 500 : 0)) + using (BeginDelayedSequence(tapTimings.Count > 0 ? transition_length : 0)) { Schedule(() => bpmText.Text = "the beat!"); bpmText.FadeIn(800, Easing.OutQuint); From 4abfb3561142fef1eb9e2a8b8cb2169bff0955c3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 16:58:14 +0900 Subject: [PATCH 026/103] Improve light rotational alignment and increase light count to 8 --- osu.Game/Screens/Edit/Timing/TapButton.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index 4eeb358066..3b4d63f7b8 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -62,7 +62,7 @@ namespace osu.Game.Screens.Edit.Timing private ScheduledDelegate? resetDelegate; - private const int light_count = 6; + private const int light_count = 8; private const int initial_taps_to_ignore = 4; @@ -70,6 +70,8 @@ namespace osu.Game.Screens.Edit.Timing private const double transition_length = 500; + private const float angular_light_gap = 0.007f; + private readonly List tapTimings = new List(); [BackgroundDependencyLoader] @@ -185,7 +187,7 @@ namespace osu.Game.Screens.Edit.Timing { var light = new Light { - Rotation = i * (360f / light_count) + Rotation = (i + 1) * (360f / light_count) + 360 * angular_light_gap / 2, }; lights.Add(light); @@ -336,6 +338,7 @@ namespace osu.Game.Screens.Edit.Timing light.Hide(); tapTimings.Clear(); + currentLight = 0; IsHandlingTapping.Value = false; } @@ -357,14 +360,12 @@ namespace osu.Game.Screens.Edit.Timing Size = new Vector2(0.98f); // Avoid bleed into masking edge. - const float angular_gap = 0.007f; - InternalChildren = new Drawable[] { new CircularProgress { RelativeSizeAxes = Axes.Both, - Current = { Value = 1f / light_count - angular_gap }, + Current = { Value = 1f / light_count - angular_light_gap }, Colour = colourProvider.Background2, }, fillContent = new Container @@ -377,7 +378,7 @@ namespace osu.Game.Screens.Edit.Timing new CircularProgress { RelativeSizeAxes = Axes.Both, - Current = { Value = 1f / light_count - angular_gap }, + Current = { Value = 1f / light_count - angular_light_gap }, Blending = BlendingParameters.Additive }, // Please do not try and make sense of this. From e75609dfb9dd33cc30ffb5779da80e9988c7031b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 17:03:48 +0900 Subject: [PATCH 027/103] Increase taps to consider for better results for longer tap periods --- osu.Game/Screens/Edit/Timing/TapButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index 3b4d63f7b8..5453fcd68d 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -66,7 +66,7 @@ namespace osu.Game.Screens.Edit.Timing private const int initial_taps_to_ignore = 4; - private const int max_taps_to_consider = 8; + private const int max_taps_to_consider = 16; private const double transition_length = 500; From ee4beefd9584358229f2478f0aee7ef3e98cc093 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 17:27:51 +0900 Subject: [PATCH 028/103] Increase max taps to 128 for now Will revisit this in the future with a more sound algorithm. --- osu.Game/Screens/Edit/Timing/TapButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index 5453fcd68d..a6227cbe27 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -66,7 +66,7 @@ namespace osu.Game.Screens.Edit.Timing private const int initial_taps_to_ignore = 4; - private const int max_taps_to_consider = 16; + private const int max_taps_to_consider = 128; private const double transition_length = 500; From c42485cea9314356e93c507d42516cc00ac36c6e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 17:29:39 +0900 Subject: [PATCH 029/103] Fix test button references --- .../Editing/TestSceneTapTimingControl.cs | 54 +++++++++---------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs index 8dd368f2a9..a1218aa3e7 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Timing; @@ -77,34 +77,6 @@ namespace osu.Game.Tests.Visual.Editing timingInfo.Text = $"offset: {selectedGroup.Value.Time:N2} bpm: {selectedGroup.Value.ControlPoints.OfType().First().BPM:N2}"; } - [Test] - public void TestNoop() - { - AddStep("do nothing", () => { }); - } - - [Test] - public void TestTapThenReset() - { - AddStep("click tap button", () => - { - control.ChildrenOfType() - .Last() - .TriggerClick(); - }); - - AddUntilStep("wait for track playing", () => Clock.IsRunning); - - AddStep("click reset button", () => - { - control.ChildrenOfType() - .First() - .TriggerClick(); - }); - - AddUntilStep("wait for track stopped", () => !Clock.IsRunning); - } - [Test] public void TestBasic() { @@ -115,7 +87,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("click tap button", () => { - control.ChildrenOfType() + control.ChildrenOfType() .Last() .TriggerClick(); }); @@ -129,6 +101,28 @@ namespace osu.Game.Tests.Visual.Editing }); } + [Test] + public void TestTapThenReset() + { + AddStep("click tap button", () => + { + control.ChildrenOfType() + .Last() + .TriggerClick(); + }); + + AddUntilStep("wait for track playing", () => Clock.IsRunning); + + AddStep("click reset button", () => + { + control.ChildrenOfType() + .First() + .TriggerClick(); + }); + + AddUntilStep("wait for track stopped", () => !Clock.IsRunning); + } + protected override void Dispose(bool isDisposing) { Beatmap.Disabled = false; From 5a0f716bf24b8613564f75eb293e9b76699144fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 18:14:26 +0900 Subject: [PATCH 030/103] Fix timing screen crash when attempting to add group to self Closes #18527. --- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index 40e6e8082a..8b1f881f88 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -189,7 +189,7 @@ namespace osu.Game.Screens.Edit.Timing // Try and create matching types from the currently selected control point. var selected = selectedGroup.Value; - if (selected != null) + if (selected != null && selected != group) { foreach (var controlPoint in selected.ControlPoints) { From 0b125ade4c439b1c3a664b683f1040f95cb58efc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 18:18:18 +0900 Subject: [PATCH 031/103] Allow clicking away to deselect the current control point group --- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index 40e6e8082a..fabc087952 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -7,6 +7,7 @@ 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.Beatmaps.ControlPoints; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -132,6 +133,12 @@ namespace osu.Game.Screens.Edit.Timing }, true); } + protected override bool OnClick(ClickEvent e) + { + selectedGroup.Value = null; + return true; + } + protected override void Update() { base.Update(); From 2fa4d46f73f2e4ec778605acf9b9fc6c69b1fad5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 18:28:13 +0900 Subject: [PATCH 032/103] Change text on timing group add button when it is going to clone instead Also disables the button when it would otherwise have no effect. --- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index 40e6e8082a..c6ac859cce 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -51,6 +51,8 @@ namespace osu.Game.Screens.Edit.Timing private readonly IBindableList controlPointGroups = new BindableList(); + private RoundedButton addButton; + [Resolved] private EditorClock clock { get; set; } @@ -105,9 +107,8 @@ namespace osu.Game.Screens.Edit.Timing Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, }, - new RoundedButton + addButton = new RoundedButton { - Text = "+ Add at current time", Action = addNew, Size = new Vector2(160, 30), Anchor = Anchor.BottomRight, @@ -122,7 +123,14 @@ namespace osu.Game.Screens.Edit.Timing { base.LoadComplete(); - selectedGroup.BindValueChanged(selected => { deleteButton.Enabled.Value = selected.NewValue != null; }, true); + selectedGroup.BindValueChanged(selected => + { + deleteButton.Enabled.Value = selected.NewValue != null; + + addButton.Text = selected.NewValue != null + ? "+ Clone to current time" + : "+ Add at current time"; + }, true); controlPointGroups.BindTo(Beatmap.ControlPointInfo.Groups); controlPointGroups.BindCollectionChanged((sender, args) => @@ -137,6 +145,8 @@ namespace osu.Game.Screens.Edit.Timing base.Update(); trackActivePoint(); + + addButton.Enabled.Value = clock.CurrentTimeAccurate != selectedGroup.Value?.Time; } /// From ad3c093a084cf035b2982a4497937fcbdfaa2551 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 18:33:09 +0900 Subject: [PATCH 033/103] Improve group tracking logic to avoid switching which point type unnecessarily --- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index 40e6e8082a..aba6b2f23e 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.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 System; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -139,6 +140,8 @@ namespace osu.Game.Screens.Edit.Timing trackActivePoint(); } + private Type trackedType; + /// /// Given the user has selected a control point group, we want to track any group which is /// active at the current point in time which matches the type the user has selected. @@ -149,16 +152,27 @@ namespace osu.Game.Screens.Edit.Timing private void trackActivePoint() { // For simplicity only match on the first type of the active control point. - var selectedPointType = selectedGroup.Value?.ControlPoints.FirstOrDefault()?.GetType(); + if (selectedGroup.Value == null) + trackedType = null; + else + { + // If the selected group only has one control point, update the tracking type. + if (selectedGroup.Value.ControlPoints.Count == 1) + trackedType = selectedGroup.Value?.ControlPoints.Single().GetType(); + // If the selected group has more than one control point, choose the first as the tracking type + // if we don't already have a singular tracked type. + else if (trackedType == null) + trackedType = selectedGroup.Value?.ControlPoints.FirstOrDefault()?.GetType(); + } - if (selectedPointType != null) + if (trackedType != null) { // We don't have an efficient way of looking up groups currently, only individual point types. // To improve the efficiency of this in the future, we should reconsider the overall structure of ControlPointInfo. // Find the next group which has the same type as the selected one. var found = Beatmap.ControlPointInfo.Groups - .Where(g => g.ControlPoints.Any(cp => cp.GetType() == selectedPointType)) + .Where(g => g.ControlPoints.Any(cp => cp.GetType() == trackedType)) .LastOrDefault(g => g.Time <= clock.CurrentTimeAccurate); if (found != null) From b1ffffc1acfbf216103b4a683db98800d7f883ca Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 2 Jun 2022 19:16:31 +0900 Subject: [PATCH 034/103] Calculate true combo value in ManiaDifficultyCalculator --- .../Difficulty/ManiaDifficultyCalculator.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index b17aa7fc4d..88f51bf961 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -52,10 +52,18 @@ namespace osu.Game.Rulesets.Mania.Difficulty // This is done the way it is to introduce fractional differences in order to match osu-stable for the time being. GreatHitWindow = Math.Ceiling((int)(getHitWindow300(mods) * clockRate) / clockRate), ScoreMultiplier = getScoreMultiplier(mods), - MaxCombo = beatmap.HitObjects.Sum(h => h is HoldNote ? 2 : 1), + MaxCombo = beatmap.HitObjects.Sum(maxComboForObject) }; } + private static int maxComboForObject(HitObject hitObject) + { + if (hitObject is HoldNote hold) + return 1 + (int)((hold.EndTime - hold.StartTime) / 100); + + return 1; + } + protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) { var sortedObjects = beatmap.HitObjects.ToArray(); From a287fd73bbc81ca412d7b67fb33783483ed5b964 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 2 Jun 2022 19:16:38 +0900 Subject: [PATCH 035/103] Write MaxCombo attribute for mania --- .../Difficulty/ManiaDifficultyAttributes.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs index 5b7a460079..c35a3dcdc2 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty foreach (var v in base.ToDatabaseAttributes()) yield return v; - // Todo: osu!mania doesn't output MaxCombo attribute for some reason. + yield return (ATTRIB_ID_MAX_COMBO, MaxCombo); yield return (ATTRIB_ID_DIFFICULTY, StarRating); yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow); yield return (ATTRIB_ID_SCORE_MULTIPLIER, ScoreMultiplier); @@ -39,6 +39,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty { base.FromDatabaseAttributes(values); + MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO]; StarRating = values[ATTRIB_ID_DIFFICULTY]; GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW]; ScoreMultiplier = values[ATTRIB_ID_SCORE_MULTIPLIER]; From ec24b32fa69a85fccd9df7da892397eb2b90e41b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 2 Jun 2022 20:36:28 +0200 Subject: [PATCH 036/103] Add NRT coverage for `FileChooserLabelledTextBox` --- .../Screens/Edit/Setup/FileChooserLabelledTextBox.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs b/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs index aae19396db..790613fc74 100644 --- a/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs +++ b/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.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.IO; @@ -27,10 +29,10 @@ namespace osu.Game.Screens.Edit.Setup public IEnumerable HandledExtensions => handledExtensions; - private readonly Bindable currentFile = new Bindable(); + private readonly Bindable currentFile = new Bindable(); [Resolved] - private OsuGameBase game { get; set; } + private OsuGameBase game { get; set; } = null!; public FileChooserLabelledTextBox(params string[] handledExtensions) { @@ -45,7 +47,7 @@ namespace osu.Game.Screens.Edit.Setup currentFile.BindValueChanged(onFileSelected); } - private void onFileSelected(ValueChangedEvent file) + private void onFileSelected(ValueChangedEvent file) { if (file.NewValue == null) return; @@ -72,7 +74,7 @@ namespace osu.Game.Screens.Edit.Setup private class FileChooserPopover : OsuPopover { - public FileChooserPopover(string[] handledExtensions, Bindable currentFile) + public FileChooserPopover(string[] handledExtensions, Bindable currentFile) { Child = new Container { From cf9b78ea2a11f1c44d90bfa1702ad3daad4d4173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 2 Jun 2022 20:38:14 +0200 Subject: [PATCH 037/103] Improve safety of `FileChooserLabelledTextBox` disposal --- osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs b/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs index 790613fc74..fd916894ea 100644 --- a/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs +++ b/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; @@ -67,7 +68,9 @@ namespace osu.Game.Screens.Edit.Setup protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - game.UnregisterImportHandler(this); + + if (game.IsNotNull()) + game.UnregisterImportHandler(this); } public override Popover GetPopover() => new FileChooserPopover(handledExtensions, currentFile); From 60fb5d5e6c721b6a975356524869a4785bee2f70 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 3 Jun 2022 02:03:04 +0300 Subject: [PATCH 038/103] Revert "Fix timeline objects disappearing prematurely on wide-screens" This reverts commit 02baf9a97abe0fb6e94af53b83708a15a508d437. --- osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 733b6c5f24..89e9fb2404 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -304,7 +304,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline /// /// The total amount of time visible on the timeline. /// - public double VisibleRange => (DisplayableContent / Content.DrawWidth) * track.Length; + public double VisibleRange => track.Length / Zoom; public SnapResult FindSnappedPositionAndTime(Vector2 screenSpacePosition, SnapType snapType = SnapType.All) => new SnapResult(screenSpacePosition, beatSnapProvider.SnapTime(getTimeFromPosition(Content.ToLocalSpace(screenSpacePosition)))); From ca68751fdcd1c3b0a01ead44e776600f0127e05b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 3 Jun 2022 02:22:16 +0300 Subject: [PATCH 039/103] Update test to match expectation --- osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs index 10f1f2fceb..d726bd004e 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs @@ -12,7 +12,7 @@ namespace osu.Game.Tests.Visual.Editing public override Drawable CreateTestComponent() => Empty(); [Test] - public void TestVisibleRangeViaZoom() + public void TestVisibleRangeUpdatesOnZoomChange() { double initialVisibleRange = 0; @@ -29,7 +29,7 @@ namespace osu.Game.Tests.Visual.Editing } [Test] - public void TestVisibleRangeViaTimelineSize() + public void TestVisibleRangeConstantOnSizeChange() { double initialVisibleRange = 0; @@ -37,12 +37,12 @@ namespace osu.Game.Tests.Visual.Editing AddStep("get initial range", () => initialVisibleRange = TimelineArea.Timeline.VisibleRange); AddStep("scale timeline size", () => TimelineArea.Timeline.Width = 2); - AddAssert("range doubled", () => TimelineArea.Timeline.VisibleRange == initialVisibleRange * 2); + AddAssert("same range", () => TimelineArea.Timeline.VisibleRange == initialVisibleRange); AddStep("descale timeline size", () => TimelineArea.Timeline.Width = 0.5f); - AddAssert("range halved", () => TimelineArea.Timeline.VisibleRange == initialVisibleRange / 2); + AddAssert("same range", () => TimelineArea.Timeline.VisibleRange == initialVisibleRange); AddStep("restore timeline size", () => TimelineArea.Timeline.Width = 1); - AddAssert("range restored", () => TimelineArea.Timeline.VisibleRange == initialVisibleRange); + AddAssert("same range", () => TimelineArea.Timeline.VisibleRange == initialVisibleRange); } } } From 588151f48b3afde6d8e006daaa235367d5583a7d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 3 Jun 2022 02:26:46 +0300 Subject: [PATCH 040/103] Add new failing test coverage --- .../Editing/TestSceneZoomableScrollContainer.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs b/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs index 95d11d6909..2d056bafdd 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs @@ -44,7 +44,12 @@ namespace osu.Game.Tests.Visual.Editing RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(30) }, - scrollContainer = new ZoomableScrollContainer { RelativeSizeAxes = Axes.Both } + scrollContainer = new ZoomableScrollContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + } } }, new MenuCursor() @@ -62,7 +67,15 @@ namespace osu.Game.Tests.Visual.Editing [Test] public void TestWidthInitialization() { - AddAssert("Inner container width was initialized", () => innerBox.DrawWidth > 0); + AddAssert("Inner container width was initialized", () => innerBox.DrawWidth == scrollContainer.DrawWidth); + } + + [Test] + public void TestWidthUpdatesOnDrawSizeChanges() + { + AddStep("Shrink scroll container", () => scrollContainer.Width = 0.5f); + AddAssert("Scroll container width shrunk", () => scrollContainer.DrawWidth == scrollContainer.Parent.DrawWidth / 2); + AddAssert("Inner container width matches scroll container", () => innerBox.DrawWidth == scrollContainer.DrawWidth); } [Test] From 21385655fed9137e350811f66b5ff9ae418f0ada Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 3 Jun 2022 02:27:16 +0300 Subject: [PATCH 041/103] Fix `ZoomableScrollContainer` not updating on parent size changes --- .../Timeline/ZoomableScrollContainer.cs | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs index 35d103ddf1..d008368b69 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Transforms; using osu.Framework.Input.Events; +using osu.Framework.Layout; using osu.Framework.Timing; using osu.Framework.Utils; using osu.Game.Graphics.Containers; @@ -40,10 +41,14 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline [Resolved(canBeNull: true)] private IFrameBasedClock editorClock { get; set; } + private readonly LayoutValue zoomedContentWidthCache = new LayoutValue(Invalidation.DrawSize); + public ZoomableScrollContainer() : base(Direction.Horizontal) { base.Content.Add(zoomedContent = new Container { RelativeSizeAxes = Axes.Y }); + + AddLayout(zoomedContentWidthCache); } private float minZoom = 1; @@ -103,12 +108,12 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline } } - protected override void LoadComplete() + protected override void Update() { - base.LoadComplete(); + base.Update(); - // This width only gets updated on the application of a transform, so this needs to be initialized here. - updateZoomedContentWidth(); + if (!zoomedContentWidthCache.IsValid) + updateZoomedContentWidth(); } protected override bool OnScroll(ScrollEvent e) @@ -128,7 +133,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline return base.OnScroll(e); } - private void updateZoomedContentWidth() => zoomedContent.Width = DrawWidth * currentZoom; + private void updateZoomedContentWidth() + { + zoomedContent.Width = DrawWidth * currentZoom; + zoomedContentWidthCache.Validate(); + } private float zoomTarget = 1; @@ -199,8 +208,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline float targetOffset = expectedWidth * (focusPoint / contentSize) - focusOffset; d.currentZoom = newZoom; - d.updateZoomedContentWidth(); + // Temporarily here to make sure ScrollTo gets the correct DrawSize for scrollable area. // TODO: Make sure draw size gets invalidated properly on the framework side, and remove this once it is. d.Invalidate(Invalidation.DrawSize); From efbde06c11229a3a8501ece576b1a10c13cc70ae Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 3 Jun 2022 05:02:00 +0300 Subject: [PATCH 042/103] Split button repeating logic from `TimingAdjustButton` to own component --- .../Edit/Timing/RepeatingButtonBehaviour.cs | 93 +++++++++++++++++++ .../Screens/Edit/Timing/TimingAdjustButton.cs | 80 ++++------------ 2 files changed, 110 insertions(+), 63 deletions(-) create mode 100644 osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs diff --git a/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs b/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs new file mode 100644 index 0000000000..5c9f384a2e --- /dev/null +++ b/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs @@ -0,0 +1,93 @@ +// 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.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Events; +using osu.Framework.Threading; + +namespace osu.Game.Screens.Edit.Timing +{ + /// + /// Represents a component that provides the behaviour of triggering button clicks repeatedly while holding with mouse. + /// + public class RepeatingButtonBehaviour : CompositeDrawable + { + private const double initial_delay = 300; + private const double minimum_delay = 80; + + private readonly Drawable button; + + private Sample sample; + + /// + /// An additive modifier for the frequency of the sample played on next actuation. + /// This can be adjusted during the button's event to affect the repeat sample playback of that click. + /// + public double SampleFrequencyModifier { get; set; } + + public RepeatingButtonBehaviour(Drawable button) + { + this.button = button; + + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sample = audio.Samples.Get(@"UI/notch-tick"); + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + beginRepeat(); + return true; + } + + protected override void OnMouseUp(MouseUpEvent e) + { + adjustDelegate?.Cancel(); + base.OnMouseUp(e); + } + + private ScheduledDelegate adjustDelegate; + private double adjustDelay = initial_delay; + + private void beginRepeat() + { + adjustDelegate?.Cancel(); + + adjustDelay = initial_delay; + adjustNext(); + + void adjustNext() + { + if (IsHovered) + { + button.TriggerClick(); + adjustDelay = Math.Max(minimum_delay, adjustDelay * 0.9f); + + var channel = sample?.GetChannel(); + + if (channel != null) + { + double repeatModifier = 0.05f * (Math.Abs(adjustDelay - initial_delay) / minimum_delay); + channel.Frequency.Value = 1 + repeatModifier + SampleFrequencyModifier; + channel.Play(); + } + } + else + { + adjustDelay = initial_delay; + } + + adjustDelegate = Scheduler.AddDelayed(adjustNext, adjustDelay); + } + } + } +} diff --git a/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs b/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs index 9fc7e56a3d..6e7338fa15 100644 --- a/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs +++ b/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs @@ -4,14 +4,11 @@ using System; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Framework.Localisation; -using osu.Framework.Threading; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; @@ -26,32 +23,24 @@ namespace osu.Game.Screens.Edit.Timing public Action Action; private readonly double adjustAmount; - private ScheduledDelegate adjustDelegate; private const int max_multiplier = 10; - private const int adjust_levels = 4; - private const double initial_delay = 300; - - private const double minimum_delay = 80; - public Container Content { get; set; } - private double adjustDelay = initial_delay; - private readonly Box background; private readonly OsuSpriteText text; - private Sample sample; - public LocalisableString Text { get => text.Text; set => text.Text = value; } + private readonly RepeatingButtonBehaviour repeatBehaviour; + [Resolved] private OverlayColourProvider colourProvider { get; set; } @@ -82,13 +71,13 @@ namespace osu.Game.Screens.Edit.Timing } } }); + + AddInternal(repeatBehaviour = new RepeatingButtonBehaviour(this)); } [BackgroundDependencyLoader] - private void load(AudioManager audio) + private void load() { - sample = audio.Samples.Get(@"UI/notch-tick"); - background.Colour = colourProvider.Background3; for (int i = 1; i <= adjust_levels; i++) @@ -98,57 +87,22 @@ namespace osu.Game.Screens.Edit.Timing } } - protected override bool OnMouseDown(MouseDownEvent e) + protected override bool OnHover(HoverEvent e) => true; + + protected override bool OnClick(ClickEvent e) { - beginRepeat(); + var hoveredBox = Content.OfType().FirstOrDefault(d => d.IsHovered); + if (hoveredBox == null) + return false; + + Action(adjustAmount * hoveredBox.Multiplier); + + hoveredBox.Flash(); + + repeatBehaviour.SampleFrequencyModifier = (hoveredBox.Multiplier / max_multiplier) * 0.2; return true; } - protected override void OnMouseUp(MouseUpEvent e) - { - adjustDelegate?.Cancel(); - base.OnMouseUp(e); - } - - private void beginRepeat() - { - adjustDelegate?.Cancel(); - - adjustDelay = initial_delay; - adjustNext(); - - void adjustNext() - { - var hoveredBox = Content.OfType().FirstOrDefault(d => d.IsHovered); - - if (hoveredBox != null) - { - Action(adjustAmount * hoveredBox.Multiplier); - - adjustDelay = Math.Max(minimum_delay, adjustDelay * 0.9f); - - hoveredBox.Flash(); - - var channel = sample?.GetChannel(); - - if (channel != null) - { - double repeatModifier = 0.05f * (Math.Abs(adjustDelay - initial_delay) / minimum_delay); - double multiplierModifier = (hoveredBox.Multiplier / max_multiplier) * 0.2f; - - channel.Frequency.Value = 1 + multiplierModifier + repeatModifier; - channel.Play(); - } - } - else - { - adjustDelay = initial_delay; - } - - adjustDelegate = Scheduler.AddDelayed(adjustNext, adjustDelay); - } - } - private class IncrementBox : CompositeDrawable { public readonly float Multiplier; From b51e0a50472e2415928a38dd9263bdfa04e3e8d5 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 3 Jun 2022 05:03:22 +0300 Subject: [PATCH 043/103] Share button repeating logic with `TimelineButton` for better UX --- .../Components/Timeline/TimelineButton.cs | 47 ++----------------- 1 file changed, 5 insertions(+), 42 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs index 5550c6a748..4c0c0335dd 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs @@ -6,13 +6,11 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Framework.Input.Events; -using osu.Framework.Threading; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using osu.Game.Screens.Edit.Timing; using osuTK; using osuTK.Graphics; -using osuTK.Input; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { @@ -27,7 +25,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline set => button.Icon = value; } - private readonly IconButton button; + private readonly TimelineIconButton button; public TimelineButton() { @@ -54,46 +52,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline IconHoverColour = Color4.White; HoverColour = OsuColour.Gray(0.25f); FlashColour = OsuColour.Gray(0.5f); + + Add(new RepeatingButtonBehaviour(this)); } - private ScheduledDelegate repeatSchedule; - - /// - /// The initial delay before mouse down repeat begins. - /// - private const int repeat_initial_delay = 250; - - /// - /// The delay between mouse down repeats after the initial repeat. - /// - private const int repeat_tick_rate = 70; - - protected override bool OnClick(ClickEvent e) - { - // don't actuate a click since we are manually handling repeats. - return true; - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - if (e.Button == MouseButton.Left) - { - Action clickAction = () => base.OnClick(new ClickEvent(e.CurrentState, e.Button)); - - // run once for initial down - clickAction(); - - Scheduler.Add(repeatSchedule = new ScheduledDelegate(clickAction, Clock.CurrentTime + repeat_initial_delay, repeat_tick_rate)); - } - - return base.OnMouseDown(e); - } - - protected override void OnMouseUp(MouseUpEvent e) - { - repeatSchedule?.Cancel(); - base.OnMouseUp(e); - } + protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds(sampleSet); } } } From 1b4c89c418a66aecadac765be1560f1ad3d4a215 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Jun 2022 14:01:04 +0900 Subject: [PATCH 044/103] Update realm to latest version Contains minor changes to async usage in line with upstream API changes. I believe a feedback issue we were seeing with offset changes (the only component using async write flow) may have been resolved by these upstream changes (see [release notes](https://github.com/realm/realm-dotnet/releases/tag/10.14.0)) but am not investigating further just yet. --- osu.Game.Tests/Database/BeatmapImporterTests.cs | 2 +- osu.Game/Database/RealmAccess.cs | 2 +- osu.Game/osu.Game.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index 00276955aa..d4956e97e0 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -710,7 +710,7 @@ namespace osu.Game.Tests.Database var imported = await LoadOszIntoStore(importer, realm.Realm); - realm.Realm.Write(() => + await realm.Realm.WriteAsync(() => { foreach (var b in imported.Beatmaps) b.OnlineID = -1; diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index dbd3b96763..086ec52d80 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -392,7 +392,7 @@ namespace osu.Game.Database { total_writes_async.Value++; using (var realm = getRealmInstance()) - await realm.WriteAsync(action); + await realm.WriteAsync(() => action(realm)); } /// diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index eb47d0468f..97a36e9bc6 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + From f224a3e922d5d8953b5c1446bb3aad4d0d11d363 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Jun 2022 14:18:47 +0900 Subject: [PATCH 045/103] Update silly mobile project references --- osu.Android.props | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 116c7dbfcd..35d902493e 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -56,6 +56,6 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index ccecad6f82..64ba7fe22e 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -89,6 +89,6 @@ - + From 3aa8bc933dc45f8c5428e0f8a5e9a73aa51e651f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 3 Jun 2022 08:21:35 +0300 Subject: [PATCH 046/103] Add sentry tag for selected beatmap --- osu.Game/Utils/SentryLogger.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Utils/SentryLogger.cs b/osu.Game/Utils/SentryLogger.cs index ecc7fc4774..bba1e514c5 100644 --- a/osu.Game/Utils/SentryLogger.cs +++ b/osu.Game/Utils/SentryLogger.cs @@ -159,6 +159,7 @@ namespace osu.Game.Utils Game = game.Clock.CurrentTime, }; + scope.SetTag(@"beatmap", $"{beatmap.OnlineID}"); scope.SetTag(@"ruleset", ruleset.ShortName); scope.SetTag(@"os", $"{RuntimeInfo.OS} ({Environment.OSVersion})"); scope.SetTag(@"processor count", Environment.ProcessorCount.ToString()); From 6cb8b2d6f47f64591d9aa3e6768a68f23c582a1e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 3 Jun 2022 09:37:17 +0300 Subject: [PATCH 047/103] Set default window mode to "Borderless" rather than "Fullscreen" on macOS --- osu.Game/OsuGame.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 785881d97a..1c25c45bc3 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Humanizer; using JetBrains.Annotations; +using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; @@ -658,11 +659,14 @@ namespace osu.Game } protected override IDictionary GetFrameworkConfigDefaults() - => new Dictionary + { + return new Dictionary { - // General expectation that osu! starts in fullscreen by default (also gives the most predictable performance) - { FrameworkSetting.WindowMode, WindowMode.Fullscreen } + // General expectation that osu! starts in fullscreen by default (also gives the most predictable performance). + // However, macOS is bound to have issues when using exclusive fullscreen as it takes full control away from OS, therefore borderless is default there. + { FrameworkSetting.WindowMode, RuntimeInfo.IsApple ? WindowMode.Borderless : WindowMode.Fullscreen } }; + } protected override void LoadComplete() { From 1af51a2b1919a39bb90d63b1edfd1e29f6f18dad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Jun 2022 16:00:40 +0900 Subject: [PATCH 048/103] 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 35d902493e..d5f0d32b80 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 97a36e9bc6..45e7ff91c0 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 64ba7fe22e..16b7d49f3f 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From eb2d822530227d303d2d10f661a2a544c3f1a3ae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Jun 2022 14:28:48 +0900 Subject: [PATCH 049/103] Fix web requests potentially being performed after cancelled Closes https://github.com/ppy/osu/issues/18524. --- osu.Game/Online/API/APIRequest.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index 776ff5fd8f..451ea117d5 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -121,8 +121,16 @@ namespace osu.Game.Online.API if (isFailing) return; - Logger.Log($@"Performing request {this}", LoggingTarget.Network); - WebRequest.Perform(); + try + { + Logger.Log($@"Performing request {this}", LoggingTarget.Network); + WebRequest.Perform(); + } + catch (OperationCanceledException) + { + // ignore this. internally Perform is running async and the fail state may have changed since + // the last check of `isFailing` above. + } if (isFailing) return; From 54a32bde44fd1fdc421a47fbd2b9cc89978d5703 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Jun 2022 16:29:55 +0900 Subject: [PATCH 050/103] Don't report sentry errors from builds targetting a different server --- osu.Game/OsuGameBase.cs | 5 ++++- osu.Game/Utils/SentryLogger.cs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 666413004a..5dbdf6f602 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -80,6 +80,9 @@ namespace osu.Game public virtual bool UseDevelopmentServer => DebugUtils.IsDebugBuild; + internal EndpointConfiguration CreateEndpoints() => + UseDevelopmentServer ? (EndpointConfiguration)new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration(); + public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(); /// @@ -268,7 +271,7 @@ namespace osu.Game dependencies.Cache(SkinManager = new SkinManager(Storage, realm, Host, Resources, Audio, Scheduler)); dependencies.CacheAs(SkinManager); - EndpointConfiguration endpoints = UseDevelopmentServer ? (EndpointConfiguration)new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration(); + EndpointConfiguration endpoints = CreateEndpoints(); MessageFormatter.WebsiteRootUrl = endpoints.WebsiteRootUrl; diff --git a/osu.Game/Utils/SentryLogger.cs b/osu.Game/Utils/SentryLogger.cs index bba1e514c5..c12fd607b4 100644 --- a/osu.Game/Utils/SentryLogger.cs +++ b/osu.Game/Utils/SentryLogger.cs @@ -43,7 +43,7 @@ namespace osu.Game.Utils sentrySession = SentrySdk.Init(options => { // Not setting the dsn will completely disable sentry. - if (game.IsDeployedBuild) + if (game.IsDeployedBuild && game.CreateEndpoints().WebsiteRootUrl.EndsWith(@".ppy.sh", StringComparison.Ordinal)) options.Dsn = "https://ad9f78529cef40ac874afb95a9aca04e@sentry.ppy.sh/2"; options.AutoSessionTracking = true; From 1a835f062213c8d86fddaa73e30f33f75245996d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 3 Jun 2022 10:23:38 +0300 Subject: [PATCH 051/103] Add warning note when running fullscreen on macOS --- osu.Game/Localisation/LayoutSettingsStrings.cs | 5 +++++ .../Overlays/Settings/Sections/Graphics/LayoutSettings.cs | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/osu.Game/Localisation/LayoutSettingsStrings.cs b/osu.Game/Localisation/LayoutSettingsStrings.cs index 5ac28f19b3..8b7ad5918b 100644 --- a/osu.Game/Localisation/LayoutSettingsStrings.cs +++ b/osu.Game/Localisation/LayoutSettingsStrings.cs @@ -24,6 +24,11 @@ namespace osu.Game.Localisation /// public static LocalisableString UnableToRunExclusiveFullscreen => new TranslatableString(getKey(@"unable_to_run_exclusive_fullscreen"), @"Unable to run exclusive fullscreen. You'll still experience some input latency."); + /// + /// "Running fullscreen on macOS takes full control away from the system, this could lead to system-wide freezes if the game becomes unresponsive." + /// + public static LocalisableString FullscreenMacOSNote => new TranslatableString(getKey(@"fullscreen_macos_note"), @"Running fullscreen on macOS takes full control away from the system, this could lead to system-wide freezes if the game becomes unresponsive."); + private static string getKey(string key) => $@"{prefix}:{key}"; } } \ No newline at end of file diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index d79ba593f7..53b6f89c1f 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -4,6 +4,7 @@ using System; using System.Drawing; using System.Linq; +using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Configuration; @@ -230,6 +231,12 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics return; } + if (RuntimeInfo.OS == RuntimeInfo.Platform.macOS) + { + windowModeDropdown.SetNoticeText(LayoutSettingsStrings.FullscreenMacOSNote, true); + return; + } + if (host.Window is WindowsWindow) { switch (fullscreenCapability.Value) From 3ad1180c48c1856a5f10640d4688e4c2be25b245 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 3 Jun 2022 10:32:43 +0300 Subject: [PATCH 052/103] Use `macOS` instead of `IsApple` for better safety --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 1c25c45bc3..b91d523151 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -664,7 +664,7 @@ namespace osu.Game { // General expectation that osu! starts in fullscreen by default (also gives the most predictable performance). // However, macOS is bound to have issues when using exclusive fullscreen as it takes full control away from OS, therefore borderless is default there. - { FrameworkSetting.WindowMode, RuntimeInfo.IsApple ? WindowMode.Borderless : WindowMode.Fullscreen } + { FrameworkSetting.WindowMode, RuntimeInfo.OS == RuntimeInfo.Platform.macOS ? WindowMode.Borderless : WindowMode.Fullscreen } }; } From e779b460e42cb89f4a196035164dda9f4cae9dd5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Jun 2022 16:49:08 +0900 Subject: [PATCH 053/103] Use `Component` instead of `CompositeDrawable` --- osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs b/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs index 5c9f384a2e..595305b20f 100644 --- a/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs +++ b/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs @@ -6,7 +6,6 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Framework.Threading; @@ -15,7 +14,7 @@ namespace osu.Game.Screens.Edit.Timing /// /// Represents a component that provides the behaviour of triggering button clicks repeatedly while holding with mouse. /// - public class RepeatingButtonBehaviour : CompositeDrawable + public class RepeatingButtonBehaviour : Component { private const double initial_delay = 300; private const double minimum_delay = 80; From 902a0a3255d2773988e74eaa27dc9a061c79b56d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 3 Jun 2022 16:50:42 +0900 Subject: [PATCH 054/103] Update max combo test value --- .../ManiaDifficultyCalculatorTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs index 715614a201..a5bd126782 100644 --- a/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs @@ -14,11 +14,11 @@ namespace osu.Game.Rulesets.Mania.Tests { protected override string ResourceAssembly => "osu.Game.Rulesets.Mania"; - [TestCase(2.3449735700206298d, 151, "diffcalc-test")] + [TestCase(2.3449735700206298d, 242, "diffcalc-test")] public void Test(double expectedStarRating, int expectedMaxCombo, string name) => base.Test(expectedStarRating, expectedMaxCombo, name); - [TestCase(2.7879104989252959d, 151, "diffcalc-test")] + [TestCase(2.7879104989252959d, 242, "diffcalc-test")] public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new ManiaModDoubleTime()); From 7b28451e3d872d03fac0411e189da2642a0426a2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 3 Jun 2022 10:50:52 +0300 Subject: [PATCH 055/103] Improve warning message for user --- osu.Game/Localisation/LayoutSettingsStrings.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Localisation/LayoutSettingsStrings.cs b/osu.Game/Localisation/LayoutSettingsStrings.cs index 8b7ad5918b..b4326b8e39 100644 --- a/osu.Game/Localisation/LayoutSettingsStrings.cs +++ b/osu.Game/Localisation/LayoutSettingsStrings.cs @@ -25,10 +25,10 @@ namespace osu.Game.Localisation public static LocalisableString UnableToRunExclusiveFullscreen => new TranslatableString(getKey(@"unable_to_run_exclusive_fullscreen"), @"Unable to run exclusive fullscreen. You'll still experience some input latency."); /// - /// "Running fullscreen on macOS takes full control away from the system, this could lead to system-wide freezes if the game becomes unresponsive." + /// "Using fullscreen on macOS makes interacting with the menu bar and spaces no longer work, and may lead to freezes if a system dialog is presented. Using borderless is recommended." /// - public static LocalisableString FullscreenMacOSNote => new TranslatableString(getKey(@"fullscreen_macos_note"), @"Running fullscreen on macOS takes full control away from the system, this could lead to system-wide freezes if the game becomes unresponsive."); + public static LocalisableString FullscreenMacOSNote => new TranslatableString(getKey(@"fullscreen_macos_note"), @"Using fullscreen on macOS makes interacting with the menu bar and spaces no longer work, and may lead to freezes if a system dialog is presented. Using borderless is recommended."); private static string getKey(string key) => $@"{prefix}:{key}"; } -} \ No newline at end of file +} From cd999cf7ac936756f055fe57e88b20d6af6c47ed Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 3 Jun 2022 10:51:20 +0300 Subject: [PATCH 056/103] Fix back-to-front conditional --- .../Settings/Sections/Graphics/LayoutSettings.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 53b6f89c1f..05890ad882 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -225,15 +225,19 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics private void updateScreenModeWarning() { - if (windowModeDropdown.Current.Value != WindowMode.Fullscreen) + if (RuntimeInfo.OS == RuntimeInfo.Platform.macOS) { - windowModeDropdown.SetNoticeText(GraphicsSettingsStrings.NotFullscreenNote, true); + if (windowModeDropdown.Current.Value == WindowMode.Fullscreen) + windowModeDropdown.SetNoticeText(LayoutSettingsStrings.FullscreenMacOSNote, true); + else + windowModeDropdown.ClearNoticeText(); + return; } - if (RuntimeInfo.OS == RuntimeInfo.Platform.macOS) + if (windowModeDropdown.Current.Value != WindowMode.Fullscreen) { - windowModeDropdown.SetNoticeText(LayoutSettingsStrings.FullscreenMacOSNote, true); + windowModeDropdown.SetNoticeText(GraphicsSettingsStrings.NotFullscreenNote, true); return; } From cd3edc869c3455fd77aa0348566faccd079a1b97 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Jun 2022 17:00:00 +0900 Subject: [PATCH 057/103] Remove unnecessary nesting of `IconButton` and update design a touch --- .../Components/Timeline/TimelineButton.cs | 63 +++++-------------- 1 file changed, 15 insertions(+), 48 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs index 4c0c0335dd..e0b21b2e22 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs @@ -1,62 +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.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; +using osu.Framework.Allocation; using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays; using osu.Game.Screens.Edit.Timing; -using osuTK; -using osuTK.Graphics; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class TimelineButton : CompositeDrawable + public class TimelineButton : IconButton { - public Action Action; - public readonly BindableBool Enabled = new BindableBool(true); - - public IconUsage Icon + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) { - get => button.Icon; - set => button.Icon = value; + // These are using colourProvider but don't match the design. + // Just something to fit until someone implements the updated design. + IconColour = colourProvider.Background1; + IconHoverColour = colourProvider.Content2; + + HoverColour = colourProvider.Background1; + FlashColour = colourProvider.Content2; + + Add(new RepeatingButtonBehaviour(this)); } - private readonly TimelineIconButton button; - - public TimelineButton() - { - InternalChild = button = new TimelineIconButton { Action = () => Action?.Invoke() }; - - button.Enabled.BindTo(Enabled); - Width = button.Width; - } - - protected override void Update() - { - base.Update(); - - button.Size = new Vector2(button.Width, DrawHeight); - } - - private class TimelineIconButton : IconButton - { - public TimelineIconButton() - { - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - IconColour = OsuColour.Gray(0.35f); - IconHoverColour = Color4.White; - HoverColour = OsuColour.Gray(0.25f); - FlashColour = OsuColour.Gray(0.5f); - - Add(new RepeatingButtonBehaviour(this)); - } - - protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds(sampleSet); - } + protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds(sampleSet); } } From 2aabcf51ae9271d51ed97d6b425115d31d8bea9d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 3 Jun 2022 18:47:07 +0900 Subject: [PATCH 058/103] Update framework again --- 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 d5f0d32b80..0058bb3577 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 45e7ff91c0..2285f61331 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 16b7d49f3f..b134a7e356 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From 646f5f0f33c47efb4fcfd6656bc470209ff538c3 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 3 Jun 2022 19:17:31 +0900 Subject: [PATCH 059/103] Isolate "server-side" multiplayer rooms in testing --- osu.Game/Online/Rooms/Room.cs | 7 +++++++ .../Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index 60c0503ddd..1933267efd 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -162,6 +162,13 @@ namespace osu.Game.Online.Rooms Password.BindValueChanged(p => HasPassword.Value = !string.IsNullOrEmpty(p.NewValue)); } + /// + /// Copies values from another into this one. + /// + /// + /// **Beware**: This will store references between s. + /// + /// The to copy values from. public void CopyFrom(Room other) { RoomID.Value = other.RoomID.Value; diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs index 8290af8f78..392f32badc 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -44,9 +45,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay switch (request) { case CreateRoomRequest createRoomRequest: - var apiRoom = new Room(); - - apiRoom.CopyFrom(createRoomRequest.Room); + var apiRoom = cloneRoom(createRoomRequest.Room); // Passwords are explicitly not copied between rooms. apiRoom.HasPassword.Value = !string.IsNullOrEmpty(createRoomRequest.Room.Password.Value); @@ -178,12 +177,13 @@ namespace osu.Game.Tests.Visual.OnlinePlay private Room createResponseRoom(Room room, bool withParticipants) { - var responseRoom = new Room(); - responseRoom.CopyFrom(room); + var responseRoom = cloneRoom(room); responseRoom.Password.Value = null; if (!withParticipants) responseRoom.RecentParticipants.Clear(); return responseRoom; } + + private Room cloneRoom(Room source) => JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source)); } } From 77289c72249566cea9fd1fc10854af4cddca4cb5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 3 Jun 2022 20:36:11 +0900 Subject: [PATCH 060/103] Fix inability to serialise-then-deserialise playlist items --- osu.Game/Online/Rooms/PlaylistItem.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Rooms/PlaylistItem.cs b/osu.Game/Online/Rooms/PlaylistItem.cs index 6ec884d79c..12091bae88 100644 --- a/osu.Game/Online/Rooms/PlaylistItem.cs +++ b/osu.Game/Online/Rooms/PlaylistItem.cs @@ -61,7 +61,13 @@ namespace osu.Game.Online.Rooms /// Used for serialising to the API. /// [JsonProperty("beatmap_id")] - private int onlineBeatmapId => Beatmap.OnlineID; + private int onlineBeatmapId + { + get => Beatmap.OnlineID; + // This setter is only required for client-side serialise-then-deserialise operations. + // Serialisation is supposed to emit only a `beatmap_id`, but a (non-null) `beatmap` is required on deserialise. + set => Beatmap = new APIBeatmap { OnlineID = value }; + } /// /// A beatmap representing this playlist item. From 41ff170b6043d67308673182765837e10fabca6c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 3 Jun 2022 21:12:09 +0900 Subject: [PATCH 061/103] Fix playlist IDs not being returned --- .../Visual/OnlinePlay/TestRoomRequestsHandler.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs index 392f32badc..3a668d6931 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using Newtonsoft.Json; using osu.Game.Beatmaps; @@ -184,6 +185,18 @@ namespace osu.Game.Tests.Visual.OnlinePlay return responseRoom; } - private Room cloneRoom(Room source) => JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source)); + private Room cloneRoom(Room source) + { + var result = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source)); + Debug.Assert(result != null); + + // Playlist item IDs aren't serialised. + if (source.CurrentPlaylistItem.Value != null) + result.CurrentPlaylistItem.Value.ID = source.CurrentPlaylistItem.Value.ID; + for (int i = 0; i < source.Playlist.Count; i++) + result.Playlist[i].ID = source.Playlist[i].ID; + + return result; + } } } From 06ac3c1ad353bdbe25caba972759eb531bd5c5d2 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 3 Jun 2022 21:12:28 +0900 Subject: [PATCH 062/103] Make MultiplayerClient update CurrentPlaylistItem --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index cae675b406..c95f3fa579 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -197,6 +197,7 @@ namespace osu.Game.Online.Multiplayer APIRoom.Playlist.Clear(); APIRoom.Playlist.AddRange(joinedRoom.Playlist.Select(createPlaylistItem)); + APIRoom.CurrentPlaylistItem.Value = APIRoom.Playlist.Single(item => item.ID == joinedRoom.Settings.PlaylistItemId); Debug.Assert(LocalUser != null); addUserToAPIRoom(LocalUser); @@ -737,6 +738,7 @@ namespace osu.Game.Online.Multiplayer APIRoom.Type.Value = Room.Settings.MatchType; APIRoom.QueueMode.Value = Room.Settings.QueueMode; APIRoom.AutoStartDuration.Value = Room.Settings.AutoStartDuration; + APIRoom.CurrentPlaylistItem.Value = APIRoom.Playlist.Single(item => item.ID == settings.PlaylistItemId); RoomUpdated?.Invoke(); } From 3df4d1b0e6328da0d20d1d24e36508666bdb1afb Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 3 Jun 2022 21:17:47 +0900 Subject: [PATCH 063/103] Fix incorrect HasPassword value for returned rooms --- osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs index 3a668d6931..8fea77833e 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs @@ -179,9 +179,15 @@ namespace osu.Game.Tests.Visual.OnlinePlay private Room createResponseRoom(Room room, bool withParticipants) { var responseRoom = cloneRoom(room); + + // Password is hidden from the response, and is only propagated via HasPassword. + bool hadPassword = responseRoom.HasPassword.Value; responseRoom.Password.Value = null; + responseRoom.HasPassword.Value = hadPassword; + if (!withParticipants) responseRoom.RecentParticipants.Clear(); + return responseRoom; } From 365819865e04b490c30784b8fec3805a7a1fdb66 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Wed, 1 Jun 2022 21:00:14 +0900 Subject: [PATCH 064/103] Remove 'submit' sample usages --- osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs | 2 +- osu.Game/Graphics/UserInterface/BackButton.cs | 2 +- osu.Game/Graphics/UserInterface/DialogButton.cs | 4 ++-- osu.Game/Graphics/UserInterface/ExternalLinkButton.cs | 2 +- osu.Game/Graphics/UserInterface/HoverSampleSet.cs | 3 --- osu.Game/Online/Chat/DrawableLinkCompiler.cs | 1 - osu.Game/Overlays/News/NewsCard.cs | 2 -- osu.Game/Overlays/News/Sidebar/MonthSection.cs | 2 -- .../Overlays/Profile/Sections/BeatmapMetadataContainer.cs | 2 -- osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs | 2 +- osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs | 2 +- osu.Game/Users/Drawables/ClickableAvatar.cs | 6 ------ osu.Game/Users/Drawables/UpdateableFlag.cs | 2 +- osu.Game/Users/UserPanel.cs | 2 +- 14 files changed, 9 insertions(+), 25 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs index 9a17d6dc9b..08aaa8da42 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs @@ -35,7 +35,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards protected readonly BeatmapDownloadTracker DownloadTracker; protected BeatmapCard(APIBeatmapSet beatmapSet, bool allowExpansion = true) - : base(HoverSampleSet.Submit) + : base(HoverSampleSet.Button) { Expanded = new BindableBool { Disabled = !allowExpansion }; diff --git a/osu.Game/Graphics/UserInterface/BackButton.cs b/osu.Game/Graphics/UserInterface/BackButton.cs index 1b564ef1b4..2b59ee0282 100644 --- a/osu.Game/Graphics/UserInterface/BackButton.cs +++ b/osu.Game/Graphics/UserInterface/BackButton.cs @@ -21,7 +21,7 @@ namespace osu.Game.Graphics.UserInterface { Size = TwoLayerButton.SIZE_EXTENDED; - Child = button = new TwoLayerButton(HoverSampleSet.Submit) + Child = button = new TwoLayerButton { Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft, diff --git a/osu.Game/Graphics/UserInterface/DialogButton.cs b/osu.Game/Graphics/UserInterface/DialogButton.cs index ad69ec4078..69fbd744c9 100644 --- a/osu.Game/Graphics/UserInterface/DialogButton.cs +++ b/osu.Game/Graphics/UserInterface/DialogButton.cs @@ -56,8 +56,8 @@ namespace osu.Game.Graphics.UserInterface private readonly SpriteText spriteText; private Vector2 hoverSpacing => new Vector2(3f, 0f); - public DialogButton() - : base(HoverSampleSet.Submit) + public DialogButton(HoverSampleSet sampleSet = HoverSampleSet.Button) + : base(sampleSet) { RelativeSizeAxes = Axes.X; diff --git a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs index 0df69a5b54..1730e1478f 100644 --- a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs +++ b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs @@ -36,7 +36,7 @@ namespace osu.Game.Graphics.UserInterface Icon = FontAwesome.Solid.ExternalLinkAlt, RelativeSizeAxes = Axes.Both }, - new HoverClickSounds(HoverSampleSet.Submit) + new HoverClickSounds() }; } diff --git a/osu.Game/Graphics/UserInterface/HoverSampleSet.cs b/osu.Game/Graphics/UserInterface/HoverSampleSet.cs index a5ea6fcfbf..b88f81a143 100644 --- a/osu.Game/Graphics/UserInterface/HoverSampleSet.cs +++ b/osu.Game/Graphics/UserInterface/HoverSampleSet.cs @@ -10,9 +10,6 @@ namespace osu.Game.Graphics.UserInterface [Description("default")] Default, - [Description("submit")] - Submit, - [Description("button")] Button, diff --git a/osu.Game/Online/Chat/DrawableLinkCompiler.cs b/osu.Game/Online/Chat/DrawableLinkCompiler.cs index 8356b36667..3b0d049528 100644 --- a/osu.Game/Online/Chat/DrawableLinkCompiler.cs +++ b/osu.Game/Online/Chat/DrawableLinkCompiler.cs @@ -38,7 +38,6 @@ namespace osu.Game.Online.Chat } public DrawableLinkCompiler(IEnumerable parts) - : base(HoverSampleSet.Submit) { Parts = parts.ToList(); } diff --git a/osu.Game/Overlays/News/NewsCard.cs b/osu.Game/Overlays/News/NewsCard.cs index 68d0704825..5ce0b9df9c 100644 --- a/osu.Game/Overlays/News/NewsCard.cs +++ b/osu.Game/Overlays/News/NewsCard.cs @@ -14,7 +14,6 @@ using osu.Framework.Platform; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.News @@ -29,7 +28,6 @@ namespace osu.Game.Overlays.News private TextFlowContainer main; public NewsCard(APINewsPost post) - : base(HoverSampleSet.Submit) { this.post = post; diff --git a/osu.Game/Overlays/News/Sidebar/MonthSection.cs b/osu.Game/Overlays/News/Sidebar/MonthSection.cs index aa83f89689..e2ce25660e 100644 --- a/osu.Game/Overlays/News/Sidebar/MonthSection.cs +++ b/osu.Game/Overlays/News/Sidebar/MonthSection.cs @@ -18,7 +18,6 @@ using System.Diagnostics; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Platform; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.News.Sidebar { @@ -129,7 +128,6 @@ namespace osu.Game.Overlays.News.Sidebar private readonly APINewsPost post; public PostButton(APINewsPost post) - : base(HoverSampleSet.Submit) { this.post = post; diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs index 94ef5e5d86..13465f3bf8 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Profile.Sections { @@ -18,7 +17,6 @@ namespace osu.Game.Overlays.Profile.Sections private readonly IBeatmapInfo beatmapInfo; protected BeatmapMetadataContainer(IBeatmapInfo beatmapInfo) - : base(HoverSampleSet.Submit) { this.beatmapInfo = beatmapInfo; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs index 35c903eb0c..0015cf8bf9 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs @@ -55,7 +55,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private void load(AudioManager audio) { sampleSelect = audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select"); - sampleJoin = audio.Samples.Get($@"UI/{HoverSampleSet.Submit.GetDescription()}-select"); + sampleJoin = audio.Samples.Get($@"UI/{HoverSampleSet.Button.GetDescription()}-select"); AddRangeInternal(new Drawable[] { diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs index 6ecb96f723..df7dd47ef3 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Select.Options public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => box.ReceivePositionalInputAt(screenSpacePos); public BeatmapOptionsButton() - : base(HoverSampleSet.Submit) + : base(HoverSampleSet.Button) { Width = width; RelativeSizeAxes = Axes.Y; diff --git a/osu.Game/Users/Drawables/ClickableAvatar.cs b/osu.Game/Users/Drawables/ClickableAvatar.cs index 0dd135b500..d85648c078 100644 --- a/osu.Game/Users/Drawables/ClickableAvatar.cs +++ b/osu.Game/Users/Drawables/ClickableAvatar.cs @@ -7,7 +7,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Users.Drawables @@ -74,11 +73,6 @@ namespace osu.Game.Users.Drawables { private LocalisableString tooltip = default_tooltip_text; - public ClickableArea() - : base(HoverSampleSet.Submit) - { - } - public override LocalisableString TooltipText { get => Enabled.Value ? tooltip : default; diff --git a/osu.Game/Users/Drawables/UpdateableFlag.cs b/osu.Game/Users/Drawables/UpdateableFlag.cs index e5debc0683..d0ef760e59 100644 --- a/osu.Game/Users/Drawables/UpdateableFlag.cs +++ b/osu.Game/Users/Drawables/UpdateableFlag.cs @@ -49,7 +49,7 @@ namespace osu.Game.Users.Drawables { RelativeSizeAxes = Axes.Both }, - new HoverClickSounds(HoverSampleSet.Submit) + new HoverClickSounds() } }; } diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 248debf1d3..40d70ca406 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -32,7 +32,7 @@ namespace osu.Game.Users protected Drawable Background { get; private set; } protected UserPanel(APIUser user) - : base(HoverSampleSet.Submit) + : base(HoverSampleSet.Button) { if (user == null) throw new ArgumentNullException(nameof(user)); From 2878bb592fc317b36b6f49127da42543027fb28b Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 3 Jun 2022 22:22:32 +0900 Subject: [PATCH 065/103] Use more appropriate sounds for certain components --- .../UserInterface/ShearedToggleButton.cs | 8 ++++-- .../Overlays/BeatmapListing/FilterTabItem.cs | 2 +- .../Chat/Listing/ChannelListingItem.cs | 27 +++++++++++++++++-- .../Header/Components/ExpandDetailsButton.cs | 2 +- 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs b/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs index 4780270f66..ee59da7279 100644 --- a/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs +++ b/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs @@ -13,6 +13,7 @@ namespace osu.Game.Graphics.UserInterface { public class ShearedToggleButton : ShearedButton { + private Sample? sampleClick; private Sample? sampleOff; private Sample? sampleOn; @@ -39,8 +40,9 @@ namespace osu.Game.Graphics.UserInterface [BackgroundDependencyLoader] private void load(AudioManager audio) { - sampleOn = audio.Samples.Get(@"UI/check-on"); - sampleOff = audio.Samples.Get(@"UI/check-off"); + sampleClick = audio.Samples.Get(@"UI/default-select"); + sampleOn = audio.Samples.Get(@"UI/dropdown-open"); + sampleOff = audio.Samples.Get(@"UI/dropdown-close"); } protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds(sampleSet); @@ -67,6 +69,8 @@ namespace osu.Game.Graphics.UserInterface private void playSample() { + sampleClick?.Play(); + if (Active.Value) sampleOn?.Play(); else diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs index 52dfcad2cc..ff43170207 100644 --- a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -40,7 +40,7 @@ namespace osu.Game.Overlays.BeatmapListing Font = OsuFont.GetFont(size: 13, weight: FontWeight.Regular), Text = LabelFor(Value) }, - new HoverClickSounds() + new HoverClickSounds(HoverSampleSet.TabSelect) }); Enabled.Value = true; diff --git a/osu.Game/Overlays/Chat/Listing/ChannelListingItem.cs b/osu.Game/Overlays/Chat/Listing/ChannelListingItem.cs index 86c81d5d79..2a21d30a4a 100644 --- a/osu.Game/Overlays/Chat/Listing/ChannelListingItem.cs +++ b/osu.Game/Overlays/Chat/Listing/ChannelListingItem.cs @@ -6,6 +6,8 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -16,6 +18,7 @@ using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.Chat; using osuTK; @@ -32,6 +35,8 @@ namespace osu.Game.Overlays.Chat.Listing public IEnumerable FilterTerms => new LocalisableString[] { Channel.Name, Channel.Topic ?? string.Empty }; public bool MatchingFilter { set => this.FadeTo(value ? 1f : 0f, 100); } + protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds(); + private Box hoverBox = null!; private SpriteIcon checkbox = null!; private OsuSpriteText channelText = null!; @@ -46,14 +51,20 @@ namespace osu.Game.Overlays.Chat.Listing private const float vertical_margin = 1.5f; + private Sample? sampleJoin; + private Sample? sampleLeave; + public ChannelListingItem(Channel channel) { Channel = channel; } [BackgroundDependencyLoader] - private void load() + private void load(AudioManager audio) { + sampleJoin = audio.Samples.Get(@"UI/check-on"); + sampleLeave = audio.Samples.Get(@"UI/check-off"); + Masking = true; CornerRadius = 5; RelativeSizeAxes = Axes.X; @@ -156,7 +167,19 @@ namespace osu.Game.Overlays.Chat.Listing } }, true); - Action = () => (channelJoined.Value ? OnRequestLeave : OnRequestJoin)?.Invoke(Channel); + Action = () => + { + if (channelJoined.Value) + { + OnRequestLeave?.Invoke(Channel); + sampleLeave?.Play(); + } + else + { + OnRequestJoin?.Invoke(Channel); + sampleJoin?.Play(); + } + }; } protected override bool OnHover(HoverEvent e) diff --git a/osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.cs b/osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.cs index b4a5d5e31b..4cfdf5cc86 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Profile.Header.Components private Sample sampleOpen; private Sample sampleClose; - protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds(); + protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(); public ExpandDetailsButton() { From 6115275bc240e72a1744c8917e59d0ecef653cbb Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 3 Jun 2022 22:28:36 +0900 Subject: [PATCH 066/103] Use 'default' sampleset for toolbar and repurpose 'toolbar' select sample temporarily --- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 2 -- osu.Game/Overlays/Toolbar/ToolbarClock.cs | 2 -- osu.Game/Screens/Select/FooterButton.cs | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index 4a839b048c..b686f11c13 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -20,7 +20,6 @@ using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osuTK; using osuTK.Graphics; @@ -83,7 +82,6 @@ namespace osu.Game.Overlays.Toolbar private RealmAccess realm { get; set; } protected ToolbarButton() - : base(HoverSampleSet.Toolbar) { Width = Toolbar.HEIGHT; RelativeSizeAxes = Axes.Y; diff --git a/osu.Game/Overlays/Toolbar/ToolbarClock.cs b/osu.Game/Overlays/Toolbar/ToolbarClock.cs index 308359570f..12529da07f 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarClock.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarClock.cs @@ -11,7 +11,6 @@ using osu.Framework.Input.Events; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; using osuTK; using osuTK.Graphics; @@ -29,7 +28,6 @@ namespace osu.Game.Overlays.Toolbar private AnalogClockDisplay analog; public ToolbarClock() - : base(HoverSampleSet.Toolbar) { RelativeSizeAxes = Axes.Y; AutoSizeAxes = Axes.X; diff --git a/osu.Game/Screens/Select/FooterButton.cs b/osu.Game/Screens/Select/FooterButton.cs index 9cb178ca8b..1587f43258 100644 --- a/osu.Game/Screens/Select/FooterButton.cs +++ b/osu.Game/Screens/Select/FooterButton.cs @@ -66,7 +66,7 @@ namespace osu.Game.Screens.Select private readonly Box light; public FooterButton() - : base(HoverSampleSet.Button) + : base(HoverSampleSet.Toolbar) { AutoSizeAxes = Axes.Both; Shear = SHEAR; From 396a566a0e577b0f2b1a2ba71ee2f1aa687b6c7b Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 3 Jun 2022 22:29:03 +0900 Subject: [PATCH 067/103] Add some randomness to click samples --- osu.Game/Graphics/UserInterface/HoverClickSounds.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index 12819840e5..ba253a7c71 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -7,6 +7,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Extensions; using osu.Framework.Input.Events; +using osu.Framework.Utils; using osuTK.Input; namespace osu.Game.Graphics.UserInterface @@ -37,7 +38,10 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnClick(ClickEvent e) { if (buttons.Contains(e.Button) && Contains(e.ScreenSpaceMousePosition)) - sampleClick?.Play(); + { + sampleClick.Frequency.Value = 0.99 + RNG.NextDouble(0.02); + sampleClick.Play(); + } return base.OnClick(e); } From 64616a6d73b3f074b2b133ff4acfce32c3297ee1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 4 Jun 2022 00:18:54 +0900 Subject: [PATCH 068/103] Remove completely gimped implementation in `VolumeMeter` --- osu.Game/Overlays/Volume/VolumeMeter.cs | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 929c362bd8..5dfcb94faf 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -15,7 +15,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Threading; using osu.Framework.Utils; @@ -28,7 +27,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Volume { - public class VolumeMeter : Container, IKeyBindingHandler, IStateful + public class VolumeMeter : Container, IStateful { private CircularProgress volumeCircle; private CircularProgress volumeCircleGlow; @@ -365,27 +364,6 @@ namespace osu.Game.Overlays.Volume { } - public bool OnPressed(KeyBindingPressEvent e) - { - if (!IsHovered) - return false; - - switch (e.Action) - { - case GlobalAction.SelectPreviousGroup: - State = SelectionState.Selected; - adjust(1, false); - return true; - - case GlobalAction.SelectNextGroup: - State = SelectionState.Selected; - adjust(-1, false); - return true; - } - - return false; - } - public void OnReleased(KeyBindingReleaseEvent e) { } From 712253a35b74d2c5fb4c92bb86e298ebec8f2717 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 4 Jun 2022 01:04:23 +0900 Subject: [PATCH 069/103] Make non-localisable strings in `VolumeMeter` verbatim --- osu.Game/Overlays/Volume/VolumeMeter.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 5dfcb94faf..24d9f785f2 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Volume [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audio) { - hoverSample = audio.Samples.Get($"UI/{HoverSampleSet.Button.GetDescription()}-hover"); + hoverSample = audio.Samples.Get($@"UI/{HoverSampleSet.Button.GetDescription()}-hover"); notchSample = audio.Samples.Get(@"UI/notch-tick"); sampleLastPlaybackTime = Time.Current; @@ -131,7 +131,7 @@ namespace osu.Game.Overlays.Volume { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Name = "Progress under covers for smoothing", + Name = @"Progress under covers for smoothing", RelativeSizeAxes = Axes.Both, Rotation = 180, Child = volumeCircle = new CircularProgress @@ -143,7 +143,7 @@ namespace osu.Game.Overlays.Volume }, new Circle { - Name = "Inner Cover", + Name = @"Inner Cover", Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, @@ -152,7 +152,7 @@ namespace osu.Game.Overlays.Volume }, new Container { - Name = "Progress overlay for glow", + Name = @"Progress overlay for glow", Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, From d0e098fbcdb02b597a28b07123605d7aef561205 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 4 Jun 2022 01:04:46 +0900 Subject: [PATCH 070/103] Allow using arrow keys to navigate volume controls when controls are already visible --- osu.Game/Overlays/VolumeOverlay.cs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index a96949e96f..9d2ed3f837 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -17,6 +17,7 @@ using osu.Game.Input.Bindings; using osu.Game.Overlays.Volume; using osuTK; using osuTK.Graphics; +using osuTK.Input; namespace osu.Game.Overlays { @@ -171,6 +172,30 @@ namespace osu.Game.Overlays return base.OnMouseMove(e); } + protected override bool OnKeyDown(KeyDownEvent e) + { + switch (e.Key) + { + case Key.Left: + Adjust(GlobalAction.PreviousVolumeMeter); + return true; + + case Key.Right: + Adjust(GlobalAction.NextVolumeMeter); + return true; + + case Key.Down: + Adjust(GlobalAction.DecreaseVolume); + return true; + + case Key.Up: + Adjust(GlobalAction.IncreaseVolume); + return true; + } + + return base.OnKeyDown(e); + } + protected override bool OnHover(HoverEvent e) { schedulePopOut(); From 045e0446370a7ff0c4b4d7d5035ae7ca92ec3189 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 4 Jun 2022 01:14:41 +0300 Subject: [PATCH 071/103] Expose `LegacySkinTransformer`'s underlying skin for pattern-matching --- osu.Game/Skinning/LegacySkinTransformer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacySkinTransformer.cs b/osu.Game/Skinning/LegacySkinTransformer.cs index 9481fc7182..34714b9dc5 100644 --- a/osu.Game/Skinning/LegacySkinTransformer.cs +++ b/osu.Game/Skinning/LegacySkinTransformer.cs @@ -23,7 +23,7 @@ namespace osu.Game.Skinning /// The which is being transformed. /// [NotNull] - protected internal ISkin Skin { get; } + public ISkin Skin { get; } protected LegacySkinTransformer([NotNull] ISkin skin) { From fe96e15b1b32301d405b8755431f301e0555a80f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 4 Jun 2022 01:15:03 +0300 Subject: [PATCH 072/103] Update spinner approach circle to handle `LegacySkinTransformer` --- .../Skinning/Legacy/LegacyNewStyleSpinner.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs index 1e170036e4..a58f62736b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs @@ -78,7 +78,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy } }); - if (!(source.FindProvider(s => s.GetTexture("spinner-top") != null) is DefaultLegacySkin)) + var topProvider = source.FindProvider(s => s.GetTexture("spinner-top") != null); + + if (topProvider is LegacySkinTransformer transformer && !(transformer.Skin is DefaultLegacySkin)) { AddInternal(ApproachCircle = new Sprite { From b342aad24a906f15da6652935fefdb9aee91c776 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 2 Jun 2022 20:53:14 -0700 Subject: [PATCH 073/103] Revert/fix some incorrectly used sorting localisation --- osu.Game/Screens/Select/Filter/SortMode.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/Filter/SortMode.cs b/osu.Game/Screens/Select/Filter/SortMode.cs index 5dfa2a2664..3dd3381059 100644 --- a/osu.Game/Screens/Select/Filter/SortMode.cs +++ b/osu.Game/Screens/Select/Filter/SortMode.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Select.Filter [Description("Author")] Author, - [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowStatsBpm))] + [LocalisableDescription(typeof(SortStrings), nameof(SortStrings.ArtistTracksBpm))] BPM, [Description("Date Added")] @@ -28,10 +28,10 @@ namespace osu.Game.Screens.Select.Filter Length, // todo: pending support (https://github.com/ppy/osu/issues/4917) - // [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchFiltersRank))] + // [Description("Rank Achieved")] // RankAchieved, - [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowInfoSource))] + [Description("Source")] Source, [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingTitle))] From 58c8562cb0d64ef5287a5a5d7dc8ff022dd3ce11 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 2 Jun 2022 20:30:56 -0700 Subject: [PATCH 074/103] Fix username placeholder text casing and missing localisation on registration form --- osu.Game/Overlays/AccountCreation/ScreenEntry.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs index 1be1321d85..f4f958e4a4 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Utils; @@ -69,7 +70,7 @@ namespace osu.Game.Overlays.AccountCreation }, usernameTextBox = new OsuTextBox { - PlaceholderText = UsersStrings.LoginUsername, + PlaceholderText = UsersStrings.LoginUsername.ToLower(), RelativeSizeAxes = Axes.X, TabbableContentContainer = this }, @@ -91,7 +92,7 @@ namespace osu.Game.Overlays.AccountCreation }, passwordTextBox = new OsuPasswordTextBox { - PlaceholderText = "password", + PlaceholderText = UsersStrings.LoginPassword.ToLower(), RelativeSizeAxes = Axes.X, TabbableContentContainer = this, }, From 4b54fedd88e5389eda73e2f363fc6c8a115032b0 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 2 Jun 2022 20:28:59 -0700 Subject: [PATCH 075/103] Add back hide common string using new `ToSentence()` extension method --- osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index 9772b1feb3..98b885eb43 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -8,6 +8,7 @@ using System.Threading; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; @@ -244,7 +245,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.ToSentence(), MenuItemType.Destructive, () => hideRequested(beatmapInfo))); return items.ToArray(); } From 30cf6bffad8a0848ed32ca60f0fd0c8f6c914a71 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 3 Jun 2022 21:41:34 -0700 Subject: [PATCH 076/103] Add tooltips to beatmap card icon pills --- .../Drawables/Cards/BeatmapCardExtra.cs | 5 ++--- .../Drawables/Cards/BeatmapCardNormal.cs | 5 ++--- osu.Game/Beatmaps/Drawables/Cards/IconPill.cs | 8 ++++++-- .../Drawables/Cards/StoryboardIconPill.cs | 19 +++++++++++++++++++ .../Beatmaps/Drawables/Cards/VideoIconPill.cs | 19 +++++++++++++++++++ 5 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 osu.Game/Beatmaps/Drawables/Cards/StoryboardIconPill.cs create mode 100644 osu.Game/Beatmaps/Drawables/Cards/VideoIconPill.cs diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs index 58c1ebee0f..7826d64296 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs @@ -6,7 +6,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Beatmaps.Drawables.Cards.Statistics; using osu.Game.Graphics; @@ -245,10 +244,10 @@ namespace osu.Game.Beatmaps.Drawables.Cards }); if (BeatmapSet.HasVideo) - leftIconArea.Add(new IconPill(FontAwesome.Solid.Film) { IconSize = new Vector2(20) }); + leftIconArea.Add(new VideoIconPill { IconSize = new Vector2(20) }); if (BeatmapSet.HasStoryboard) - leftIconArea.Add(new IconPill(FontAwesome.Solid.Image) { IconSize = new Vector2(20) }); + leftIconArea.Add(new StoryboardIconPill { IconSize = new Vector2(20) }); if (BeatmapSet.FeaturedInSpotlight) { diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs index 3d7e81de21..c1ba521925 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Beatmaps.Drawables.Cards.Statistics; using osu.Game.Graphics; @@ -226,10 +225,10 @@ namespace osu.Game.Beatmaps.Drawables.Cards }); if (BeatmapSet.HasVideo) - leftIconArea.Add(new IconPill(FontAwesome.Solid.Film) { IconSize = new Vector2(20) }); + leftIconArea.Add(new VideoIconPill { IconSize = new Vector2(20) }); if (BeatmapSet.HasStoryboard) - leftIconArea.Add(new IconPill(FontAwesome.Solid.Image) { IconSize = new Vector2(20) }); + leftIconArea.Add(new StoryboardIconPill { IconSize = new Vector2(20) }); if (BeatmapSet.FeaturedInSpotlight) { diff --git a/osu.Game/Beatmaps/Drawables/Cards/IconPill.cs b/osu.Game/Beatmaps/Drawables/Cards/IconPill.cs index c55e9c0a28..1b2c5d3ffc 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/IconPill.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/IconPill.cs @@ -3,14 +3,16 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osuTK; using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables.Cards { - public class IconPill : CircularContainer + public abstract class IconPill : CircularContainer, IHasTooltip { public Vector2 IconSize { @@ -20,7 +22,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards private readonly Container iconContainer; - public IconPill(IconUsage icon) + protected IconPill(IconUsage icon) { AutoSizeAxes = Axes.Both; Masking = true; @@ -47,5 +49,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards }, }; } + + public abstract LocalisableString TooltipText { get; } } } diff --git a/osu.Game/Beatmaps/Drawables/Cards/StoryboardIconPill.cs b/osu.Game/Beatmaps/Drawables/Cards/StoryboardIconPill.cs new file mode 100644 index 0000000000..2ebf9107f5 --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/StoryboardIconPill.cs @@ -0,0 +1,19 @@ +// 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.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Beatmaps.Drawables.Cards +{ + public class StoryboardIconPill : IconPill + { + public StoryboardIconPill() + : base(FontAwesome.Solid.Image) + { + } + + public override LocalisableString TooltipText => BeatmapsetsStrings.ShowInfoStoryboard; + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/VideoIconPill.cs b/osu.Game/Beatmaps/Drawables/Cards/VideoIconPill.cs new file mode 100644 index 0000000000..b81e18b0dd --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/VideoIconPill.cs @@ -0,0 +1,19 @@ +// 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.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Beatmaps.Drawables.Cards +{ + public class VideoIconPill : IconPill + { + public VideoIconPill() + : base(FontAwesome.Solid.Film) + { + } + + public override LocalisableString TooltipText => BeatmapsetsStrings.ShowInfoVideo; + } +} From 8ad588d9279058f0746c204e9dfe08e7dbdc43f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 4 Jun 2022 22:12:53 +0900 Subject: [PATCH 077/103] 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 0058bb3577..ab96504e94 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 2285f61331..fd6715c58a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index b134a7e356..9a36e1073b 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From c0aaeff2b3cfbf7ab75d17ba839af27165986afd Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sat, 4 Jun 2022 16:11:49 +0100 Subject: [PATCH 078/103] Update `DaySeparator` to use new design throughout Moves `DaySeparator` chat component to it's own file and update it to match new chat design. Makes use of several virtual attributes that can be overridden to update spacing and layout in other usage contexts. Remove redundant usage of `ChatOverlayDaySeparator`, since the new design is now part of the base class. Create `StandAloneDaySeparator` to use in `StandAloneChatDisplay` which overrides attributes to match correct spacing and layout for its design. Ensure that `DrawableChannel.CreateDaySeparator` returns type of `DaySeparator` instead of `Drawable`. --- .../Online/TestSceneStandAloneChatDisplay.cs | 4 +- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 34 ++++-- .../Chat/ChatOverlayDrawableChannel.cs | 82 +------------- osu.Game/Overlays/Chat/DaySeparator.cs | 105 ++++++++++++++++++ osu.Game/Overlays/Chat/DrawableChannel.cs | 80 +------------ 5 files changed, 138 insertions(+), 167 deletions(-) create mode 100644 osu.Game/Overlays/Chat/DaySeparator.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs index 860ef5d565..cb52f41c33 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs @@ -128,11 +128,11 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Ensure no adjacent day separators", () => { - var indices = chatDisplay.FillFlow.OfType().Select(ds => chatDisplay.FillFlow.IndexOf(ds)); + var indices = chatDisplay.FillFlow.OfType().Select(ds => chatDisplay.FillFlow.IndexOf(ds)); foreach (int i in indices) { - if (i < chatDisplay.FillFlow.Count && chatDisplay.FillFlow[i + 1] is DrawableChannel.DaySeparator) + if (i < chatDisplay.FillFlow.Count && chatDisplay.FillFlow[i + 1] is DaySeparator) return false; } diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index b7e1bc999b..f57ffcfe25 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -155,9 +155,6 @@ namespace osu.Game.Online.Chat { public Func CreateChatLineAction; - [Resolved] - private OsuColour colours { get; set; } - public StandAloneDrawableChannel(Channel channel) : base(channel) { @@ -166,25 +163,40 @@ namespace osu.Game.Online.Chat [BackgroundDependencyLoader] private void load() { + // TODO: Remove once DrawableChannel & ChatLine padding is fixed ChatLineFlow.Padding = new MarginPadding { Horizontal = 0 }; } protected override ChatLine CreateChatLine(Message m) => CreateChatLineAction(m); - protected override Drawable CreateDaySeparator(DateTimeOffset time) => new DaySeparator(time) + protected override DaySeparator CreateDaySeparator(DateTimeOffset time) => new StandAloneDaySeparator(time); + } + + protected class StandAloneDaySeparator : DaySeparator + { + protected override float TextSize => 14; + protected override float LineHeight => 1; + protected override float Spacing => 10; + protected override float DateAlign => 120; + + public StandAloneDaySeparator(DateTimeOffset time) + : base(time) { - TextSize = 14, - Colour = colours.Yellow, - LineHeight = 1, - Padding = new MarginPadding { Horizontal = 10 }, - Margin = new MarginPadding { Vertical = 5 }, - }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Height = 25; + Colour = colours.Yellow; + // TODO: Remove once DrawableChannel & ChatLine padding is fixed + Padding = new MarginPadding { Horizontal = 10 }; + } } protected class StandAloneMessage : ChatLine { protected override float TextSize => 15; - protected override float HorizontalPadding => 10; protected override float MessagePadding => 120; protected override float TimestampPadding => 50; diff --git a/osu.Game/Overlays/Chat/ChatOverlayDrawableChannel.cs b/osu.Game/Overlays/Chat/ChatOverlayDrawableChannel.cs index 3b47adc4b7..a5d22f678e 100644 --- a/osu.Game/Overlays/Chat/ChatOverlayDrawableChannel.cs +++ b/osu.Game/Overlays/Chat/ChatOverlayDrawableChannel.cs @@ -6,10 +6,6 @@ using System; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; using osu.Game.Online.Chat; namespace osu.Game.Overlays.Chat @@ -24,85 +20,19 @@ namespace osu.Game.Overlays.Chat [BackgroundDependencyLoader] private void load() { + // TODO: Remove once DrawableChannel & ChatLine padding is fixed ChatLineFlow.Padding = new MarginPadding(0); } - protected override Drawable CreateDaySeparator(DateTimeOffset time) => new ChatOverlayDaySeparator(time); + protected override DaySeparator CreateDaySeparator(DateTimeOffset time) => new ChatOverlayDaySeparator(time); - private class ChatOverlayDaySeparator : Container + private class ChatOverlayDaySeparator : DaySeparator { - private readonly DateTimeOffset time; - public ChatOverlayDaySeparator(DateTimeOffset time) + : base(time) { - this.time = time; - } - - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Padding = new MarginPadding { Horizontal = 15, Vertical = 20 }; - Child = new GridContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.Absolute, 200), - new Dimension(GridSizeMode.Absolute, 15), - new Dimension(), - }, - Content = new[] - { - new[] - { - new GridContainer - { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.Absolute, 15), - new Dimension(GridSizeMode.AutoSize), - }, - Content = new[] - { - new[] - { - new Circle - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Colour = colourProvider.Background5, - RelativeSizeAxes = Axes.X, - Height = 2, - }, - Drawable.Empty(), - new OsuSpriteText - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Text = time.ToLocalTime().ToString("dd MMMM yyyy").ToUpper(), - Font = OsuFont.Torus.With(size: 15, weight: FontWeight.SemiBold), - Colour = colourProvider.Content1, - }, - }, - }, - }, - Drawable.Empty(), - new Circle - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Colour = colourProvider.Background5, - RelativeSizeAxes = Axes.X, - Height = 2, - }, - }, - }, - }; + // TODO: Remove once DrawableChannel & ChatLine padding is fixed + Padding = new MarginPadding { Horizontal = 15 }; } } } diff --git a/osu.Game/Overlays/Chat/DaySeparator.cs b/osu.Game/Overlays/Chat/DaySeparator.cs new file mode 100644 index 0000000000..2e3796151c --- /dev/null +++ b/osu.Game/Overlays/Chat/DaySeparator.cs @@ -0,0 +1,105 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Overlays.Chat +{ + public class DaySeparator : Container + { + protected virtual float TextSize => 15; + + protected virtual float LineHeight => 2; + + protected virtual float DateAlign => 200; + + protected virtual float Spacing => 15; + + private readonly DateTimeOffset time; + + [Resolved(CanBeNull = true)] + private OverlayColourProvider? colourProvider { get; set; } + + public DaySeparator(DateTimeOffset time) + { + this.time = time; + Height = 40; + } + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.X; + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RowDimensions = new[] { new Dimension() }, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.Absolute, DateAlign), + new Dimension(GridSizeMode.Absolute, Spacing), + new Dimension(), + }, + Content = new[] + { + new[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] { new Dimension() }, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.Absolute, Spacing), + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new[] + { + new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + Height = LineHeight, + Colour = colourProvider?.Background5 ?? Colour4.White, + }, + Drawable.Empty(), + new OsuSpriteText + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Text = time.ToLocalTime().ToString("dd MMMM yyyy").ToUpper(), + Font = OsuFont.Torus.With(size: TextSize, weight: FontWeight.SemiBold), + Colour = colourProvider?.Content1 ?? Colour4.White, + }, + } + }, + }, + Drawable.Empty(), + new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + Height = LineHeight, + Colour = colourProvider?.Background5 ?? Colour4.White, + }, + } + } + }; + } + } +} diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index f2d4a3e301..f0d4d12f4f 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -7,14 +7,9 @@ using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; using osu.Game.Graphics.Cursor; -using osu.Game.Graphics.Sprites; using osu.Game.Online.Chat; using osuTK.Graphics; @@ -40,9 +35,6 @@ namespace osu.Game.Overlays.Chat } } - [Resolved] - private OsuColour colours { get; set; } - public DrawableChannel(Channel channel) { Channel = channel; @@ -67,7 +59,7 @@ namespace osu.Game.Overlays.Chat Padding = new MarginPadding { Bottom = 5 }, Child = ChatLineFlow = new FillFlowContainer { - Padding = new MarginPadding { Left = 20, Right = 20 }, + Padding = new MarginPadding { Horizontal = 15 }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, @@ -121,11 +113,7 @@ namespace osu.Game.Overlays.Chat protected virtual ChatLine CreateChatLine(Message m) => new ChatLine(m); - protected virtual Drawable CreateDaySeparator(DateTimeOffset time) => new DaySeparator(time) - { - Colour = colours.ChatBlue.Lighten(0.7f), - Margin = new MarginPadding { Vertical = 10 }, - }; + protected virtual DaySeparator CreateDaySeparator(DateTimeOffset time) => new DaySeparator(time); private void newMessagesArrived(IEnumerable newMessages) => Schedule(() => { @@ -203,69 +191,5 @@ namespace osu.Game.Overlays.Chat }); private IEnumerable chatLines => ChatLineFlow.Children.OfType(); - - public class DaySeparator : Container - { - public float TextSize - { - get => text.Font.Size; - set => text.Font = text.Font.With(size: value); - } - - private float lineHeight = 2; - - public float LineHeight - { - get => lineHeight; - set => lineHeight = leftBox.Height = rightBox.Height = value; - } - - private readonly SpriteText text; - private readonly Box leftBox; - private readonly Box rightBox; - - public DaySeparator(DateTimeOffset time) - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Child = new GridContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - }, - RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize), }, - Content = new[] - { - new Drawable[] - { - leftBox = new Box - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.X, - Height = lineHeight, - }, - text = new OsuSpriteText - { - Margin = new MarginPadding { Horizontal = 10 }, - Text = time.ToLocalTime().ToString("dd MMM yyyy"), - }, - rightBox = new Box - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.X, - Height = lineHeight, - }, - } - } - }; - } - } } } From f1af3205ca2ee2a92727e9c95b0cc8044b215a41 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 5 Jun 2022 13:15:05 +0900 Subject: [PATCH 079/103] 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 ab96504e94..aad8cf10d0 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 fd6715c58a..ca92d06aed 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 9a36e1073b..a0fafa635b 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From 6351f652a2eeaeb2128254638bb9e4143edb5f59 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 6 Jun 2022 17:56:25 +0900 Subject: [PATCH 080/103] Fix combo starting at 0 when spectating --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 4a5897c621..df094ddb7c 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -460,6 +460,7 @@ namespace osu.Game.Rulesets.Scoring currentMaximumScoringValues.BaseScore = maximum.BaseScore; currentMaximumScoringValues.MaxCombo = maximum.MaxCombo; + Combo.Value = frame.Header.Combo; HighestCombo.Value = frame.Header.MaxCombo; scoreResultCounts.Clear(); From 4e35ac8d4c5bba0c1577f9ab859b4d319c34dc7c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 6 Jun 2022 18:01:52 +0900 Subject: [PATCH 081/103] Add test --- osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs index af4b002bc9..97be1dcfaa 100644 --- a/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs @@ -59,12 +59,14 @@ namespace osu.Game.Tests.Gameplay scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], new TestJudgement(HitResult.Great)) { Type = HitResult.Great }); Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(1_000_000)); Assert.That(scoreProcessor.JudgedHits, Is.EqualTo(1)); + Assert.That(scoreProcessor.Combo.Value, Is.EqualTo(1)); // No header shouldn't cause any change scoreProcessor.ResetFromReplayFrame(new OsuReplayFrame()); Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(1_000_000)); Assert.That(scoreProcessor.JudgedHits, Is.EqualTo(1)); + Assert.That(scoreProcessor.Combo.Value, Is.EqualTo(1)); // Reset with a miss instead. scoreProcessor.ResetFromReplayFrame(new OsuReplayFrame @@ -74,6 +76,7 @@ namespace osu.Game.Tests.Gameplay Assert.That(scoreProcessor.TotalScore.Value, Is.Zero); Assert.That(scoreProcessor.JudgedHits, Is.EqualTo(1)); + Assert.That(scoreProcessor.Combo.Value, Is.EqualTo(0)); // Reset with no judged hit. scoreProcessor.ResetFromReplayFrame(new OsuReplayFrame @@ -83,6 +86,7 @@ namespace osu.Game.Tests.Gameplay Assert.That(scoreProcessor.TotalScore.Value, Is.Zero); Assert.That(scoreProcessor.JudgedHits, Is.Zero); + Assert.That(scoreProcessor.Combo.Value, Is.EqualTo(0)); } private class TestJudgement : Judgement From cd0e0fe70feda949ced24a7b4ba0e3f522001b40 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Jun 2022 18:02:42 +0900 Subject: [PATCH 082/103] Fix skin editor not accounting for aspect ratios in base-game sizing logic --- .../Screens/Edit/Components/EditorSidebar.cs | 4 ++- osu.Game/Skinning/Editor/SkinEditor.cs | 6 ++-- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 31 +++++++++++++++++-- .../Skinning/Editor/SkinEditorSceneLibrary.cs | 4 ++- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/EditorSidebar.cs b/osu.Game/Screens/Edit/Components/EditorSidebar.cs index 4edcef41b1..4e9b1d5222 100644 --- a/osu.Game/Screens/Edit/Components/EditorSidebar.cs +++ b/osu.Game/Screens/Edit/Components/EditorSidebar.cs @@ -16,13 +16,15 @@ namespace osu.Game.Screens.Edit.Components /// internal class EditorSidebar : Container { + public const float WIDTH = 250; + private readonly Box background; protected override Container Content { get; } public EditorSidebar() { - Width = 250; + Width = WIDTH; RelativeSizeAxes = Axes.Y; InternalChildren = new Drawable[] diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index e36d5ca3c6..30c33006ad 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -29,6 +29,8 @@ namespace osu.Game.Skinning.Editor { public const double TRANSITION_DURATION = 500; + public const float MENU_HEIGHT = 40; + public readonly BindableList SelectedComponents = new BindableList(); protected override bool StartHidden => true; @@ -78,8 +80,6 @@ namespace osu.Game.Skinning.Editor { RelativeSizeAxes = Axes.Both; - const float menu_height = 40; - InternalChild = new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, @@ -102,7 +102,7 @@ namespace osu.Game.Skinning.Editor Name = "Menu container", RelativeSizeAxes = Axes.X, Depth = float.MinValue, - Height = menu_height, + Height = MENU_HEIGHT, Children = new Drawable[] { new EditorMenuBar diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 497283a820..6b4b8abe1a 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -4,14 +4,17 @@ using System.Diagnostics; using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Layout; using osu.Game.Graphics.Containers; using osu.Game.Input.Bindings; using osu.Game.Screens; +using osu.Game.Screens.Edit.Components; namespace osu.Game.Skinning.Editor { @@ -81,15 +84,37 @@ namespace osu.Game.Skinning.Editor protected override void PopOut() => skinEditor?.Hide(); + protected override bool OnInvalidate(Invalidation invalidation, InvalidationSource source) + { + if (invalidation.HasFlagFast(Invalidation.DrawSize)) + Scheduler.AddOnce(updateScreenSizing); + + return base.OnInvalidate(invalidation, source); + } + + private void updateScreenSizing() + { + if (skinEditor?.State.Value != Visibility.Visible) return; + + float relativeSidebarWidth = EditorSidebar.WIDTH / DrawWidth; + float relativeToolbarHeight = (SkinEditorSceneLibrary.HEIGHT + SkinEditor.MENU_HEIGHT) / DrawHeight; + + var rect = new RectangleF( + relativeSidebarWidth, + relativeToolbarHeight, + 1 - relativeSidebarWidth * 2, + 1f - relativeToolbarHeight); + + scalingContainer.SetCustomRect(rect, true); + } + private void updateComponentVisibility() { Debug.Assert(skinEditor != null); - const float toolbar_padding_requirement = 0.18f; - if (skinEditor.State.Value == Visibility.Visible) { - scalingContainer.SetCustomRect(new RectangleF(toolbar_padding_requirement, 0.2f, 0.8f - toolbar_padding_requirement, 0.7f), true); + Scheduler.AddOnce(updateScreenSizing); game?.Toolbar.Hide(); game?.CloseAllOverlays(); diff --git a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs index 2124ba9b6d..dc5a8aefc0 100644 --- a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs @@ -27,6 +27,8 @@ namespace osu.Game.Skinning.Editor { public class SkinEditorSceneLibrary : CompositeDrawable { + public const float HEIGHT = BUTTON_HEIGHT + padding * 2; + public const float BUTTON_HEIGHT = 40; private const float padding = 10; @@ -42,7 +44,7 @@ namespace osu.Game.Skinning.Editor public SkinEditorSceneLibrary() { - Height = BUTTON_HEIGHT + padding * 2; + Height = HEIGHT; } [BackgroundDependencyLoader] From 003a3de270ad5585ce5bdbc02ef2d622bc8b4a84 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Jun 2022 18:06:46 +0900 Subject: [PATCH 083/103] Adjust transitions to look better --- osu.Game/Graphics/Containers/ScalingContainer.cs | 14 +++++++------- osu.Game/Skinning/Editor/SkinEditor.cs | 5 ++++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/osu.Game/Graphics/Containers/ScalingContainer.cs b/osu.Game/Graphics/Containers/ScalingContainer.cs index 11bfd80ec1..5c6e315225 100644 --- a/osu.Game/Graphics/Containers/ScalingContainer.cs +++ b/osu.Game/Graphics/Containers/ScalingContainer.cs @@ -21,7 +21,7 @@ namespace osu.Game.Graphics.Containers /// public class ScalingContainer : Container { - private const float duration = 500; + internal const float TRANSITION_DURATION = 500; private Bindable sizeX; private Bindable sizeY; @@ -99,7 +99,7 @@ namespace osu.Game.Graphics.Containers if (applyUIScale) { uiScale = osuConfig.GetBindable(OsuSetting.UIScale); - uiScale.BindValueChanged(args => this.TransformTo(nameof(CurrentScale), args.NewValue, duration, Easing.OutQuart), true); + uiScale.BindValueChanged(args => this.TransformTo(nameof(CurrentScale), args.NewValue, TRANSITION_DURATION, Easing.OutQuart), true); } } @@ -163,10 +163,10 @@ namespace osu.Game.Graphics.Containers backgroundStack.Push(new ScalingBackgroundScreen()); } - backgroundStack.FadeIn(duration); + backgroundStack.FadeIn(TRANSITION_DURATION); } else - backgroundStack?.FadeOut(duration); + backgroundStack?.FadeOut(TRANSITION_DURATION); } RectangleF targetRect = new RectangleF(Vector2.Zero, Vector2.One); @@ -195,13 +195,13 @@ namespace osu.Game.Graphics.Containers if (requiresMasking) sizableContainer.Masking = true; - sizableContainer.MoveTo(targetRect.Location, duration, Easing.OutQuart); - sizableContainer.ResizeTo(targetRect.Size, duration, Easing.OutQuart); + sizableContainer.MoveTo(targetRect.Location, TRANSITION_DURATION, Easing.OutQuart); + sizableContainer.ResizeTo(targetRect.Size, TRANSITION_DURATION, Easing.OutQuart); // Of note, this will not work great in the case of nested ScalingContainers where multiple are applying corner radius. // Masking and corner radius should likely only be applied at one point in the full game stack to fix this. // An example of how this can occur is when the skin editor is visible and the game screen scaling is set to "Everything". - sizableContainer.TransformTo(nameof(CornerRadius), requiresMasking ? corner_radius : 0, duration, requiresMasking ? Easing.OutQuart : Easing.None) + sizableContainer.TransformTo(nameof(CornerRadius), requiresMasking ? corner_radius : 0, TRANSITION_DURATION, requiresMasking ? Easing.OutQuart : Easing.None) .OnComplete(_ => { sizableContainer.Masking = requiresMasking; }); } diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index 30c33006ad..095763de18 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -322,7 +322,10 @@ namespace osu.Game.Skinning.Editor protected override void PopIn() { - this.FadeIn(TRANSITION_DURATION, Easing.OutQuint); + this + // align animation to happen after the majority of the ScalingContainer animation completes. + .Delay(ScalingContainer.TRANSITION_DURATION * 0.3f) + .FadeIn(TRANSITION_DURATION, Easing.OutQuint); } protected override void PopOut() From 28c9c61f71e89d80528369718e02d4cbe7a5499f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Jun 2022 18:26:52 +0900 Subject: [PATCH 084/103] Fix potential null reference in skin editor if target screen is null (during exit) ```csharp [runtime] 2022-06-06 09:24:31 [verbose]: Host execution state changed to Stopping [runtime] 2022-06-06 09:24:31 [error]: An unhandled error has occurred. [runtime] 2022-06-06 09:24:31 [error]: System.NullReferenceException: Object reference not set to an instance of an object. [runtime] 2022-06-06 09:24:31 [error]: at osu.Game.Skinning.Editor.SkinEditorOverlay.setTarget(OsuScreen target) in /Users/dean/Projects/osu/osu.Game/Skinning/Editor/SkinEditorOverlay.cs:line 173 [runtime] 2022-06-06 09:24:31 [error]: at osu.Framework.Threading.ScheduledDelegate.RunTaskInternal() [runtime] 2022-06-06 09:24:31 [error]: at osu.Framework.Threading.Scheduler.Update() [runtime] 2022-06-06 09:24:31 [error]: at osu.Framework.Graphics.Drawable.UpdateSubTree() [runtime] 2022-06-06 09:24:31 [error]: at osu.Framework.Graphics.Containers.CompositeDrawable.UpdateSubTree() [runtime] 2022-06-06 09:24:31 [error]: at osu.Framework.Graphics.Containers.CompositeDrawable.UpdateSubTree() [runtime] 2022-06-06 09:24:31 [error]: at osu.Framework.Graphics.Containers.CompositeDrawable.UpdateSubTree() [runtime] 2022-06-06 09:24:31 [error]: at osu.Framework.Graphics.Containers.CompositeDrawable.UpdateSubTree() ``` --- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 497283a820..d4acfd1c4e 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -127,6 +127,9 @@ namespace osu.Game.Skinning.Editor private void setTarget(OsuScreen target) { + if (target == null) + return; + Debug.Assert(skinEditor != null); if (!target.IsLoaded) From a8764b67e1ac962cdbb78d97ddba6ab270167e78 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Jun 2022 18:27:41 +0900 Subject: [PATCH 085/103] Add padding and avoid using invalidation (triggers too often when toolbar is being toggled) --- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 6b4b8abe1a..c96abe3e1e 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -15,6 +15,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Input.Bindings; using osu.Game.Screens; using osu.Game.Screens.Edit.Components; +using osuTK; namespace osu.Game.Skinning.Editor { @@ -36,6 +37,8 @@ namespace osu.Game.Skinning.Editor private OsuScreen lastTargetScreen; + private Vector2 lastDrawSize; + public SkinEditorOverlay(ScalingContainer scalingContainer) { this.scalingContainer = scalingContainer; @@ -92,18 +95,31 @@ namespace osu.Game.Skinning.Editor return base.OnInvalidate(invalidation, source); } + protected override void Update() + { + base.Update(); + + if (game.DrawSize != lastDrawSize) + { + lastDrawSize = game.DrawSize; + updateScreenSizing(); + } + } + private void updateScreenSizing() { if (skinEditor?.State.Value != Visibility.Visible) return; - float relativeSidebarWidth = EditorSidebar.WIDTH / DrawWidth; - float relativeToolbarHeight = (SkinEditorSceneLibrary.HEIGHT + SkinEditor.MENU_HEIGHT) / DrawHeight; + const float padding = 10; + + float relativeSidebarWidth = (EditorSidebar.WIDTH + padding) / DrawWidth; + float relativeToolbarHeight = (SkinEditorSceneLibrary.HEIGHT + SkinEditor.MENU_HEIGHT + padding) / DrawHeight; var rect = new RectangleF( relativeSidebarWidth, relativeToolbarHeight, 1 - relativeSidebarWidth * 2, - 1f - relativeToolbarHeight); + 1f - relativeToolbarHeight - padding / DrawHeight); scalingContainer.SetCustomRect(rect, true); } From 3862681d94d93b1a6642b15d2416d31102a8754b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Jun 2022 19:43:08 +0900 Subject: [PATCH 086/103] Change `skin.ini` boolean parsing to match osu!stable Closes https://github.com/ppy/osu/issues/18579. --- osu.Game/Skinning/LegacySkin.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index b65ba8b04c..9524d3f615 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -303,8 +303,13 @@ namespace osu.Game.Skinning if (Configuration.ConfigDictionary.TryGetValue(lookup.ToString(), out string val)) { // special case for handling skins which use 1 or 0 to signify a boolean state. + // ..or in some cases 2 (https://github.com/ppy/osu/issues/18579). if (typeof(TValue) == typeof(bool)) - val = val == "1" ? "true" : "false"; + { + val = bool.TryParse(val, out bool boolVal) + ? Convert.ChangeType(boolVal, typeof(bool)).ToString() + : Convert.ChangeType(Convert.ToInt32(val), typeof(bool)).ToString(); + } var bindable = new Bindable(); if (val != null) From da000ee5f0f28b162ae5f09054158e62123f03d2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Jun 2022 20:11:43 +0900 Subject: [PATCH 087/103] Centralise video file extensions --- osu.Game/Beatmaps/BeatmapModelManager.cs | 4 ++-- osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapModelManager.cs b/osu.Game/Beatmaps/BeatmapModelManager.cs index 9d3ea7d192..541a78089e 100644 --- a/osu.Game/Beatmaps/BeatmapModelManager.cs +++ b/osu.Game/Beatmaps/BeatmapModelManager.cs @@ -34,7 +34,7 @@ namespace osu.Game.Beatmaps protected override string[] HashableFileTypes => new[] { ".osu" }; - private static readonly string[] video_extensions = { ".mp4", ".mov", ".avi", ".flv" }; + public static readonly string[] VIDEO_EXTENSIONS = { ".mp4", ".mov", ".avi", ".flv" }; public BeatmapModelManager(RealmAccess realm, Storage storage, BeatmapOnlineLookupQueue? onlineLookupQueue = null) : base(realm, storage, onlineLookupQueue) @@ -146,7 +146,7 @@ namespace osu.Game.Beatmaps notification.Text = $"Deleting videos from {HumanisedModelName}s ({++i} of {items.Count})"; - var video = b.Files.FirstOrDefault(f => video_extensions.Any(ex => f.Filename.EndsWith(ex, StringComparison.Ordinal))); + var video = b.Files.FirstOrDefault(f => VIDEO_EXTENSIONS.Any(ex => f.Filename.EndsWith(ex, StringComparison.Ordinal))); if (video != null) DeleteFile(b, video); diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs b/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs index 3d09d09833..d9dbf4974b 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs @@ -2,11 +2,13 @@ // See the LICENCE file in the repository root for full licence text. using System.IO; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; +using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -65,6 +67,9 @@ namespace osu.Game.Graphics.UserInterfaceV2 { get { + if (BeatmapModelManager.VIDEO_EXTENSIONS.Contains(File.Extension)) + return FontAwesome.Regular.FileVideo; + switch (File.Extension) { case @".ogg": @@ -77,12 +82,6 @@ namespace osu.Game.Graphics.UserInterfaceV2 case @".png": return FontAwesome.Regular.FileImage; - case @".mp4": - case @".avi": - case @".mov": - case @".flv": - return FontAwesome.Regular.FileVideo; - default: return FontAwesome.Regular.File; } From b104b7a90d3a50f3c89ac791a8d5bf316a686600 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Jun 2022 20:12:18 +0900 Subject: [PATCH 088/103] Rename method to mention "all" --- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- .../Overlays/Settings/Sections/Maintenance/GeneralSettings.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 92266924df..dba457c81c 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -319,7 +319,7 @@ namespace osu.Game.Beatmaps }); } - public void DeleteVideos() + public void DeleteAllVideos() { realm.Write(r => { diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 37758875ea..054de8dbd7 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance dialogOverlay?.Push(new MassVideoDeleteConfirmationDialog(() => { deleteBeatmapVideosButton.Enabled.Value = false; - Task.Run(beatmaps.DeleteVideos).ContinueWith(t => Schedule(() => deleteBeatmapVideosButton.Enabled.Value = true)); + Task.Run(beatmaps.DeleteAllVideos).ContinueWith(t => Schedule(() => deleteBeatmapVideosButton.Enabled.Value = true)); })); } }); From f96340e37d3d852a67132175dd0bffc70d8b360e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Jun 2022 20:18:32 +0900 Subject: [PATCH 089/103] Improve messaging of deletion progress / completion --- osu.Game/Beatmaps/BeatmapModelManager.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapModelManager.cs b/osu.Game/Beatmaps/BeatmapModelManager.cs index 541a78089e..ed64a43097 100644 --- a/osu.Game/Beatmaps/BeatmapModelManager.cs +++ b/osu.Game/Beatmaps/BeatmapModelManager.cs @@ -130,13 +130,15 @@ namespace osu.Game.Beatmaps { Progress = 0, Text = $"Preparing to delete all {HumanisedModelName} videos...", - CompletionText = $"Deleted all {HumanisedModelName} videos!", + CompletionText = $"No videos found to delete!", State = ProgressNotificationState.Active, }; + if (!silent) PostNotification?.Invoke(notification); int i = 0; + int deleted = 0; foreach (var b in items) { @@ -144,13 +146,18 @@ namespace osu.Game.Beatmaps // user requested abort return; - notification.Text = $"Deleting videos from {HumanisedModelName}s ({++i} of {items.Count})"; - var video = b.Files.FirstOrDefault(f => VIDEO_EXTENSIONS.Any(ex => f.Filename.EndsWith(ex, StringComparison.Ordinal))); - if (video != null) - DeleteFile(b, video); - notification.Progress = (float)i / items.Count; + if (video != null) + { + DeleteFile(b, video); + deleted++; + notification.CompletionText = $"Deleted {deleted} {HumanisedModelName} video(s)!"; + } + + notification.Text = $"Deleting videos from {HumanisedModelName}s ({deleted} deleted)"; + + notification.Progress = (float)++i / items.Count; } notification.State = ProgressNotificationState.Completed; From 3b4b35c51e3618e995058dde2494053d76e704f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Jun 2022 20:18:57 +0900 Subject: [PATCH 090/103] Remove unnecessary string interpolation --- osu.Game/Beatmaps/BeatmapModelManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapModelManager.cs b/osu.Game/Beatmaps/BeatmapModelManager.cs index ed64a43097..277047348e 100644 --- a/osu.Game/Beatmaps/BeatmapModelManager.cs +++ b/osu.Game/Beatmaps/BeatmapModelManager.cs @@ -130,7 +130,7 @@ namespace osu.Game.Beatmaps { Progress = 0, Text = $"Preparing to delete all {HumanisedModelName} videos...", - CompletionText = $"No videos found to delete!", + CompletionText = "No videos found to delete!", State = ProgressNotificationState.Active, }; From 211f0d1e04c5cad2d892dfae2086f1bb299db163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 6 Jun 2022 19:57:08 +0200 Subject: [PATCH 091/103] Expand test coverage for parsing bool skin config values --- .../Skins/TestSceneSkinConfigurationLookup.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs index d3cacaa88c..d68398236a 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs @@ -59,11 +59,13 @@ namespace osu.Game.Tests.Skins AddAssert("Check float parse lookup", () => requester.GetConfig("FloatTest")?.Value == 1.1f); } - [Test] - public void TestBoolLookup() + [TestCase("0", false)] + [TestCase("1", true)] + [TestCase("2", true)] // https://github.com/ppy/osu/issues/18579 + public void TestBoolLookup(string originalValue, bool expectedParsedValue) { - AddStep("Add config values", () => userSource.Configuration.ConfigDictionary["BoolTest"] = "1"); - AddAssert("Check bool parse lookup", () => requester.GetConfig("BoolTest")?.Value == true); + AddStep("Add config values", () => userSource.Configuration.ConfigDictionary["BoolTest"] = originalValue); + AddAssert("Check bool parse lookup", () => requester.GetConfig("BoolTest")?.Value == expectedParsedValue); } [Test] From 0eaf420fa1d20c94b1b867f204294ddbff04a560 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 7 Jun 2022 00:29:14 +0300 Subject: [PATCH 092/103] Specify full size for spinner ticks container --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index a904658a4c..fa095edafa 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -79,7 +79,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { Result = { BindTarget = SpinsPerMinute }, }, - ticks = new Container(), + ticks = new Container + { + RelativeSizeAxes = Axes.Both, + }, new AspectContainer { Anchor = Anchor.Centre, From 4158146c719f6ef3d7f58991b284cf599426d8e5 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 7 Jun 2022 00:29:53 +0300 Subject: [PATCH 093/103] Fix spinenr tick samples not positioned at centre Causing samples to be played at left ear rather than centre. --- .../Objects/Drawables/DrawableSpinnerTick.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs index 726fbd3ea6..39239c8233 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.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. +using osu.Framework.Graphics; + namespace osu.Game.Rulesets.Osu.Objects.Drawables { public class DrawableSpinnerTick : DrawableOsuHitObject @@ -10,13 +12,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected DrawableSpinner DrawableSpinner => (DrawableSpinner)ParentHitObject; public DrawableSpinnerTick() - : base(null) + : this(null) { } public DrawableSpinnerTick(SpinnerTick spinnerTick) : base(spinnerTick) { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; } protected override double MaximumJudgementOffset => DrawableSpinner.HitObject.Duration; From b6e97e699a9f411f07062228697713e9a61b5539 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 7 Jun 2022 00:34:18 +0300 Subject: [PATCH 094/103] Remove unnecessary position specification --- osu.Game.Rulesets.Osu/Objects/Spinner.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs index ddee4d3ebd..1a130e96b3 100644 --- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs @@ -69,8 +69,8 @@ namespace osu.Game.Rulesets.Osu.Objects double startTime = StartTime + (float)(i + 1) / totalSpins * Duration; AddNested(i < SpinsRequired - ? new SpinnerTick { StartTime = startTime, Position = Position } - : new SpinnerBonusTick { StartTime = startTime, Position = Position }); + ? new SpinnerTick { StartTime = startTime } + : new SpinnerBonusTick { StartTime = startTime }); } } From 46eba86ad17f9721c57f66fbb7578b9b8e59695b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 09:29:30 +0900 Subject: [PATCH 095/103] Remove unintended left-over invalidation code --- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index c96abe3e1e..ffd94e0aad 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -4,13 +4,11 @@ using System.Diagnostics; using JetBrains.Annotations; using osu.Framework.Allocation; -using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; -using osu.Framework.Layout; using osu.Game.Graphics.Containers; using osu.Game.Input.Bindings; using osu.Game.Screens; @@ -87,14 +85,6 @@ namespace osu.Game.Skinning.Editor protected override void PopOut() => skinEditor?.Hide(); - protected override bool OnInvalidate(Invalidation invalidation, InvalidationSource source) - { - if (invalidation.HasFlagFast(Invalidation.DrawSize)) - Scheduler.AddOnce(updateScreenSizing); - - return base.OnInvalidate(invalidation, source); - } - protected override void Update() { base.Update(); From 0bfbfc6411afaf3315b151594832f4d62e518a6c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 7 Jun 2022 11:51:24 +0900 Subject: [PATCH 096/103] Update package --- .config/dotnet-tools.json | 2 +- osu.Game/osu.Game.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 65ac05261a..cbd0231fdb 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -21,7 +21,7 @@ ] }, "ppy.localisationanalyser.tools": { - "version": "2022.417.0", + "version": "2022.607.0", "commands": [ "localisation" ] diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ca92d06aed..63b8cf4cb5 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -31,7 +31,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From f576d53aed47845b562360dd77c5d018d5a3cef2 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 7 Jun 2022 11:54:31 +0900 Subject: [PATCH 097/103] Update some unmatching strings --- osu.Game/Localisation/AudioSettingsStrings.cs | 6 +++--- osu.Game/Localisation/GlobalActionKeyBindingStrings.cs | 4 ++-- osu.Game/Localisation/JoystickSettingsStrings.cs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Localisation/AudioSettingsStrings.cs b/osu.Game/Localisation/AudioSettingsStrings.cs index f298717c99..0f0f560df9 100644 --- a/osu.Game/Localisation/AudioSettingsStrings.cs +++ b/osu.Game/Localisation/AudioSettingsStrings.cs @@ -30,12 +30,12 @@ namespace osu.Game.Localisation public static LocalisableString OutputDevice => new TranslatableString(getKey(@"output_device"), @"Output device"); /// - /// "Master" + /// "Hitsound stereo separation" /// public static LocalisableString PositionalLevel => new TranslatableString(getKey(@"positional_hitsound_audio_level"), @"Hitsound stereo separation"); /// - /// "Level" + /// "Master" /// public static LocalisableString MasterVolume => new TranslatableString(getKey(@"master_volume"), @"Master"); @@ -69,6 +69,6 @@ namespace osu.Game.Localisation /// public static LocalisableString OffsetWizard => new TranslatableString(getKey(@"offset_wizard"), @"Offset wizard"); - private static string getKey(string key) => $"{prefix}:{key}"; + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index 586e29a432..82d03dbb5b 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -210,7 +210,7 @@ namespace osu.Game.Localisation public static LocalisableString ToggleInGameInterface => new TranslatableString(getKey(@"toggle_in_game_interface"), @"Toggle in-game interface"); /// - /// "Toggle Mod Select" + /// "Toggle mod select" /// public static LocalisableString ToggleModSelection => new TranslatableString(getKey(@"toggle_mod_selection"), @"Toggle mod select"); @@ -299,6 +299,6 @@ namespace osu.Game.Localisation /// public static LocalisableString ToggleChatFocus => new TranslatableString(getKey(@"toggle_chat_focus"), @"Toggle chat focus"); - private static string getKey(string key) => $"{prefix}:{key}"; + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/JoystickSettingsStrings.cs b/osu.Game/Localisation/JoystickSettingsStrings.cs index 410cd0a6f5..976ec1adde 100644 --- a/osu.Game/Localisation/JoystickSettingsStrings.cs +++ b/osu.Game/Localisation/JoystickSettingsStrings.cs @@ -15,10 +15,10 @@ namespace osu.Game.Localisation public static LocalisableString JoystickGamepad => new TranslatableString(getKey(@"joystick_gamepad"), @"Joystick / Gamepad"); /// - /// "Deadzone Threshold" + /// "Deadzone" /// public static LocalisableString DeadzoneThreshold => new TranslatableString(getKey(@"deadzone_threshold"), @"Deadzone"); private static string getKey(string key) => $@"{prefix}:{key}"; } -} \ No newline at end of file +} From ef5d601f6783ab6e5d0cc452e8a00f142132288e Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Tue, 7 Jun 2022 12:05:03 +0800 Subject: [PATCH 098/103] Fix difficulty name overflow in score panel --- .../Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs | 1 + osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs index 8b646df362..2a31728f87 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs @@ -96,6 +96,7 @@ namespace osu.Game.Tests.Visual.Ranking beatmap.Metadata.Author = author; beatmap.Metadata.Title = "Verrrrrrrrrrrrrrrrrrry looooooooooooooooooooooooong beatmap title"; beatmap.Metadata.Artist = "Verrrrrrrrrrrrrrrrrrry looooooooooooooooooooooooong beatmap artist"; + beatmap.DifficultyName = "Verrrrrrrrrrrrrrrrrrry looooooooooooooooooooooooong difficulty name"; return beatmap; } diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 5b3129dad6..b924fbd5df 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -159,6 +159,8 @@ namespace osu.Game.Screens.Ranking.Expanded Origin = Anchor.TopCentre, Text = beatmap.DifficultyName, Font = OsuFont.Torus.With(size: 16, weight: FontWeight.SemiBold), + MaxWidth = ScorePanel.EXPANDED_WIDTH - padding * 2, + Truncate = true, }, new OsuTextFlowContainer(s => s.Font = OsuFont.Torus.With(size: 12)) { From ac5b1fba1fc5993a61d60cbdcd7e48c20f6809c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 15:36:26 +0900 Subject: [PATCH 099/103] Add blacklisted auto-import rules which conflict with osu!/osu!framework naming --- osu.sln.DotSettings | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 68cf8138e2..286a1eb29f 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -790,6 +790,15 @@ See the LICENCE file in the repository root for full licence text. <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + True + True + True + True + True + True + True + True + True True True True From 8578f12a58a5b4043fa97b512686a227a90b4067 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 7 Jun 2022 18:35:10 +0900 Subject: [PATCH 100/103] Fix taiko circle fills missing after rewind --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 504b10e9bc..2dd332fc13 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; +using osu.Framework.Graphics.Primitives; using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Judgements; @@ -321,12 +322,14 @@ namespace osu.Game.Rulesets.Taiko.UI private class ProxyContainer : LifetimeManagementContainer { - public new MarginPadding Padding - { - set => base.Padding = value; - } - public void Add(Drawable proxy) => AddInternal(proxy); + + public override bool UpdateSubTreeMasking(Drawable source, RectangleF maskingBounds) + { + // DrawableHitObject disables masking. + // Hitobject content is proxied and unproxied based on hit status and the IsMaskedAway value could get stuck because of this. + return false; + } } } } From 2e0b8884105f977ed6cfc2d582a7aca1796bf004 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Jun 2022 16:31:58 +0900 Subject: [PATCH 101/103] Fix song select carousel invalidating every frame during global overlay dimming --- osu.Game/Screens/Select/BeatmapCarousel.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index a59f14647d..8a588c519b 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -10,6 +10,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Caching; +using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; @@ -633,7 +634,7 @@ namespace osu.Game.Screens.Select protected override bool OnInvalidate(Invalidation invalidation, InvalidationSource source) { // handles the vertical size of the carousel changing (ie. on window resize when aspect ratio has changed). - if ((invalidation & Invalidation.Layout) > 0) + if (invalidation.HasFlagFast(Invalidation.DrawSize)) itemsCache.Invalidate(); return base.OnInvalidate(invalidation, source); From c69d53df0035ed1a469233cbbcd145ca706979ad Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 8 Jun 2022 04:29:48 +0300 Subject: [PATCH 102/103] Add failing test case --- .../Visual/Online/TestSceneMessageNotifier.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 79f62a16e3..5f7c8b3c51 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; @@ -178,6 +179,36 @@ namespace osu.Game.Tests.Visual.Online AddAssert("1 notification fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 1); } + /// + /// Ensures that handles channels which have not been or could not be resolved (i.e. = 0). + /// + [Test] + public void TestSendInUnresolvedChannel() + { + int i = 1; + Channel unresolved = null; + + AddRepeatStep("join unresolved channels", () => testContainer.ChannelManager.JoinChannel(unresolved = new Channel(new APIUser + { + Id = 100 + i, + Username = $"Foreign #{i++}", + })), 5); + + AddStep("send message in unresolved channel", () => + { + Debug.Assert(unresolved.Id == 0); + + unresolved.AddLocalEcho(new LocalEchoMessage + { + Sender = API.LocalUser.Value, + ChannelId = unresolved.Id, + Content = "Some message", + }); + }); + + AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0); + } + private void receiveMessage(APIUser sender, Channel channel, string content) => channel.AddNewMessages(createMessage(sender, channel, content)); private Message createMessage(APIUser sender, Channel channel, string content) => new Message(messageIdCounter++) From 830ff666888e2d82303c38e6284553e1c169c698 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 8 Jun 2022 04:31:31 +0300 Subject: [PATCH 103/103] Fix message notifier not handling unresolved PM channels --- osu.Game/Online/Chat/MessageNotifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index ca6082e19b..fbc5ef79ef 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -77,7 +77,7 @@ namespace osu.Game.Online.Chat if (!messages.Any()) return; - var channel = channelManager.JoinedChannels.SingleOrDefault(c => c.Id == messages.First().ChannelId); + var channel = channelManager.JoinedChannels.SingleOrDefault(c => c.Id > 0 && c.Id == messages.First().ChannelId); if (channel == null) return;