diff --git a/osu.Android.props b/osu.Android.props
index 8f4750e831..75828147a5 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,7 +52,7 @@
-
+
diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs
index 8d6aef99ad..ae1f3de6bf 100644
--- a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs
+++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs
@@ -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));
}
}
}
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs
index 86a977fd3f..216c35de65 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs
@@ -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().Any());
+ AddStep("Reload Editor Beatmap", reloadEditorBeatmap);
+
+ AddUntilStep("Wait for rows to load", () => Child.ChildrenOfType().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().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().First().IsScrolledToEnd());
+ }
+
protected override void Dispose(bool isDisposing)
{
Beatmap.Disabled = false;
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs
index aa33866fa4..f5cf4c1ff2 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs
@@ -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);
}
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs
index c017227243..4675410164 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs
@@ -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() });
+
+ 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)
diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs
index 4e295ba665..24c2eee783 100644
--- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs
+++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs
@@ -62,7 +62,6 @@ namespace osu.Game.Tests.Visual.Settings
section.Children.Where(f => f.IsPresent)
.OfType()
.OfType()
- .Where(f => !(f is IHasFilterableChildren))
.All(f => f.FilterTerms.Any(t => t.ToString().Contains("scaling")))
));
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeFilterControl.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeFilterControl.cs
deleted file mode 100644
index 275e6ca753..0000000000
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeFilterControl.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) ppy Pty Ltd . 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),
- };
- });
- }
- }
-}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs
new file mode 100644
index 0000000000..b780764e7f
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs
@@ -0,0 +1,79 @@
+// Copyright (c) ppy Pty Ltd . 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 customStart = new BindableNumber
+ {
+ MinValue = 0,
+ MaxValue = 100,
+ Precision = 0.1f
+ };
+
+ private readonly BindableNumber customEnd = new BindableNumber(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));
+ }
+ }
+}
diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs
index 6e9e7591a8..d543f082b4 100644
--- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs
+++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs
@@ -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;
///
/// sqrt(3) / 2
///
private const float equilateral_triangle_ratio = 0.866f;
- private readonly Bindable colourTop = new Bindable(Color4.White);
- private readonly Bindable colourBottom = new Bindable(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()
///
@@ -70,9 +52,6 @@ namespace osu.Game.Graphics.Backgrounds
private readonly List parts = new List();
- [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(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 parts = new List();
+
+ 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("thickness").UpdateValue(ref thickness);
shader.GetUniform("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);
diff --git a/osu.Game/Graphics/UserInterface/RangeSlider.cs b/osu.Game/Graphics/UserInterface/RangeSlider.cs
new file mode 100644
index 0000000000..483119cd58
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/RangeSlider.cs
@@ -0,0 +1,212 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+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
+ {
+ ///
+ /// The lower limiting value
+ ///
+ public Bindable LowerBound
+ {
+ get => lowerBound.Current;
+ set => lowerBound.Current = value;
+ }
+
+ ///
+ /// The upper limiting value
+ ///
+ public Bindable UpperBound
+ {
+ get => upperBound.Current;
+ set => upperBound.Current = value;
+ }
+
+ ///
+ /// Text that describes this RangeSlider's functionality
+ ///
+ public string Label
+ {
+ set => label.Text = value;
+ }
+
+ public float NubWidth
+ {
+ set => lowerBound.NubWidth = upperBound.NubWidth = value;
+ }
+
+ ///
+ /// Minimum difference between the lower bound and higher bound
+ ///
+ public float MinRange
+ {
+ set => minRange = value;
+ }
+
+ ///
+ /// lower bound display for when it is set to its default value
+ ///
+ public string DefaultStringLowerBound
+ {
+ set => lowerBound.DefaultString = value;
+ }
+
+ ///
+ /// upper bound display for when it is set to its default value
+ ///
+ 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
+ {
+ 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;
+ }
+ }
+ }
+}
diff --git a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs
index 6dc99f5269..6aded3fe32 100644
--- a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs
+++ b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs
@@ -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)
diff --git a/osu.Game/Online/API/Requests/GetUpdatesRequest.cs b/osu.Game/Online/API/Requests/GetUpdatesRequest.cs
index ce2689d262..529c579996 100644
--- a/osu.Game/Online/API/Requests/GetUpdatesRequest.cs
+++ b/osu.Game/Online/API/Requests/GetUpdatesRequest.cs
@@ -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;
}
diff --git a/osu.Game/Online/API/Requests/GetUpdatesResponse.cs b/osu.Game/Online/API/Requests/GetUpdatesResponse.cs
index 61f6a8664d..7e030ce922 100644
--- a/osu.Game/Online/API/Requests/GetUpdatesResponse.cs
+++ b/osu.Game/Online/API/Requests/GetUpdatesResponse.cs
@@ -16,5 +16,7 @@ namespace osu.Game.Online.API.Requests
[JsonProperty]
public List Messages;
+
+ // TODO: Handle Silences here (will need to add to includes[] in the request).
}
}
diff --git a/osu.Game/Online/Chat/NowPlayingCommand.cs b/osu.Game/Online/Chat/NowPlayingCommand.cs
index 76f1de5f29..9902704883 100644
--- a/osu.Game/Online/Chat/NowPlayingCommand.cs
+++ b/osu.Game/Online/Chat/NowPlayingCommand.cs
@@ -1,13 +1,17 @@
// Copyright (c) ppy Pty Ltd . 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 currentBeatmap { get; set; }
+ private Bindable currentBeatmap { get; set; } = null!;
- private readonly Channel target;
+ [Resolved]
+ private Bindable> selectedMods { get; set; } = null!;
+
+ [Resolved]
+ private IBindable currentRuleset { get; set; } = null!;
+
+ [Resolved]
+ private LocalisationManager localisation { get; set; } = null!;
+
+ private readonly Channel? target;
///
/// Creates a new to post the currently-playing beatmap to a parenting .
///
/// The target channel to post to. If null, the currently-selected channel will be posted to.
- 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();
+ }
}
}
}
diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs
index 9c89333ee7..7fd6f99102 100644
--- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs
+++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs
@@ -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;
diff --git a/osu.Game/Online/Notifications/NotificationsClient.cs b/osu.Game/Online/Notifications/NotificationsClient.cs
index 6198707111..5762e0e588 100644
--- a/osu.Game/Online/Notifications/NotificationsClient.cs
+++ b/osu.Game/Online/Notifications/NotificationsClient.cs
@@ -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 messages)
+ protected void HandleMessages(List? messages)
{
+ if (messages == null)
+ return;
+
NewMessages?.Invoke(messages);
lastMessageId = Math.Max(lastMessageId, messages.LastOrDefault()?.Id ?? 0);
}
diff --git a/osu.Game/Online/Rooms/APICreatedRoom.cs b/osu.Game/Online/Rooms/APICreatedRoom.cs
index 7f2bd13aec..254a338a60 100644
--- a/osu.Game/Online/Rooms/APICreatedRoom.cs
+++ b/osu.Game/Online/Rooms/APICreatedRoom.cs
@@ -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")]
diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs
index bdd7d6ce1c..8f346c4057 100644
--- a/osu.Game/Online/Rooms/Room.cs
+++ b/osu.Game/Online/Rooms/Room.cs
@@ -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")]
diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs
index 1c768101bf..2b8718939e 100644
--- a/osu.Game/Overlays/Chat/ChatLine.cs
+++ b/osu.Game/Overlays/Chat/ChatLine.cs
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
using 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 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 prefer24HourTime = new Bindable();
-
- 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 prefer24HourTime = new Bindable();
+
+ 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());
}
///
@@ -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
-
+
@@ -82,7 +82,7 @@
-
+