1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 11:22:57 +08:00

Merge remote-tracking branch 'upstream/master' into flashlight-dim

This commit is contained in:
David Zhao 2019-05-07 12:04:58 +09:00
commit 732b0b22a3
196 changed files with 2679 additions and 1463 deletions

View File

@ -6,6 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces; using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;

View File

@ -3,7 +3,7 @@
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;
using osuTK.Graphics; using osuTK.Graphics;

View File

@ -7,6 +7,7 @@ using osuTK.Graphics;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;

View File

@ -5,7 +5,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;

View File

@ -7,6 +7,7 @@ using osuTK.Graphics;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;

View File

@ -4,6 +4,7 @@
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;
using osuTK.Graphics; using osuTK.Graphics;

View File

@ -6,6 +6,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;

View File

@ -7,6 +7,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Graphics; using osu.Game.Graphics;

View File

@ -4,6 +4,7 @@
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;

View File

@ -12,6 +12,7 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
@ -41,6 +42,8 @@ namespace osu.Game.Rulesets.Osu.Mods
scoreProcessor.Health.ValueChanged += health => { blinds.AnimateClosedness((float)health.NewValue); }; scoreProcessor.Health.ValueChanged += health => { blinds.AnimateClosedness((float)health.NewValue); };
} }
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
/// <summary> /// <summary>
/// Element for the Blinds mod drawing 2 black boxes covering the whole screen which resize inside a restricted area with some leniency. /// Element for the Blinds mod drawing 2 black boxes covering the whole screen which resize inside a restricted area with some leniency.
/// </summary> /// </summary>

View File

@ -6,6 +6,7 @@ using osuTK.Graphics;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Skinning; using osu.Game.Skinning;

View File

@ -4,6 +4,7 @@
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;

View File

@ -4,6 +4,7 @@
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;

View File

@ -5,6 +5,7 @@ using System;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;

View File

@ -43,22 +43,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private readonly InputResampler resampler = new InputResampler(); private readonly InputResampler resampler = new InputResampler();
protected override DrawNode CreateDrawNode() => new TrailDrawNode(); protected override DrawNode CreateDrawNode() => new TrailDrawNode(this);
protected override void ApplyDrawNode(DrawNode node)
{
base.ApplyDrawNode(node);
TrailDrawNode tNode = (TrailDrawNode)node;
tNode.Shader = shader;
tNode.Texture = texture;
tNode.Size = size;
tNode.Time = time;
for (int i = 0; i < parts.Length; ++i)
if (parts[i].InvalidationID > tNode.Parts[i].InvalidationID)
tNode.Parts[i] = parts[i];
}
public CursorTrail() public CursorTrail()
{ {
@ -167,33 +152,52 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private class TrailDrawNode : DrawNode private class TrailDrawNode : DrawNode
{ {
public IShader Shader; protected new CursorTrail Source => (CursorTrail)base.Source;
public Texture Texture;
public float Time; private IShader shader;
private Texture texture;
public readonly TrailPart[] Parts = new TrailPart[max_sprites]; private float time;
public Vector2 Size;
private readonly TrailPart[] parts = new TrailPart[max_sprites];
private Vector2 size;
private readonly VertexBuffer<TexturedTrailVertex> vertexBuffer = new QuadVertexBuffer<TexturedTrailVertex>(max_sprites, BufferUsageHint.DynamicDraw); private readonly VertexBuffer<TexturedTrailVertex> vertexBuffer = new QuadVertexBuffer<TexturedTrailVertex>(max_sprites, BufferUsageHint.DynamicDraw);
public TrailDrawNode() public TrailDrawNode(CursorTrail source)
: base(source)
{ {
for (int i = 0; i < max_sprites; i++) for (int i = 0; i < max_sprites; i++)
{ {
Parts[i].InvalidationID = 0; parts[i].InvalidationID = 0;
Parts[i].WasUpdated = false; parts[i].WasUpdated = false;
}
}
public override void ApplyState()
{
base.ApplyState();
shader = Source.shader;
texture = Source.texture;
size = Source.size;
time = Source.time;
for (int i = 0; i < Source.parts.Length; ++i)
{
if (Source.parts[i].InvalidationID > parts[i].InvalidationID)
parts[i] = Source.parts[i];
} }
} }
public override void Draw(Action<TexturedVertex2D> vertexAction) public override void Draw(Action<TexturedVertex2D> vertexAction)
{ {
Shader.GetUniform<float>("g_FadeClock").UpdateValue(ref Time); shader.GetUniform<float>("g_FadeClock").UpdateValue(ref time);
int updateStart = -1, updateEnd = 0; int updateStart = -1, updateEnd = 0;
for (int i = 0; i < Parts.Length; ++i) for (int i = 0; i < parts.Length; ++i)
{ {
if (Parts[i].WasUpdated) if (parts[i].WasUpdated)
{ {
if (updateStart == -1) if (updateStart == -1)
updateStart = i; updateStart = i;
@ -202,22 +206,22 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
int start = i * 4; int start = i * 4;
int end = start; int end = start;
Vector2 pos = Parts[i].Position; Vector2 pos = parts[i].Position;
float time = Parts[i].Time; float localTime = parts[i].Time;
Texture.DrawQuad( texture.DrawQuad(
new Quad(pos.X - Size.X / 2, pos.Y - Size.Y / 2, Size.X, Size.Y), new Quad(pos.X - size.X / 2, pos.Y - size.Y / 2, size.X, size.Y),
DrawColourInfo.Colour, DrawColourInfo.Colour,
null, null,
v => vertexBuffer.Vertices[end++] = new TexturedTrailVertex v => vertexBuffer.Vertices[end++] = new TexturedTrailVertex
{ {
Position = v.Position, Position = v.Position,
TexturePosition = v.TexturePosition, TexturePosition = v.TexturePosition,
Time = time + 1, Time = localTime + 1,
Colour = v.Colour, Colour = v.Colour,
}); });
Parts[i].WasUpdated = false; parts[i].WasUpdated = false;
} }
else if (updateStart != -1) else if (updateStart != -1)
{ {
@ -232,12 +236,12 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
base.Draw(vertexAction); base.Draw(vertexAction);
Shader.Bind(); shader.Bind();
Texture.TextureGL.Bind(); texture.TextureGL.Bind();
vertexBuffer.Draw(); vertexBuffer.Draw();
Shader.Unbind(); shader.Unbind();
} }
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)

View File

@ -6,6 +6,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Configuration; using osu.Game.Configuration;

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Input; using osu.Framework.Input;
@ -61,7 +62,7 @@ namespace osu.Game.Rulesets.Osu.UI
get get
{ {
var first = (OsuHitObject)Objects.First(); var first = (OsuHitObject)Objects.First();
return first.StartTime - first.TimePreempt; return first.StartTime - Math.Max(2000, first.TimePreempt);
} }
} }
} }

View File

@ -9,6 +9,7 @@ using osu.Game.Graphics.Backgrounds;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Effects;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces
{ {

View File

@ -5,6 +5,7 @@ using osuTK;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;

View File

@ -6,6 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics; using osu.Game.Graphics;

View File

@ -3,12 +3,13 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Audio; using osu.Framework.Graphics.Audio;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Editor namespace osu.Game.Tests.Visual.Editor
@ -16,35 +17,38 @@ namespace osu.Game.Tests.Visual.Editor
[TestFixture] [TestFixture]
public class TestCaseWaveform : OsuTestCase public class TestCaseWaveform : OsuTestCase
{ {
private WorkingBeatmap waveformBeatmap;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Beatmap.Value = new WaveformTestBeatmap(); waveformBeatmap = new WaveformTestBeatmap();
}
FillFlowContainer flow; [TestCase(1f)]
Child = flow = new FillFlowContainer [TestCase(1f / 2)]
[TestCase(1f / 4)]
[TestCase(1f / 8)]
[TestCase(1f / 16)]
[TestCase(0f)]
public void TestResolution(float resolution)
{ {
RelativeSizeAxes = Axes.Both, TestWaveformGraph graph = null;
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 10),
};
for (int i = 1; i <= 16; i *= 2) AddStep("add graph", () =>
{ {
var newDisplay = new WaveformGraph Child = new Container
{
RelativeSizeAxes = Axes.Both,
Resolution = 1f / i,
Waveform = Beatmap.Value.Waveform,
};
flow.Add(new Container
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Height = 100, Height = 100,
Children = new Drawable[] Children = new Drawable[]
{ {
newDisplay, graph = new TestWaveformGraph
{
RelativeSizeAxes = Axes.Both,
Resolution = resolution,
Waveform = waveformBeatmap.Waveform,
},
new Container new Container
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
@ -62,13 +66,42 @@ namespace osu.Game.Tests.Visual.Editor
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Text = $"Resolution: {1f / i:0.00}" Text = $"Resolution: {resolution:0.00}"
} }
} }
} }
} }
};
}); });
AddUntilStep("wait for load", () => graph.ResampledWaveform != null);
} }
[Test]
public void TestDefaultBeatmap()
{
TestWaveformGraph graph = null;
AddStep("add graph", () =>
{
Child = new Container
{
RelativeSizeAxes = Axes.X,
Height = 100,
Child = graph = new TestWaveformGraph
{
RelativeSizeAxes = Axes.Both,
Waveform = new DummyWorkingBeatmap().Waveform,
},
};
});
AddUntilStep("wait for load", () => graph.ResampledWaveform != null);
}
public class TestWaveformGraph : WaveformGraph
{
public new Waveform ResampledWaveform => base.ResampledWaveform;
} }
} }
} }

