1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 11:42:56 +08:00

Merge branch 'master' into comment-editor-1

This commit is contained in:
Dean Herbert 2022-11-30 17:22:59 +09:00
commit 4a747182b4
40 changed files with 914 additions and 608 deletions

View File

@ -52,7 +52,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.1127.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.1126.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.1130.0" />
</ItemGroup>
<ItemGroup Label="Transitive Dependencies">
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->

View File

@ -7,12 +7,14 @@ using osu.Framework.Graphics.Shapes;
using osuTK;
using osuTK.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Framework.Graphics.Colour;
namespace osu.Game.Tests.Visual.Background
{
public partial class TestSceneTrianglesV2Background : OsuTestScene
{
private readonly TrianglesV2 triangles;
private readonly Box box;
public TestSceneTrianglesV2Background()
{
@ -23,27 +25,44 @@ namespace osu.Game.Tests.Visual.Background
RelativeSizeAxes = Axes.Both,
Colour = Color4.Gray
},
new Container
new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500, 100),
Masking = true,
CornerRadius = 40,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 5),
Children = new Drawable[]
{
new Box
new Container
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Red
Size = new Vector2(500, 100),
Masking = true,
CornerRadius = 40,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Red
},
triangles = new TrianglesV2
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both
}
}
},
triangles = new TrianglesV2
new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
ColourTop = Color4.White,
ColourBottom = Color4.Red
Size = new Vector2(500, 100),
Masking = true,
CornerRadius = 40,
Child = box = new Box
{
RelativeSizeAxes = Axes.Both
}
}
}
}
@ -54,8 +73,16 @@ namespace osu.Game.Tests.Visual.Background
{
base.LoadComplete();
AddSliderStep("Spawn ratio", 0f, 2f, 1f, s => triangles.SpawnRatio = s);
AddSliderStep("Spawn ratio", 0f, 10f, 1f, s =>
{
triangles.SpawnRatio = s;
triangles.Reset(1234);
});
AddSliderStep("Thickness", 0f, 1f, 0.02f, t => triangles.Thickness = t);
AddStep("White colour", () => box.Colour = triangles.Colour = Color4.White);
AddStep("Vertical gradient", () => box.Colour = triangles.Colour = ColourInfo.GradientVertical(Color4.White, Color4.Red));
AddStep("Horizontal gradient", () => box.Colour = triangles.Colour = ColourInfo.GradientHorizontal(Color4.White, Color4.Red));
}
}
}

View File

@ -10,6 +10,8 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics.Containers;
using osu.Game.Overlays;
using osu.Game.Rulesets.Edit;
using osu.Game.Screens.Edit;
@ -26,6 +28,7 @@ namespace osu.Game.Tests.Visual.Editing
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
private TimingScreen timingScreen;
private EditorBeatmap editorBeatmap;
protected override bool ScrollUsingMouseWheel => false;
@ -35,8 +38,11 @@ namespace osu.Game.Tests.Visual.Editing
Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value);
Beatmap.Disabled = true;
}
var editorBeatmap = new EditorBeatmap(Beatmap.Value.GetPlayableBeatmap(Ruleset.Value));
private void reloadEditorBeatmap()
{
editorBeatmap = new EditorBeatmap(Beatmap.Value.GetPlayableBeatmap(Ruleset.Value));
Child = new DependencyProvidingContainer
{
@ -58,7 +64,9 @@ namespace osu.Game.Tests.Visual.Editing
{
AddStep("Stop clock", () => EditorClock.Stop());
AddUntilStep("wait for rows to load", () => Child.ChildrenOfType<EffectRowAttribute>().Any());
AddStep("Reload Editor Beatmap", reloadEditorBeatmap);
AddUntilStep("Wait for rows to load", () => Child.ChildrenOfType<EffectRowAttribute>().Any());
}
[Test]
@ -95,6 +103,37 @@ namespace osu.Game.Tests.Visual.Editing
AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 69670);
}
[Test]
public void TestScrollControlGroupIntoView()
{
AddStep("Add many control points", () =>
{
editorBeatmap.ControlPointInfo.Clear();
editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint());
for (int i = 0; i < 100; i++)
{
editorBeatmap.ControlPointInfo.Add((i + 1) * 1000, new EffectControlPoint
{
KiaiMode = Convert.ToBoolean(i % 2),
});
}
});
AddStep("Select first effect point", () =>
{
InputManager.MoveMouseTo(Child.ChildrenOfType<EffectRowAttribute>().First());
InputManager.Click(MouseButton.Left);
});
AddStep("Seek to beginning", () => EditorClock.Seek(0));
AddStep("Seek to last point", () => EditorClock.Seek(101 * 1000));
AddUntilStep("Scrolled to end", () => timingScreen.ChildrenOfType<OsuScrollContainer>().First().IsScrolledToEnd());
}
protected override void Dispose(bool isDisposing)
{
Beatmap.Disabled = false;

View File

@ -130,11 +130,11 @@ namespace osu.Game.Tests.Visual.Online
Color4 textColour = isAction && hasBackground ? Color4Extensions.FromHex(newLine.Message.Sender.Colour) : Color4.White;
var linkCompilers = newLine.ContentFlow.Where(d => d is DrawableLinkCompiler).ToList();
var linkCompilers = newLine.DrawableContentFlow.Where(d => d is DrawableLinkCompiler).ToList();
var linkSprites = linkCompilers.SelectMany(comp => ((DrawableLinkCompiler)comp).Parts);
return linkSprites.All(d => d.Colour == linkColour)
&& newLine.ContentFlow.Except(linkSprites.Concat(linkCompilers)).All(d => d.Colour == textColour);
&& newLine.DrawableContentFlow.Except(linkSprites.Concat(linkCompilers)).All(d => d.Colour == textColour);
}
}
}

View File

@ -11,6 +11,7 @@ using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.Chat;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Users;
namespace osu.Game.Tests.Visual.Online
@ -33,7 +34,7 @@ namespace osu.Game.Tests.Visual.Online
{
AddStep("Set activity", () => api.Activity.Value = new UserActivity.InLobby(null));
AddStep("Run command", () => Add(new NowPlayingCommand()));
AddStep("Run command", () => Add(new NowPlayingCommand(new Channel())));
AddAssert("Check correct response", () => postTarget.LastMessage.Contains("is listening"));
}
@ -43,7 +44,7 @@ namespace osu.Game.Tests.Visual.Online
{
AddStep("Set activity", () => api.Activity.Value = new UserActivity.Editing(new BeatmapInfo()));
AddStep("Run command", () => Add(new NowPlayingCommand()));
AddStep("Run command", () => Add(new NowPlayingCommand(new Channel())));
AddAssert("Check correct response", () => postTarget.LastMessage.Contains("is editing"));
}
@ -53,7 +54,7 @@ namespace osu.Game.Tests.Visual.Online
{
AddStep("Set activity", () => api.Activity.Value = new UserActivity.InSoloGame(new BeatmapInfo(), new RulesetInfo()));
AddStep("Run command", () => Add(new NowPlayingCommand()));
AddStep("Run command", () => Add(new NowPlayingCommand(new Channel())));
AddAssert("Check correct response", () => postTarget.LastMessage.Contains("is playing"));
}
@ -69,7 +70,7 @@ namespace osu.Game.Tests.Visual.Online
BeatmapInfo = { OnlineID = hasOnlineId ? 1234 : -1 }
});
AddStep("Run command", () => Add(new NowPlayingCommand()));
AddStep("Run command", () => Add(new NowPlayingCommand(new Channel())));
if (hasOnlineId)
AddAssert("Check link presence", () => postTarget.LastMessage.Contains("/b/1234"));
@ -77,6 +78,18 @@ namespace osu.Game.Tests.Visual.Online
AddAssert("Check link not present", () => !postTarget.LastMessage.Contains("https://"));
}
[Test]
public void TestModPresence()
{
AddStep("Set activity", () => api.Activity.Value = new UserActivity.InSoloGame(new BeatmapInfo(), new RulesetInfo()));
AddStep("Add Hidden mod", () => SelectedMods.Value = new[] { Ruleset.Value.CreateInstance().CreateMod<ModHidden>() });
AddStep("Run command", () => Add(new NowPlayingCommand(new Channel())));
AddAssert("Check mod is present", () => postTarget.LastMessage.Contains("+HD"));
}
public partial class PostTarget : Component, IChannelPostTarget
{
public void PostMessage(string text, bool isAction = false, Channel target = null)

View File

@ -62,7 +62,6 @@ namespace osu.Game.Tests.Visual.Settings
section.Children.Where(f => f.IsPresent)
.OfType<ISettingsItem>()
.OfType<IFilterable>()
.Where(f => !(f is IHasFilterableChildren))
.All(f => f.FilterTerms.Any(t => t.ToString().Contains("scaling")))
));

