Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion osu.Game/Database/RealmAccess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,9 @@ public class RealmAccess : IDisposable
/// 49 2025-06-10 Reset the LegacyOnlineID to -1 for all scores that have it set to 0 (which is semantically the same) for consistency of handling with OnlineID.
/// 50 2025-07-11 Add UserTags to BeatmapMetadata.
/// 51 2025-07-22 Add ScoreInfo.Pauses.
/// 52 2025-12-13 Added SavedBeatmapFilter.
/// </summary>
private const int schema_version = 51;
private const int schema_version = 52;

/// <summary>
/// Lock object which is held during <see cref="BlockAllOperations"/> sections, blocking realm retrieval during blocking periods.
Expand Down Expand Up @@ -1326,6 +1327,10 @@ void remapKeyBinding(int oldAction, int newAction)
score.LegacyOnlineID = -1;

break;

case 52:
// SavedBeatmapFilter added.
break;
}

Logger.Log($"Migration completed in {stopwatch.ElapsedMilliseconds}ms");
Expand Down
22 changes: 17 additions & 5 deletions osu.Game/Graphics/UserInterface/ShearedSearchTextBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public partial class ShearedSearchTextBox : CompositeDrawable, IHasCurrentValue<

private readonly Box background;
protected readonly InnerSearchTextBox TextBox;
protected readonly Container BackgroundContent;
protected readonly Container RightInterface;

public Bindable<string> Current
{
Expand Down Expand Up @@ -62,6 +64,10 @@ public ShearedSearchTextBox()
{
RelativeSizeAxes = Axes.Both
},
BackgroundContent = new Container
{
RelativeSizeAxes = Axes.Both
},
new GridContainer
{
RelativeSizeAxes = Axes.Both,
Expand All @@ -70,13 +76,19 @@ public ShearedSearchTextBox()
new Drawable[]
{
TextBox = CreateInnerTextBox(),
new SpriteIcon
RightInterface = new Container
{
Icon = FontAwesome.Solid.Search,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Size = new Vector2(16),
Shear = -Shear
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Child = new SpriteIcon
{
Icon = FontAwesome.Solid.Search,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Size = new Vector2(16),
Shear = -Shear
}
}
}
},
Expand Down
115 changes: 115 additions & 0 deletions osu.Game/Screens/SelectV2/FilterControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Collections;
using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.UserInterfaceV2;
Expand Down Expand Up @@ -114,6 +118,9 @@ private void load(IAPIProvider api)
{
RelativeSizeAxes = Axes.X,
HoldFocus = true,
ApplyFilter = applyFilter,
SaveFilter = saveFilter,
Ruleset = ruleset,
},
},
new GridContainer
Expand Down Expand Up @@ -260,6 +267,51 @@ protected override void Dispose(bool isDisposing)
collectionsSubscription?.Dispose();
}

private void applyFilter(SavedBeatmapFilter filter)
{
searchTextBox.Current.Value = filter.SearchQuery;

sortDropdown.Current.Value = Enum.IsDefined(typeof(SortMode), filter.SortMode)
? (SortMode)filter.SortMode
: SortMode.Title;

groupDropdown.Current.Value = Enum.IsDefined(typeof(GroupMode), filter.GroupMode)
? (GroupMode)filter.GroupMode
: GroupMode.None;

showConvertedBeatmapsButton.Active.Value = filter.ShowConverted;

var lowerBound = (BindableNumber<double>)difficultyRangeSlider.LowerBound;
var upperBound = (BindableNumber<double>)difficultyRangeSlider.UpperBound;

double min = Math.Clamp(filter.MinStars, lowerBound.MinValue, lowerBound.MaxValue);
double max = Math.Clamp(filter.MaxStars, upperBound.MinValue, upperBound.MaxValue);

if (min > max)
min = max;

difficultyRangeSlider.LowerBound.Value = min;
difficultyRangeSlider.UpperBound.Value = max;
}

private void saveFilter(string name)
{
if (string.IsNullOrEmpty(ruleset.Value?.ShortName))
return;

realm.Write(r => r.Add(new SavedBeatmapFilter
{
Name = name.Trim(),
SearchQuery = searchTextBox.Current.Value,
SortMode = (int)sortDropdown.Current.Value,
GroupMode = (int)groupDropdown.Current.Value,
ShowConverted = showConvertedBeatmapsButton.Active.Value,
MinStars = difficultyRangeSlider.LowerBound.Value,
MaxStars = difficultyRangeSlider.UpperBound.Value,
RulesetShortName = ruleset.Value.ShortName
}));
}

/// <summary>
/// Creates a <see cref="FilterCriteria"/> based on the current state of the controls.
/// </summary>
Expand Down Expand Up @@ -330,6 +382,63 @@ protected override void PopOut()

internal partial class SongSelectSearchTextBox : ShearedFilterTextBox
{
public Action<SavedBeatmapFilter>? ApplyFilter { get; set; }
public Action<string>? SaveFilter { get; set; }
public IBindable<RulesetInfo> Ruleset { get; set; } = null!;

private readonly Box hoverBox;

public SongSelectSearchTextBox()
{
var filterButton = new SearchFilterButton
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
};

RightInterface.Clear();
RightInterface.Add(filterButton);

// Create hover box
hoverBox = new Box
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
RelativeSizeAxes = Axes.Y,
Width = 55,
Alpha = 0,
};

BackgroundContent.Add(hoverBox);

var popoverTarget = new PopoverTarget
{
Anchor = Anchor.BottomRight,
Origin = Anchor.TopRight,
RelativePositionAxes = Axes.Y,
Y = 1,
Size = Vector2.Zero,
CreatePopover = createPopover
};

AddInternal(popoverTarget);

filterButton.HoverTarget = hoverBox;
filterButton.PopoverTarget = popoverTarget;
filterButton.SetIconShear(-Shear);
}

[Resolved]
private OsuColour colours { get; set; } = null!;

[BackgroundDependencyLoader]
private void load()
{
hoverBox.Colour = colours.Blue;
}

private Popover createPopover() => new SavedFiltersPopover(f => ApplyFilter?.Invoke(f), n => SaveFilter?.Invoke(n), Ruleset.Value);

protected override InnerSearchTextBox CreateInnerTextBox() => new InnerTextBox();

private partial class InnerTextBox : InnerFilterTextBox
Expand All @@ -349,6 +458,12 @@ public override bool OnPressed(KeyBindingPressEvent<PlatformAction> e)
return base.OnPressed(e);
}
}

private partial class PopoverTarget : Container, IHasPopover
{
public Func<Popover>? CreatePopover { get; set; }
public Popover GetPopover() => CreatePopover?.Invoke()!;
}
}
}
}
29 changes: 29 additions & 0 deletions osu.Game/Screens/SelectV2/SavedBeatmapFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using osu.Game.Database;
using Realms;

namespace osu.Game.Screens.SelectV2
{
public class SavedBeatmapFilter : RealmObject, IHasGuidPrimaryKey
{
[PrimaryKey]
public Guid ID { get; set; } = Guid.NewGuid();

public string Name { get; set; } = string.Empty;

public string SearchQuery { get; set; } = string.Empty;

public int SortMode { get; set; }
public int GroupMode { get; set; }

public bool ShowConverted { get; set; }

public double MinStars { get; set; }
public double MaxStars { get; set; }

public string RulesetShortName { get; set; } = string.Empty;
}
}
Loading