View File

@ -12,6 +12,7 @@ using osu.Framework.Screens;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens; using osu.Game.Screens;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Tests.Beatmaps; using osu.Game.Tests.Beatmaps;
@ -96,6 +97,8 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
Applied = true; Applied = true;
} }
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
} }
private class TestPlayer : Player private class TestPlayer : Player

View File

@ -120,12 +120,8 @@ namespace osu.Game.Tests.Visual.Gameplay
} }
} }
private class SecondarySource : ISkinSource private class SecondarySource : ISkin
{ {
public event Action SourceChanged;
public void TriggerSourceChanged() => SourceChanged?.Invoke();
public Drawable GetDrawableComponent(string componentName) => new SecondarySourceBox(); public Drawable GetDrawableComponent(string componentName) => new SecondarySourceBox();
public Texture GetTexture(string componentName) => throw new NotImplementedException(); public Texture GetTexture(string componentName) => throw new NotImplementedException();
@ -135,12 +131,8 @@ namespace osu.Game.Tests.Visual.Gameplay
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => throw new NotImplementedException(); public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => throw new NotImplementedException();
} }
private class SkinSourceContainer : Container, ISkinSource private class SkinSourceContainer : Container, ISkin
{ {
public event Action SourceChanged;
public void TriggerSourceChanged() => SourceChanged?.Invoke();
public Drawable GetDrawableComponent(string componentName) => new BaseSourceBox(); public Drawable GetDrawableComponent(string componentName) => new BaseSourceBox();
public Texture GetTexture(string componentName) => throw new NotImplementedException(); public Texture GetTexture(string componentName) => throw new NotImplementedException();

View File

@ -1,62 +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 System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Overlays.Profile.Header;
using osu.Game.Users;
namespace osu.Game.Tests.Visual.Online
{
[TestFixture]
public class TestCaseBadgeContainer : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(BadgeContainer) };
public TestCaseBadgeContainer()
{
BadgeContainer badgeContainer;
Child = badgeContainer = new BadgeContainer
{
RelativeSizeAxes = Axes.Both
};
AddStep("Show 1 badge", () => badgeContainer.ShowBadges(new[]
{
new Badge
{
AwardedAt = DateTimeOffset.Now,
Description = "Appreciates compasses",
ImageUrl = "https://assets.ppy.sh/profile-badges/mg2018-1star.png",
}
}));
AddStep("Show 2 badges", () => badgeContainer.ShowBadges(new[]
{
new Badge
{
AwardedAt = DateTimeOffset.Now,
Description = "Contributed to osu!lazer testing",
ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.png",
},
new Badge
{
AwardedAt = DateTimeOffset.Now,
Description = "Appreciates compasses",
ImageUrl = "https://assets.ppy.sh/profile-badges/mg2018-1star.png",
}
}));
AddStep("Show many badges", () => badgeContainer.ShowBadges(Enumerable.Range(1, 20).Select(i => new Badge
{
AwardedAt = DateTimeOffset.Now,
Description = $"Contributed to osu!lazer testing {i} times",
ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.jpg",
}).ToArray()));
}
}
}

View File

@ -9,7 +9,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Profile.Header; using osu.Game.Overlays.Profile.Header.Components;
using osu.Game.Users; using osu.Game.Users;
using osuTK; using osuTK;

View File

@ -38,6 +38,7 @@ namespace osu.Game.Tests.Visual.Online
Country = new Country { FlagName = @"AU" }, Country = new Country { FlagName = @"AU" },
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
IsSupporter = true, IsSupporter = true,
SupportLevel = 3,
}) { Width = 300 }, }) { Width = 300 },
}, },
}); });

View File