View File

@ -1,28 +0,0 @@
// 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 NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Screens.Select;
using osuTK;
namespace osu.Game.Tests.Visual.SongSelect
{
public partial class TestSceneDifficultyRangeFilterControl : OsuTestScene
{
[Test]
public void TestBasic()
{
AddStep("create control", () =>
{
Child = new DifficultyRangeFilterControl
{
Width = 200,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Scale = new Vector2(3),
};
});
}
}
}

View File

@ -0,0 +1,79 @@
// 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 NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays;
using osuTK;
namespace osu.Game.Tests.Visual.UserInterface
{
public partial class TestSceneRangeSlider : OsuTestScene
{
[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Red);
private readonly BindableNumber<double> customStart = new BindableNumber<double>
{
MinValue = 0,
MaxValue = 100,
Precision = 0.1f
};
private readonly BindableNumber<double> customEnd = new BindableNumber<double>(100)
{
MinValue = 0,
MaxValue = 100,
Precision = 0.1f
};
private RangeSlider rangeSlider = null!;
[SetUpSteps]
public void SetUpSteps()
{
AddStep("create control", () => Child = rangeSlider = new RangeSlider
{
Width = 200,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Scale = new Vector2(3),
LowerBound = customStart,
UpperBound = customEnd,
TooltipSuffix = "suffix",
NubWidth = Nub.HEIGHT * 2,
DefaultStringLowerBound = "Start",
DefaultStringUpperBound = "End",
MinRange = 10
});
}
[Test]
public void TestAdjustRange()
{
AddAssert("Initial lower bound is correct", () => rangeSlider.LowerBound.Value, () => Is.EqualTo(0).Within(0.1f));
AddAssert("Initial upper bound is correct", () => rangeSlider.UpperBound.Value, () => Is.EqualTo(100).Within(0.1f));
AddStep("Adjust range", () =>
{
customStart.Value = 50;
customEnd.Value = 75;
});
AddAssert("Adjusted lower bound is correct", () => rangeSlider.LowerBound.Value, () => Is.EqualTo(50).Within(0.1f));
AddAssert("Adjusted upper bound is correct", () => rangeSlider.UpperBound.Value, () => Is.EqualTo(75).Within(0.1f));
AddStep("Test nub pushing", () =>
{
customStart.Value = 90;
});
AddAssert("Pushed lower bound is correct", () => rangeSlider.LowerBound.Value, () => Is.EqualTo(90).Within(0.1f));
AddAssert("Pushed upper bound is correct", () => rangeSlider.UpperBound.Value, () => Is.EqualTo(100).Within(0.1f));
}
}
}

View File

