1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-17 17:33:02 +08:00

Merge pull request #35757 from peppy/settings-wank

Adjust settings buttons and general section to feel better
This commit is contained in:
Bartłomiej Dach
2025-11-25 08:46:00 +01:00
committed by GitHub
Unverified
17 changed files with 239 additions and 191 deletions
@@ -121,7 +121,7 @@ namespace osu.Game.Tests.Visual.Settings
AddStep("schedule button clicks", () =>
{
var clearButton = firstRow.ChildrenOfType<KeyBindingRow.ClearButton>().Single();
var clearButton = firstRow.ChildrenOfType<DangerousRoundedButton>().Single();
InputManager.MoveMouseTo(clearButton);
@@ -179,7 +179,7 @@ namespace osu.Game.Tests.Visual.Settings
{
AddStep("click clear button", () =>
{
var clearButton = multiBindingRow.ChildrenOfType<KeyBindingRow.ClearButton>().Single();
var clearButton = multiBindingRow.ChildrenOfType<DangerousRoundedButton>().Single();
InputManager.MoveMouseTo(clearButton);
InputManager.Click(MouseButton.Left);
@@ -386,7 +386,7 @@ namespace osu.Game.Tests.Visual.Settings
AddStep("clear binding", () =>
{
var row = panel.ChildrenOfType<KeyBindingRow>().First(r => r.ChildrenOfType<OsuSpriteText>().Any(s => s.Text.ToString() == "Left (centre)"));
row.ChildrenOfType<KeyBindingRow.ClearButton>().Single().TriggerClick();
row.ChildrenOfType<DangerousRoundedButton>().Single().TriggerClick();
});
scrollToAndStartBinding("Left (rim)");
AddStep("bind M1", () => InputManager.Click(MouseButton.Left));
@@ -462,7 +462,7 @@ namespace osu.Game.Tests.Visual.Settings
AddStep("clear binding", () =>
{
var row = panel.ChildrenOfType<KeyBindingRow>().First(r => r.ChildrenOfType<OsuSpriteText>().Any(s => s.Text.ToString() == "Left (centre)"));
row.ChildrenOfType<KeyBindingRow.ClearButton>().Single().TriggerClick();
row.ChildrenOfType<DangerousRoundedButton>().Single().TriggerClick();
});
}
@@ -6,7 +6,7 @@ using osu.Game.Graphics.UserInterfaceV2;
namespace osu.Game.Graphics.UserInterface
{
public partial class DangerousRoundedButton : RoundedButton
public sealed partial class DangerousRoundedButton : RoundedButton
{
[BackgroundDependencyLoader]
private void load(OsuColour colours)
@@ -56,7 +56,8 @@ namespace osu.Game.Graphics.UserInterface
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
CornerRadius = 5,
CornerRadius = 10,
CornerExponent = 2.5f,
Masking = true,
EdgeEffect = new EdgeEffectParameters
{
@@ -357,7 +357,8 @@ namespace osu.Game.Graphics.UserInterface
Icon = FontAwesome.Solid.ChevronDown,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Size = new Vector2(16),
Size = new Vector2(10),
Margin = new MarginPadding { Right = 2 },
},
}
}
@@ -178,7 +178,8 @@ namespace osu.Game.Graphics.UserInterfaceV2
Size = new Vector2(70);
Masking = true;
CornerRadius = 35;
CornerRadius = 10;
CornerExponent = 2.5f;
Action = this.ShowPopover;
Children = new Drawable[]
@@ -26,18 +26,6 @@ namespace osu.Game.Graphics.UserInterfaceV2
private Color4? triangleGradientSecondColour;
public override float Height
{
get => base.Height;
set
{
base.Height = value;
if (IsLoaded)
updateCornerRadius();
}
}
public override Color4 BackgroundColour
{
get => base.BackgroundColour;
@@ -61,7 +49,10 @@ namespace osu.Game.Graphics.UserInterfaceV2
{
base.LoadComplete();
updateCornerRadius();
// This doesn't match the latest design spec (should be 5) but is an in-between that feels right to the eye
// until we move everything over to Form controls.
Content.CornerRadius = 10;
Content.CornerExponent = 2.5f;
Add(Triangles = new TrianglesV2
{
@@ -98,8 +89,6 @@ namespace osu.Game.Graphics.UserInterfaceV2
base.OnHoverLost(e);
}
private void updateCornerRadius() => Content.CornerRadius = DrawHeight / 2;
public virtual IEnumerable<LocalisableString> FilterTerms => new[] { Text };
public bool MatchingFilter
@@ -29,6 +29,16 @@ namespace osu.Game.Localisation
/// </summary>
public static LocalisableString Prefer24HourTimeDisplay => new TranslatableString(getKey(@"prefer_24_hour_time_display"), @"Prefer 24-hour time display");
/// <summary>
/// "Installation"
/// </summary>
public static LocalisableString InstallationHeader => new TranslatableString(getKey(@"installation_header"), @"Installation");
/// <summary>
/// "Quick Actions"
/// </summary>
public static LocalisableString QuickActionsHeader => new TranslatableString(getKey(@"quick_actions_header"), @"Quick Actions");
/// <summary>
/// "Updates"
/// </summary>
@@ -0,0 +1,37 @@
// 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.Localisation;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings.Sections.Maintenance;
namespace osu.Game.Overlays.Settings.Sections.General
{
public partial class InstallationSettings : SettingsSubsection
{
protected override LocalisableString Header => GeneralSettingsStrings.InstallationHeader;
[Resolved]
private OsuGame? game { get; set; }
[BackgroundDependencyLoader]
private void load(Storage storage)
{
Add(new SettingsButton
{
Text = GeneralSettingsStrings.OpenOsuFolder,
Keywords = new[] { @"logs", @"files", @"access", "directory" },
Action = () => storage.PresentExternally(),
});
Add(new DangerousSettingsButton
{
Text = GeneralSettingsStrings.ChangeFolderLocation,
Action = () => game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen()))
});
}
}
}
@@ -0,0 +1,125 @@
// 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.Threading.Tasks;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Statistics;
using osu.Game.Graphics;
using osu.Game.IO;
using osu.Game.Localisation;
using osu.Game.Online.Chat;
using osu.Game.Overlays.Notifications;
using osu.Game.Utils;
using SharpCompress.Archives.Zip;
namespace osu.Game.Overlays.Settings.Sections.General
{
public partial class QuickActionSettings : SettingsSubsection
{
[Resolved(CanBeNull = true)]
private FirstRunSetupOverlay? firstRunSetupOverlay { get; set; }
[Resolved(CanBeNull = true)]
private OsuGame? game { get; set; }
protected override LocalisableString Header => GeneralSettingsStrings.QuickActionsHeader;
[BackgroundDependencyLoader]
private void load(OsuColour colours, Storage storage)
{
AddRange(new Drawable[]
{
new SettingsButton
{
Text = GeneralSettingsStrings.RunSetupWizard,
Keywords = new[] { @"first run", @"initial", @"getting started", @"import", @"tutorial", @"recommended beatmaps" },
TooltipText = FirstRunSetupOverlayStrings.FirstRunSetupDescription,
Action = () => firstRunSetupOverlay?.Show(),
},
new SettingsButton
{
Text = GeneralSettingsStrings.LearnMoreAboutLazer,
TooltipText = GeneralSettingsStrings.LearnMoreAboutLazerTooltip,
BackgroundColour = colours.YellowDark,
Action = () => game?.ShowWiki(@"Help_centre/Upgrading_to_lazer")
},
new SettingsButton
{
Text = GeneralSettingsStrings.ReportIssue,
TooltipText = GeneralSettingsStrings.ReportIssueTooltip,
BackgroundColour = colours.YellowDarker,
Action = () => game?.OpenUrlExternally(@"https://osu.ppy.sh/community/forums/topics/create?forum_id=5", LinkWarnMode.NeverWarn)
},
});
bool supportsExport = RuntimeInfo.OS != RuntimeInfo.Platform.Android;
if (supportsExport)
{
Add(new SettingsButton
{
Text = GeneralSettingsStrings.ExportLogs,
BackgroundColour = colours.YellowDarker.Darken(0.5f),
Keywords = new[] { @"bug", "report", "logs", "files" },
Action = () => Task.Run(exportLogs),
});
exportStorage = (storage as OsuStorage)?.GetExportStorage() ?? storage.GetStorageForDirectory(@"exports");
}
}
[Resolved]
private INotificationOverlay? notifications { get; set; }
private Storage exportStorage = null!;
private void exportLogs()
{
ProgressNotification notification = new ProgressNotification
{
State = ProgressNotificationState.Active,
Text = "Exporting logs...",
};
notifications?.Post(notification);
const string archive_filename = "compressed-logs.zip";
try
{
GlobalStatistics.OutputToLog();
Logger.Flush();
var logStorage = Logger.Storage;
using (var outStream = exportStorage.CreateFileSafely(archive_filename))
using (var zip = ZipArchive.Create())
{
foreach (string? f in logStorage.GetFiles(string.Empty, "*.log"))
FileUtils.AttemptOperation(z => z.AddEntry(f, logStorage.GetStream(f), true), zip);
zip.SaveTo(outStream);
}
}
catch
{
notification.State = ProgressNotificationState.Cancelled;
// cleanup if export is failed or canceled.
exportStorage.Delete(archive_filename);
throw;
}
notification.CompletionText = "Exported logs! Click to view.";
notification.CompletionClickAction = () => exportStorage.PresentFileExternally(archive_filename);
notification.State = ProgressNotificationState.Completed;
}
}
}
@@ -7,20 +7,12 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Statistics;
using osu.Game.Configuration;
using osu.Game.IO;
using osu.Game.Localisation;
using osu.Game.Online.Multiplayer;
using osu.Game.Overlays.Dialog;
using osu.Game.Overlays.Notifications;
using osu.Game.Overlays.Settings.Sections.Maintenance;
using osu.Game.Updater;
using osu.Game.Utils;
using SharpCompress.Archives.Zip;
namespace osu.Game.Overlays.Settings.Sections.General
{
@@ -45,79 +37,40 @@ namespace osu.Game.Overlays.Settings.Sections.General
[Resolved]
private IDialogOverlay? dialogOverlay { get; set; }
private Storage exportStorage = null!;
[BackgroundDependencyLoader]
private void load(OsuConfigManager config, Storage storage)
private void load(OsuConfigManager config)
{
config.BindWith(OsuSetting.ReleaseStream, configReleaseStream);
bool isDesktop = RuntimeInfo.IsDesktop;
bool supportsExport = RuntimeInfo.OS != RuntimeInfo.Platform.Android;
bool canCheckUpdates = updateManager?.CanCheckForUpdate == true;
if (canCheckUpdates)
// For simplicity, hide the concept of release streams from mobile users.
if (isDesktop)
{
// For simplicity, hide the concept of release streams from mobile users.
if (isDesktop)
Add(releaseStreamDropdown = new SettingsEnumDropdown<ReleaseStream>
{
Add(releaseStreamDropdown = new SettingsEnumDropdown<ReleaseStream>
{
LabelText = GeneralSettingsStrings.ReleaseStream,
Current = { Value = configReleaseStream.Value },
Keywords = new[] { @"version" },
});
LabelText = GeneralSettingsStrings.ReleaseStream,
Current = { Value = configReleaseStream.Value },
Keywords = new[] { @"version" },
});
if (updateManager!.FixedReleaseStream != null)
{
configReleaseStream.Value = updateManager.FixedReleaseStream.Value;
if (updateManager!.FixedReleaseStream != null)
{
configReleaseStream.Value = updateManager.FixedReleaseStream.Value;
releaseStreamDropdown.ShowsDefaultIndicator = false;
releaseStreamDropdown.Items = [updateManager.FixedReleaseStream.Value];
releaseStreamDropdown.SetNoticeText(GeneralSettingsStrings.ChangeReleaseStreamPackageManagerWarning);
}
releaseStreamDropdown.Current.BindValueChanged(releaseStreamChanged);
releaseStreamDropdown.ShowsDefaultIndicator = false;
releaseStreamDropdown.Items = [updateManager.FixedReleaseStream.Value];
releaseStreamDropdown.SetNoticeText(GeneralSettingsStrings.ChangeReleaseStreamPackageManagerWarning);
}
Add(checkForUpdatesButton = new SettingsButton
{
Text = GeneralSettingsStrings.CheckUpdate,
Action = () => checkForUpdates().FireAndForget()
});
releaseStreamDropdown.Current.BindValueChanged(releaseStreamChanged);
}
// Loosely update-related maintenance buttons.
if (isDesktop)
Add(checkForUpdatesButton = new SettingsButton
{
Add(new SettingsButton
{
Text = GeneralSettingsStrings.OpenOsuFolder,
Keywords = new[] { @"logs", @"files", @"access", "directory" },
Action = () => storage.PresentExternally(),
});
}
if (supportsExport)
{
Add(new SettingsButton
{
Text = GeneralSettingsStrings.ExportLogs,
Keywords = new[] { @"bug", "report", "logs", "files" },
Action = () => Task.Run(exportLogs),
});
}
if (isDesktop)
{
Add(new SettingsButton
{
Text = GeneralSettingsStrings.ChangeFolderLocation,
Action = () => game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen()))
});
}
exportStorage = (storage as OsuStorage)?.GetExportStorage() ?? storage.GetStorageForDirectory(@"exports");
Text = GeneralSettingsStrings.CheckUpdate,
Action = () => checkForUpdates().FireAndForget()
});
}
private void releaseStreamChanged(ValueChangedEvent<ReleaseStream> stream)
@@ -176,48 +129,5 @@ namespace osu.Game.Overlays.Settings.Sections.General
checkForUpdatesButton.Enabled.Value = true;
}
}
private void exportLogs()
{
ProgressNotification notification = new ProgressNotification
{
State = ProgressNotificationState.Active,
Text = "Exporting logs...",
};
notifications?.Post(notification);
const string archive_filename = "compressed-logs.zip";
try
{
GlobalStatistics.OutputToLog();
Logger.Flush();
var logStorage = Logger.Storage;
using (var outStream = exportStorage.CreateFileSafely(archive_filename))
using (var zip = ZipArchive.Create())
{
foreach (string? f in logStorage.GetFiles(string.Empty, "*.log"))
FileUtils.AttemptOperation(z => z.AddEntry(f, logStorage.GetStream(f), true), zip);
zip.SaveTo(outStream);
}
}
catch
{
notification.State = ProgressNotificationState.Cancelled;
// cleanup if export is failed or canceled.
exportStorage.Delete(archive_filename);
throw;
}
notification.CompletionText = "Exported logs! Click to view.";
notification.CompletionClickAction = () => exportStorage.PresentFileExternally(archive_filename);
notification.State = ProgressNotificationState.Completed;
}
}
}
@@ -1,25 +1,20 @@
// 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;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Localisation;
using osu.Game.Online.Chat;
using osu.Game.Overlays.Settings.Sections.General;
using osu.Game.Updater;
namespace osu.Game.Overlays.Settings.Sections
{
public partial class GeneralSection : SettingsSection
{
[Resolved(CanBeNull = true)]
private FirstRunSetupOverlay? firstRunSetupOverlay { get; set; }
[Resolved(CanBeNull = true)]
private OsuGame? game { get; set; }
public override LocalisableString Header => CommonStrings.General;
public override Drawable CreateIcon() => new SpriteIcon
@@ -28,34 +23,14 @@ namespace osu.Game.Overlays.Settings.Sections
};
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(UpdateManager? updateManager)
{
Children = new Drawable[]
{
new SettingsButton
{
Text = GeneralSettingsStrings.RunSetupWizard,
Keywords = new[] { @"first run", @"initial", @"getting started", @"import", @"tutorial", @"recommended beatmaps" },
TooltipText = FirstRunSetupOverlayStrings.FirstRunSetupDescription,
Action = () => firstRunSetupOverlay?.Show(),
},
new SettingsButton
{
Text = GeneralSettingsStrings.LearnMoreAboutLazer,
TooltipText = GeneralSettingsStrings.LearnMoreAboutLazerTooltip,
BackgroundColour = colours.YellowDark,
Action = () => game?.ShowWiki(@"Help_centre/Upgrading_to_lazer")
},
new SettingsButton
{
Text = GeneralSettingsStrings.ReportIssue,
TooltipText = GeneralSettingsStrings.ReportIssueTooltip,
BackgroundColour = colours.DarkOrange2,
Action = () => game?.OpenUrlExternally(@"https://osu.ppy.sh/community/forums/topics/create?forum_id=5", LinkWarnMode.NeverWarn)
},
new LanguageSettings(),
new UpdateSettings(),
};
Add(new QuickActionSettings());
Add(new LanguageSettings());
if (updateManager?.CanCheckForUpdate == true)
Add(new UpdateSettings());
if (RuntimeInfo.IsDesktop)
Add(new InstallationSettings());
}
}
}
@@ -191,8 +191,18 @@ namespace osu.Game.Overlays.Settings.Sections.Input
Spacing = new Vector2(5),
Children = new Drawable[]
{
new CancelButton { Action = () => finalise(false) },
new ClearButton { Action = clear },
new RoundedButton
{
Text = CommonStrings.ButtonsCancel,
Size = new Vector2(80, 20),
Action = () => finalise(false)
},
new DangerousRoundedButton
{
Text = CommonStrings.ButtonsClear,
Size = new Vector2(80, 20),
Action = clear
},
},
},
new HoverClickSounds()
@@ -538,23 +548,5 @@ namespace osu.Game.Overlays.Settings.Sections.Input
{
isDefault.Value = KeyBindings.Select(b => b.KeyCombination).SequenceEqual(Defaults);
}
private partial class CancelButton : RoundedButton
{
public CancelButton()
{
Text = CommonStrings.ButtonsCancel;
Size = new Vector2(80, 20);
}
}
public partial class ClearButton : DangerousRoundedButton
{
public ClearButton()
{
Text = CommonStrings.ButtonsClear;
Size = new Vector2(80, 20);
}
}
}
}
@@ -137,7 +137,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
rotation.BindValueChanged(val =>
{
usableAreaContainer.RotateTo(val.NewValue, 100, Easing.OutQuint);
tabletContainer.RotateTo(-val.NewValue, 800, Easing.OutQuint);
tabletContainer.RotateTo(-val.NewValue, 400, Easing.OutQuint);
checkBounds();
}, true);
@@ -126,7 +126,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
Alpha = 0,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(0, 8),
Spacing = new Vector2(0, SettingsSection.ITEM_SPACING),
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
+6 -1
View File
@@ -16,7 +16,12 @@ namespace osu.Game.Overlays.Settings
public SettingsButton()
{
RelativeSizeAxes = Axes.X;
Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS };
Margin = new MarginPadding { Vertical = -5 };
Padding = new MarginPadding
{
Left = SettingsPanel.CONTENT_MARGINS,
Right = SettingsPanel.CONTENT_MARGINS,
};
}
public IEnumerable<string> Keywords { get; set; } = Array.Empty<string>();
+1 -1
View File
@@ -11,7 +11,7 @@ using osu.Game.Graphics.UserInterfaceV2;
namespace osu.Game.Rulesets.Edit
{
public partial class ExpandableButton : RoundedButton, IExpandable
public sealed partial class ExpandableButton : RoundedButton, IExpandable
{
private float actualHeight;
@@ -50,11 +50,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
ColumnDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.Absolute, 5),
new Dimension(GridSizeMode.AutoSize)
},
Content = new[]
{
new Drawable[]
new Drawable?[]
{
readyButton = new MultiplayerReadyButton
{
@@ -62,6 +63,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
Size = Vector2.One,
Action = onReadyButtonClick,
},
null,
countdownButton = new MultiplayerCountdownButton
{
RelativeSizeAxes = Axes.Y,