1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-13 17:13:06 +08:00

Merge pull request #17926 from peppy/first-run-behaviour-screen

Add first-run "behaviour" screen to allow users a choice of more familiar UX
This commit is contained in:
Dan Balasescu 2022-04-29 11:21:14 +09:00 committed by GitHub
commit 7097ce6501
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 234 additions and 5 deletions

View File

@ -33,6 +33,7 @@ namespace osu.Game.Rulesets.Osu.UI
},
new SettingsCheckbox
{
ClassicDefault = false,
LabelText = "Snaking out sliders",
Current = config.GetBindable<bool>(OsuRulesetSetting.SnakingOutSliders)
},

View File

@ -0,0 +1,24 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Screens;
using osu.Game.Overlays;
using osu.Game.Overlays.FirstRunSetup;
namespace osu.Game.Tests.Visual.UserInterface
{
public class TestSceneFirstRunScreenBehaviour : OsuManualInputManagerTestScene
{
[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
public TestSceneFirstRunScreenBehaviour()
{
AddStep("load screen", () =>
{
Child = new ScreenStack(new ScreenBehaviour());
});
}
}
}

View File

@ -17,7 +17,8 @@ namespace osu.Game.Localisation
/// <summary>
/// "Click to resume first-run setup at any point"
/// </summary>
public static LocalisableString ClickToResumeFirstRunSetupAtAnyPoint => new TranslatableString(getKey(@"click_to_resume_first_run_setup_at_any_point"), @"Click to resume first-run setup at any point");
public static LocalisableString ClickToResumeFirstRunSetupAtAnyPoint =>
new TranslatableString(getKey(@"click_to_resume_first_run_setup_at_any_point"), @"Click to resume first-run setup at any point");
/// <summary>
/// "First-run setup"
@ -48,6 +49,31 @@ osu! is a very configurable game, and diving straight into the settings can some
/// </summary>
public static LocalisableString UIScaleDescription => new TranslatableString(getKey(@"ui_scale_description"), @"The size of the osu! user interface can be adjusted to your liking.");
/// <summary>
/// "Behaviour"
/// </summary>
public static LocalisableString Behaviour => new TranslatableString(getKey(@"behaviour"), @"Behaviour");
/// <summary>
/// "Some new defaults for game behaviours have been implemented, with the aim of improving the game experience and making it more accessible to everyone.
///
/// We recommend you give the new defaults a try, but if you&#39;d like to have things feel more like classic versions of osu!, you can easily apply some sane defaults below."
/// </summary>
public static LocalisableString BehaviourDescription => new TranslatableString(getKey(@"behaviour_description"),
@"Some new defaults for game behaviours have been implemented, with the aim of improving the game experience and making it more accessible to everyone.
We recommend you give the new defaults a try, but if you'd like to have things feel more like classic versions of osu!, you can easily apply some sane defaults below.");
/// <summary>
/// "New defaults"
/// </summary>
public static LocalisableString NewDefaults => new TranslatableString(getKey(@"new_defaults"), @"New defaults");
/// <summary>
/// "Classic defaults"
/// </summary>
public static LocalisableString ClassicDefaults => new TranslatableString(getKey(@"classic_defaults"), @"Classic defaults");
private static string getKey(string key) => $@"{prefix}:{key}";
}
}

View File

@ -30,6 +30,7 @@ namespace osu.Game.Overlays.FirstRunSetup
new OsuScrollContainer(Direction.Vertical)
{
RelativeSizeAxes = Axes.Both,
ScrollbarOverlapsContent = false,
Children = new Drawable[]
{
new OsuSpriteText

View File

@ -0,0 +1,109 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation;
using osu.Framework.Testing;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings;
using osu.Game.Overlays.Settings.Sections;
namespace osu.Game.Overlays.FirstRunSetup
{
[LocalisableDescription(typeof(FirstRunSetupOverlayStrings), nameof(FirstRunSetupOverlayStrings.Behaviour))]
public class ScreenBehaviour : FirstRunSetupScreen
{
private SearchContainer<SettingsSection> searchContainer;
[BackgroundDependencyLoader]
private void load()
{
Content.Children = new Drawable[]
{
new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 24))
{
Text = FirstRunSetupOverlayStrings.BehaviourDescription,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y
},
new GridContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
ColumnDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.Absolute, 10),
new Dimension(),
},
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize),
},
Content = new[]
{
new[]
{
new TriangleButton
{
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
Text = FirstRunSetupOverlayStrings.NewDefaults,
RelativeSizeAxes = Axes.X,
Action = applyStandard,
},
Empty(),
new DangerousTriangleButton
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Text = FirstRunSetupOverlayStrings.ClassicDefaults,
RelativeSizeAxes = Axes.X,
Action = applyClassic
}
},
},
},
searchContainer = new SearchContainer<SettingsSection>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new SettingsSection[]
{
// This list should be kept in sync with SettingsOverlay.
new GeneralSection(),
new SkinSection(),
// InputSection is intentionally omitted for now due to its sub-panel being a pain to set up.
new UserInterfaceSection(),
new GameplaySection(),
new RulesetSection(),
new AudioSection(),
new GraphicsSection(),
new OnlineSection(),
new MaintenanceSection(),
new DebugSection(),
},
SearchTerm = SettingsItem<bool>.CLASSIC_DEFAULT_SEARCH_TERM,
}
};
}
private void applyClassic()
{
foreach (var i in searchContainer.ChildrenOfType<ISettingsItem>().Where(s => s.HasClassicDefault))
i.ApplyClassicDefault();
}
private void applyStandard()
{
foreach (var i in searchContainer.ChildrenOfType<ISettingsItem>().Where(s => s.HasClassicDefault))
i.ApplyDefault();
}
}
}