@ -11,9 +11,7 @@ using osu.Framework.Allocation;
using System.Collections.Generic;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Graphics.Rendering.Vertices;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp;
using osuTK.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -23,28 +21,12 @@ namespace osu.Game.Graphics.Backgrounds
{
private const float triangle_size = 100;
private const float base_velocity = 50;
private const int texture_height = 128;
/// <summary>
/// sqrt(3) / 2
/// </summary>
private const float equilateral_triangle_ratio = 0.866f;
private readonly Bindable<Color4> colourTop = new Bindable<Color4>(Color4.White);
private readonly Bindable<Color4> colourBottom = new Bindable<Color4>(Color4.Black);
public Color4 ColourTop
{
get => colourTop.Value;
set => colourTop.Value = value;
}
public Color4 ColourBottom
{
get => colourBottom.Value;
set => colourBottom.Value = value;
}
public float Thickness { get; set; } = 0.02f; // No need for invalidation since it's happening in Update()
/// <summary>
@ -70,9 +52,6 @@ namespace osu.Game.Graphics.Backgrounds
private readonly List<TriangleParticle> parts = new List<TriangleParticle>();
[Resolved]
private IRenderer renderer { get; set; } = null!;
private Random? stableRandom;
private IShader shader = null!;
@ -89,42 +68,19 @@ namespace osu.Game.Graphics.Backgrounds
}
[BackgroundDependencyLoader]
private void load(ShaderManager shaders)
private void load(ShaderManager shaders, IRenderer renderer)
{
shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, "TriangleBorder");
texture = renderer.WhitePixel;
}
protected override void LoadComplete()
{
base.LoadComplete();
colourTop.BindValueChanged(_ => updateTexture());
colourBottom.BindValueChanged(_ => updateTexture(), true);
spawnRatio.BindValueChanged(_ => Reset(), true);
}
private void updateTexture()
{
var image = new Image<Rgba32>(texture_height, 1);
texture = renderer.CreateTexture(1, texture_height, true);
for (int i = 0; i < texture_height; i++)
{
float ratio = (float)i / texture_height;
image[i, 0] = new Rgba32(
colourBottom.Value.R * ratio + colourTop.Value.R * (1f - ratio),
colourBottom.Value.G * ratio + colourTop.Value.G * (1f - ratio),
colourBottom.Value.B * ratio + colourTop.Value.B * (1f - ratio)
);
}
texture.SetData(new TextureUpload(image));
Invalidate(Invalidation.DrawNode);
}
protected override void Update()
{
base.Update();
@ -227,6 +183,9 @@ namespace osu.Game.Graphics.Backgrounds
private Texture texture = null!;
private readonly List<TriangleParticle> parts = new List<TriangleParticle>();
private readonly Vector2 triangleSize = new Vector2(1f, equilateral_triangle_ratio) * triangle_size;
private Vector2 size;
private float thickness;
private float texelSize;
@ -246,7 +205,15 @@ namespace osu.Game.Graphics.Backgrounds
texture = Source.texture;
size = Source.DrawSize;
thickness = Source.Thickness;
texelSize = Math.Max(1.5f / Source.ScreenSpaceDrawQuad.Size.X, 1.5f / Source.ScreenSpaceDrawQuad.Size.Y);
Quad triangleQuad = new Quad(
Vector2Extensions.Transform(Vector2.Zero, DrawInfo.Matrix),
Vector2Extensions.Transform(new Vector2(triangle_size, 0f), DrawInfo.Matrix),
Vector2Extensions.Transform(new Vector2(0f, triangleSize.Y), DrawInfo.Matrix),
Vector2Extensions.Transform(triangleSize, DrawInfo.Matrix)
);
texelSize = 1.5f / triangleQuad.Height;
parts.Clear();
parts.AddRange(Source.parts);
@ -256,7 +223,7 @@ namespace osu.Game.Graphics.Backgrounds
{
base.Draw(renderer);
if (Source.AimCount == 0)
if (Source.AimCount == 0 || thickness == 0)
return;
if (vertexBatch == null || vertexBatch.Size != Source.AimCount)
@ -269,35 +236,42 @@ namespace osu.Game.Graphics.Backgrounds
shader.GetUniform<float>("thickness").UpdateValue(ref thickness);
shader.GetUniform<float>("texelSize").UpdateValue(ref texelSize);
float relativeHeight = triangleSize.Y / size.Y;
float relativeWidth = triangleSize.X / size.X;
foreach (TriangleParticle particle in parts)
{
var offset = triangle_size * new Vector2(0.5f, equilateral_triangle_ratio);
Vector2 topLeft = particle.Position * size + new Vector2(-offset.X, 0f);
Vector2 topRight = particle.Position * size + new Vector2(offset.X, 0);
Vector2 bottomLeft = particle.Position * size + new Vector2(-offset.X, offset.Y);
Vector2 bottomRight = particle.Position * size + new Vector2(offset.X, offset.Y);
Vector2 topLeft = particle.Position - new Vector2(relativeWidth * 0.5f, 0f);
Vector2 topRight = topLeft + new Vector2(relativeWidth, 0f);
Vector2 bottomLeft = topLeft + new Vector2(0f, relativeHeight);
Vector2 bottomRight = bottomLeft + new Vector2(relativeWidth, 0f);
var drawQuad = new Quad(
Vector2Extensions.Transform(topLeft, DrawInfo.Matrix),
Vector2Extensions.Transform(topRight, DrawInfo.Matrix),
Vector2Extensions.Transform(bottomLeft, DrawInfo.Matrix),
Vector2Extensions.Transform(bottomRight, DrawInfo.Matrix)
Vector2Extensions.Transform(topLeft * size, DrawInfo.Matrix),
Vector2Extensions.Transform(topRight * size, DrawInfo.Matrix),
Vector2Extensions.Transform(bottomLeft * size, DrawInfo.Matrix),
Vector2Extensions.Transform(bottomRight * size, DrawInfo.Matrix)
);
var tRect = new Quad(
topLeft.X / size.X,
topLeft.Y / size.Y * texture_height,
(topRight.X - topLeft.X) / size.X,
(bottomRight.Y - topRight.Y) / size.Y * texture_height
).AABBFloat;
ColourInfo colourInfo = triangleColourInfo(DrawColourInfo.Colour, new Quad(topLeft, topRight, bottomLeft, bottomRight));
renderer.DrawQuad(texture, drawQuad, DrawColourInfo.Colour, tRect, vertexBatch.AddAction, textureCoords: tRect);
renderer.DrawQuad(texture, drawQuad, colourInfo, vertexAction: vertexBatch.AddAction);
}
shader.Unbind();
}
private static ColourInfo triangleColourInfo(ColourInfo source, Quad quad)
{
return new ColourInfo
{
TopLeft = source.Interpolate(quad.TopLeft),
TopRight = source.Interpolate(quad.TopRight),
BottomLeft = source.Interpolate(quad.BottomLeft),
BottomRight = source.Interpolate(quad.BottomRight)
};
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);

View File

@ -0,0 +1,212 @@
// 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;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public partial class RangeSlider : CompositeDrawable
{
/// <summary>
/// The lower limiting value
/// </summary>
public Bindable<double> LowerBound
{
get => lowerBound.Current;
set => lowerBound.Current = value;
}
/// <summary>
/// The upper limiting value
/// </summary>
public Bindable<double> UpperBound
{
get => upperBound.Current;
set => upperBound.Current = value;
}
/// <summary>
/// Text that describes this RangeSlider's functionality
/// </summary>
public string Label
{
set => label.Text = value;
}
public float NubWidth
{
set => lowerBound.NubWidth = upperBound.NubWidth = value;
}
/// <summary>
/// Minimum difference between the lower bound and higher bound
/// </summary>
public float MinRange
{
set => minRange = value;
}
/// <summary>
/// lower bound display for when it is set to its default value
/// </summary>
public string DefaultStringLowerBound
{
set => lowerBound.DefaultString = value;
}
/// <summary>
/// upper bound display for when it is set to its default value
/// </summary>
public string DefaultStringUpperBound
{
set => upperBound.DefaultString = value;
}
public LocalisableString DefaultTooltipLowerBound
{
set => lowerBound.DefaultTooltip = value;
}
public LocalisableString DefaultTooltipUpperBound
{
set => upperBound.DefaultTooltip = value;
}
public string TooltipSuffix
{
set => upperBound.TooltipSuffix = lowerBound.TooltipSuffix = value;
}
private float minRange = 0.1f;
private readonly OsuSpriteText label;
private readonly LowerBoundSlider lowerBound;
private readonly UpperBoundSlider upperBound;
public RangeSlider()
{
const float vertical_offset = 13;
InternalChildren = new Drawable[]
{
label = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 14),
},
upperBound = new UpperBoundSlider
{
KeyboardStep = 0.1f,
RelativeSizeAxes = Axes.X,
Y = vertical_offset,
},
lowerBound = new LowerBoundSlider
{
KeyboardStep = 0.1f,
RelativeSizeAxes = Axes.X,
Y = vertical_offset,
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
lowerBound.Current.ValueChanged += min => upperBound.Current.Value = Math.Max(min.NewValue + minRange, upperBound.Current.Value);
upperBound.Current.ValueChanged += max => lowerBound.Current.Value = Math.Min(max.NewValue - minRange, lowerBound.Current.Value);
}
private partial class LowerBoundSlider : BoundSlider
{
protected override void LoadComplete()
{
base.LoadComplete();
LeftBox.Height = 6; // hide any colour bleeding from overlap
AccentColour = BackgroundColour;
BackgroundColour = Color4.Transparent;
}
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) =>
base.ReceivePositionalInputAt(screenSpacePos)
&& screenSpacePos.X <= Nub.ScreenSpaceDrawQuad.TopRight.X;
}
private partial class UpperBoundSlider : BoundSlider
{
protected override void LoadComplete()
{
base.LoadComplete();
RightBox.Height = 6; // just to match the left bar height really
}
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) =>
base.ReceivePositionalInputAt(screenSpacePos)
&& screenSpacePos.X >= Nub.ScreenSpaceDrawQuad.TopLeft.X;
}
protected partial class BoundSlider : OsuSliderBar<double>
{
public string? DefaultString;
public LocalisableString? DefaultTooltip;
public string? TooltipSuffix;
public float NubWidth { get; set; } = Nub.HEIGHT;
public override LocalisableString TooltipText =>
(Current.IsDefault ? DefaultTooltip : Current.Value.ToString($@"0.## {TooltipSuffix}")) ?? Current.Value.ToString($@"0.## {TooltipSuffix}");
protected override bool OnHover(HoverEvent e)
{
base.OnHover(e);
return true; // Make sure only one nub shows hover effect at once.
}
protected override void LoadComplete()
{
base.LoadComplete();
Nub.Width = NubWidth;
RangePadding = Nub.Width / 2;
OsuSpriteText currentDisplay;
Nub.Add(currentDisplay = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Y = -0.5f,
Colour = Color4.White,
Font = OsuFont.Torus.With(size: 10),
});
Current.BindValueChanged(current =>
{
currentDisplay.Text = (current.NewValue != Current.Default ? current.NewValue.ToString("N1") : DefaultString) ?? current.NewValue.ToString("N1");
}, true);
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider? colourProvider)
{
if (colourProvider == null) return;
AccentColour = colourProvider.Background2;
Nub.AccentColour = colourProvider.Background2;
Nub.GlowingAccentColour = colourProvider.Background1;
Nub.GlowColour = colourProvider.Background2;
}
}
}
}

View File

@ -6,6 +6,7 @@ using System.Diagnostics;
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.Input.Events;
using osu.Framework.Localisation;
@ -79,8 +80,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
Debug.Assert(triangleGradientSecondColour != null);
Triangles.ColourTop = triangleGradientSecondColour.Value;
Triangles.ColourBottom = BackgroundColour;
Triangles.Colour = ColourInfo.GradientVertical(triangleGradientSecondColour.Value, BackgroundColour);
}
protected override bool OnHover(HoverEvent e)

View File

@ -25,6 +25,7 @@ namespace osu.Game.Online.API.Requests
var req = base.CreateWebRequest();
if (channel != null) req.AddParameter(@"channel", channel.Id.ToString());
req.AddParameter(@"since", since.ToString());
req.AddParameter(@"includes[]", "presence");
return req;
}

View File

@ -16,5 +16,7 @@ namespace osu.Game.Online.API.Requests
[JsonProperty]
public List<Message> Messages;
// TODO: Handle Silences here (will need to add to includes[] in the request).
}
}

View File