@ -6,11 +6,12 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Overlays.Profile; using osu.Game.Overlays.Profile;
using osu.Game.Overlays.Profile.Header; using osu.Game.Overlays.Profile.Header.Components;
using osu.Game.Users; using osu.Game.Users;
namespace osu.Game.Tests.Visual.Online namespace osu.Game.Tests.Visual.Online
@ -19,7 +20,9 @@ namespace osu.Game.Tests.Visual.Online
public class TestCaseUserProfile : OsuTestCase public class TestCaseUserProfile : OsuTestCase
{ {
private readonly TestUserProfileOverlay profile; private readonly TestUserProfileOverlay profile;
private IAPIProvider api;
[Resolved]
private IAPIProvider api { get; set; }
public override IReadOnlyList<Type> RequiredTypes => new[] public override IReadOnlyList<Type> RequiredTypes => new[]
{ {
@ -27,25 +30,11 @@ namespace osu.Game.Tests.Visual.Online
typeof(UserProfileOverlay), typeof(UserProfileOverlay),
typeof(RankGraph), typeof(RankGraph),
typeof(LineGraph), typeof(LineGraph),
typeof(BadgeContainer) typeof(SectionsContainer<>),
typeof(SupporterIcon)
}; };
public TestCaseUserProfile() public static readonly User TEST_USER = new User
{
Add(profile = new TestUserProfileOverlay());
}
[BackgroundDependencyLoader]
private void load(IAPIProvider api)
{
this.api = api;
}
protected override void LoadComplete()
{
base.LoadComplete();
AddStep("Show offline dummy", () => profile.ShowUser(new User
{ {
Username = @"Somebody", Username = @"Somebody",
Id = 1, Id = 1,
@ -58,6 +47,11 @@ namespace osu.Game.Tests.Visual.Online
{ {
Ranks = new UserStatistics.UserRanks { Global = 2148, Country = 1 }, Ranks = new UserStatistics.UserRanks { Global = 2148, Country = 1 },
PP = 4567.89m, PP = 4567.89m,
Level = new UserStatistics.LevelInfo
{
Current = 727,
Progress = 69,
}
}, },
RankHistory = new User.RankHistoryData RankHistory = new User.RankHistoryData
{ {
@ -72,10 +66,22 @@ namespace osu.Game.Tests.Visual.Online
Description = "Outstanding help by being a voluntary test subject.", Description = "Outstanding help by being a voluntary test subject.",
ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.jpg" ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.jpg"
} }
} },
}, false)); Title = "osu!volunteer",
Colour = "ff0000",
Achievements = new User.UserAchievement[0],
};
checkSupporterTag(false); public TestCaseUserProfile()
{
Add(profile = new TestUserProfileOverlay());
}
protected override void LoadComplete()
{
base.LoadComplete();
AddStep("Show offline dummy", () => profile.ShowUser(TEST_USER, false));
AddStep("Show null dummy", () => profile.ShowUser(new User AddStep("Show null dummy", () => profile.ShowUser(new User
{ {
@ -92,8 +98,6 @@ namespace osu.Game.Tests.Visual.Online
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg" CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg"
}, api.IsLoggedIn)); }, api.IsLoggedIn));
checkSupporterTag(true);
AddStep("Show flyte", () => profile.ShowUser(new User AddStep("Show flyte", () => profile.ShowUser(new User
{ {
Username = @"flyte", Username = @"flyte",
@ -106,15 +110,6 @@ namespace osu.Game.Tests.Visual.Online
AddStep("Show without reload", profile.Show); AddStep("Show without reload", profile.Show);
} }
private void checkSupporterTag(bool isSupporter)
{
AddUntilStep("wait for load", () => profile.Header.User != null);
if (isSupporter)
AddAssert("is supporter", () => profile.Header.SupporterTag.Alpha == 1);
else
AddAssert("no supporter", () => profile.Header.SupporterTag.Alpha == 0);
}
private class TestUserProfileOverlay : UserProfileOverlay private class TestUserProfileOverlay : UserProfileOverlay
{ {
public new ProfileHeader Header => base.Header; public new ProfileHeader Header => base.Header;

View File

@ -0,0 +1,81 @@
// 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.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Profile;
using osu.Game.Overlays.Profile.Header;
using osu.Game.Overlays.Profile.Header.Components;
using osu.Game.Users;
namespace osu.Game.Tests.Visual.Online
{
public class TestCaseUserProfileHeader : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(ProfileHeader),
typeof(RankGraph),
typeof(LineGraph),
typeof(ProfileHeaderTabControl),
typeof(CentreHeaderContainer),
typeof(BottomHeaderContainer),
typeof(DetailHeaderContainer),
typeof(ProfileHeaderButton)
};
[Resolved]
private IAPIProvider api { get; set; }
private readonly ProfileHeader header;
public TestCaseUserProfileHeader()
{
header = new ProfileHeader();
Add(header);
AddStep("Show offline dummy", () => header.User.Value = TestCaseUserProfile.TEST_USER);
AddStep("Show null dummy", () => header.User.Value = new User
{
Username = "Null"
});
addOnlineStep("Show ppy", new User
{
Username = @"peppy",
Id = 2,
IsSupporter = true,
Country = new Country { FullName = @"Australia", FlagName = @"AU" },
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg"
});
addOnlineStep("Show flyte", new User
{
Username = @"flyte",
Id = 3103765,
Country = new Country { FullName = @"Japan", FlagName = @"JP" },
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg"
});
}
private void addOnlineStep(string name, User fallback)
{
AddStep(name, () =>
{
if (api.IsLoggedIn)
{
var request = new GetUserRequest(fallback.Id);
request.Success += user => header.User.Value = user;
api.Queue(request);
}
else
header.User.Value = fallback;
});
}
}
}

View File

@ -4,7 +4,7 @@
namespace osu.Game.Audio namespace osu.Game.Audio
{ {
/// <summary> /// <summary>
/// Interface for objects that can own <see cref="IPreviewTrack"/>s. /// Interface for objects that can own <see cref="PreviewTrack"/>s.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// <see cref="IPreviewTrackOwner"/>s can cancel the currently playing <see cref="PreviewTrack"/> through the /// <see cref="IPreviewTrackOwner"/>s can cancel the currently playing <see cref="PreviewTrack"/> through the

View File

@ -98,7 +98,7 @@ namespace osu.Game.Beatmaps
protected abstract IEnumerable<Type> ValidConversionTypes { get; } protected abstract IEnumerable<Type> ValidConversionTypes { get; }
/// <summary> /// <summary>
/// Creates the <see cref="Beatmap{T}"/> that will be returned by this <see cref="BeatmapProcessor{T}"/>. /// Creates the <see cref="Beatmap{T}"/> that will be returned by this <see cref="BeatmapProcessor"/>.
/// </summary> /// </summary>
protected virtual Beatmap<T> CreateBeatmap() => new Beatmap<T>(); protected virtual Beatmap<T> CreateBeatmap() => new Beatmap<T>();

View File

@ -217,7 +217,7 @@ namespace osu.Game.Beatmaps
{ {
request.Perform(api); request.Perform(api);
} }
catch (Exception e) catch
{ {
// no need to handle here as exceptions will filter down to request.Failure above. // no need to handle here as exceptions will filter down to request.Failure above.
} }
@ -382,7 +382,6 @@ namespace osu.Game.Beatmaps
/// Query the API to populate missing values like OnlineBeatmapID / OnlineBeatmapSetID or (Rank-)Status. /// Query the API to populate missing values like OnlineBeatmapID / OnlineBeatmapSetID or (Rank-)Status.
/// </summary> /// </summary>
/// <param name="beatmap">The beatmap to populate.</param> /// <param name="beatmap">The beatmap to populate.</param>
/// <param name="otherBeatmaps">The other beatmaps contained within this set.</param>
/// <param name="force">Whether to re-query if the provided beatmap already has populated values.</param> /// <param name="force">Whether to re-query if the provided beatmap already has populated values.</param>
/// <returns>True if population was successful.</returns> /// <returns>True if population was successful.</returns>
private bool fetchAndPopulateOnlineValues(BeatmapInfo beatmap, bool force = false) private bool fetchAndPopulateOnlineValues(BeatmapInfo beatmap, bool force = false)

View File

@ -12,7 +12,7 @@ namespace osu.Game.Beatmaps
{ {
/// <summary> /// <summary>
/// A <see cref="Bindable{T}"/> for the <see cref="OsuGame"/> beatmap. /// A <see cref="Bindable{T}"/> for the <see cref="OsuGame"/> beatmap.
/// This should be used sparingly in-favour of <see cref="IBindable<WorkingBeatmap>"/>. /// This should be used sparingly in-favour of <see cref="IBindable{WorkingBeatmap}"/>.
/// </summary> /// </summary>
public abstract class BindableBeatmap : NonNullableBindable<WorkingBeatmap> public abstract class BindableBeatmap : NonNullableBindable<WorkingBeatmap>
{ {
@ -67,6 +67,6 @@ namespace osu.Game.Beatmaps
/// If you are further binding to events of the retrieved <see cref="BindableBeatmap"/>, ensure a local reference is held. /// If you are further binding to events of the retrieved <see cref="BindableBeatmap"/>, ensure a local reference is held.
/// </summary> /// </summary>
[NotNull] [NotNull]
public abstract BindableBeatmap GetBoundCopy(); public new abstract BindableBeatmap GetBoundCopy();
} }
} }

View File

@ -6,6 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty;
@ -73,9 +74,18 @@ namespace osu.Game.Beatmaps
private class DummyBeatmapConverter : IBeatmapConverter private class DummyBeatmapConverter : IBeatmapConverter
{ {
public event Action<HitObject, IEnumerable<HitObject>> ObjectConverted; public event Action<HitObject, IEnumerable<HitObject>> ObjectConverted;
public IBeatmap Beatmap { get; set; } public IBeatmap Beatmap { get; set; }
public bool CanConvert => true; public bool CanConvert => true;
public IBeatmap Convert() => Beatmap;
public IBeatmap Convert()
{
foreach (var obj in Beatmap.HitObjects)
ObjectConverted?.Invoke(obj, obj.Yield());
return Beatmap;
}
} }
} }
} }

View File

@ -95,7 +95,7 @@ namespace osu.Game.Beatmaps.Formats
{ {
colour = new Color4(byte.Parse(split[0]), byte.Parse(split[1]), byte.Parse(split[2]), split.Length == 4 ? byte.Parse(split[3]) : (byte)255); colour = new Color4(byte.Parse(split[0]), byte.Parse(split[1]), byte.Parse(split[2]), split.Length == 4 ? byte.Parse(split[3]) : (byte)255);
} }
catch (Exception e) catch
{ {
throw new InvalidOperationException(@"Color must be specified with 8-bit integer components"); throw new InvalidOperationException(@"Color must be specified with 8-bit integer components");
} }

View File

@ -73,6 +73,7 @@ namespace osu.Game.Beatmaps
/// </para> /// </para>
/// </summary> /// </summary>
/// <param name="ruleset">The <see cref="RulesetInfo"/> to create a playable <see cref="IBeatmap"/> for.</param> /// <param name="ruleset">The <see cref="RulesetInfo"/> to create a playable <see cref="IBeatmap"/> for.</param>
/// <param name="mods">The <see cref="Mod"/>s to apply to the <see cref="IBeatmap"/>.</param>
/// <returns>The converted <see cref="IBeatmap"/>.</returns> /// <returns>The converted <see cref="IBeatmap"/>.</returns>
/// <exception cref="BeatmapInvalidForRulesetException">If <see cref="Beatmap"/> could not be converted to <paramref name="ruleset"/>.</exception> /// <exception cref="BeatmapInvalidForRulesetException">If <see cref="Beatmap"/> could not be converted to <paramref name="ruleset"/>.</exception>
public IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList<Mod> mods) public IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList<Mod> mods)

View File

@ -563,7 +563,7 @@ namespace osu.Game.Database
/// <summary> /// <summary>
/// Check whether an existing model already exists for a new import item. /// Check whether an existing model already exists for a new import item.
/// </summary> /// </summary>
/// <param name="model">The new model proposed for import. /// <param name="model">The new model proposed for import.</param>
/// <returns>An existing model which matches the criteria to skip importing, else null.</returns> /// <returns>An existing model which matches the criteria to skip importing, else null.</returns>
protected TModel CheckForExisting(TModel model) => model.Hash == null ? null : ModelStore.ConsumableItems.FirstOrDefault(b => b.Hash == model.Hash); protected TModel CheckForExisting(TModel model) => model.Hash == null ? null : ModelStore.ConsumableItems.FirstOrDefault(b => b.Hash == model.Hash);

View File

@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Storage;
@ -67,7 +66,7 @@ namespace osu.Game.Database
context = threadContexts.Value; context = threadContexts.Value;
} }
} }
catch (Exception e) catch
{ {
// retrieval of a context could trigger a fatal error. // retrieval of a context could trigger a fatal error.
Monitor.Exit(writeLock); Monitor.Exit(writeLock);

View File

@ -70,7 +70,7 @@ namespace osu.Game.Database
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
} }
} }
catch (Exception e) catch
{ {
connection.Close(); connection.Close();
throw; throw;

View File

@ -178,64 +178,68 @@ namespace osu.Game.Graphics.Backgrounds
/// <returns>The colour.</returns> /// <returns>The colour.</returns>
protected virtual Color4 CreateTriangleShade() => Interpolation.ValueAt(RNG.NextSingle(), ColourDark, ColourLight, 0, 1); protected virtual Color4 CreateTriangleShade() => Interpolation.ValueAt(RNG.NextSingle(), ColourDark, ColourLight, 0, 1);
protected override DrawNode CreateDrawNode() => new TrianglesDrawNode(); protected override DrawNode CreateDrawNode() => new TrianglesDrawNode(this);
protected override void ApplyDrawNode(DrawNode node)
{
base.ApplyDrawNode(node);
var trianglesNode = (TrianglesDrawNode)node;
trianglesNode.Shader = shader;
trianglesNode.Texture = texture;
trianglesNode.Size = DrawSize;
trianglesNode.Parts.Clear();
trianglesNode.Parts.AddRange(parts);
}
private class TrianglesDrawNode : DrawNode private class TrianglesDrawNode : DrawNode
{ {
public IShader Shader; protected new Triangles Source => (Triangles)base.Source;
public Texture Texture;
public readonly List<TriangleParticle> Parts = new List<TriangleParticle>(); private IShader shader;
public Vector2 Size; private Texture texture;
private readonly List<TriangleParticle> parts = new List<TriangleParticle>();
private Vector2 size;
private readonly LinearBatch<TexturedVertex2D> vertexBatch = new LinearBatch<TexturedVertex2D>(100 * 3, 10, PrimitiveType.Triangles); private readonly LinearBatch<TexturedVertex2D> vertexBatch = new LinearBatch<TexturedVertex2D>(100 * 3, 10, PrimitiveType.Triangles);
public TrianglesDrawNode(Triangles source)
: base(source)
{
}
public override void ApplyState()
{
base.ApplyState();
shader = Source.shader;
texture = Source.texture;
size = Source.DrawSize;
parts.Clear();
parts.AddRange(Source.parts);
}
public override void Draw(Action<TexturedVertex2D> vertexAction) public override void Draw(Action<TexturedVertex2D> vertexAction)
{ {
base.Draw(vertexAction); base.Draw(vertexAction);
Shader.Bind(); shader.Bind();
Texture.TextureGL.Bind(); texture.TextureGL.Bind();
Vector2 localInflationAmount = edge_smoothness * DrawInfo.MatrixInverse.ExtractScale().Xy; Vector2 localInflationAmount = edge_smoothness * DrawInfo.MatrixInverse.ExtractScale().Xy;
foreach (TriangleParticle particle in Parts) foreach (TriangleParticle particle in parts)
{ {
var offset = triangle_size * new Vector2(particle.Scale * 0.5f, particle.Scale * 0.866f); var offset = triangle_size * new Vector2(particle.Scale * 0.5f, particle.Scale * 0.866f);
var size = new Vector2(2 * offset.X, offset.Y);
var triangle = new Triangle( var triangle = new Triangle(
Vector2Extensions.Transform(particle.Position * Size, DrawInfo.Matrix), Vector2Extensions.Transform(particle.Position * size, DrawInfo.Matrix),
Vector2Extensions.Transform(particle.Position * Size + offset, DrawInfo.Matrix), Vector2Extensions.Transform(particle.Position * size + offset, DrawInfo.Matrix),
Vector2Extensions.Transform(particle.Position * Size + new Vector2(-offset.X, offset.Y), DrawInfo.Matrix) Vector2Extensions.Transform(particle.Position * size + new Vector2(-offset.X, offset.Y), DrawInfo.Matrix)
); );
ColourInfo colourInfo = DrawColourInfo.Colour; ColourInfo colourInfo = DrawColourInfo.Colour;
colourInfo.ApplyChild(particle.Colour); colourInfo.ApplyChild(particle.Colour);
Texture.DrawTriangle( texture.DrawTriangle(
triangle, triangle,
colourInfo, colourInfo,
null, null,
vertexBatch.AddAction, vertexBatch.AddAction,
Vector2.Divide(localInflationAmount, size)); Vector2.Divide(localInflationAmount, new Vector2(2 * offset.X, offset.Y)));
} }
Shader.Unbind(); shader.Unbind();
} }
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)

View File

@ -4,6 +4,7 @@
using System; using System;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osuTK; using osuTK;
namespace osu.Game.Graphics.Containers namespace osu.Game.Graphics.Containers

View File

@ -103,7 +103,7 @@ namespace osu.Game.Graphics.Containers
{ {
channelManager?.OpenChannel(linkArgument); channelManager?.OpenChannel(linkArgument);
} }
catch (ChannelNotFoundException e) catch (ChannelNotFoundException)
{ {
Logger.Log($"The requested channel \"{linkArgument}\" does not exist"); Logger.Log($"The requested channel \"{linkArgument}\" does not exist");
} }

View File

@ -30,7 +30,6 @@ namespace osu.Game.Graphics.Containers
/// Assign the logo that should track the facade's position, as well as how it should transform to its initial position. /// Assign the logo that should track the facade's position, as well as how it should transform to its initial position.
/// </summary> /// </summary>
/// <param name="logo">The instance of the logo to be used for tracking.</param> /// <param name="logo">The instance of the logo to be used for tracking.</param>
/// <param name="facadeScale">The scale of the facade. Does not actually affect the logo itself.</param>
/// <param name="duration">The duration of the initial transform. Default is instant.</param> /// <param name="duration">The duration of the initial transform. Default is instant.</param>
/// <param name="easing">The easing type of the initial transform.</param> /// <param name="easing">The easing type of the initial transform.</param>
public void StartTracking(OsuLogo logo, double duration = 0, Easing easing = Easing.None) public void StartTracking(OsuLogo logo, double duration = 0, Easing easing = Easing.None)
@ -132,7 +131,7 @@ namespace osu.Game.Graphics.Containers
private class InternalFacade : Facade private class InternalFacade : Facade
{ {
public void SetSize(Vector2 size) public new void SetSize(Vector2 size)
{ {
base.SetSize(size); base.SetSize(size);
} }

View File

@ -35,6 +35,7 @@ namespace osu.Game.Graphics.Containers
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
if (HoverColour == default)
HoverColour = colours.Yellow; HoverColour = colours.Yellow;
} }

View File

@ -142,6 +142,17 @@ namespace osu.Game.Graphics.Containers
public void ScrollToTop() => scrollContainer.ScrollTo(0); public void ScrollToTop() => scrollContainer.ScrollTo(0);
public override void InvalidateFromChild(Invalidation invalidation, Drawable source = null)
{
base.InvalidateFromChild(invalidation, source);
if ((invalidation & Invalidation.DrawSize) != 0)
{
if (source == ExpandableHeader) //We need to recalculate the positions if the ExpandableHeader changed its size
lastKnownScroll = -1;
}
}
private float lastKnownScroll; private float lastKnownScroll;
protected override void UpdateAfterChildren() protected override void UpdateAfterChildren()

View File

@ -5,6 +5,7 @@ using System;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osuTK.Graphics; using osuTK.Graphics;

View File

@ -6,8 +6,8 @@ using osuTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;

View File

@ -92,5 +92,15 @@ namespace osu.Game.Graphics
public readonly Color4 ChatBlue = FromHex(@"17292e"); public readonly Color4 ChatBlue = FromHex(@"17292e");
public readonly Color4 ContextMenuGray = FromHex(@"223034"); public readonly Color4 ContextMenuGray = FromHex(@"223034");
public readonly Color4 CommunityUserGreenLight = FromHex(@"deff87");
public readonly Color4 CommunityUserGreen = FromHex(@"05ffa2");
public readonly Color4 CommunityUserGreenDark = FromHex(@"a6cc00");
public readonly Color4 CommunityUserGrayGreenLighter = FromHex(@"9ebab1");
public readonly Color4 CommunityUserGrayGreenLight = FromHex(@"77998e");
public readonly Color4 CommunityUserGrayGreen = FromHex(@"4e7466");
public readonly Color4 CommunityUserGrayGreenDark = FromHex(@"33413c");
public readonly Color4 CommunityUserGrayGreenDarker = FromHex(@"2c3532");
public readonly Color4 CommunityUserGrayGreenDarkest = FromHex(@"1e2422");
} }
} }