View File

@ -60,7 +60,8 @@ namespace osu.Game.Overlays
private readonly Type[] steps =
{
typeof(ScreenWelcome),
typeof(ScreenUIScale)
typeof(ScreenUIScale),
typeof(ScreenBehaviour),
};
private Container stackContainer = null!;

View File

@ -9,5 +9,20 @@ namespace osu.Game.Overlays.Settings
public interface ISettingsItem : IDrawable, IDisposable
{
event Action SettingChanged;
/// <summary>
/// Whether this setting has a classic default (ie. a different default which better aligns with osu-stable expectations).
/// </summary>
bool HasClassicDefault { get; }
/// <summary>
/// Apply the classic default value of the associated setting. Will throw if <see cref="HasClassicDefault"/> is <c>false</c>.
/// </summary>
void ApplyClassicDefault();
/// <summary>
/// Apply the default value of the associated setting.
/// </summary>
void ApplyDefault();
}
}

View File

@ -28,6 +28,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
},
new SettingsCheckbox
{
ClassicDefault = false,
LabelText = GameplaySettingsStrings.AlwaysPlayFirstComboBreak,
Current = config.GetBindable<bool>(OsuSetting.AlwaysPlayFirstComboBreak)
}

View File

@ -21,6 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
{
new SettingsEnumDropdown<ScoringMode>
{
ClassicDefault = ScoringMode.Classic,
LabelText = GameplaySettingsStrings.ScoreDisplayMode,
Current = config.GetBindable<ScoringMode>(OsuSetting.ScoreDisplayMode),
Keywords = new[] { "scoring" }

View File

@ -30,6 +30,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
},
new SettingsCheckbox
{
ClassicDefault = false,
LabelText = GameplaySettingsStrings.ShowHealthDisplayWhenCantFail,
Current = config.GetBindable<bool>(OsuSetting.ShowHealthDisplayWhenCantFail),
Keywords = new[] { "hp", "bar" }

View File

@ -37,6 +37,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
},
new SettingsSlider<double, TimeSlider>
{
ClassicDefault = 0,
LabelText = UserInterfaceStrings.HoldToConfirmActivationTime,
Current = config.GetBindable<double>(OsuSetting.UIHoldActivationDelay),
Keywords = new[] { @"delay" },

View File

@ -32,6 +32,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
{
new SettingsCheckbox
{
ClassicDefault = true,
LabelText = UserInterfaceStrings.RightMouseScroll,
Current = config.GetBindable<bool>(OsuSetting.SongSelectRightMouseScroll),
},

View File

@ -30,6 +30,8 @@ namespace osu.Game.Overlays.Settings
/// </summary>
public object SettingSourceObject { get; internal set; }
public const string CLASSIC_DEFAULT_SEARCH_TERM = @"has-classic-default";
private IHasCurrentValue<T> controlWithCurrent => Control as IHasCurrentValue<T>;
protected override Container<Drawable> Content => FlowContent;
@ -96,7 +98,21 @@ namespace osu.Game.Overlays.Settings
set => controlWithCurrent.Current = value;
}
public virtual IEnumerable<string> FilterTerms => Keywords == null ? new[] { LabelText.ToString() } : new List<string>(Keywords) { LabelText.ToString() }.ToArray();
public virtual IEnumerable<string> FilterTerms
{
get
{
var keywords = new List<string>(Keywords ?? Array.Empty<string>())
{
LabelText.ToString()
};
if (HasClassicDefault)
keywords.Add(CLASSIC_DEFAULT_SEARCH_TERM);
return keywords;
}
}
public IEnumerable<string> Keywords { get; set; }
@ -122,6 +138,32 @@ namespace osu.Game.Overlays.Settings
public event Action SettingChanged;
private T classicDefault;
public bool HasClassicDefault { get; private set; }
/// <summary>
/// A "classic" default value for this setting.
/// </summary>
public T ClassicDefault
{
set
{
classicDefault = value;
HasClassicDefault = true;
}
}
public void ApplyClassicDefault()
{
if (!HasClassicDefault)
throw new InvalidOperationException($"Cannot apply a classic default to a setting which doesn't have one defined via {nameof(ClassicDefault)}.");
Current.Value = classicDefault;
}
public void ApplyDefault() => Current.SetDefault();
protected SettingsItem()
{
RelativeSizeAxes = Axes.X;

View File

@ -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 osu.Framework.Allocation;
using osu.Framework.Bindables;
@ -58,7 +59,7 @@ namespace osu.Game.Overlays.Settings
public bool FilteringActive { get; set; }
[Resolved]
[Resolved(canBeNull: true)]
private SettingsPanel settingsPanel { get; set; }
protected SettingsSection()
@ -131,7 +132,7 @@ namespace osu.Game.Overlays.Settings
},
});
selectedSection = settingsPanel.CurrentSection.GetBoundCopy();
selectedSection = settingsPanel?.CurrentSection.GetBoundCopy() ?? new Bindable<SettingsSection>(this);
selectedSection.BindValueChanged(_ => updateContentFade(), true);
}
@ -152,7 +153,10 @@ namespace osu.Game.Overlays.Settings
protected override bool OnClick(ClickEvent e)
{
if (!isCurrentSection)
{
Debug.Assert(settingsPanel != null);
settingsPanel.SectionsContainer.ScrollTo(this);
}
return base.OnClick(e);
}

View File

@ -23,6 +23,7 @@ namespace osu.Game.Overlays
protected override IEnumerable<SettingsSection> CreateSections() => new SettingsSection[]
{
// This list should be kept in sync with ScreenBehaviour.
new GeneralSection(),
new SkinSection(),
new InputSection(createSubPanel(new KeyBindingPanel())),