@ -1,13 +1,17 @@
// 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.
#nullable disable
using System.Collections.Generic;
using System.Linq;
using System.Text;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Users;
namespace osu.Game.Online.Chat
@ -15,21 +19,30 @@ namespace osu.Game.Online.Chat
public partial class NowPlayingCommand : Component
{
[Resolved]
private IChannelPostTarget channelManager { get; set; }
private IChannelPostTarget channelManager { get; set; } = null!;
[Resolved]
private IAPIProvider api { get; set; }
private IAPIProvider api { get; set; } = null!;
[Resolved]
private Bindable<WorkingBeatmap> currentBeatmap { get; set; }
private Bindable<WorkingBeatmap> currentBeatmap { get; set; } = null!;
private readonly Channel target;
[Resolved]
private Bindable<IReadOnlyList<Mod>> selectedMods { get; set; } = null!;
[Resolved]
private IBindable<RulesetInfo> currentRuleset { get; set; } = null!;
[Resolved]
private LocalisationManager localisation { get; set; } = null!;
private readonly Channel? target;
/// <summary>
/// Creates a new <see cref="NowPlayingCommand"/> to post the currently-playing beatmap to a parenting <see cref="IChannelPostTarget"/>.
/// </summary>
/// <param name="target">The target channel to post to. If <c>null</c>, the currently-selected channel will be posted to.</param>
public NowPlayingCommand(Channel target = null)
public NowPlayingCommand(Channel target)
{
this.target = target;
}
@ -59,10 +72,55 @@ namespace osu.Game.Online.Chat
break;
}
string beatmapString = beatmapInfo.OnlineID > 0 ? $"[{api.WebsiteRootUrl}/b/{beatmapInfo.OnlineID} {beatmapInfo}]" : beatmapInfo.ToString();
string[] pieces =
{
"is",
verb,
getBeatmapPart(),
getRulesetPart(),
getModPart(),
};
channelManager.PostMessage($"is {verb} {beatmapString}", true, target);
channelManager.PostMessage(string.Join(' ', pieces.Where(p => !string.IsNullOrEmpty(p))), true, target);
Expire();
string getBeatmapPart()
{
string beatmapInfoString = localisation.GetLocalisedBindableString(beatmapInfo.GetDisplayTitleRomanisable()).Value;
return beatmapInfo.OnlineID > 0 ? $"[{api.WebsiteRootUrl}/b/{beatmapInfo.OnlineID} {beatmapInfoString}]" : beatmapInfoString;
}
string getRulesetPart()
{
if (api.Activity.Value is not UserActivity.InGame) return string.Empty;
return $"<{currentRuleset.Value.Name}>";
}
string getModPart()
{
if (api.Activity.Value is not UserActivity.InGame) return string.Empty;
if (selectedMods.Value.Count == 0)
{
return string.Empty;
}
StringBuilder modsString = new StringBuilder();
foreach (var mod in selectedMods.Value.Where(mod => mod.Type == ModType.DifficultyIncrease))
{
modsString.Append($"+{mod.Acronym} ");
}
foreach (var mod in selectedMods.Value.Where(mod => mod.Type != ModType.DifficultyIncrease))
{
modsString.Append($"-{mod.Acronym} ");
}
return modsString.ToString().Trim();
}
}
}
}

View File

@ -192,7 +192,7 @@ namespace osu.Game.Online.Chat
protected partial class StandAloneMessage : ChatLine
{
protected override float TextSize => 15;
protected override float FontSize => 15;
protected override float Spacing => 5;
protected override float UsernameWidth => 75;

View File

@ -33,11 +33,11 @@ namespace osu.Game.Online.Notifications
public override Task ConnectAsync(CancellationToken cancellationToken)
{
API.Queue(CreateFetchMessagesRequest(0));
API.Queue(CreateInitialFetchRequest(0));
return Task.CompletedTask;
}
protected APIRequest CreateFetchMessagesRequest(long? lastMessageId = null)
protected APIRequest CreateInitialFetchRequest(long? lastMessageId = null)
{
var fetchReq = new GetUpdatesRequest(lastMessageId ?? this.lastMessageId);
@ -67,8 +67,11 @@ namespace osu.Game.Online.Notifications
protected void HandleChannelParted(Channel channel) => ChannelParted?.Invoke(channel);
protected void HandleMessages(List<Message> messages)
protected void HandleMessages(List<Message>? messages)
{
if (messages == null)
return;
NewMessages?.Invoke(messages);
lastMessageId = Math.Max(lastMessageId, messages.LastOrDefault()?.Id ?? 0);
}

View File

@ -7,8 +7,6 @@ using Newtonsoft.Json;
namespace osu.Game.Online.Rooms
{
// TODO: Remove disable below after merging https://github.com/ppy/osu-framework/pull/5548 and applying follow-up changes game-side.
// ReSharper disable once PartialTypeWithSinglePart
public partial class APICreatedRoom : Room
{
[JsonProperty("error")]

View File

@ -16,7 +16,7 @@ using osu.Game.Online.Rooms.RoomStatuses;
namespace osu.Game.Online.Rooms
{
[JsonObject(MemberSerialization.OptIn)]
public partial class Room
public partial class Room : IDependencyInjectionCandidate
{
[Cached]
[JsonProperty("id")]

View File

@ -1,7 +1,6 @@
// 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;
using System.Linq;
using System.Collections.Generic;
using osu.Framework.Allocation;
@ -9,25 +8,20 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Chat;
using osuTK;
using osuTK.Graphics;
using osu.Framework.Graphics.Sprites;
namespace osu.Game.Overlays.Chat
{
public partial class ChatLine : CompositeDrawable
{
private Message message = null!;
public Message Message
{
get => message;
@ -44,49 +38,35 @@ namespace osu.Game.Overlays.Chat
}
}
public LinkFlowContainer ContentFlow { get; private set; } = null!;
public IReadOnlyCollection<Drawable> DrawableContentFlow => drawableContentFlow;
protected virtual float TextSize => 20;
protected virtual float FontSize => 20;
protected virtual float Spacing => 15;
protected virtual float UsernameWidth => 130;
private Color4 usernameColour;
private OsuSpriteText timestamp = null!;
private Message message = null!;
private OsuSpriteText username = null!;
private Container? highlight;
private readonly Bindable<bool> prefer24HourTime = new Bindable<bool>();
private bool senderHasColour => !string.IsNullOrEmpty(message.Sender.Colour);
private bool messageHasColour => Message.IsAction && senderHasColour;
[Resolved]
private ChannelManager? chatManager { get; set; }
[Resolved]
private OsuColour colours { get; set; } = null!;
private OverlayColourProvider? colourProvider { get; set; }
private readonly OsuSpriteText drawableTimestamp;
private readonly DrawableUsername drawableUsername;
private readonly LinkFlowContainer drawableContentFlow;
private readonly Bindable<bool> prefer24HourTime = new Bindable<bool>();
private Container? highlight;
public ChatLine(Message message)
{
Message = message;
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider? colourProvider, OsuConfigManager configManager)
{
usernameColour = senderHasColour
? Color4Extensions.FromHex(message.Sender.Colour)
: username_colours[message.Sender.Id % username_colours.Length];
InternalChild = new GridContainer
{
@ -103,30 +83,24 @@ namespace osu.Game.Overlays.Chat
{
new Drawable[]
{
timestamp = new OsuSpriteText
drawableTimestamp = new OsuSpriteText
{
Shadow = false,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Font = OsuFont.GetFont(size: TextSize * 0.75f, weight: FontWeight.SemiBold, fixedWidth: true),
Colour = colourProvider?.Background1 ?? Colour4.White,
Font = OsuFont.GetFont(size: FontSize * 0.75f, weight: FontWeight.SemiBold, fixedWidth: true),
AlwaysPresent = true,
},
new MessageSender(message.Sender)
drawableUsername = new DrawableUsername(message.Sender)
{
Width = UsernameWidth,
FontSize = FontSize,
AutoSizeAxes = Axes.Y,
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
Child = createUsername(),
Margin = new MarginPadding { Horizontal = Spacing },
},
ContentFlow = new LinkFlowContainer(t =>
{
t.Shadow = false;
t.Font = t.Font.With(size: TextSize, italics: Message.IsAction);
t.Colour = messageHasColour ? Color4Extensions.FromHex(message.Sender.Colour) : colourProvider?.Content1 ?? Colour4.White;
})
drawableContentFlow = new LinkFlowContainer(styleMessageContent)
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
@ -134,18 +108,23 @@ namespace osu.Game.Overlays.Chat
},
}
};
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager configManager)
{
configManager.BindWith(OsuSetting.Prefer24HourTime, prefer24HourTime);
prefer24HourTime.BindValueChanged(_ => updateTimestamp());
}
protected override void LoadComplete()
{
base.LoadComplete();
drawableTimestamp.Colour = colourProvider?.Background1 ?? Colour4.White;
updateMessageContent();
FinishTransforms(true);
prefer24HourTime.BindValueChanged(_ => updateTimestamp());
}
/// <summary>
@ -160,7 +139,7 @@ namespace osu.Game.Overlays.Chat
CornerRadius = 2f,
Masking = true,
RelativeSizeAxes = Axes.Both,
Colour = usernameColour.Darken(1f),
Colour = drawableUsername.AccentColour.Darken(1f),
Depth = float.MaxValue,
Child = new Box { RelativeSizeAxes = Axes.Both }
});
@ -170,166 +149,35 @@ namespace osu.Game.Overlays.Chat
highlight.Expire();
}
private void styleMessageContent(SpriteText text)
{
text.Shadow = false;
text.Font = text.Font.With(size: FontSize, italics: Message.IsAction);
bool messageHasColour = Message.IsAction && !string.IsNullOrEmpty(message.Sender.Colour);
text.Colour = messageHasColour ? Color4Extensions.FromHex(message.Sender.Colour) : colourProvider?.Content1 ?? Colour4.White;
}
private void updateMessageContent()
{
this.FadeTo(message is LocalEchoMessage ? 0.4f : 1.0f, 500, Easing.OutQuint);
timestamp.FadeTo(message is LocalEchoMessage ? 0 : 1, 500, Easing.OutQuint);
drawableTimestamp.FadeTo(message is LocalEchoMessage ? 0 : 1, 500, Easing.OutQuint);
updateTimestamp();
username.Text = $@"{message.Sender.Username}";
drawableUsername.Text = $@"{message.Sender.Username}";
// remove non-existent channels from the link list
message.Links.RemoveAll(link => link.Action == LinkAction.OpenChannel && chatManager?.AvailableChannels.Any(c => c.Name == link.Argument.ToString()) != true);
ContentFlow.Clear();
ContentFlow.AddLinks(message.DisplayContent, message.Links);
drawableContentFlow.Clear();
drawableContentFlow.AddLinks(message.DisplayContent, message.Links);
}
private void updateTimestamp()
{
timestamp.Text = prefer24HourTime.Value
drawableTimestamp.Text = prefer24HourTime.Value
? $@"{message.Timestamp.LocalDateTime:HH:mm:ss}"
: $@"{message.Timestamp.LocalDateTime:hh:mm:ss tt}";
}
private Drawable createUsername()
{
username = new OsuSpriteText
{
Shadow = false,
Colour = senderHasColour ? colours.ChatBlue : usernameColour,
Truncate = true,
EllipsisString = "…",
Font = OsuFont.GetFont(size: TextSize, weight: FontWeight.Bold, italics: true),
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
MaxWidth = UsernameWidth,
};
if (!senderHasColour)
return username;
// Background effect
return new Container
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
AutoSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 4,
EdgeEffect = new EdgeEffectParameters
{
Roundness = 1,
Radius = 1,
Colour = Color4.Black.Opacity(0.3f),
Offset = new Vector2(0, 1),
Type = EdgeEffectType.Shadow,
},
Child = new Container
{
AutoSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 4,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = usernameColour,
},
new Container
{
AutoSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = 4, Right = 4, Bottom = 1, Top = -2 },
Child = username
}
}
}
};
}
private partial class MessageSender : OsuClickableContainer, IHasContextMenu
{
private readonly APIUser sender;
private Action startChatAction = null!;
[Resolved]
private IAPIProvider api { get; set; } = null!;
public MessageSender(APIUser sender)
{
this.sender = sender;
}
[BackgroundDependencyLoader]
private void load(UserProfileOverlay? profile, ChannelManager? chatManager, ChatOverlay? chatOverlay)
{
Action = () => profile?.ShowUser(sender);
startChatAction = () =>
{
chatManager?.OpenPrivateChannel(sender);
chatOverlay?.Show();
};
}
public MenuItem[] ContextMenuItems
{
get
{
if (sender.Equals(APIUser.SYSTEM_USER))
return Array.Empty<MenuItem>();
List<MenuItem> items = new List<MenuItem>
{
new OsuMenuItem("View Profile", MenuItemType.Highlighted, Action)
};
if (!sender.Equals(api.LocalUser.Value))
items.Add(new OsuMenuItem("Start Chat", MenuItemType.Standard, startChatAction));
return items.ToArray();
}
}
}
private static readonly Color4[] username_colours =
{
Color4Extensions.FromHex("588c7e"),
Color4Extensions.FromHex("b2a367"),
Color4Extensions.FromHex("c98f65"),
Color4Extensions.FromHex("bc5151"),
Color4Extensions.FromHex("5c8bd6"),
Color4Extensions.FromHex("7f6ab7"),
Color4Extensions.FromHex("a368ad"),
Color4Extensions.FromHex("aa6880"),
Color4Extensions.FromHex("6fad9b"),
Color4Extensions.FromHex("f2e394"),
Color4Extensions.FromHex("f2ae72"),
Color4Extensions.FromHex("f98f8a"),
Color4Extensions.FromHex("7daef4"),
Color4Extensions.FromHex("a691f2"),
Color4Extensions.FromHex("c894d3"),
Color4Extensions.FromHex("d895b0"),
Color4Extensions.FromHex("53c4a1"),
Color4Extensions.FromHex("eace5c"),
Color4Extensions.FromHex("ea8c47"),
Color4Extensions.FromHex("fc4f4f"),
Color4Extensions.FromHex("3d94ea"),
Color4Extensions.FromHex("7760ea"),
Color4Extensions.FromHex("af52c6"),
Color4Extensions.FromHex("e25696"),
Color4Extensions.FromHex("677c66"),
Color4Extensions.FromHex("9b8732"),
Color4Extensions.FromHex("8c5129"),
Color4Extensions.FromHex("8c3030"),
Color4Extensions.FromHex("1f5d91"),
Color4Extensions.FromHex("4335a5"),
Color4Extensions.FromHex("812a96"),
Color4Extensions.FromHex("992861"),
};
}
}

