diff --git a/README.md b/README.md index 19aba5a31f..55f2eebec9 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ If the build fails, try to restore nuget packages with `dotnet restore`. On Linux, the environment variable `LD_LIBRARY_PATH` must point to the build directory, located at `osu.Desktop/bin/Debug/$NETCORE_VERSION`. -`$NETCORE_VERSION` is the version of .NET Core SDK. You can have it with `grep TargetFramework osu.Desktop/osu.Desktop.csproj | sed -r 's/.*>(.*)<\/.*/\1/'`. +`$NETCORE_VERSION` is the version of the targeted .NET Core SDK. You can check it by running `grep TargetFramework osu.Desktop/osu.Desktop.csproj | sed -r 's/.*>(.*)<\/.*/\1/'`. For example, you can run osu! with the following command: diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index d72c334ed3..893c7875fa 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -73,7 +74,10 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor { case OsuAction.LeftButton: case OsuAction.RightButton: - if (--downCount == 0) + // Todo: Math.Max() is required as a temporary measure to address https://github.com/ppy/osu-framework/issues/2576 + downCount = Math.Max(0, downCount - 1); + + if (downCount == 0) updateExpandedState(); break; } diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index 8245de9f70..81381d75ed 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osuTK; @@ -97,6 +98,8 @@ namespace osu.Game.Graphics.UserInterface protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuDropdownMenuItem(item) { AccentColour = accentColour }; + protected override ScrollContainer CreateScrollContainer(Direction direction) => new OsuScrollContainer(direction); + #region DrawableOsuDropdownMenuItem public class DrawableOsuDropdownMenuItem : DrawableDropdownMenuItem, IHasAccentColour @@ -247,8 +250,8 @@ namespace osu.Game.Graphics.UserInterface Icon = FontAwesome.Solid.ChevronDown, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Margin = new MarginPadding { Right = 4 }, - Size = new Vector2(20), + Margin = new MarginPadding { Right = 5 }, + Size = new Vector2(12), }, }; diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs index f8234cb81f..c4c6950eb1 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osuTK; @@ -46,6 +47,8 @@ namespace osu.Game.Graphics.UserInterface protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuMenuItem(item); + protected override ScrollContainer CreateScrollContainer(Direction direction) => new OsuScrollContainer(direction); + protected override Menu CreateSubMenu() => new OsuMenu(Direction.Vertical) { Anchor = Direction == Direction.Horizontal ? Anchor.BottomLeft : Anchor.TopRight diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 904aa9c8c0..14d356f889 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -95,9 +95,6 @@ namespace osu.Game.Input.Bindings [Description("Quick retry (hold)")] QuickRetry, - [Description("Quick exit (Hold)")] - QuickExit, - [Description("Take screenshot")] TakeScreenshot, @@ -115,5 +112,8 @@ namespace osu.Game.Input.Bindings [Description("Select")] Select, + + [Description("Quick exit (Hold)")] + QuickExit, } } diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index 96f3b85272..e8eff5a3a9 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -88,7 +88,12 @@ namespace osu.Game.Online.API if (checkAndScheduleFailure()) return; - API.Schedule(delegate { Success?.Invoke(); }); + API.Schedule(delegate + { + if (cancelled) return; + + Success?.Invoke(); + }); } public void Cancel() => Fail(new OperationCanceledException(@"Request cancelled")); diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index fb6c50d867..bc006f1375 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; -using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -40,6 +39,10 @@ namespace osu.Game.Overlays.BeatmapSet private readonly FavouriteButton favouriteButton; + private readonly FillFlowContainer fadeContent; + + private readonly LoadingAnimation loading; + public Header() { ExternalLinkButton externalLink; @@ -96,8 +99,7 @@ namespace osu.Game.Overlays.BeatmapSet }, new Container { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Top = 20, @@ -105,63 +107,71 @@ namespace osu.Game.Overlays.BeatmapSet Left = BeatmapSetOverlay.X_PADDING, Right = BeatmapSetOverlay.X_PADDING + BeatmapSetOverlay.RIGHT_WIDTH, }, - Child = new FillFlowContainer + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] + fadeContent = new FillFlowContainer { - new Container + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Child = Picker = new BeatmapPicker(), - }, - new FillFlowContainer - { - Direction = FillDirection.Horizontal, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] + new Container { - title = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 37, weight: FontWeight.Bold, italics: true) - }, - externalLink = new ExternalLinkButton - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Margin = new MarginPadding { Left = 3, Bottom = 4 }, //To better lineup with the font - }, - } - }, - artist = new OsuSpriteText { Font = OsuFont.GetFont(size: 25, weight: FontWeight.SemiBold, italics: true) }, - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Top = 20 }, - Child = author = new AuthorInfo(), - }, - new Container - { - RelativeSizeAxes = Axes.X, - Height = buttons_height, - Margin = new MarginPadding { Top = 10 }, - Children = new Drawable[] + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = Picker = new BeatmapPicker(), + }, + new FillFlowContainer { - favouriteButton = new FavouriteButton(), - downloadButtonsContainer = new FillFlowContainer + Direction = FillDirection.Horizontal, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = buttons_height + buttons_spacing }, - Spacing = new Vector2(buttons_spacing), + title = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 37, weight: FontWeight.Bold, italics: true) + }, + externalLink = new ExternalLinkButton + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Margin = new MarginPadding { Left = 3, Bottom = 4 }, //To better lineup with the font + }, + } + }, + artist = new OsuSpriteText { Font = OsuFont.GetFont(size: 25, weight: FontWeight.SemiBold, italics: true) }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding { Top = 20 }, + Child = author = new AuthorInfo(), + }, + new Container + { + RelativeSizeAxes = Axes.X, + Height = buttons_height, + Margin = new MarginPadding { Top = 10 }, + Children = new Drawable[] + { + favouriteButton = new FavouriteButton(), + downloadButtonsContainer = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = buttons_height + buttons_spacing }, + Spacing = new Vector2(buttons_spacing), + }, }, }, }, }, - }, + loading = new LoadingAnimation + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + } }, new FillFlowContainer { @@ -187,8 +197,11 @@ namespace osu.Game.Overlays.BeatmapSet }, }; - Picker.Beatmap.ValueChanged += b => Details.Beatmap = b.NewValue; - Picker.Beatmap.ValueChanged += b => externalLink.Link = $@"https://osu.ppy.sh/beatmapsets/{BeatmapSet.Value?.OnlineBeatmapSetID}#{b.NewValue?.Ruleset.ShortName}/{b.NewValue?.OnlineBeatmapID}"; + Picker.Beatmap.ValueChanged += b => + { + Details.Beatmap = b.NewValue; + externalLink.Link = $@"https://osu.ppy.sh/beatmapsets/{BeatmapSet.Value?.OnlineBeatmapSetID}#{b.NewValue?.Ruleset.ShortName}/{b.NewValue?.OnlineBeatmapID}"; + }; } [BackgroundDependencyLoader] @@ -201,24 +214,35 @@ namespace osu.Game.Overlays.BeatmapSet BeatmapSet.BindValueChanged(setInfo => { Picker.BeatmapSet = author.BeatmapSet = Details.BeatmapSet = setInfo.NewValue; - - title.Text = setInfo.NewValue?.Metadata.Title ?? string.Empty; - artist.Text = setInfo.NewValue?.Metadata.Artist ?? string.Empty; - onlineStatusPill.Status = setInfo.NewValue?.OnlineInfo.Status ?? BeatmapSetOnlineStatus.None; cover.BeatmapSet = setInfo.NewValue; - if (setInfo.NewValue != null) - { - downloadButtonsContainer.FadeIn(transition_duration); - favouriteButton.FadeIn(transition_duration); - } - else + if (setInfo.NewValue == null) { + onlineStatusPill.FadeTo(0.5f, 500, Easing.OutQuint); + fadeContent.Hide(); + + loading.Show(); + downloadButtonsContainer.FadeOut(transition_duration); favouriteButton.FadeOut(transition_duration); } + else + { + fadeContent.FadeIn(500, Easing.OutQuint); - updateDownloadButtons(); + loading.Hide(); + + title.Text = setInfo.NewValue.Metadata.Title ?? string.Empty; + artist.Text = setInfo.NewValue.Metadata.Artist ?? string.Empty; + + onlineStatusPill.FadeIn(500, Easing.OutQuint); + onlineStatusPill.Status = setInfo.NewValue.OnlineInfo.Status; + + downloadButtonsContainer.FadeIn(transition_duration); + favouriteButton.FadeIn(transition_duration); + + updateDownloadButtons(); + } }, true); } diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs index 5ee143850f..1d9c4e7fc8 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs @@ -53,7 +53,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Size = new Vector2(40), FillMode = FillMode.Fit, }, - avatar = new UpdateableAvatar + avatar = new UpdateableAvatar(hideImmediately: true) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -90,7 +90,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Origin = Anchor.CentreLeft, Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold) }, - flag = new UpdateableFlag + flag = new UpdateableFlag(hideImmediately: true) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs index 7f7545eee3..2c25808170 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs @@ -73,7 +73,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio private class AudioDeviceSettingsDropdown : SettingsDropdown { - protected override OsuDropdown CreateDropdown() => new AudioDeviceDropdownControl { Items = Items }; + protected override OsuDropdown CreateDropdown() => new AudioDeviceDropdownControl(); private class AudioDeviceDropdownControl : DropdownControl { diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 36c4fb5252..f4de4c0c41 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -237,7 +237,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics private class ResolutionSettingsDropdown : SettingsDropdown { - protected override OsuDropdown CreateDropdown() => new ResolutionDropdownControl { Items = Items }; + protected override OsuDropdown CreateDropdown() => new ResolutionDropdownControl(); private class ResolutionDropdownControl : DropdownControl { diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 100022bd13..51c687314a 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -108,7 +108,7 @@ namespace osu.Game.Overlays.Settings.Sections private class SkinSettingsDropdown : SettingsDropdown { - protected override OsuDropdown CreateDropdown() => new SkinDropdownControl { Items = Items }; + protected override OsuDropdown CreateDropdown() => new SkinDropdownControl(); private class SkinDropdownControl : DropdownControl { diff --git a/osu.Game/Overlays/Settings/SettingsDropdown.cs b/osu.Game/Overlays/Settings/SettingsDropdown.cs index de3f741cd7..167061f485 100644 --- a/osu.Game/Overlays/Settings/SettingsDropdown.cs +++ b/osu.Game/Overlays/Settings/SettingsDropdown.cs @@ -13,39 +13,23 @@ namespace osu.Game.Overlays.Settings { protected new OsuDropdown Control => (OsuDropdown)base.Control; - private IEnumerable items = Enumerable.Empty(); - public IEnumerable Items { - get => items; - set - { - items = value; - - if (Control != null) - Control.Items = value; - } + get => Control.Items; + set => Control.Items = value; } - private IBindableList itemSource; - public IBindableList ItemSource { - get => itemSource; - set - { - itemSource = value; - - if (Control != null) - Control.ItemSource = value; - } + get => Control.ItemSource; + set => Control.ItemSource = value; } public override IEnumerable FilterTerms => base.FilterTerms.Concat(Control.Items.Select(i => i.ToString())); protected sealed override Drawable CreateControl() => CreateDropdown(); - protected virtual OsuDropdown CreateDropdown() => new DropdownControl { Items = Items, ItemSource = ItemSource }; + protected virtual OsuDropdown CreateDropdown() => new DropdownControl(); protected class DropdownControl : OsuDropdown { diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 9de9f5cec8..681ce701d0 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -247,6 +247,7 @@ namespace osu.Game.Screens.Play public override void OnSuspending(IScreen next) { + BackgroundBrightnessReduction = false; base.OnSuspending(next); cancelLoad(); } @@ -258,6 +259,7 @@ namespace osu.Game.Screens.Play cancelLoad(); Background.EnableUserDim.Value = false; + BackgroundBrightnessReduction = false; return base.OnExiting(next); } @@ -273,6 +275,22 @@ namespace osu.Game.Screens.Play } } + private bool backgroundBrightnessReduction; + + protected bool BackgroundBrightnessReduction + { + get => backgroundBrightnessReduction; + set + { + if (value == backgroundBrightnessReduction) + return; + + backgroundBrightnessReduction = value; + + Background.FadeColour(OsuColour.Gray(backgroundBrightnessReduction ? 0.8f : 1), 200); + } + } + protected override void Update() { base.Update(); @@ -287,12 +305,16 @@ namespace osu.Game.Screens.Play // Preview user-defined background dim and blur when hovered on the visual settings panel. Background.EnableUserDim.Value = true; Background.BlurAmount.Value = 0; + + BackgroundBrightnessReduction = false; } else { // Returns background dim and blur to the values specified by PlayerLoader. Background.EnableUserDim.Value = false; Background.BlurAmount.Value = BACKGROUND_BLUR; + + BackgroundBrightnessReduction = true; } } diff --git a/osu.Game/Users/Drawables/UpdateableAvatar.cs b/osu.Game/Users/Drawables/UpdateableAvatar.cs index 795b90ba11..a49f2d079b 100644 --- a/osu.Game/Users/Drawables/UpdateableAvatar.cs +++ b/osu.Game/Users/Drawables/UpdateableAvatar.cs @@ -5,6 +5,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Transforms; namespace osu.Game.Users.Drawables { @@ -37,6 +38,8 @@ namespace osu.Game.Users.Drawables set => base.EdgeEffect = value; } + protected override bool TransformImmediately { get; } + /// /// Whether to show a default guest representation on null user (as opposed to nothing). /// @@ -47,11 +50,14 @@ namespace osu.Game.Users.Drawables /// public readonly BindableBool OpenOnClick = new BindableBool(true); - public UpdateableAvatar(User user = null) + public UpdateableAvatar(User user = null, bool hideImmediately = false) { + TransformImmediately = hideImmediately; User = user; } + protected override TransformSequence ApplyHideTransforms(Drawable drawable) => TransformImmediately ? drawable?.FadeOut() : base.ApplyHideTransforms(drawable); + protected override Drawable CreateDrawable(User user) { if (user == null && !ShowGuestOnNull) diff --git a/osu.Game/Users/Drawables/UpdateableFlag.cs b/osu.Game/Users/Drawables/UpdateableFlag.cs index abc16b2390..78d1a8de20 100644 --- a/osu.Game/Users/Drawables/UpdateableFlag.cs +++ b/osu.Game/Users/Drawables/UpdateableFlag.cs @@ -3,6 +3,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Transforms; namespace osu.Game.Users.Drawables { @@ -14,16 +15,21 @@ namespace osu.Game.Users.Drawables set => Model = value; } + protected override bool TransformImmediately { get; } + /// /// Whether to show a place holder on null country. /// public bool ShowPlaceholderOnNull = true; - public UpdateableFlag(Country country = null) + public UpdateableFlag(Country country = null, bool hideImmediately = false) { + TransformImmediately = hideImmediately; Country = country; } + protected override TransformSequence ApplyHideTransforms(Drawable drawable) => TransformImmediately ? drawable?.FadeOut() : base.ApplyHideTransforms(drawable); + protected override Drawable CreateDrawable(Country country) { if (country == null && !ShowPlaceholderOnNull) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 563e90cec9..b4af007447 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -15,7 +15,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index a36638cf84..9f21af05a1 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -105,8 +105,8 @@ - - + +