View File

@ -61,9 +61,9 @@ namespace osu.Game.Graphics
/// <summary> /// <summary>
/// Retrieves the string representation of a <see cref="FontWeight"/>. /// Retrieves the string representation of a <see cref="FontWeight"/>.
/// </summary> /// </summary>
/// <param name="typeface">The <see cref="Typeface"/>.</param> /// <param name="family">The family string.</param>
/// <param name="weight">The <see cref="FontWeight"/>.</param> /// <param name="weight">The <see cref="FontWeight"/>.</param>
/// <returns>The string representation of <paramref name="weight"/> in the specified <paramref name="typeface"/>.</returns> /// <returns>The string representation of <paramref name="weight"/> in the specified <paramref name="family"/>.</returns>
public static string GetWeightString(string family, FontWeight weight) public static string GetWeightString(string family, FontWeight weight)
{ {
string weightString = weight.ToString(); string weightString = weight.ToString();
@ -81,6 +81,7 @@ namespace osu.Game.Graphics
/// <summary> /// <summary>
/// Creates a new <see cref="FontUsage"/> by applying adjustments to this <see cref="FontUsage"/>. /// Creates a new <see cref="FontUsage"/> by applying adjustments to this <see cref="FontUsage"/>.
/// </summary> /// </summary>
/// <param name="usage">The base <see cref="FontUsage"/>.</param>
/// <param name="typeface">The font typeface. If null, the value is copied from this <see cref="FontUsage"/>.</param> /// <param name="typeface">The font typeface. If null, the value is copied from this <see cref="FontUsage"/>.</param>
/// <param name="size">The text size. If null, the value is copied from this <see cref="FontUsage"/>.</param> /// <param name="size">The text size. If null, the value is copied from this <see cref="FontUsage"/>.</param>
/// <param name="weight">The font weight. If null, the value is copied from this <see cref="FontUsage"/>.</param> /// <param name="weight">The font weight. If null, the value is copied from this <see cref="FontUsage"/>.</param>

View File

@ -12,6 +12,7 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Effects;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;

View File

@ -9,6 +9,7 @@ using osuTK;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Lines; using osu.Framework.Graphics.Lines;
using osuTK.Graphics;
namespace osu.Game.Graphics.UserInterface namespace osu.Game.Graphics.UserInterface
{ {
@ -63,6 +64,12 @@ namespace osu.Game.Graphics.UserInterface
} }
} }
public Color4 LineColour
{
get => maskingContainer.Colour;
set => maskingContainer.Colour = value;
}
public LineGraph() public LineGraph()
{ {
Add(maskingContainer = new Container<Path> Add(maskingContainer = new Container<Path>

View File

@ -8,6 +8,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;

View File

@ -5,6 +5,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;

View File

@ -5,7 +5,7 @@ using osuTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects;
namespace osu.Game.Graphics.UserInterface namespace osu.Game.Graphics.UserInterface
{ {

View File

@ -8,7 +8,7 @@ using osu.Framework.Screens;
namespace osu.Game.Graphics.UserInterface namespace osu.Game.Graphics.UserInterface
{ {
/// <summary> /// <summary>
/// A <see cref="BreadcrumbControl"/> which follows the active screen (and allows navigation) in a <see cref="Screen"/> stack. /// A <see cref="BreadcrumbControl{IScreen}"/> which follows the active screen (and allows navigation) in a <see cref="Screen"/> stack.
/// </summary> /// </summary>
public class ScreenBreadcrumbControl : BreadcrumbControl<IScreen> public class ScreenBreadcrumbControl : BreadcrumbControl<IScreen>
{ {

View File

@ -14,6 +14,8 @@ namespace osu.Game.Graphics.UserInterface
{ {
private readonly SpriteIcon iconSprite; private readonly SpriteIcon iconSprite;
private readonly OsuSpriteText titleText, pageText; private readonly OsuSpriteText titleText, pageText;
public const float ICON_WIDTH = icon_size + icon_spacing;
private const float icon_size = 25, icon_spacing = 10;
protected IconUsage Icon protected IconUsage Icon
{ {
@ -48,12 +50,12 @@ namespace osu.Game.Graphics.UserInterface
new FillFlowContainer new FillFlowContainer
{ {
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Spacing = new Vector2(10, 0), Spacing = new Vector2(icon_spacing, 0),
Children = new Drawable[] Children = new Drawable[]
{ {
iconSprite = new SpriteIcon iconSprite = new SpriteIcon
{ {
Size = new Vector2(25), Size = new Vector2(icon_size),
}, },
new FillFlowContainer new FillFlowContainer
{ {

View File

@ -12,6 +12,7 @@ using osu.Game.Graphics.Containers;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using System; using System;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;

View File

@ -253,7 +253,7 @@ namespace osu.Game.Online.API
handleWebException(we); handleWebException(we);
return false; return false;
} }
catch (Exception e) catch
{ {
return false; return false;
} }

View File

@ -7,7 +7,6 @@ using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring.Legacy; using osu.Game.Scoring.Legacy;
using osu.Game.Users; using osu.Game.Users;
@ -71,7 +70,6 @@ namespace osu.Game.Online.API.Requests.Responses
{ {
foreach (var kvp in value) foreach (var kvp in value)
{ {
HitResult newKey;
switch (kvp.Key) switch (kvp.Key)
{ {
case @"count_geki": case @"count_geki":

View File

@ -8,5 +8,7 @@ namespace osu.Game.Online.API.Requests.Responses
public class APIMod : IMod public class APIMod : IMod
{ {
public string Acronym { get; set; } public string Acronym { get; set; }
public bool Equals(IMod other) => Acronym == other?.Acronym;
} }
} }

View File

@ -10,16 +10,16 @@ namespace osu.Game.Online.API.Requests.Responses
public class APIUserMostPlayedBeatmap public class APIUserMostPlayedBeatmap
{ {
[JsonProperty("beatmap_id")] [JsonProperty("beatmap_id")]
public int BeatmapID; public int BeatmapID { get; set; }
[JsonProperty("count")] [JsonProperty("count")]
public int PlayCount; public int PlayCount { get; set; }
[JsonProperty] [JsonProperty]
private BeatmapInfo beatmap; private BeatmapInfo beatmap { get; set; }
[JsonProperty] [JsonProperty]
private APIBeatmapSet beatmapSet; private APIBeatmapSet beatmapSet { get; set; }
public BeatmapInfo GetBeatmapInfo(RulesetStore rulesets) public BeatmapInfo GetBeatmapInfo(RulesetStore rulesets)
{ {

View File

@ -27,8 +27,6 @@ namespace osu.Game.Online.Chat
protected ChannelManager ChannelManager; protected ChannelManager ChannelManager;
private ScrollContainer scroll;
private DrawableChannel drawableChannel; private DrawableChannel drawableChannel;
private readonly bool postingTextbox; private readonly bool postingTextbox;

View File

@ -8,6 +8,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;

View File

@ -272,7 +272,6 @@ namespace osu.Game
/// Present a score's replay immediately. /// Present a score's replay immediately.
/// The user should have already requested this interactively. /// The user should have already requested this interactively.
/// </summary> /// </summary>
/// <param name="beatmap">The beatmap to select.</param>
public void PresentScore(ScoreInfo score) public void PresentScore(ScoreInfo score)
{ {
var databasedScore = ScoreManager.GetScore(score); var databasedScore = ScoreManager.GetScore(score);

View File

@ -5,6 +5,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Graphics; using osu.Game.Graphics;

View File

@ -11,6 +11,7 @@ using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics; using osu.Game.Graphics;

View File

@ -6,6 +6,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables;

View File

@ -6,6 +6,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;

View File

@ -5,6 +5,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Graphics; using osu.Game.Graphics;

View File

@ -6,6 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;

View File

@ -7,6 +7,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;

View File

@ -8,6 +8,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;

View File

@ -26,7 +26,7 @@ namespace osu.Game.Overlays.Chat.Tabs
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private new void load(OsuColour colour) private void load(OsuColour colour)
{ {
BackgroundInactive = colour.Gray2; BackgroundInactive = colour.Gray2;
BackgroundActive = colour.Gray3; BackgroundActive = colour.Gray3;

View File

@ -6,6 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;

View File

@ -9,7 +9,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat; using osu.Game.Online.Chat;
using osu.Game.Users; using osu.Game.Users;
using osuTK; using osuTK;
@ -18,9 +17,6 @@ namespace osu.Game.Overlays.Chat.Tabs
{ {
public class PrivateChannelTabItem : ChannelTabItem public class PrivateChannelTabItem : ChannelTabItem
{ {
private readonly OsuSpriteText username;
private readonly Avatar avatarContainer;
protected override IconUsage DisplayIcon => FontAwesome.Solid.At; protected override IconUsage DisplayIcon => FontAwesome.Solid.At;
public PrivateChannelTabItem(Channel value) public PrivateChannelTabItem(Channel value)

View File

@ -6,6 +6,7 @@ using System.Linq;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;

View File

@ -8,6 +8,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;

View File

@ -11,7 +11,7 @@ namespace osu.Game.Overlays
{ {
/// <summary> /// <summary>
/// An overlay which will display a black screen that dims over a period before confirming an exit action. /// An overlay which will display a black screen that dims over a period before confirming an exit action.
/// Action is BYO (derived class will need to call <see cref="BeginConfirm"/> and <see cref="AbortConfirm"/> from a user event). /// Action is BYO (derived class will need to call <see cref="HoldToConfirmContainer.BeginConfirm"/> and <see cref="HoldToConfirmContainer.AbortConfirm"/> from a user event).
/// </summary> /// </summary>
public abstract class HoldToConfirmOverlay : HoldToConfirmContainer public abstract class HoldToConfirmOverlay : HoldToConfirmContainer
{ {

View File

@ -8,6 +8,7 @@ using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;

View File

@ -19,6 +19,7 @@ using osu.Framework.Graphics.Textures;
using osuTK.Input; using osuTK.Input;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using System; using System;
using osu.Framework.Graphics.Effects;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;

View File

@ -6,7 +6,7 @@ using osuTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;

View File

@ -8,6 +8,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;

View File

@ -10,6 +10,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
@ -50,7 +51,6 @@ namespace osu.Game.Overlays
private BeatmapManager beatmaps; private BeatmapManager beatmaps;
private List<BeatmapSetInfo> beatmapSets; private List<BeatmapSetInfo> beatmapSets;
private BeatmapSetInfo currentSet;
private Container dragContainer; private Container dragContainer;
private Container playerContainer; private Container playerContainer;

View File

@ -7,6 +7,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Game.Graphics; using osu.Game.Graphics;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;

View File

@ -14,6 +14,7 @@ using osu.Game.Graphics;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Transforms; using osu.Framework.Graphics.Transforms;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Game.Configuration; using osu.Game.Configuration;

View File

@ -1,20 +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.Game.Graphics;
namespace osu.Game.Overlays.Profile.Components
{
public class DrawableJoinDate : DrawableDate
{
public DrawableJoinDate(DateTimeOffset date)
: base(date)
{
}
protected override string Format() => Text = Date.ToUniversalTime().Year < 2008 ? "Here since the beginning" : $"{Date:MMMM yyyy}";
public override string TooltipText => $"{Date:MMMM d, yyyy}";
}
}

View File

@ -1,50 +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 osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Profile.Components
{
public class GradeBadge : Container
{
private const float width = 50;
private readonly string grade;
private readonly Sprite badge;
private readonly SpriteText numberText;
public int DisplayCount
{
set => numberText.Text = value.ToString(@"#,0");
}
public GradeBadge(string grade)
{
this.grade = grade;
Width = width;
Height = 41;
Add(badge = new Sprite
{
Width = width,
Height = 26
});
Add(numberText = new OsuSpriteText
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold)
});
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
badge.Texture = textures.Get($"Grades/{grade}");
}
}
}

View File

@ -1,197 +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.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Overlays.Profile.Header
{
public class BadgeContainer : Container
{
private static readonly Vector2 badge_size = new Vector2(86, 40);
private static readonly MarginPadding outer_padding = new MarginPadding(3);
private OsuSpriteText badgeCountText;
private FillFlowContainer badgeFlowContainer;
private FillFlowContainer outerBadgeContainer;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Child = new Container
{
Masking = true,
CornerRadius = 4,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.Gray3
},
outerBadgeContainer = new OuterBadgeContainer(onOuterHover, onOuterHoverLost)
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Direction = FillDirection.Vertical,
Padding = outer_padding,
Width = DrawableBadge.DRAWABLE_BADGE_SIZE.X + outer_padding.TotalHorizontal,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
badgeCountText = new OsuSpriteText
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Alpha = 0,
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular)
},
new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
AutoSizeAxes = Axes.Both,
Child = badgeFlowContainer = new FillFlowContainer
{
Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both,
}
}
}
},
}
};
Scheduler.AddDelayed(rotateBadges, 3000, true);
}
private void rotateBadges()
{
if (outerBadgeContainer.IsHovered) return;
visibleBadge = (visibleBadge + 1) % badgeCount;
badgeFlowContainer.MoveToX(-DrawableBadge.DRAWABLE_BADGE_SIZE.X * visibleBadge, 500, Easing.InOutQuad);
}
private int visibleBadge;
private int badgeCount;
public void ShowBadges(Badge[] badges)
{
if (badges == null || badges.Length == 0)
{
Hide();
return;
}
badgeCount = badges.Length;
badgeCountText.FadeTo(badgeCount > 1 ? 1 : 0);
badgeCountText.Text = $"{badges.Length} badges";
Show();
visibleBadge = 0;
badgeFlowContainer.Clear();
for (var index = 0; index < badges.Length; index++)
{
int displayIndex = index;
LoadComponentAsync(new DrawableBadge(badges[index])
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
}, asyncBadge =>
{
badgeFlowContainer.Add(asyncBadge);
// load in stable order regardless of async load order.
badgeFlowContainer.SetLayoutPosition(asyncBadge, displayIndex);
});
}
}
private void onOuterHover()
{
badgeFlowContainer.ClearTransforms();
badgeFlowContainer.X = 0;
badgeFlowContainer.Direction = FillDirection.Full;
outerBadgeContainer.AutoSizeAxes = Axes.Both;
badgeFlowContainer.MaximumSize = new Vector2(ChildSize.X, float.MaxValue);
}
private void onOuterHoverLost()
{
badgeFlowContainer.X = -DrawableBadge.DRAWABLE_BADGE_SIZE.X * visibleBadge;
badgeFlowContainer.Direction = FillDirection.Horizontal;
outerBadgeContainer.AutoSizeAxes = Axes.Y;
outerBadgeContainer.Width = DrawableBadge.DRAWABLE_BADGE_SIZE.X + outer_padding.TotalHorizontal;
}
private class OuterBadgeContainer : FillFlowContainer
{
private readonly Action hoverAction;
private readonly Action hoverLostAction;
public OuterBadgeContainer(Action hoverAction, Action hoverLostAction)
{
this.hoverAction = hoverAction;
this.hoverLostAction = hoverLostAction;
}
protected override bool OnHover(HoverEvent e)
{
hoverAction();
return true;
}
protected override void OnHoverLost(HoverLostEvent e) => hoverLostAction();
}
private class DrawableBadge : Container, IHasTooltip
{
public static readonly Vector2 DRAWABLE_BADGE_SIZE = badge_size + outer_padding.Total;
private readonly Badge badge;
public DrawableBadge(Badge badge)
{
this.badge = badge;
Padding = outer_padding;
Size = DRAWABLE_BADGE_SIZE;
}
[BackgroundDependencyLoader]
private void load(LargeTextureStore textures)
{
Child = new Sprite
{
FillMode = FillMode.Fit,
RelativeSizeAxes = Axes.Both,
Texture = textures.Get(badge.ImageUrl),
};
}
protected override void LoadComplete()
{
base.LoadComplete();
Child.FadeInFromZero(200);
}
public string TooltipText => badge.Description;
}
}
}

View File

@ -0,0 +1,153 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Users;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.Profile.Header
{
public class BottomHeaderContainer : CompositeDrawable
{
public readonly Bindable<User> User = new Bindable<User>();
private LinkFlowContainer topLinkContainer;
private LinkFlowContainer bottomLinkContainer;
private Color4 iconColour;
public BottomHeaderContainer()
{
AutoSizeAxes = Axes.Y;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
iconColour = colours.CommunityUserGrayGreenLighter;
InternalChildren = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.CommunityUserGrayGreenDarker,
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 },
Spacing = new Vector2(0, 10),
Children = new Drawable[]
{
topLinkContainer = new LinkFlowContainer(text => text.Font = text.Font.With(size: 12))
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
},
bottomLinkContainer = new LinkFlowContainer(text => text.Font = text.Font.With(size: 12))
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
}
}
}
};
User.BindValueChanged(user => updateDisplay(user.NewValue));
}
private void updateDisplay(User user)
{
topLinkContainer.Clear();
bottomLinkContainer.Clear();
if (user == null) return;
if (user.JoinDate.ToUniversalTime().Year < 2008)
topLinkContainer.AddText("Here since the beginning");
else
{
topLinkContainer.AddText("Joined ");
topLinkContainer.AddText(new DrawableDate(user.JoinDate), embolden);
}
addSpacer(topLinkContainer);
if (user.PlayStyles?.Length > 0)
{
topLinkContainer.AddText("Plays with ");
topLinkContainer.AddText(string.Join(", ", user.PlayStyles.Select(style => style.GetDescription())), embolden);
addSpacer(topLinkContainer);
}
if (user.LastVisit.HasValue)
{
topLinkContainer.AddText("Last seen ");
topLinkContainer.AddText(new DrawableDate(user.LastVisit.Value), embolden);
addSpacer(topLinkContainer);
}
topLinkContainer.AddText("Contributed ");
topLinkContainer.AddLink($@"{user.PostCount:#,##0} forum posts", $"https://osu.ppy.sh/users/{user.Id}/posts", creationParameters: embolden);
string websiteWithoutProtcol = user.Website;
if (!string.IsNullOrEmpty(websiteWithoutProtcol))
{
if (Uri.TryCreate(websiteWithoutProtcol, UriKind.Absolute, out var uri))
{
websiteWithoutProtcol = uri.Host + uri.PathAndQuery + uri.Fragment;
websiteWithoutProtcol = websiteWithoutProtcol.TrimEnd('/');
}
}
tryAddInfo(FontAwesome.Solid.MapMarker, user.Location);
tryAddInfo(OsuIcon.Heart, user.Interests);
tryAddInfo(FontAwesome.Solid.Suitcase, user.Occupation);
bottomLinkContainer.NewLine();
if (!string.IsNullOrEmpty(user.Twitter))
tryAddInfo(FontAwesome.Brands.Twitter, "@" + user.Twitter, $@"https://twitter.com/{user.Twitter}");
tryAddInfo(FontAwesome.Brands.Discord, user.Discord);
tryAddInfo(FontAwesome.Brands.Skype, user.Skype, @"skype:" + user.Skype + @"?chat");
tryAddInfo(FontAwesome.Brands.Lastfm, user.Lastfm, $@"https://last.fm/users/{user.Lastfm}");
tryAddInfo(FontAwesome.Solid.Link, websiteWithoutProtcol, user.Website);
}
private void addSpacer(OsuTextFlowContainer textFlow) => textFlow.AddArbitraryDrawable(new Container { Width = 15 });
private void tryAddInfo(IconUsage icon, string content, string link = null)
{
if (string.IsNullOrEmpty(content)) return;
bottomLinkContainer.AddIcon(icon, text =>
{
text.Font = text.Font.With(size: 10);
text.Colour = iconColour;
});
if (link != null)
bottomLinkContainer.AddLink(" " + content, link, creationParameters: embolden);
else
bottomLinkContainer.AddText(" " + content, embolden);
addSpacer(bottomLinkContainer);
}
private void embolden(SpriteText text) => text.Font = text.Font.With(weight: FontWeight.Bold);
}
}

View File

@ -0,0 +1,150 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
using osu.Game.Overlays.Profile.Header.Components;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Overlays.Profile.Header
{
public class CentreHeaderContainer : CompositeDrawable
{
public readonly BindableBool DetailsVisible = new BindableBool(true);
public readonly Bindable<User> User = new Bindable<User>();
private OverlinedInfoContainer hiddenDetailGlobal;
private OverlinedInfoContainer hiddenDetailCountry;
public CentreHeaderContainer()
{
Height = 60;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, TextureStore textures)
{
Container<Drawable> hiddenDetailContainer;
Container<Drawable> expandedDetailContainer;
InternalChildren = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.CommunityUserGrayGreenDark
},
new FillFlowContainer
{
AutoSizeAxes = Axes.X,
RelativeSizeAxes = Axes.Y,
Direction = FillDirection.Horizontal,
Padding = new MarginPadding { Vertical = 10 },
Margin = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN },
Spacing = new Vector2(10, 0),
Children = new Drawable[]
{
new AddFriendButton
{
RelativeSizeAxes = Axes.Y,
User = { BindTarget = User }
},
new MessageUserButton
{
User = { BindTarget = User }
},
}
},
new Container
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
RelativeSizeAxes = Axes.Y,
Padding = new MarginPadding { Vertical = 10 },
Width = UserProfileOverlay.CONTENT_X_MARGIN,
Child = new ExpandDetailsButton
{
RelativeSizeAxes = Axes.Y,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
DetailsVisible = { BindTarget = DetailsVisible }
},
},
new Container
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Right = UserProfileOverlay.CONTENT_X_MARGIN },
Children = new Drawable[]
{
new LevelBadge
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Size = new Vector2(40),
User = { BindTarget = User }
},
expandedDetailContainer = new Container
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Width = 200,
Height = 6,
Margin = new MarginPadding { Right = 50 },
Child = new LevelProgressBar
{
RelativeSizeAxes = Axes.Both,
User = { BindTarget = User }
}
},
hiddenDetailContainer = new FillFlowContainer
{
Direction = FillDirection.Horizontal,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Width = 200,
AutoSizeAxes = Axes.Y,
Alpha = 0,
Spacing = new Vector2(10, 0),
Margin = new MarginPadding { Right = 50 },
Children = new[]
{
hiddenDetailGlobal = new OverlinedInfoContainer
{
Title = "Global Ranking",
LineColour = colours.Yellow
},
hiddenDetailCountry = new OverlinedInfoContainer
{
Title = "Country Ranking",
LineColour = colours.Yellow
},
}
}
}
}
};
DetailsVisible.BindValueChanged(visible =>
{
hiddenDetailContainer.Alpha = visible.NewValue ? 0 : 1;
expandedDetailContainer.Alpha = visible.NewValue ? 1 : 0;
}, true);
User.BindValueChanged(user => updateDisplay(user.NewValue));
}
private void updateDisplay(User user)
{
hiddenDetailGlobal.Content = user?.Statistics?.Ranks.Global?.ToString("\\##,##0") ?? "-";
hiddenDetailCountry.Content = user?.Statistics?.Ranks.Country?.ToString("\\##,##0") ?? "-";
}
}
}

View File

@ -0,0 +1,58 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Overlays.Profile.Header.Components
{
public class AddFriendButton : ProfileHeaderButton
{
public readonly Bindable<User> User = new Bindable<User>();
public override string TooltipText => "friends";
private OsuSpriteText followerText;
[BackgroundDependencyLoader]
private void load()
{
Child = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Direction = FillDirection.Horizontal,
Padding = new MarginPadding { Right = 10 },
Children = new Drawable[]
{
new SpriteIcon
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Icon = FontAwesome.Solid.User,
FillMode = FillMode.Fit,
Size = new Vector2(50, 14)
},
followerText = new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Font = OsuFont.GetFont(weight: FontWeight.Bold)
}
}
};
User.BindValueChanged(user => updateFollowers(user.NewValue), true);
}
private void updateFollowers(User user) => followerText.Text = user?.FollowerCount?.Length > 0 ? user.FollowerCount[0].ToString("#,##0") : "0";
}
}

View File

@ -0,0 +1,46 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Overlays.Profile.Header.Components
{
public class DrawableBadge : CompositeDrawable, IHasTooltip
{
public static readonly Vector2 DRAWABLE_BADGE_SIZE = new Vector2(86, 40);
private readonly Badge badge;
public DrawableBadge(Badge badge)
{
this.badge = badge;
Size = DRAWABLE_BADGE_SIZE;
}
[BackgroundDependencyLoader]
private void load(LargeTextureStore textures)
{
InternalChild = new Sprite
{
FillMode = FillMode.Fit,
RelativeSizeAxes = Axes.Both,
Texture = textures.Get(badge.ImageUrl),
};
}
protected override void LoadComplete()
{
base.LoadComplete();
InternalChild.FadeInFromZero(200);
}
public string TooltipText => badge.Description;
}
}

View File

@ -0,0 +1,45 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osuTK;
namespace osu.Game.Overlays.Profile.Header.Components
{
public class ExpandDetailsButton : ProfileHeaderButton
{
public readonly BindableBool DetailsVisible = new BindableBool();
public override string TooltipText => DetailsVisible.Value ? "collapse" : "expand";
private SpriteIcon icon;
public ExpandDetailsButton()
{
Action = () => DetailsVisible.Toggle();
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
IdleColour = colours.CommunityUserGrayGreen;
HoverColour = colours.CommunityUserGrayGreen.Darken(0.2f);
Child = icon = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(20, 12)
};
DetailsVisible.BindValueChanged(visible => updateState(visible.NewValue), true);
}
private void updateState(bool detailsVisible) => icon.Icon = detailsVisible ? FontAwesome.Solid.ChevronUp : FontAwesome.Solid.ChevronDown;
}
}

View File

@ -0,0 +1,57 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Users;
namespace osu.Game.Overlays.Profile.Header.Components
{
public class LevelBadge : CompositeDrawable, IHasTooltip
{
public readonly Bindable<User> User = new Bindable<User>();
public string TooltipText { get; }
private OsuSpriteText levelText;
public LevelBadge()
{
TooltipText = "Level";
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, TextureStore textures)
{
InternalChildren = new Drawable[]
{
new Sprite
{
RelativeSizeAxes = Axes.Both,
Texture = textures.Get("Profile/levelbadge"),
Colour = colours.Yellow,
},
levelText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 20)
}
};
User.BindValueChanged(user => updateLevel(user.NewValue));
}
private void updateLevel(User user)
{
levelText.Text = user?.Statistics?.Level.Current.ToString() ?? "0";
}
}
}

View File

@ -0,0 +1,65 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Users;
using osuTK.Graphics;
namespace osu.Game.Overlays.Profile.Header.Components
{
public class LevelProgressBar : CompositeDrawable, IHasTooltip
{
public readonly Bindable<User> User = new Bindable<User>();
public string TooltipText { get; }
private Bar levelProgressBar;
private OsuSpriteText levelProgressText;
public LevelProgressBar()
{
TooltipText = "Progress to next level";
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
InternalChildren = new Drawable[]
{
new CircularContainer
{
RelativeSizeAxes = Axes.Both,
Masking = true,
Child = levelProgressBar = new Bar
{
RelativeSizeAxes = Axes.Both,
BackgroundColour = Color4.Black,
Direction = BarDirection.LeftToRight,
AccentColour = colours.Yellow
}
},
levelProgressText = new OsuSpriteText
{
Anchor = Anchor.BottomRight,
Origin = Anchor.TopRight,
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold)
}
};
User.BindValueChanged(user => updateProgress(user.NewValue));
}
private void updateProgress(User user)
{
levelProgressBar.Length = user?.Statistics?.Level.Progress / 100f ?? 0;
levelProgressText.Text = user?.Statistics?.Level.Progress.ToString("0'%'");
}
}
}

View File

@ -0,0 +1,59 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Online.API;
using osu.Game.Online.Chat;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Overlays.Profile.Header.Components
{
public class MessageUserButton : ProfileHeaderButton
{
public readonly Bindable<User> User = new Bindable<User>();
public override string TooltipText => "send message";
[Resolved(CanBeNull = true)]
private ChannelManager channelManager { get; set; }
[Resolved(CanBeNull = true)]
private UserProfileOverlay userOverlay { get; set; }
[Resolved(CanBeNull = true)]
private ChatOverlay chatOverlay { get; set; }
[Resolved]
private IAPIProvider apiProvider { get; set; }
public MessageUserButton()
{
Content.Alpha = 0;
RelativeSizeAxes = Axes.Y;
Child = new SpriteIcon
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Icon = FontAwesome.Solid.Envelope,
FillMode = FillMode.Fit,
Size = new Vector2(50, 14)
};
Action = () =>
{
if (!Content.IsPresent) return;
channelManager?.OpenPrivateChannel(User.Value);
userOverlay?.Hide();
chatOverlay?.Show();
};
User.ValueChanged += e => Content.Alpha = !e.NewValue.PMFriendsOnly && apiProvider.LocalUser.Value.Id != e.NewValue.Id ? 1 : 0;
}
}
}

View File

@ -0,0 +1,64 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osuTK.Graphics;
namespace osu.Game.Overlays.Profile.Header.Components
{
public class OverlinedInfoContainer : CompositeDrawable
{
private readonly Circle line;
private readonly OsuSpriteText title;
private readonly OsuSpriteText content;
public string Title
{
set => title.Text = value;
}
public string Content
{
set => content.Text = value;
}
public Color4 LineColour
{
set => line.Colour = value;
}
public OverlinedInfoContainer(bool big = false, int minimumWidth = 60)
{
AutoSizeAxes = Axes.Both;
InternalChild = new FillFlowContainer
{
Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
line = new Circle
{
RelativeSizeAxes = Axes.X,
Height = 4,
},
title = new OsuSpriteText
{
Font = OsuFont.GetFont(size: big ? 14 : 12, weight: FontWeight.Bold)
},
content = new OsuSpriteText
{
Font = OsuFont.GetFont(size: big ? 40 : 18, weight: FontWeight.Light)
},
new Container //Add a minimum size to the FillFlowContainer
{
Width = minimumWidth,
}
}
};
}
}
}

View File

@ -0,0 +1,69 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Game.Graphics;
using osu.Game.Users;
namespace osu.Game.Overlays.Profile.Header.Components
{
public class OverlinedTotalPlayTime : CompositeDrawable, IHasTooltip
{
public readonly Bindable<User> User = new Bindable<User>();
public string TooltipText { get; set; }
private OverlinedInfoContainer info;
public OverlinedTotalPlayTime()
{
AutoSizeAxes = Axes.Both;
TooltipText = "0 hours";
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
InternalChild = info = new OverlinedInfoContainer
{
Title = "Total Play Time",
LineColour = colours.Yellow,
};
User.BindValueChanged(updateTime, true);
}
private void updateTime(ValueChangedEvent<User> user)
{
TooltipText = (user.NewValue?.Statistics?.PlayTime ?? 0) / 3600 + " hours";
info.Content = formatTime(user.NewValue?.Statistics?.PlayTime);
}
private string formatTime(int? secondsNull)
{
if (secondsNull == null) return "0h 0m";
int seconds = secondsNull.Value;
string time = "";
int days = seconds / 86400;
seconds -= days * 86400;
if (days > 0)
time += days + "d ";
int hours = seconds / 3600;
seconds -= hours * 3600;
time += hours + "h ";
int minutes = seconds / 60;
time += minutes + "m";
return time;
}
}
}

View File

@ -0,0 +1,54 @@
// 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.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osuTK.Graphics;
namespace osu.Game.Overlays.Profile.Header.Components
{
public abstract class ProfileHeaderButton : OsuHoverContainer, IHasTooltip
{
public abstract string TooltipText { get; }
private readonly Box background;
private readonly Container content;
protected override Container<Drawable> Content => content;
protected override IEnumerable<Drawable> EffectTargets => new[] { background };
protected ProfileHeaderButton()
{
AutoSizeAxes = Axes.X;
IdleColour = Color4.Black;
HoverColour = OsuColour.Gray(0.1f);
base.Content.Add(new CircularContainer
{
Masking = true,
AutoSizeAxes = Axes.X,
RelativeSizeAxes = Axes.Y,
Children = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
},
content = new Container
{
AutoSizeAxes = Axes.X,
RelativeSizeAxes = Axes.Y,
Padding = new MarginPadding { Horizontal = 10 },
}
}
});
}
}
}

View File

@ -0,0 +1,280 @@
// 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 System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Overlays.Profile.Header.Components
{
public class RankGraph : Container, IHasCustomTooltip
{
private const float secondary_textsize = 13;
private const float padding = 10;
private const float fade_duration = 150;
private const int ranked_days = 88;
private readonly RankChartLineGraph graph;
private readonly OsuSpriteText placeholder;
private KeyValuePair<int, int>[] ranks;
private int dayIndex;
public Bindable<User> User = new Bindable<User>();
public RankGraph()
{
Padding = new MarginPadding { Vertical = padding };
Children = new Drawable[]
{
placeholder = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = "No recent plays",
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular)
},
graph = new RankChartLineGraph
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.Both,
Y = -secondary_textsize,
Alpha = 0,
}
};
graph.OnBallMove += i => dayIndex = i;
User.ValueChanged += userChanged;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
graph.LineColour = colours.Yellow;
}
private void userChanged(ValueChangedEvent<User> e)
{
placeholder.FadeIn(fade_duration, Easing.Out);
if (e.NewValue?.Statistics?.Ranks.Global == null)
{
graph.FadeOut(fade_duration, Easing.Out);
ranks = null;
return;
}
int[] userRanks = e.NewValue.RankHistory?.Data ?? new[] { e.NewValue.Statistics.Ranks.Global.Value };
ranks = userRanks.Select((x, index) => new KeyValuePair<int, int>(index, x)).Where(x => x.Value != 0).ToArray();
if (ranks.Length > 1)
{
placeholder.FadeOut(fade_duration, Easing.Out);
graph.DefaultValueCount = ranks.Length;
graph.Values = ranks.Select(x => -(float)Math.Log(x.Value));
}
graph.FadeTo(ranks.Length > 1 ? 1 : 0, fade_duration, Easing.Out);
}
protected override bool OnHover(HoverEvent e)
{
if (ranks?.Length > 1)
{
graph.UpdateBallPosition(e.MousePosition.X);
graph.ShowBall();
}
return base.OnHover(e);
}
protected override bool OnMouseMove(MouseMoveEvent e)
{
if (ranks?.Length > 1)
graph.UpdateBallPosition(e.MousePosition.X);
return base.OnMouseMove(e);
}
protected override void OnHoverLost(HoverLostEvent e)
{
if (ranks?.Length > 1)
{
graph.HideBall();
}
base.OnHoverLost(e);
}
private class RankChartLineGraph : LineGraph
{
private readonly CircularContainer movingBall;
private readonly Box ballBg;
private readonly Box movingBar;
public Action<int> OnBallMove;
public RankChartLineGraph()
{
Add(movingBar = new Box
{
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Y,
Width = 1.5f,
Alpha = 0,
RelativePositionAxes = Axes.Both,
});
Add(movingBall = new CircularContainer
{
Origin = Anchor.Centre,
Size = new Vector2(18),
Alpha = 0,
Masking = true,
BorderThickness = 4,
RelativePositionAxes = Axes.Both,
Child = ballBg = new Box { RelativeSizeAxes = Axes.Both }
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
ballBg.Colour = colours.CommunityUserGrayGreenDarkest;
movingBall.BorderColour = colours.Yellow;
movingBar.Colour = colours.Yellow;
}
public void UpdateBallPosition(float mouseXPosition)
{
int index = calculateIndex(mouseXPosition);
movingBall.Position = calculateBallPosition(index);
movingBar.X = movingBall.X;
OnBallMove.Invoke(index);
}
public void ShowBall()
{
movingBall.FadeIn(fade_duration);
movingBar.FadeIn(fade_duration);
}
public void HideBall()
{
movingBall.FadeOut(fade_duration);
movingBar.FadeOut(fade_duration);
}
private int calculateIndex(float mouseXPosition) => (int)Math.Round(mouseXPosition / DrawWidth * (DefaultValueCount - 1));
private Vector2 calculateBallPosition(int index)
{
float y = GetYPosition(Values.ElementAt(index));
return new Vector2(index / (float)(DefaultValueCount - 1), y);
}
}
public string TooltipText => User.Value?.Statistics?.Ranks.Global == null ? "" : $"#{ranks[dayIndex].Value:#,##0}|{ranked_days - ranks[dayIndex].Key + 1}";
public ITooltip GetCustomTooltip() => new RankGraphTooltip();
public class RankGraphTooltip : VisibilityContainer, ITooltip
{
private readonly OsuSpriteText globalRankingText, timeText;
private readonly Box background;
public string TooltipText { get; set; }
public RankGraphTooltip()
{
AutoSizeAxes = Axes.Both;
Masking = true;
CornerRadius = 10;
Children = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both
},
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Padding = new MarginPadding(10),
Children = new Drawable[]
{
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
new OsuSpriteText
{
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
Text = "Global Ranking "
},
globalRankingText = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
}
}
},
timeText = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
}
}
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
background.Colour = colours.CommunityUserGrayGreenDarker;
}
public void Refresh()
{
var info = TooltipText.Split('|');
globalRankingText.Text = info[0];
timeText.Text = info[1] == "0" ? "now" : $"{info[1]} days ago";
}
private bool instantMove = true;
public void Move(Vector2 pos)
{
if (instantMove)
{
Position = pos;
instantMove = false;
}
else
this.MoveTo(pos, 200, Easing.OutQuint);
}
protected override void PopIn() => this.FadeIn(200, Easing.OutQuint);
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
}
}
}

Some files were not shown because too many files have changed in this diff Show More