View File

@ -0,0 +1,225 @@
// 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;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
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.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Chat;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.Chat
{
public partial class DrawableUsername : OsuClickableContainer, IHasContextMenu
{
public Color4 AccentColour { get; }
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) =>
Child.ReceivePositionalInputAt(screenSpacePos);
public float FontSize
{
set => drawableText.Font = OsuFont.GetFont(size: value, weight: FontWeight.Bold, italics: true);
}
public LocalisableString Text
{
set => drawableText.Text = value;
}
public override float Width
{
get => base.Width;
set => base.Width = drawableText.MaxWidth = value;
}
[Resolved]
private IAPIProvider api { get; set; } = null!;
[Resolved]
private OsuColour colours { get; set; } = null!;
[Resolved(canBeNull: true)]
private ChannelManager? chatManager { get; set; }
[Resolved(canBeNull: true)]
private ChatOverlay? chatOverlay { get; set; }
[Resolved(canBeNull: true)]
private UserProfileOverlay? profileOverlay { get; set; }
private readonly APIUser user;
private readonly OsuSpriteText drawableText;
private readonly Drawable colouredDrawable;
public DrawableUsername(APIUser user)
{
this.user = user;
Action = openUserProfile;
drawableText = new OsuSpriteText
{
Shadow = false,
Truncate = true,
EllipsisString = "…",
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
};
if (string.IsNullOrWhiteSpace(user.Colour))
{
AccentColour = default_colours[user.Id % default_colours.Length];
Child = colouredDrawable = drawableText;
}
else
{
AccentColour = Color4Extensions.FromHex(user.Colour);
Child = new Container
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
AutoSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 4,
EdgeEffect = new EdgeEffectParameters
{
Roundness = 1,
Radius = 1,
Colour = Color4.Black.Opacity(0.3f),
Offset = new Vector2(0, 1),
Type = EdgeEffectType.Shadow,
},
Child = new Container
{
AutoSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 4,
Children = new[]
{
colouredDrawable = new Box
{
RelativeSizeAxes = Axes.Both,
},
new Container
{
AutoSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = 4, Right = 4, Bottom = 1, Top = -2 },
Child = drawableText,
}
}
}
};
}
}
protected override void LoadComplete()
{
base.LoadComplete();
drawableText.Colour = colours.ChatBlue;
colouredDrawable.Colour = AccentColour;
}
public MenuItem[] ContextMenuItems
{
get
{
if (user.Equals(APIUser.SYSTEM_USER))
return Array.Empty<MenuItem>();
List<MenuItem> items = new List<MenuItem>
{
new OsuMenuItem("View Profile", MenuItemType.Highlighted, openUserProfile)
};
if (!user.Equals(api.LocalUser.Value))
items.Add(new OsuMenuItem("Start Chat", MenuItemType.Standard, openUserChannel));
return items.ToArray();
}
}
private void openUserChannel()
{
chatManager?.OpenPrivateChannel(user);
chatOverlay?.Show();
}
private void openUserProfile()
{
profileOverlay?.ShowUser(user);
}
protected override bool OnHover(HoverEvent e)
{
colouredDrawable.FadeColour(AccentColour.Lighten(0.6f), 30, Easing.OutQuint);
return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e)
{
base.OnHoverLost(e);
colouredDrawable.FadeColour(AccentColour, 800, Easing.OutQuint);
}
private static readonly Color4[] default_colours =
{
Color4Extensions.FromHex("588c7e"),
Color4Extensions.FromHex("b2a367"),
Color4Extensions.FromHex("c98f65"),
Color4Extensions.FromHex("bc5151"),
Color4Extensions.FromHex("5c8bd6"),
Color4Extensions.FromHex("7f6ab7"),
Color4Extensions.FromHex("a368ad"),
Color4Extensions.FromHex("aa6880"),
Color4Extensions.FromHex("6fad9b"),
Color4Extensions.FromHex("f2e394"),
Color4Extensions.FromHex("f2ae72"),
Color4Extensions.FromHex("f98f8a"),
Color4Extensions.FromHex("7daef4"),
Color4Extensions.FromHex("a691f2"),
Color4Extensions.FromHex("c894d3"),
Color4Extensions.FromHex("d895b0"),
Color4Extensions.FromHex("53c4a1"),
Color4Extensions.FromHex("eace5c"),
Color4Extensions.FromHex("ea8c47"),
Color4Extensions.FromHex("fc4f4f"),
Color4Extensions.FromHex("3d94ea"),
Color4Extensions.FromHex("7760ea"),
Color4Extensions.FromHex("af52c6"),
Color4Extensions.FromHex("e25696"),
Color4Extensions.FromHex("677c66"),
Color4Extensions.FromHex("9b8732"),
Color4Extensions.FromHex("8c5129"),
Color4Extensions.FromHex("8c3030"),
Color4Extensions.FromHex("1f5d91"),
Color4Extensions.FromHex("4335a5"),
Color4Extensions.FromHex("812a96"),
Color4Extensions.FromHex("992861"),
};
}
}

View File

@ -331,11 +331,11 @@ namespace osu.Game.Overlays.Comments
if (WasDeleted)
makeDeleted();
actionsContainer.AddLink("Copy link", copyUrl);
actionsContainer.AddLink(CommonStrings.ButtonsPermalink, copyUrl);
actionsContainer.AddArbitraryDrawable(Empty().With(d => d.Width = 10));
if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id)
actionsContainer.AddLink("Delete", deleteComment);
actionsContainer.AddLink(CommonStrings.ButtonsDelete, deleteComment);
else
actionsContainer.AddArbitraryDrawable(new CommentReportButton(Comment));
@ -553,12 +553,12 @@ namespace osu.Game.Overlays.Comments
};
}
private string getParentMessage()
private LocalisableString getParentMessage()
{
if (parentComment == null)
return string.Empty;
return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? "deleted" : string.Empty;
return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? CommentsStrings.Deleted : string.Empty;
}
}
}

View File

@ -233,7 +233,7 @@ namespace osu.Game.Overlays.FirstRunSetup
return parentDependencies.Get(type, info);
}
public void Inject<T>(T instance) where T : class
public void Inject<T>(T instance) where T : class, IDependencyInjectionCandidate
{
parentDependencies.Inject(instance);
}

View File

@ -177,13 +177,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
updateScreenModeWarning();
}, true);
windowModes.BindCollectionChanged((_, _) =>
{
if (windowModes.Count > 1)
windowModeDropdown.Show();
else
windowModeDropdown.Hide();
}, true);
windowModes.BindCollectionChanged((_, _) => updateDisplaySettingsVisibility());
currentDisplay.BindValueChanged(display => Schedule(() =>
{
@ -219,7 +213,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
scalingSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint);
scalingSettings.AutoSizeAxes = scalingMode.Value != ScalingMode.Off ? Axes.Y : Axes.None;
scalingSettings.ForEach(s => s.TransferValueOnCommit = scalingMode.Value == ScalingMode.Everything);
scalingSettings.ForEach(s =>
{
s.TransferValueOnCommit = scalingMode.Value == ScalingMode.Everything;
s.CanBeShown.Value = scalingMode.Value != ScalingMode.Off;
});
}
}
@ -234,20 +232,10 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
private void updateDisplaySettingsVisibility()
{
if (resolutions.Count > 1 && windowModeDropdown.Current.Value == WindowMode.Fullscreen)
resolutionDropdown.Show();
else
resolutionDropdown.Hide();
if (displayDropdown.Items.Count() > 1)
displayDropdown.Show();
else
displayDropdown.Hide();
if (host.Window?.SafeAreaPadding.Value.Total != Vector2.Zero)
safeAreaConsiderationsCheckbox.Show();
else
safeAreaConsiderationsCheckbox.Hide();
windowModeDropdown.CanBeShown.Value = windowModes.Count > 1;
resolutionDropdown.CanBeShown.Value = resolutions.Count > 1 && windowModeDropdown.Current.Value == WindowMode.Fullscreen;
displayDropdown.CanBeShown.Value = displayDropdown.Items.Count() > 1;
safeAreaConsiderationsCheckbox.CanBeShown.Value = host.Window?.SafeAreaPadding.Value.Total != Vector2.Zero;
}
private void updateScreenModeWarning()

View File

@ -143,6 +143,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
areaOffset.SetDefault();
areaSize.SetDefault();
},
CanBeShown = { BindTarget = enabled }
},
new SettingsButton
{
@ -150,25 +151,29 @@ namespace osu.Game.Overlays.Settings.Sections.Input
Action = () =>
{
forceAspectRatio((float)host.Window.ClientSize.Width / host.Window.ClientSize.Height);
}
},
CanBeShown = { BindTarget = enabled }
},
new SettingsSlider<float>
{
TransferValueOnCommit = true,
LabelText = TabletSettingsStrings.XOffset,
Current = offsetX
Current = offsetX,
CanBeShown = { BindTarget = enabled }
},
new SettingsSlider<float>
{
TransferValueOnCommit = true,
LabelText = TabletSettingsStrings.YOffset,
Current = offsetY
Current = offsetY,
CanBeShown = { BindTarget = enabled }
},
new SettingsSlider<float>
{
TransferValueOnCommit = true,
LabelText = TabletSettingsStrings.Rotation,
Current = rotation
Current = rotation,
CanBeShown = { BindTarget = enabled }
},
new RotationPresetButtons(tabletHandler)
{
@ -181,24 +186,28 @@ namespace osu.Game.Overlays.Settings.Sections.Input
{
TransferValueOnCommit = true,
LabelText = TabletSettingsStrings.AspectRatio,
Current = aspectRatio
Current = aspectRatio,
CanBeShown = { BindTarget = enabled }
},
new SettingsCheckbox
{
LabelText = TabletSettingsStrings.LockAspectRatio,
Current = aspectLock
Current = aspectLock,
CanBeShown = { BindTarget = enabled }
},
new SettingsSlider<float>
{
TransferValueOnCommit = true,
LabelText = CommonStrings.Width,
Current = sizeX
Current = sizeX,
CanBeShown = { BindTarget = enabled }
},
new SettingsSlider<float>
{
TransferValueOnCommit = true,
LabelText = CommonStrings.Height,
Current = sizeY
Current = sizeY,
CanBeShown = { BindTarget = enabled }
},
}
},

View File

@ -3,14 +3,16 @@
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterfaceV2;
namespace osu.Game.Overlays.Settings
{
public partial class SettingsButton : RoundedButton, IHasTooltip
public partial class SettingsButton : RoundedButton, IHasTooltip, IConditionalFilterable
{
public SettingsButton()
{
@ -20,6 +22,9 @@ namespace osu.Game.Overlays.Settings
public LocalisableString TooltipText { get; set; }
public BindableBool CanBeShown { get; } = new BindableBool(true);
IBindable<bool> IConditionalFilterable.CanBeShown => CanBeShown;
public override IEnumerable<LocalisableString> FilterTerms
{
get

View File

@ -22,7 +22,7 @@ using osuTK;
namespace osu.Game.Overlays.Settings
{
public abstract partial class SettingsItem<T> : Container, IFilterable, ISettingsItem, IHasCurrentValue<T>, IHasTooltip
public abstract partial class SettingsItem<T> : Container, IConditionalFilterable, ISettingsItem, IHasCurrentValue<T>, IHasTooltip
{
protected abstract Drawable CreateControl();
@ -144,6 +144,9 @@ namespace osu.Game.Overlays.Settings
public bool FilteringActive { get; set; }
public BindableBool CanBeShown { get; } = new BindableBool(true);
IBindable<bool> IConditionalFilterable.CanBeShown => CanBeShown;
public event Action SettingChanged;
private T classicDefault;

View File

@ -5,7 +5,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -19,7 +18,7 @@ using osuTK;
namespace osu.Game.Overlays.Settings
{
public abstract partial class SettingsSection : Container, IHasFilterableChildren
public abstract partial class SettingsSection : Container, IFilterable
{
protected FillFlowContainer FlowContent;
protected override Container<Drawable> Content => FlowContent;
@ -33,7 +32,6 @@ namespace osu.Game.Overlays.Settings
public abstract Drawable CreateIcon();
public abstract LocalisableString Header { get; }
public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>();
public virtual IEnumerable<LocalisableString> FilterTerms => new[] { Header };
public const int ITEM_SPACING = 14;

View File

@ -8,7 +8,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Localisation;
using osu.Framework.Testing;
@ -17,7 +16,7 @@ using osu.Game.Graphics;
namespace osu.Game.Overlays.Settings
{
[ExcludeFromDynamicCompile]
public abstract partial class SettingsSubsection : FillFlowContainer, IHasFilterableChildren
public abstract partial class SettingsSubsection : FillFlowContainer, IFilterable
{
protected override Container<Drawable> Content => FlowContent;
@ -25,8 +24,6 @@ namespace osu.Game.Overlays.Settings
protected abstract LocalisableString Header { get; }
public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>();
public virtual IEnumerable<LocalisableString> FilterTerms => new[] { Header };
public bool MatchingFilter

View File

@ -1,8 +1,7 @@
// 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.
#nullable disable
using System;
using osu.Framework.Allocation;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
@ -20,6 +19,8 @@ namespace osu.Game.Screens.Edit
{
public abstract partial class EditorTable : TableContainer
{
public event Action<Drawable>? OnRowSelected;
private const float horizontal_inset = 20;
protected const float ROW_HEIGHT = 25;
@ -45,7 +46,18 @@ namespace osu.Game.Screens.Edit
});
}
protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? default);
protected void SetSelectedRow(object? item)
{
foreach (var b in BackgroundFlow)
{
b.Selected = ReferenceEquals(b.Item, item);
if (b.Selected)
OnRowSelected?.Invoke(b);
}
}
protected override Drawable CreateHeader(int index, TableColumn? column) => new HeaderText(column?.Header ?? default);
private partial class HeaderText : OsuSpriteText
{
@ -84,11 +96,6 @@ namespace osu.Game.Screens.Edit
Alpha = 0,
},
};
// todo delete
Action = () =>
{
};
}
private Color4 colourHover;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
@ -23,10 +21,10 @@ namespace osu.Game.Screens.Edit.Timing
public partial class ControlPointTable : EditorTable
{
[Resolved]
private Bindable<ControlPointGroup> selectedGroup { get; set; }
private Bindable<ControlPointGroup> selectedGroup { get; set; } = null!;
[Resolved]
private EditorClock clock { get; set; }
private EditorClock clock { get; set; } = null!;
public const float TIMING_COLUMN_WIDTH = 230;
@ -37,7 +35,7 @@ namespace osu.Game.Screens.Edit.Timing
Content = null;
BackgroundFlow.Clear();
if (value?.Any() != true)
if (!value.Any())
return;
foreach (var group in value)
@ -63,19 +61,10 @@ namespace osu.Game.Screens.Edit.Timing
{
base.LoadComplete();
selectedGroup.BindValueChanged(_ =>
{
// TODO: This should scroll the selected row into view.
updateSelectedGroup();
}, true);
selectedGroup.BindValueChanged(_ => updateSelectedGroup(), true);
}
private void updateSelectedGroup()
{
// TODO: This should scroll the selected row into view.
foreach (var b in BackgroundFlow)
b.Selected = ReferenceEquals(b.Item, selectedGroup?.Value);
}
private void updateSelectedGroup() => SetSelectedRow(selectedGroup.Value);
private TableColumn[] createHeaders()
{
@ -92,32 +81,38 @@ namespace osu.Game.Screens.Edit.Timing
{
return new Drawable[]
{
new FillFlowContainer
{
RelativeSizeAxes = Axes.Y,
Width = TIMING_COLUMN_WIDTH,
Spacing = new Vector2(5),
Children = new Drawable[]
{
new OsuSpriteText
{
Text = group.Time.ToEditorFormattedString(),
Font = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.Bold),
Width = 70,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
},
new ControlGroupAttributes(group, c => c is TimingControlPoint)
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
}
}
},
new ControlGroupAttributes(group, c => !(c is TimingControlPoint))
new ControlGroupTiming(group),
new ControlGroupAttributes(group, c => c is not TimingControlPoint)
};
}
private partial class ControlGroupTiming : FillFlowContainer
{
public ControlGroupTiming(ControlPointGroup group)
{
Name = @"ControlGroupTiming";
RelativeSizeAxes = Axes.Y;
Width = TIMING_COLUMN_WIDTH;
Spacing = new Vector2(5);
Children = new Drawable[]
{
new OsuSpriteText
{
Text = group.Time.ToEditorFormattedString(),
Font = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.Bold),
Width = 70,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
},
new ControlGroupAttributes(group, c => c is TimingControlPoint)
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
}
};
}
}
private partial class ControlGroupAttributes : CompositeDrawable
{
private readonly Func<ControlPoint, bool> matchFunction;
@ -132,6 +127,7 @@ namespace osu.Game.Screens.Edit.Timing
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
Name = @"ControlGroupAttributes";
InternalChild = fill = new FillFlowContainer
{
@ -161,7 +157,6 @@ namespace osu.Game.Screens.Edit.Timing
fill.ChildrenEnumerable = controlPoints
.Where(matchFunction)
.Select(createAttribute)
.Where(c => c != null)
// arbitrary ordering to make timing points first.
// probably want to explicitly define order in the future.
.OrderByDescending(c => c.GetType().Name);
@ -184,7 +179,7 @@ namespace osu.Game.Screens.Edit.Timing
return new SampleRowAttribute(sample);
}
return null;
throw new ArgumentOutOfRangeException(nameof(controlPoint), $"Control point type {controlPoint.GetType()} is not supported");
}
}
}

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using System;
using System.Linq;
using osu.Framework.Allocation;
@ -50,24 +48,24 @@ namespace osu.Game.Screens.Edit.Timing
public partial class ControlPointList : CompositeDrawable
{
private OsuButton deleteButton;
private ControlPointTable table;
private OsuButton deleteButton = null!;
private ControlPointTable table = null!;
private OsuScrollContainer scroll = null!;
private RoundedButton addButton = null!;
private readonly IBindableList<ControlPointGroup> controlPointGroups = new BindableList<ControlPointGroup>();
private RoundedButton addButton;
[Resolved]
private EditorClock clock { get; set; } = null!;
[Resolved]
private EditorClock clock { get; set; }
protected EditorBeatmap Beatmap { get; private set; } = null!;
[Resolved]
protected EditorBeatmap Beatmap { get; private set; }
private Bindable<ControlPointGroup?> selectedGroup { get; set; } = null!;
[Resolved]
private Bindable<ControlPointGroup> selectedGroup { get; set; }
[Resolved(canBeNull: true)]
private IEditorChangeHandler changeHandler { get; set; }
private IEditorChangeHandler? changeHandler { get; set; }
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colours)
@ -88,7 +86,7 @@ namespace osu.Game.Screens.Edit.Timing
RelativeSizeAxes = Axes.Y,
Width = ControlPointTable.TIMING_COLUMN_WIDTH + margins,
},
new OsuScrollContainer
scroll = new OsuScrollContainer
{
RelativeSizeAxes = Axes.Both,
Child = table = new ControlPointTable(),
@ -142,6 +140,8 @@ namespace osu.Game.Screens.Edit.Timing
table.ControlGroups = controlPointGroups;
changeHandler?.SaveState();
}, true);
table.OnRowSelected += drawable => scroll.ScrollIntoView(drawable);
}
protected override bool OnClick(ClickEvent e)
@ -159,7 +159,7 @@ namespace osu.Game.Screens.Edit.Timing
addButton.Enabled.Value = clock.CurrentTimeAccurate != selectedGroup.Value?.Time;
}
private Type trackedType;
private Type? trackedType;
/// <summary>
/// Given the user has selected a control point group, we want to track any group which is

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
@ -20,19 +18,19 @@ namespace osu.Game.Screens.Edit.Verify
{
public partial class IssueTable : EditorTable
{
[Resolved]
private VerifyScreen verify { get; set; }
private Bindable<Issue> selectedIssue;
private Bindable<Issue> selectedIssue = null!;
[Resolved]
private EditorClock clock { get; set; }
private VerifyScreen verify { get; set; } = null!;
[Resolved]
private EditorBeatmap editorBeatmap { get; set; }
private EditorClock clock { get; set; } = null!;
[Resolved]
private Editor editor { get; set; }
private EditorBeatmap editorBeatmap { get; set; } = null!;
[Resolved]
private Editor editor { get; set; } = null!;
public IEnumerable<Issue> Issues
{
@ -41,7 +39,7 @@ namespace osu.Game.Screens.Edit.Verify
Content = null;
BackgroundFlow.Clear();
if (value == null)
if (!value.Any())
return;
foreach (var issue in value)
@ -79,7 +77,7 @@ namespace osu.Game.Screens.Edit.Verify
selectedIssue = verify.SelectedIssue.GetBoundCopy();
selectedIssue.BindValueChanged(issue =>
{
foreach (var b in BackgroundFlow) b.Selected = b.Item == issue.NewValue;
SetSelectedRow(issue.NewValue);
}, true);
}

View File

@ -1,152 +0,0 @@
// 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;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.Select
{
internal partial class DifficultyRangeFilterControl : CompositeDrawable
{
private Bindable<double> lowerStars = null!;
private Bindable<double> upperStars = null!;
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
const float vertical_offset = 13;
InternalChildren = new Drawable[]
{
new OsuSpriteText
{
Text = "Difficulty range",
Font = OsuFont.GetFont(size: 14),
},
new MaximumStarsSlider
{
Current = config.GetBindable<double>(OsuSetting.DisplayStarsMaximum),
KeyboardStep = 0.1f,
RelativeSizeAxes = Axes.X,
Y = vertical_offset,
},
new MinimumStarsSlider
{
Current = config.GetBindable<double>(OsuSetting.DisplayStarsMinimum),
KeyboardStep = 0.1f,
RelativeSizeAxes = Axes.X,
Y = vertical_offset,
}
};
lowerStars = config.GetBindable<double>(OsuSetting.DisplayStarsMinimum);
upperStars = config.GetBindable<double>(OsuSetting.DisplayStarsMaximum);
}
protected override void LoadComplete()
{
base.LoadComplete();
lowerStars.ValueChanged += min => upperStars.Value = Math.Max(min.NewValue + 0.1, upperStars.Value);
upperStars.ValueChanged += max => lowerStars.Value = Math.Min(max.NewValue - 0.1, lowerStars.Value);
}
private partial class MinimumStarsSlider : StarsSlider
{
public MinimumStarsSlider()
: base("0")
{
}
public override LocalisableString TooltipText => Current.Value.ToString(@"0.## stars");
protected override void LoadComplete()
{
base.LoadComplete();
LeftBox.Height = 6; // hide any colour bleeding from overlap
AccentColour = BackgroundColour;
BackgroundColour = Color4.Transparent;
}
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) =>
base.ReceivePositionalInputAt(screenSpacePos)
&& screenSpacePos.X <= Nub.ScreenSpaceDrawQuad.TopRight.X;
}
private partial class MaximumStarsSlider : StarsSlider
{
public MaximumStarsSlider()
: base("∞")
{
}
protected override void LoadComplete()
{
base.LoadComplete();
RightBox.Height = 6; // just to match the left bar height really
}
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) =>
base.ReceivePositionalInputAt(screenSpacePos)
&& screenSpacePos.X >= Nub.ScreenSpaceDrawQuad.TopLeft.X;
}
private partial class StarsSlider : OsuSliderBar<double>
{
private readonly string defaultString;
public override LocalisableString TooltipText => Current.IsDefault
? UserInterfaceStrings.NoLimit
: Current.Value.ToString(@"0.## stars");
protected StarsSlider(string defaultString)
{
this.defaultString = defaultString;
}
protected override bool OnHover(HoverEvent e)
{
base.OnHover(e);
return true; // Make sure only one nub shows hover effect at once.
}
protected override void LoadComplete()
{
base.LoadComplete();
Nub.Width = Nub.HEIGHT;
RangePadding = Nub.Width / 2;
OsuSpriteText currentDisplay;
Nub.Add(currentDisplay = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Y = -0.5f,
Colour = Color4.White,
Font = OsuFont.Torus.With(size: 10),
});
Current.BindValueChanged(current =>
{
currentDisplay.Text = current.NewValue != Current.Default ? current.NewValue.ToString("N1") : defaultString;
}, true);
}
}
}
}

View File

@ -16,6 +16,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets;
using osu.Game.Screens.Select.Filter;
@ -172,12 +173,19 @@ namespace osu.Game.Screens.Select
Height = 40,
Children = new Drawable[]
{
new DifficultyRangeFilterControl
new RangeSlider
{
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
Label = "Difficulty range",
LowerBound = config.GetBindable<double>(OsuSetting.DisplayStarsMinimum),
UpperBound = config.GetBindable<double>(OsuSetting.DisplayStarsMaximum),
RelativeSizeAxes = Axes.Both,
Width = 0.48f,
DefaultStringLowerBound = "0",
DefaultStringUpperBound = "∞",
DefaultTooltipUpperBound = UserInterfaceStrings.NoLimit,
TooltipSuffix = "stars"
},
collectionDropdown = new CollectionDropdown
{

View File

@ -164,7 +164,7 @@ namespace osu.Game.Tests.Beatmaps
return fallback.Get(type, info);
}
public void Inject<T>(T instance) where T : class
public void Inject<T>(T instance) where T : class, IDependencyInjectionCandidate
{
// Never used directly
}

View File

@ -24,7 +24,7 @@ namespace osu.Game.Tests
{
while (!cancellationToken.IsCancellationRequested)
{
await API.PerformAsync(CreateFetchMessagesRequest());
await API.PerformAsync(CreateInitialFetchRequest());
await Task.Delay(1000, cancellationToken);
}
}, cancellationToken);

View File

@ -128,7 +128,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay
=> OnlinePlayDependencies?.Get(type, info) ?? parent.Get(type, info);
public void Inject<T>(T instance)
where T : class
where T : class, IDependencyInjectionCandidate
=> injectableDependencies.Inject(instance);
}
}

View File

@ -65,7 +65,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay
=> dependencies.Get(type, info);
public void Inject<T>(T instance)
where T : class
where T : class, IDependencyInjectionCandidate
=> dependencies.Inject(instance);
protected void Cache(object instance)

View File

@ -35,7 +35,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Realm" Version="10.18.0" />
<PackageReference Include="ppy.osu.Framework" Version="2022.1126.0" />
<PackageReference Include="ppy.osu.Framework" Version="2022.1130.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.1127.0" />
<PackageReference Include="Sentry" Version="3.23.1" />
<PackageReference Include="SharpCompress" Version="0.32.2" />

View File

@ -62,7 +62,7 @@
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.1127.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.1126.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.1130.0" />
</ItemGroup>
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net6.0) -->
<PropertyGroup>
@ -82,7 +82,7 @@
<PackageReference Include="DiffPlex" Version="1.7.1" />
<PackageReference Include="Humanizer" Version="2.14.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2022.1126.0" />
<PackageReference Include="ppy.osu.Framework" Version="2022.1130.0" />
<PackageReference Include="SharpCompress" Version="0.32.2" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />