mirror of
https://github.com/osukey/osukey.git
synced 2025-08-06 16:13:57 +09:00
Merge branch 'master' into fix-carousel-sort-change-after-play
This commit is contained in:
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Rulesets.Mania.Mods;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Mods
|
||||||
|
{
|
||||||
|
public partial class TestSceneManiaModFadeIn : ModTestScene
|
||||||
|
{
|
||||||
|
protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset();
|
||||||
|
|
||||||
|
[TestCase(0.5f)]
|
||||||
|
[TestCase(0.1f)]
|
||||||
|
[TestCase(0.7f)]
|
||||||
|
public void TestCoverage(float coverage) => CreateModTest(new ModTestData { Mod = new ManiaModFadeIn { Coverage = { Value = coverage } }, PassCondition = () => true });
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Rulesets.Mania.Mods;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Mods
|
||||||
|
{
|
||||||
|
public partial class TestSceneManiaModHidden : ModTestScene
|
||||||
|
{
|
||||||
|
protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset();
|
||||||
|
|
||||||
|
[TestCase(0.5f)]
|
||||||
|
[TestCase(0.2f)]
|
||||||
|
[TestCase(0.8f)]
|
||||||
|
public void TestCoverage(float coverage) => CreateModTest(new ModTestData { Mod = new ManiaModHidden { Coverage = { Value = coverage } }, PassCondition = () => true });
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
|
||||||
@ -18,5 +19,13 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ManiaModHidden)).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ManiaModHidden)).ToArray();
|
||||||
|
|
||||||
protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AlongScroll;
|
protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AlongScroll;
|
||||||
|
|
||||||
|
public override BindableNumber<float> Coverage { get; } = new BindableFloat(0.5f)
|
||||||
|
{
|
||||||
|
Precision = 0.1f,
|
||||||
|
MinValue = 0.1f,
|
||||||
|
MaxValue = 0.7f,
|
||||||
|
Default = 0.5f,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Mods
|
namespace osu.Game.Rulesets.Mania.Mods
|
||||||
{
|
{
|
||||||
@ -13,6 +14,14 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
public override LocalisableString Description => @"Keys fade out before you hit them!";
|
public override LocalisableString Description => @"Keys fade out before you hit them!";
|
||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
|
|
||||||
|
public override BindableNumber<float> Coverage { get; } = new BindableFloat(0.5f)
|
||||||
|
{
|
||||||
|
Precision = 0.1f,
|
||||||
|
MinValue = 0.2f,
|
||||||
|
MaxValue = 0.8f,
|
||||||
|
Default = 0.5f,
|
||||||
|
};
|
||||||
|
|
||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ManiaModFadeIn)).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ManiaModFadeIn)).ToArray();
|
||||||
|
|
||||||
protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AgainstScroll;
|
protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AgainstScroll;
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -22,6 +24,9 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected abstract CoverExpandDirection ExpandDirection { get; }
|
protected abstract CoverExpandDirection ExpandDirection { get; }
|
||||||
|
|
||||||
|
[SettingSource("Coverage", "The proportion of playfield height that notes will be hidden for.")]
|
||||||
|
public abstract BindableNumber<float> Coverage { get; }
|
||||||
|
|
||||||
public virtual void ApplyToDrawableRuleset(DrawableRuleset<ManiaHitObject> drawableRuleset)
|
public virtual void ApplyToDrawableRuleset(DrawableRuleset<ManiaHitObject> drawableRuleset)
|
||||||
{
|
{
|
||||||
ManiaPlayfield maniaPlayfield = (ManiaPlayfield)drawableRuleset.Playfield;
|
ManiaPlayfield maniaPlayfield = (ManiaPlayfield)drawableRuleset.Playfield;
|
||||||
@ -36,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
{
|
{
|
||||||
c.RelativeSizeAxes = Axes.Both;
|
c.RelativeSizeAxes = Axes.Both;
|
||||||
c.Direction = ExpandDirection;
|
c.Direction = ExpandDirection;
|
||||||
c.Coverage = 0.5f;
|
c.Coverage = Coverage.Value;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,10 +31,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestMaximumDistanceTrackingWithoutMovement(
|
public void TestMaximumDistanceTrackingWithoutMovement(
|
||||||
[Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)]
|
[Values(0, 5, 10)] float circleSize,
|
||||||
float circleSize,
|
[Values(0, 5, 10)] double velocity)
|
||||||
[Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)]
|
|
||||||
double velocity)
|
|
||||||
{
|
{
|
||||||
const double time_slider_start = 1000;
|
const double time_slider_start = 1000;
|
||||||
|
|
||||||
|
BIN
osu.Game.Tests/Resources/Archives/modified-default-20230117.osk
Normal file
BIN
osu.Game.Tests/Resources/Archives/modified-default-20230117.osk
Normal file
Binary file not shown.
@ -44,7 +44,9 @@ namespace osu.Game.Tests.Skins
|
|||||||
// Covers TextElement and BeatmapInfoDrawable
|
// Covers TextElement and BeatmapInfoDrawable
|
||||||
"Archives/modified-default-20221102.osk",
|
"Archives/modified-default-20221102.osk",
|
||||||
// Covers BPM counter.
|
// Covers BPM counter.
|
||||||
"Archives/modified-default-20221205.osk"
|
"Archives/modified-default-20221205.osk",
|
||||||
|
// Covers judgement counter.
|
||||||
|
"Archives/modified-default-20230117.osk"
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
144
osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs
Normal file
144
osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
// 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.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Mania;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Screens.Play.HUD.JudgementCounter;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
|
{
|
||||||
|
public partial class TestSceneJudgementCounter : OsuTestScene
|
||||||
|
{
|
||||||
|
private ScoreProcessor scoreProcessor = null!;
|
||||||
|
private JudgementTally judgementTally = null!;
|
||||||
|
private TestJudgementCounterDisplay counterDisplay = null!;
|
||||||
|
|
||||||
|
private readonly Bindable<JudgementResult> lastJudgementResult = new Bindable<JudgementResult>();
|
||||||
|
|
||||||
|
private int iteration;
|
||||||
|
|
||||||
|
[SetUpSteps]
|
||||||
|
public void SetupSteps() => AddStep("Create components", () =>
|
||||||
|
{
|
||||||
|
var ruleset = CreateRuleset();
|
||||||
|
|
||||||
|
Debug.Assert(ruleset != null);
|
||||||
|
|
||||||
|
scoreProcessor = new ScoreProcessor(ruleset);
|
||||||
|
Child = new DependencyProvidingContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
CachedDependencies = new (Type, object)[] { (typeof(ScoreProcessor), scoreProcessor), (typeof(Ruleset), ruleset) },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
judgementTally = new JudgementTally(),
|
||||||
|
new DependencyProvidingContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
CachedDependencies = new (Type, object)[] { (typeof(JudgementTally), judgementTally) },
|
||||||
|
Child = counterDisplay = new TestJudgementCounterDisplay
|
||||||
|
{
|
||||||
|
Margin = new MarginPadding { Top = 100 },
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
protected override Ruleset CreateRuleset() => new ManiaRuleset();
|
||||||
|
|
||||||
|
private void applyOneJudgement(HitResult result)
|
||||||
|
{
|
||||||
|
lastJudgementResult.Value = new OsuJudgementResult(new HitObject
|
||||||
|
{
|
||||||
|
StartTime = iteration * 10000
|
||||||
|
}, new OsuJudgement())
|
||||||
|
{
|
||||||
|
Type = result,
|
||||||
|
};
|
||||||
|
scoreProcessor.ApplyResult(lastJudgementResult.Value);
|
||||||
|
|
||||||
|
iteration++;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAddJudgementsToCounters()
|
||||||
|
{
|
||||||
|
AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.Great), 2);
|
||||||
|
AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.Miss), 2);
|
||||||
|
AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.Meh), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAddWhilstHidden()
|
||||||
|
{
|
||||||
|
AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.LargeTickHit), 2);
|
||||||
|
AddAssert("Check value added whilst hidden", () => hiddenCount() == 2);
|
||||||
|
AddStep("Show all judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.All);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestChangeFlowDirection()
|
||||||
|
{
|
||||||
|
AddStep("Set direction vertical", () => counterDisplay.FlowDirection.Value = Direction.Vertical);
|
||||||
|
AddStep("Set direction horizontal", () => counterDisplay.FlowDirection.Value = Direction.Horizontal);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestToggleJudgementNames()
|
||||||
|
{
|
||||||
|
AddStep("Hide judgement names", () => counterDisplay.ShowJudgementNames.Value = false);
|
||||||
|
AddWaitStep("wait some", 2);
|
||||||
|
AddAssert("Assert hidden", () => counterDisplay.CounterFlow.Children.First().ResultName.Alpha == 0);
|
||||||
|
AddStep("Hide judgement names", () => counterDisplay.ShowJudgementNames.Value = true);
|
||||||
|
AddWaitStep("wait some", 2);
|
||||||
|
AddAssert("Assert shown", () => counterDisplay.CounterFlow.Children.First().ResultName.Alpha == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHideMaxValue()
|
||||||
|
{
|
||||||
|
AddStep("Hide max judgement", () => counterDisplay.ShowMaxJudgement.Value = false);
|
||||||
|
AddWaitStep("wait some", 2);
|
||||||
|
AddAssert("Check max hidden", () => counterDisplay.CounterFlow.ChildrenOfType<JudgementCounter>().First().Alpha == 0);
|
||||||
|
AddStep("Show max judgement", () => counterDisplay.ShowMaxJudgement.Value = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCycleDisplayModes()
|
||||||
|
{
|
||||||
|
AddStep("Show basic judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.Simple);
|
||||||
|
AddWaitStep("wait some", 2);
|
||||||
|
AddAssert("Check only basic", () => counterDisplay.CounterFlow.ChildrenOfType<JudgementCounter>().Last().Alpha == 0);
|
||||||
|
AddStep("Show normal judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.Normal);
|
||||||
|
AddStep("Show all judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.All);
|
||||||
|
AddWaitStep("wait some", 2);
|
||||||
|
AddAssert("Check all visible", () => counterDisplay.CounterFlow.ChildrenOfType<JudgementCounter>().Last().Alpha == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int hiddenCount()
|
||||||
|
{
|
||||||
|
var num = counterDisplay.CounterFlow.Children.First(child => child.Result.Type == HitResult.LargeTickHit);
|
||||||
|
return num.Result.ResultCount.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private partial class TestJudgementCounterDisplay : JudgementCounterDisplay
|
||||||
|
{
|
||||||
|
public new FillFlowContainer<JudgementCounter> CounterFlow => base.CounterFlow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +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.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -11,7 +9,10 @@ using osu.Game.Overlays;
|
|||||||
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.Sprites;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
@ -27,15 +28,20 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
|
|
||||||
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
|
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
|
||||||
|
|
||||||
private CommentsContainer commentsContainer;
|
private CommentsContainer commentsContainer = null!;
|
||||||
|
|
||||||
|
private TextBox editorTextBox = null!;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp() => Schedule(() =>
|
public void SetUp() => Schedule(() =>
|
||||||
|
{
|
||||||
Child = new BasicScrollContainer
|
Child = new BasicScrollContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = commentsContainer = new CommentsContainer()
|
Child = commentsContainer = new CommentsContainer()
|
||||||
});
|
};
|
||||||
|
editorTextBox = commentsContainer.ChildrenOfType<TextBox>().First();
|
||||||
|
});
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestIdleState()
|
public void TestIdleState()
|
||||||
@ -126,6 +132,44 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
commentsContainer.ChildrenOfType<DrawableComment>().Count(d => d.Comment.Pinned == withPinned) == 1);
|
commentsContainer.ChildrenOfType<DrawableComment>().Count(d => d.Comment.Pinned == withPinned) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPost()
|
||||||
|
{
|
||||||
|
setUpCommentsResponse(new CommentBundle { Comments = new List<Comment>() });
|
||||||
|
AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123));
|
||||||
|
AddAssert("no comments placeholder shown", () => commentsContainer.ChildrenOfType<CommentsContainer.NoCommentsPlaceholder>().Any());
|
||||||
|
|
||||||
|
setUpPostResponse();
|
||||||
|
AddStep("enter text", () => editorTextBox.Current.Value = "comm");
|
||||||
|
AddStep("submit", () => commentsContainer.ChildrenOfType<RoundedButton>().First().TriggerClick());
|
||||||
|
|
||||||
|
AddUntilStep("comment sent", () =>
|
||||||
|
{
|
||||||
|
string writtenText = editorTextBox.Current.Value;
|
||||||
|
var comment = commentsContainer.ChildrenOfType<DrawableComment>().LastOrDefault();
|
||||||
|
return comment != null && comment.ChildrenOfType<SpriteText>().Any(y => y.Text == writtenText);
|
||||||
|
});
|
||||||
|
AddAssert("no comments placeholder removed", () => !commentsContainer.ChildrenOfType<CommentsContainer.NoCommentsPlaceholder>().Any());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPostWithExistingComments()
|
||||||
|
{
|
||||||
|
setUpCommentsResponse(getExampleComments());
|
||||||
|
AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123));
|
||||||
|
|
||||||
|
setUpPostResponse();
|
||||||
|
AddStep("enter text", () => editorTextBox.Current.Value = "comm");
|
||||||
|
AddStep("submit", () => commentsContainer.ChildrenOfType<CommentEditor>().Single().ChildrenOfType<RoundedButton>().First().TriggerClick());
|
||||||
|
|
||||||
|
AddUntilStep("comment sent", () =>
|
||||||
|
{
|
||||||
|
string writtenText = editorTextBox.Current.Value;
|
||||||
|
var comment = commentsContainer.ChildrenOfType<DrawableComment>().LastOrDefault();
|
||||||
|
return comment != null && comment.ChildrenOfType<SpriteText>().Any(y => y.Text == writtenText);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void setUpCommentsResponse(CommentBundle commentBundle)
|
private void setUpCommentsResponse(CommentBundle commentBundle)
|
||||||
=> AddStep("set up response", () =>
|
=> AddStep("set up response", () =>
|
||||||
{
|
{
|
||||||
@ -139,7 +183,33 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
private CommentBundle getExampleComments(bool withPinned = false)
|
private void setUpPostResponse()
|
||||||
|
=> AddStep("set up response", () =>
|
||||||
|
{
|
||||||
|
dummyAPI.HandleRequest = request =>
|
||||||
|
{
|
||||||
|
if (!(request is CommentPostRequest req))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
req.TriggerSuccess(new CommentBundle
|
||||||
|
{
|
||||||
|
Comments = new List<Comment>
|
||||||
|
{
|
||||||
|
new Comment
|
||||||
|
{
|
||||||
|
Id = 98,
|
||||||
|
Message = req.Message,
|
||||||
|
LegacyName = "FirstUser",
|
||||||
|
CreatedAt = DateTimeOffset.Now,
|
||||||
|
VotesCount = 98,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
private static CommentBundle getExampleComments(bool withPinned = false)
|
||||||
{
|
{
|
||||||
var bundle = new CommentBundle
|
var bundle = new CommentBundle
|
||||||
{
|
{
|
||||||
|
@ -19,6 +19,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"join the real-time discussion");
|
public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"join the real-time discussion");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Mention"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString MentionUser => new TranslatableString(getKey(@"mention_user"), @"Mention");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
41
osu.Game/Online/API/Requests/CommentPostRequest.cs
Normal file
41
osu.Game/Online/API/Requests/CommentPostRequest.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// 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.Net.Http;
|
||||||
|
using osu.Framework.IO.Network;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
|
||||||
|
namespace osu.Game.Online.API.Requests
|
||||||
|
{
|
||||||
|
public class CommentPostRequest : APIRequest<CommentBundle>
|
||||||
|
{
|
||||||
|
public readonly CommentableType Commentable;
|
||||||
|
public readonly long CommentableId;
|
||||||
|
public readonly string Message;
|
||||||
|
public readonly long? ParentCommentId;
|
||||||
|
|
||||||
|
public CommentPostRequest(CommentableType commentable, long commentableId, string message, long? parentCommentId = null)
|
||||||
|
{
|
||||||
|
Commentable = commentable;
|
||||||
|
CommentableId = commentableId;
|
||||||
|
Message = message;
|
||||||
|
ParentCommentId = parentCommentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override WebRequest CreateWebRequest()
|
||||||
|
{
|
||||||
|
var req = base.CreateWebRequest();
|
||||||
|
req.Method = HttpMethod.Post;
|
||||||
|
|
||||||
|
req.AddParameter(@"comment[commentable_type]", Commentable.ToString().ToLowerInvariant());
|
||||||
|
req.AddParameter(@"comment[commentable_id]", $"{CommentableId}");
|
||||||
|
req.AddParameter(@"comment[message]", Message);
|
||||||
|
if (ParentCommentId.HasValue)
|
||||||
|
req.AddParameter(@"comment[parent_id]", $"{ParentCommentId}");
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string Target => "comments";
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,7 @@ namespace osu.Game.Online.Chat
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class StandAloneChatDisplay : CompositeDrawable
|
public partial class StandAloneChatDisplay : CompositeDrawable
|
||||||
{
|
{
|
||||||
|
[Cached]
|
||||||
public readonly Bindable<Channel> Channel = new Bindable<Channel>();
|
public readonly Bindable<Channel> Channel = new Bindable<Channel>();
|
||||||
|
|
||||||
protected readonly ChatTextBox TextBox;
|
protected readonly ChatTextBox TextBox;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
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;
|
||||||
@ -24,6 +25,7 @@ using osu.Game.Online.Chat;
|
|||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
using ChatStrings = osu.Game.Localisation.ChatStrings;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Chat
|
namespace osu.Game.Overlays.Chat
|
||||||
{
|
{
|
||||||
@ -65,6 +67,9 @@ namespace osu.Game.Overlays.Chat
|
|||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private UserProfileOverlay? profileOverlay { get; set; }
|
private UserProfileOverlay? profileOverlay { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private Bindable<Channel?>? currentChannel { get; set; }
|
||||||
|
|
||||||
private readonly APIUser user;
|
private readonly APIUser user;
|
||||||
private readonly OsuSpriteText drawableText;
|
private readonly OsuSpriteText drawableText;
|
||||||
|
|
||||||
@ -156,6 +161,14 @@ namespace osu.Game.Overlays.Chat
|
|||||||
if (!user.Equals(api.LocalUser.Value))
|
if (!user.Equals(api.LocalUser.Value))
|
||||||
items.Add(new OsuMenuItem(UsersStrings.CardSendMessage, MenuItemType.Standard, openUserChannel));
|
items.Add(new OsuMenuItem(UsersStrings.CardSendMessage, MenuItemType.Standard, openUserChannel));
|
||||||
|
|
||||||
|
if (currentChannel?.Value != null)
|
||||||
|
{
|
||||||
|
items.Add(new OsuMenuItem(ChatStrings.MentionUser, MenuItemType.Standard, () =>
|
||||||
|
{
|
||||||
|
currentChannel.Value.TextBoxMessage.Value += $"@{user.Username} ";
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
return items.ToArray();
|
return items.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
@ -17,16 +18,22 @@ using osu.Framework.Extensions.IEnumerableExtensions;
|
|||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
using APIUser = osu.Game.Online.API.Requests.Responses.APIUser;
|
using osu.Game.Users.Drawables;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Comments
|
namespace osu.Game.Overlays.Comments
|
||||||
{
|
{
|
||||||
|
[Cached]
|
||||||
public partial class CommentsContainer : CompositeDrawable
|
public partial class CommentsContainer : CompositeDrawable
|
||||||
{
|
{
|
||||||
private readonly Bindable<CommentableType> type = new Bindable<CommentableType>();
|
private readonly Bindable<CommentableType> type = new Bindable<CommentableType>();
|
||||||
private readonly BindableLong id = new BindableLong();
|
private readonly BindableLong id = new BindableLong();
|
||||||
|
public IBindable<CommentableType> Type => type;
|
||||||
|
public IBindable<long> Id => id;
|
||||||
|
|
||||||
public readonly Bindable<CommentsSortCriteria> Sort = new Bindable<CommentsSortCriteria>();
|
public readonly Bindable<CommentsSortCriteria> Sort = new Bindable<CommentsSortCriteria>();
|
||||||
public readonly BindableBool ShowDeleted = new BindableBool();
|
public readonly BindableBool ShowDeleted = new BindableBool();
|
||||||
@ -46,12 +53,14 @@ namespace osu.Game.Overlays.Comments
|
|||||||
private DeletedCommentsCounter deletedCommentsCounter;
|
private DeletedCommentsCounter deletedCommentsCounter;
|
||||||
private CommentsShowMoreButton moreButton;
|
private CommentsShowMoreButton moreButton;
|
||||||
private TotalCommentsCounter commentCounter;
|
private TotalCommentsCounter commentCounter;
|
||||||
|
private UpdateableAvatar avatar;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OverlayColourProvider colourProvider)
|
private void load(OverlayColourProvider colourProvider)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
AddRangeInternal(new Drawable[]
|
AddRangeInternal(new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
@ -86,6 +95,32 @@ namespace osu.Game.Overlays.Comments
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Padding = new MarginPadding { Horizontal = 50, Vertical = 20 },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
avatar = new UpdateableAvatar(api.LocalUser.Value)
|
||||||
|
{
|
||||||
|
Size = new Vector2(50),
|
||||||
|
CornerExponent = 2,
|
||||||
|
CornerRadius = 25,
|
||||||
|
Masking = true,
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Padding = new MarginPadding { Left = 60 },
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Child = new NewCommentEditor
|
||||||
|
{
|
||||||
|
OnPost = prependPostedComments
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
new CommentsHeader
|
new CommentsHeader
|
||||||
{
|
{
|
||||||
Sort = { BindTarget = Sort },
|
Sort = { BindTarget = Sort },
|
||||||
@ -151,6 +186,7 @@ namespace osu.Game.Overlays.Comments
|
|||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
User.BindValueChanged(_ => refetchComments());
|
User.BindValueChanged(_ => refetchComments());
|
||||||
|
User.BindValueChanged(e => avatar.User = e.NewValue);
|
||||||
Sort.BindValueChanged(_ => refetchComments(), true);
|
Sort.BindValueChanged(_ => refetchComments(), true);
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
}
|
}
|
||||||
@ -245,7 +281,6 @@ namespace osu.Game.Overlays.Comments
|
|||||||
{
|
{
|
||||||
pinnedContent.AddRange(loaded.Where(d => d.Comment.Pinned));
|
pinnedContent.AddRange(loaded.Where(d => d.Comment.Pinned));
|
||||||
content.AddRange(loaded.Where(d => !d.Comment.Pinned));
|
content.AddRange(loaded.Where(d => !d.Comment.Pinned));
|
||||||
|
|
||||||
deletedCommentsCounter.Count.Value += topLevelComments.Select(d => d.Comment).Count(c => c.IsDeleted && c.IsTopLevel);
|
deletedCommentsCounter.Count.Value += topLevelComments.Select(d => d.Comment).Count(c => c.IsDeleted && c.IsTopLevel);
|
||||||
|
|
||||||
if (bundle.HasMore)
|
if (bundle.HasMore)
|
||||||
@ -288,6 +323,34 @@ namespace osu.Game.Overlays.Comments
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void prependPostedComments(CommentBundle bundle)
|
||||||
|
{
|
||||||
|
var topLevelComments = new List<DrawableComment>();
|
||||||
|
|
||||||
|
foreach (var comment in bundle.Comments)
|
||||||
|
{
|
||||||
|
// Exclude possible duplicated comments.
|
||||||
|
if (CommentDictionary.ContainsKey(comment.Id))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
topLevelComments.Add(getDrawableComment(comment));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (topLevelComments.Any())
|
||||||
|
{
|
||||||
|
LoadComponentsAsync(topLevelComments, loaded =>
|
||||||
|
{
|
||||||
|
if (content.Count > 0 && content[0] is NoCommentsPlaceholder placeholder)
|
||||||
|
content.Remove(placeholder, true);
|
||||||
|
|
||||||
|
foreach (var comment in loaded)
|
||||||
|
{
|
||||||
|
content.Insert((int)-Clock.CurrentTime, comment);
|
||||||
|
}
|
||||||
|
}, (loadCancellation = new CancellationTokenSource()).Token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private DrawableComment getDrawableComment(Comment comment)
|
private DrawableComment getDrawableComment(Comment comment)
|
||||||
{
|
{
|
||||||
if (CommentDictionary.TryGetValue(comment.Id, out var existing))
|
if (CommentDictionary.TryGetValue(comment.Id, out var existing))
|
||||||
@ -317,7 +380,7 @@ namespace osu.Game.Overlays.Comments
|
|||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
private partial class NoCommentsPlaceholder : CompositeDrawable
|
internal partial class NoCommentsPlaceholder : CompositeDrawable
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
@ -336,5 +399,41 @@ namespace osu.Game.Overlays.Comments
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private partial class NewCommentEditor : CommentEditor
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private CommentsContainer commentsContainer { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
|
public Action<CommentBundle> OnPost;
|
||||||
|
|
||||||
|
//TODO should match web, left empty due to no multiline support
|
||||||
|
protected override LocalisableString FooterText => default;
|
||||||
|
|
||||||
|
protected override LocalisableString CommitButtonText => CommonStrings.ButtonsPost;
|
||||||
|
|
||||||
|
protected override LocalisableString TextBoxPlaceholder => CommentsStrings.PlaceholderNew;
|
||||||
|
|
||||||
|
protected override void OnCommit(string text)
|
||||||
|
{
|
||||||
|
ShowLoadingSpinner = true;
|
||||||
|
CommentPostRequest req = new CommentPostRequest(commentsContainer.Type.Value, commentsContainer.Id.Value, text);
|
||||||
|
req.Failure += e => Schedule(() =>
|
||||||
|
{
|
||||||
|
ShowLoadingSpinner = false;
|
||||||
|
Logger.Error(e, "Posting comment failed.");
|
||||||
|
});
|
||||||
|
req.Success += cb => Schedule(() =>
|
||||||
|
{
|
||||||
|
ShowLoadingSpinner = false;
|
||||||
|
Current.Value = string.Empty;
|
||||||
|
OnPost?.Invoke(cb);
|
||||||
|
});
|
||||||
|
api.Queue(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,11 @@ namespace osu.Game.Overlays.Comments
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool WasDeleted { get; protected set; }
|
public bool WasDeleted { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tracks this comment's level of nesting. 0 means that this comment has no parents.
|
||||||
|
/// </summary>
|
||||||
|
public int Level { get; private set; }
|
||||||
|
|
||||||
private FillFlowContainer childCommentsVisibilityContainer = null!;
|
private FillFlowContainer childCommentsVisibilityContainer = null!;
|
||||||
private FillFlowContainer childCommentsContainer = null!;
|
private FillFlowContainer childCommentsContainer = null!;
|
||||||
private LoadRepliesButton loadRepliesButton = null!;
|
private LoadRepliesButton loadRepliesButton = null!;
|
||||||
@ -70,7 +75,7 @@ namespace osu.Game.Overlays.Comments
|
|||||||
private GridContainer content = null!;
|
private GridContainer content = null!;
|
||||||
private VotePill votePill = null!;
|
private VotePill votePill = null!;
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved]
|
||||||
private IDialogOverlay? dialogOverlay { get; set; }
|
private IDialogOverlay? dialogOverlay { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -79,7 +84,7 @@ namespace osu.Game.Overlays.Comments
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private GameHost host { get; set; } = null!;
|
private GameHost host { get; set; } = null!;
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved]
|
||||||
private OnScreenDisplay? onScreenDisplay { get; set; }
|
private OnScreenDisplay? onScreenDisplay { get; set; }
|
||||||
|
|
||||||
public DrawableComment(Comment comment)
|
public DrawableComment(Comment comment)
|
||||||
@ -88,12 +93,16 @@ namespace osu.Game.Overlays.Comments
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OverlayColourProvider colourProvider)
|
private void load(OverlayColourProvider colourProvider, DrawableComment? parentComment)
|
||||||
{
|
{
|
||||||
LinkFlowContainer username;
|
LinkFlowContainer username;
|
||||||
FillFlowContainer info;
|
FillFlowContainer info;
|
||||||
CommentMarkdownContainer message;
|
CommentMarkdownContainer message;
|
||||||
|
|
||||||
|
Level = parentComment?.Level + 1 ?? 0;
|
||||||
|
|
||||||
|
float childrenPadding = Level < 6 ? 20 : 5;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
@ -248,7 +257,7 @@ namespace osu.Game.Overlays.Comments
|
|||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Padding = new MarginPadding { Left = 20 },
|
Padding = new MarginPadding { Left = childrenPadding },
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
childCommentsContainer = new FillFlowContainer
|
childCommentsContainer = new FillFlowContainer
|
||||||
|
110
osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs
Normal file
110
osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// 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.LocalisationExtensions;
|
||||||
|
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.Resources.Localisation.Web;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public partial class ExtendedDetails : CompositeDrawable
|
||||||
|
{
|
||||||
|
public Bindable<UserProfileData?> User { get; } = new Bindable<UserProfileData?>();
|
||||||
|
|
||||||
|
private SpriteText rankedScore = null!;
|
||||||
|
private SpriteText hitAccuracy = null!;
|
||||||
|
private SpriteText playCount = null!;
|
||||||
|
private SpriteText totalScore = null!;
|
||||||
|
private SpriteText totalHits = null!;
|
||||||
|
private SpriteText maximumCombo = null!;
|
||||||
|
private SpriteText replaysWatched = null!;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
var font = OsuFont.Default.With(size: 12);
|
||||||
|
const float vertical_spacing = 4;
|
||||||
|
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
// this should really be a grid, but trying to avoid one to avoid the performance hit.
|
||||||
|
InternalChild = new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(20, 0),
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Name = @"Labels",
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(0, vertical_spacing),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsRankedScore },
|
||||||
|
new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsHitAccuracy },
|
||||||
|
new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsPlayCount },
|
||||||
|
new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsTotalScore },
|
||||||
|
new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsTotalHits },
|
||||||
|
new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsMaximumCombo },
|
||||||
|
new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsReplaysWatchedByOthers },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Name = @"Values",
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(0, vertical_spacing),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
rankedScore = new OsuSpriteText { Font = font },
|
||||||
|
hitAccuracy = new OsuSpriteText { Font = font },
|
||||||
|
playCount = new OsuSpriteText { Font = font },
|
||||||
|
totalScore = new OsuSpriteText { Font = font },
|
||||||
|
totalHits = new OsuSpriteText { Font = font },
|
||||||
|
maximumCombo = new OsuSpriteText { Font = font },
|
||||||
|
replaysWatched = new OsuSpriteText { Font = font },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
User.BindValueChanged(user => updateStatistics(user.NewValue?.User.Statistics), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateStatistics(UserStatistics? statistics)
|
||||||
|
{
|
||||||
|
if (statistics == null)
|
||||||
|
{
|
||||||
|
Alpha = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Alpha = 1;
|
||||||
|
|
||||||
|
rankedScore.Text = statistics.RankedScore.ToLocalisableString(@"N0");
|
||||||
|
hitAccuracy.Text = statistics.DisplayAccuracy;
|
||||||
|
playCount.Text = statistics.PlayCount.ToLocalisableString(@"N0");
|
||||||
|
totalScore.Text = statistics.TotalScore.ToLocalisableString(@"N0");
|
||||||
|
totalHits.Text = statistics.TotalHits.ToLocalisableString(@"N0");
|
||||||
|
maximumCombo.Text = statistics.MaxCombo.ToLocalisableString(@"N0");
|
||||||
|
replaysWatched.Text = statistics.ReplaysWatched.ToLocalisableString(@"N0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
186
osu.Game/Overlays/Profile/Header/Components/MainDetails.cs
Normal file
186
osu.Game/Overlays/Profile/Header/Components/MainDetails.cs
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
// 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.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Online.Leaderboards;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public partial class MainDetails : CompositeDrawable
|
||||||
|
{
|
||||||
|
private readonly Dictionary<ScoreRank, ScoreRankInfo> scoreRankInfos = new Dictionary<ScoreRank, ScoreRankInfo>();
|
||||||
|
private ProfileValueDisplay medalInfo = null!;
|
||||||
|
private ProfileValueDisplay ppInfo = null!;
|
||||||
|
private ProfileValueDisplay detailGlobalRank = null!;
|
||||||
|
private ProfileValueDisplay detailCountryRank = null!;
|
||||||
|
private RankGraph rankGraph = null!;
|
||||||
|
|
||||||
|
public readonly Bindable<UserProfileData?> User = new Bindable<UserProfileData?>();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
|
InternalChild = new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
AutoSizeDuration = 200,
|
||||||
|
AutoSizeEasing = Easing.OutQuint,
|
||||||
|
Masking = true,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(0, 15),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(20),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
detailGlobalRank = new ProfileValueDisplay(true)
|
||||||
|
{
|
||||||
|
Title = UsersStrings.ShowRankGlobalSimple,
|
||||||
|
},
|
||||||
|
detailCountryRank = new ProfileValueDisplay(true)
|
||||||
|
{
|
||||||
|
Title = UsersStrings.ShowRankCountrySimple,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 60,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
rankGraph = new RankGraph
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(10, 0),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
medalInfo = new ProfileValueDisplay
|
||||||
|
{
|
||||||
|
Title = UsersStrings.ShowStatsMedals,
|
||||||
|
},
|
||||||
|
ppInfo = new ProfileValueDisplay
|
||||||
|
{
|
||||||
|
Title = "pp",
|
||||||
|
},
|
||||||
|
new TotalPlayTime
|
||||||
|
{
|
||||||
|
User = { BindTarget = User }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(5),
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
scoreRankInfos[ScoreRank.XH] = new ScoreRankInfo(ScoreRank.XH),
|
||||||
|
scoreRankInfos[ScoreRank.X] = new ScoreRankInfo(ScoreRank.X),
|
||||||
|
scoreRankInfos[ScoreRank.SH] = new ScoreRankInfo(ScoreRank.SH),
|
||||||
|
scoreRankInfos[ScoreRank.S] = new ScoreRankInfo(ScoreRank.S),
|
||||||
|
scoreRankInfos[ScoreRank.A] = new ScoreRankInfo(ScoreRank.A),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
User.BindValueChanged(e => updateDisplay(e.NewValue), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDisplay(UserProfileData? data)
|
||||||
|
{
|
||||||
|
var user = data?.User;
|
||||||
|
|
||||||
|
medalInfo.Content = user?.Achievements?.Length.ToString() ?? "0";
|
||||||
|
ppInfo.Content = user?.Statistics?.PP?.ToLocalisableString("#,##0") ?? (LocalisableString)"0";
|
||||||
|
|
||||||
|
foreach (var scoreRankInfo in scoreRankInfos)
|
||||||
|
scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0;
|
||||||
|
|
||||||
|
detailGlobalRank.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-";
|
||||||
|
detailCountryRank.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-";
|
||||||
|
|
||||||
|
rankGraph.Statistics.Value = user?.Statistics;
|
||||||
|
}
|
||||||
|
|
||||||
|
private partial class ScoreRankInfo : CompositeDrawable
|
||||||
|
{
|
||||||
|
private readonly OsuSpriteText rankCount;
|
||||||
|
|
||||||
|
public int RankCount
|
||||||
|
{
|
||||||
|
set => rankCount.Text = value.ToLocalisableString("#,##0");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScoreRankInfo(ScoreRank rank)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
InternalChild = new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Width = 44,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new DrawableRank(rank)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 22,
|
||||||
|
},
|
||||||
|
rankCount = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,33 +1,17 @@
|
|||||||
// 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.Collections.Generic;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.LocalisationExtensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Localisation;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using osu.Game.Online.Leaderboards;
|
|
||||||
using osu.Game.Overlays.Profile.Header.Components;
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
|
||||||
using osu.Game.Scoring;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Profile.Header
|
namespace osu.Game.Overlays.Profile.Header
|
||||||
{
|
{
|
||||||
public partial class DetailHeaderContainer : CompositeDrawable
|
public partial class DetailHeaderContainer : CompositeDrawable
|
||||||
{
|
{
|
||||||
private readonly Dictionary<ScoreRank, ScoreRankInfo> scoreRankInfos = new Dictionary<ScoreRank, ScoreRankInfo>();
|
|
||||||
private ProfileValueDisplay medalInfo = null!;
|
|
||||||
private ProfileValueDisplay ppInfo = null!;
|
|
||||||
private ProfileValueDisplay detailGlobalRank = null!;
|
|
||||||
private ProfileValueDisplay detailCountryRank = null!;
|
|
||||||
private RankGraph rankGraph = null!;
|
|
||||||
|
|
||||||
public readonly Bindable<UserProfileData?> User = new Bindable<UserProfileData?>();
|
public readonly Bindable<UserProfileData?> User = new Bindable<UserProfileData?>();
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -35,8 +19,6 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
User.ValueChanged += e => updateDisplay(e.NewValue);
|
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
@ -44,149 +26,52 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = colourProvider.Background5,
|
Colour = colourProvider.Background5,
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
AutoSizeDuration = 200,
|
|
||||||
AutoSizeEasing = Easing.OutQuint,
|
|
||||||
Masking = true,
|
|
||||||
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 },
|
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 },
|
||||||
Direction = FillDirection.Vertical,
|
Child = new GridContainer
|
||||||
Spacing = new Vector2(0, 15),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
RowDimensions = new[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Spacing = new Vector2(20),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
detailGlobalRank = new ProfileValueDisplay(true)
|
|
||||||
{
|
|
||||||
Title = UsersStrings.ShowRankGlobalSimple,
|
|
||||||
},
|
|
||||||
detailCountryRank = new ProfileValueDisplay(true)
|
|
||||||
{
|
|
||||||
Title = UsersStrings.ShowRankCountrySimple,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
new Container
|
ColumnDimensions = new[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
new Dimension(),
|
||||||
Height = 60,
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
Children = new Drawable[]
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
{
|
|
||||||
rankGraph = new RankGraph
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
new Container
|
Content = new[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
new Drawable[]
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
new MainDetails
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
User = { BindTarget = User }
|
||||||
|
},
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = 2,
|
||||||
|
Colour = colourProvider.Background6,
|
||||||
|
Margin = new MarginPadding { Horizontal = 15 }
|
||||||
|
},
|
||||||
|
new ExtendedDetails
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Direction = FillDirection.Horizontal,
|
User = { BindTarget = User }
|
||||||
Spacing = new Vector2(10, 0),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
medalInfo = new ProfileValueDisplay
|
|
||||||
{
|
|
||||||
Title = UsersStrings.ShowStatsMedals,
|
|
||||||
},
|
|
||||||
ppInfo = new ProfileValueDisplay
|
|
||||||
{
|
|
||||||
Title = "pp",
|
|
||||||
},
|
|
||||||
new TotalPlayTime
|
|
||||||
{
|
|
||||||
User = { BindTarget = User }
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.CentreRight,
|
|
||||||
Origin = Anchor.CentreRight,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Spacing = new Vector2(5),
|
|
||||||
Children = new[]
|
|
||||||
{
|
|
||||||
scoreRankInfos[ScoreRank.XH] = new ScoreRankInfo(ScoreRank.XH),
|
|
||||||
scoreRankInfos[ScoreRank.X] = new ScoreRankInfo(ScoreRank.X),
|
|
||||||
scoreRankInfos[ScoreRank.SH] = new ScoreRankInfo(ScoreRank.SH),
|
|
||||||
scoreRankInfos[ScoreRank.S] = new ScoreRankInfo(ScoreRank.S),
|
|
||||||
scoreRankInfos[ScoreRank.A] = new ScoreRankInfo(ScoreRank.A),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateDisplay(UserProfileData? data)
|
|
||||||
{
|
|
||||||
var user = data?.User;
|
|
||||||
|
|
||||||
medalInfo.Content = user?.Achievements?.Length.ToString() ?? "0";
|
|
||||||
ppInfo.Content = user?.Statistics?.PP?.ToLocalisableString("#,##0") ?? (LocalisableString)"0";
|
|
||||||
|
|
||||||
foreach (var scoreRankInfo in scoreRankInfos)
|
|
||||||
scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0;
|
|
||||||
|
|
||||||
detailGlobalRank.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-";
|
|
||||||
detailCountryRank.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-";
|
|
||||||
|
|
||||||
rankGraph.Statistics.Value = user?.Statistics;
|
|
||||||
}
|
|
||||||
|
|
||||||
private partial class ScoreRankInfo : CompositeDrawable
|
|
||||||
{
|
|
||||||
private readonly OsuSpriteText rankCount;
|
|
||||||
|
|
||||||
public int RankCount
|
|
||||||
{
|
|
||||||
set => rankCount.Text = value.ToLocalisableString("#,##0");
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScoreRankInfo(ScoreRank rank)
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both;
|
|
||||||
InternalChild = new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Width = 44,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new DrawableRank(rank)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 22,
|
|
||||||
},
|
|
||||||
rankCount = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,18 +5,15 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Extensions.LocalisationExtensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Localisation;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Overlays.Profile.Header.Components;
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
|
||||||
using osu.Game.Users.Drawables;
|
using osu.Game.Users.Drawables;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -38,7 +35,6 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
private OsuSpriteText titleText = null!;
|
private OsuSpriteText titleText = null!;
|
||||||
private UpdateableFlag userFlag = null!;
|
private UpdateableFlag userFlag = null!;
|
||||||
private OsuSpriteText userCountryText = null!;
|
private OsuSpriteText userCountryText = null!;
|
||||||
private FillFlowContainer userStats = null!;
|
|
||||||
private GroupBadgeFlow groupBadgeFlow = null!;
|
private GroupBadgeFlow groupBadgeFlow = null!;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -164,16 +160,6 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
userStats = new FillFlowContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopRight,
|
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Width = 300,
|
|
||||||
Margin = new MarginPadding { Right = UserProfileOverlay.CONTENT_X_MARGIN },
|
|
||||||
Padding = new MarginPadding { Vertical = 15 },
|
|
||||||
Spacing = new Vector2(0, 2)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
User.BindValueChanged(user => updateUser(user.NewValue));
|
User.BindValueChanged(user => updateUser(user.NewValue));
|
||||||
@ -192,43 +178,6 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
titleText.Text = user?.Title ?? string.Empty;
|
titleText.Text = user?.Title ?? string.Empty;
|
||||||
titleText.Colour = Color4Extensions.FromHex(user?.Colour ?? "fff");
|
titleText.Colour = Color4Extensions.FromHex(user?.Colour ?? "fff");
|
||||||
groupBadgeFlow.User.Value = user;
|
groupBadgeFlow.User.Value = user;
|
||||||
|
|
||||||
userStats.Clear();
|
|
||||||
|
|
||||||
if (user?.Statistics != null)
|
|
||||||
{
|
|
||||||
userStats.Add(new UserStatsLine(UsersStrings.ShowStatsRankedScore, user.Statistics.RankedScore.ToLocalisableString("#,##0")));
|
|
||||||
userStats.Add(new UserStatsLine(UsersStrings.ShowStatsHitAccuracy, user.Statistics.DisplayAccuracy));
|
|
||||||
userStats.Add(new UserStatsLine(UsersStrings.ShowStatsPlayCount, user.Statistics.PlayCount.ToLocalisableString("#,##0")));
|
|
||||||
userStats.Add(new UserStatsLine(UsersStrings.ShowStatsTotalScore, user.Statistics.TotalScore.ToLocalisableString("#,##0")));
|
|
||||||
userStats.Add(new UserStatsLine(UsersStrings.ShowStatsTotalHits, user.Statistics.TotalHits.ToLocalisableString("#,##0")));
|
|
||||||
userStats.Add(new UserStatsLine(UsersStrings.ShowStatsMaximumCombo, user.Statistics.MaxCombo.ToLocalisableString("#,##0")));
|
|
||||||
userStats.Add(new UserStatsLine(UsersStrings.ShowStatsReplaysWatchedByOthers, user.Statistics.ReplaysWatched.ToLocalisableString("#,##0")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private partial class UserStatsLine : Container
|
|
||||||
{
|
|
||||||
public UserStatsLine(LocalisableString left, LocalisableString right)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X;
|
|
||||||
AutoSizeAxes = Axes.Y;
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new OsuSpriteText
|
|
||||||
{
|
|
||||||
Font = OsuFont.GetFont(size: 15),
|
|
||||||
Text = left,
|
|
||||||
},
|
|
||||||
new OsuSpriteText
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopRight,
|
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold),
|
|
||||||
Text = right,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,14 +15,12 @@ namespace osu.Game.Screens.Play.HUD.ClicksPerSecond
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IGameplayClock gameplayClock { get; set; } = null!;
|
private IGameplayClock gameplayClock { get; set; } = null!;
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved]
|
||||||
private DrawableRuleset? drawableRuleset { get; set; }
|
private IFrameStableClock? frameStableClock { get; set; }
|
||||||
|
|
||||||
public int Value { get; private set; }
|
public int Value { get; private set; }
|
||||||
|
|
||||||
// Even though `FrameStabilityContainer` caches as a `GameplayClock`, we need to check it directly via `drawableRuleset`
|
private IGameplayClock clock => frameStableClock ?? gameplayClock;
|
||||||
// as this calculator is not contained within the `FrameStabilityContainer` and won't see the dependency.
|
|
||||||
private IGameplayClock clock => drawableRuleset?.FrameStableClock ?? gameplayClock;
|
|
||||||
|
|
||||||
public ClicksPerSecondCalculator()
|
public ClicksPerSecondCalculator()
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
// 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.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play.HUD.JudgementCounter
|
||||||
|
{
|
||||||
|
public partial class JudgementCounter : VisibilityContainer
|
||||||
|
{
|
||||||
|
public BindableBool ShowName = new BindableBool();
|
||||||
|
public Bindable<FillDirection> Direction = new Bindable<FillDirection>();
|
||||||
|
|
||||||
|
public readonly JudgementTally.JudgementCount Result;
|
||||||
|
|
||||||
|
public JudgementCounter(JudgementTally.JudgementCount result) => Result = result;
|
||||||
|
|
||||||
|
public OsuSpriteText ResultName = null!;
|
||||||
|
private FillFlowContainer flowContainer = null!;
|
||||||
|
private JudgementRollingCounter counter = null!;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours, IBindable<RulesetInfo> ruleset)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
InternalChild = flowContainer = new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
counter = new JudgementRollingCounter
|
||||||
|
{
|
||||||
|
Current = Result.ResultCount
|
||||||
|
},
|
||||||
|
ResultName = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Alpha = 0,
|
||||||
|
Font = OsuFont.Numeric.With(size: 8),
|
||||||
|
Text = ruleset.Value.CreateInstance().GetDisplayNameForHitResult(Result.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = Result.Type;
|
||||||
|
|
||||||
|
Colour = result.IsBasic() ? colours.ForHitResult(Result.Type) : !result.IsBonus() ? colours.PurpleLight : colours.PurpleLighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
ShowName.BindValueChanged(value =>
|
||||||
|
ResultName.FadeTo(value.NewValue ? 1 : 0, JudgementCounterDisplay.TRANSFORM_DURATION, Easing.OutQuint), true);
|
||||||
|
|
||||||
|
Direction.BindValueChanged(direction =>
|
||||||
|
{
|
||||||
|
flowContainer.Direction = direction.NewValue;
|
||||||
|
changeAnchor(direction.NewValue == FillDirection.Vertical ? Anchor.TopLeft : Anchor.BottomLeft);
|
||||||
|
|
||||||
|
void changeAnchor(Anchor anchor) => counter.Anchor = ResultName.Anchor = counter.Origin = ResultName.Origin = anchor;
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
base.LoadComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopIn() => this.FadeIn(JudgementCounterDisplay.TRANSFORM_DURATION, Easing.OutQuint);
|
||||||
|
protected override void PopOut() => this.FadeOut(100);
|
||||||
|
|
||||||
|
private sealed partial class JudgementRollingCounter : RollingCounter<int>
|
||||||
|
{
|
||||||
|
protected override OsuSpriteText CreateSpriteText()
|
||||||
|
=> base.CreateSpriteText().With(s => s.Font = s.Font.With(fixedWidth: true, size: 16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,139 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play.HUD.JudgementCounter
|
||||||
|
{
|
||||||
|
public partial class JudgementCounterDisplay : CompositeDrawable, ISkinnableDrawable
|
||||||
|
{
|
||||||
|
public const int TRANSFORM_DURATION = 250;
|
||||||
|
|
||||||
|
public bool UsesFixedAnchor { get; set; }
|
||||||
|
|
||||||
|
[SettingSource("Display mode")]
|
||||||
|
public Bindable<DisplayMode> Mode { get; set; } = new Bindable<DisplayMode>();
|
||||||
|
|
||||||
|
[SettingSource("Counter direction")]
|
||||||
|
public Bindable<Direction> FlowDirection { get; set; } = new Bindable<Direction>();
|
||||||
|
|
||||||
|
[SettingSource("Show judgement names")]
|
||||||
|
public BindableBool ShowJudgementNames { get; set; } = new BindableBool(true);
|
||||||
|
|
||||||
|
[SettingSource("Show max judgement")]
|
||||||
|
public BindableBool ShowMaxJudgement { get; set; } = new BindableBool(true);
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private JudgementTally tally { get; set; } = null!;
|
||||||
|
|
||||||
|
protected FillFlowContainer<JudgementCounter> CounterFlow = null!;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
InternalChild = CounterFlow = new FillFlowContainer<JudgementCounter>
|
||||||
|
{
|
||||||
|
Direction = getFillDirection(FlowDirection.Value),
|
||||||
|
Spacing = new Vector2(10),
|
||||||
|
AutoSizeAxes = Axes.Both
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var result in tally.Results)
|
||||||
|
CounterFlow.Add(createCounter(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
FlowDirection.BindValueChanged(direction =>
|
||||||
|
{
|
||||||
|
var convertedDirection = getFillDirection(direction.NewValue);
|
||||||
|
|
||||||
|
CounterFlow.Direction = convertedDirection;
|
||||||
|
|
||||||
|
foreach (var counter in CounterFlow.Children)
|
||||||
|
counter.Direction.Value = convertedDirection;
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
Mode.BindValueChanged(_ => updateMode(), true);
|
||||||
|
|
||||||
|
ShowMaxJudgement.BindValueChanged(value =>
|
||||||
|
{
|
||||||
|
var firstChild = CounterFlow.Children.FirstOrDefault();
|
||||||
|
firstChild.FadeTo(value.NewValue ? 1 : 0, TRANSFORM_DURATION, Easing.OutQuint);
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMode()
|
||||||
|
{
|
||||||
|
foreach (var counter in CounterFlow.Children)
|
||||||
|
{
|
||||||
|
if (shouldShow(counter))
|
||||||
|
counter.Show();
|
||||||
|
else
|
||||||
|
counter.Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shouldShow(JudgementCounter counter)
|
||||||
|
{
|
||||||
|
if (counter.Result.Type.IsBasic())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
switch (Mode.Value)
|
||||||
|
{
|
||||||
|
case DisplayMode.Simple:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case DisplayMode.Normal:
|
||||||
|
return !counter.Result.Type.IsBonus();
|
||||||
|
|
||||||
|
case DisplayMode.All:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private FillDirection getFillDirection(Direction flow)
|
||||||
|
{
|
||||||
|
switch (flow)
|
||||||
|
{
|
||||||
|
case Direction.Horizontal:
|
||||||
|
return FillDirection.Horizontal;
|
||||||
|
|
||||||
|
case Direction.Vertical:
|
||||||
|
return FillDirection.Vertical;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(flow), flow, @"Unsupported direction");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JudgementCounter createCounter(JudgementTally.JudgementCount info) =>
|
||||||
|
new JudgementCounter(info)
|
||||||
|
{
|
||||||
|
State = { Value = Visibility.Hidden },
|
||||||
|
ShowName = { BindTarget = ShowJudgementNames }
|
||||||
|
};
|
||||||
|
|
||||||
|
public enum DisplayMode
|
||||||
|
{
|
||||||
|
Simple,
|
||||||
|
Normal,
|
||||||
|
All
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs
Normal file
60
osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// 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 System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play.HUD.JudgementCounter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Keeps track of judgements for a current play session, exposing bindable counts which can
|
||||||
|
/// be used for display purposes.
|
||||||
|
/// </summary>
|
||||||
|
public partial class JudgementTally : CompositeDrawable
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private ScoreProcessor scoreProcessor { get; set; } = null!;
|
||||||
|
|
||||||
|
public List<JudgementCount> Results = new List<JudgementCount>();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(IBindable<RulesetInfo> ruleset)
|
||||||
|
{
|
||||||
|
foreach (var result in ruleset.Value.CreateInstance().GetHitResults())
|
||||||
|
{
|
||||||
|
Results.Add(new JudgementCount
|
||||||
|
{
|
||||||
|
Type = result.result,
|
||||||
|
ResultCount = new BindableInt()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
scoreProcessor.NewJudgement += judgement => updateCount(judgement, false);
|
||||||
|
scoreProcessor.JudgementReverted += judgement => updateCount(judgement, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateCount(JudgementResult judgement, bool revert)
|
||||||
|
{
|
||||||
|
foreach (JudgementCount result in Results.Where(result => result.Type == judgement.Type))
|
||||||
|
result.ResultCount.Value = revert ? result.ResultCount.Value - 1 : result.ResultCount.Value + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct JudgementCount
|
||||||
|
{
|
||||||
|
public HitResult Type { get; set; }
|
||||||
|
|
||||||
|
public BindableInt ResultCount { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,10 +25,15 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
protected IGameplayClock GameplayClock { get; private set; } = null!;
|
protected IGameplayClock GameplayClock { get; private set; } = null!;
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved]
|
||||||
private DrawableRuleset? drawableRuleset { get; set; }
|
private IFrameStableClock? frameStableClock { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The reference clock is used to accurately tell the current playfield's time (including catch-up lag).
|
||||||
|
/// However, if none is available (i.e. used in tests), we fall back to the gameplay clock.
|
||||||
|
/// </summary>
|
||||||
|
protected IClock FrameStableClock => frameStableClock ?? GameplayClock;
|
||||||
|
|
||||||
private IClock? referenceClock;
|
|
||||||
private IEnumerable<HitObject>? objects;
|
private IEnumerable<HitObject>? objects;
|
||||||
|
|
||||||
public IEnumerable<HitObject> Objects
|
public IEnumerable<HitObject> Objects
|
||||||
@ -58,12 +63,11 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
protected virtual void UpdateObjects(IEnumerable<HitObject> objects) { }
|
protected virtual void UpdateObjects(IEnumerable<HitObject> objects) { }
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load(DrawableRuleset? drawableRuleset)
|
||||||
{
|
{
|
||||||
if (drawableRuleset != null)
|
if (drawableRuleset != null)
|
||||||
{
|
{
|
||||||
Objects = drawableRuleset.Objects;
|
Objects = drawableRuleset.Objects;
|
||||||
referenceClock = drawableRuleset.FrameStableClock;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,9 +78,7 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
if (objects == null)
|
if (objects == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// The reference clock is used to accurately tell the playfield's time. This is obtained from the drawable ruleset.
|
double currentTime = FrameStableClock.CurrentTime;
|
||||||
// However, if no drawable ruleset is available (i.e. used in tests), we fall back to the gameplay clock.
|
|
||||||
double currentTime = referenceClock?.CurrentTime ?? GameplayClock.CurrentTime;
|
|
||||||
|
|
||||||
bool isInIntro = currentTime < FirstHitTime;
|
bool isInIntro = currentTime < FirstHitTime;
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ using osu.Game.Rulesets.Scoring;
|
|||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osu.Game.Screens.Play.HUD.ClicksPerSecond;
|
using osu.Game.Screens.Play.HUD.ClicksPerSecond;
|
||||||
|
using osu.Game.Screens.Play.HUD.JudgementCounter;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
@ -59,6 +60,9 @@ namespace osu.Game.Screens.Play
|
|||||||
[Cached]
|
[Cached]
|
||||||
private readonly ClicksPerSecondCalculator clicksPerSecondCalculator;
|
private readonly ClicksPerSecondCalculator clicksPerSecondCalculator;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private readonly JudgementTally tally;
|
||||||
|
|
||||||
public Bindable<bool> ShowHealthBar = new Bindable<bool>(true);
|
public Bindable<bool> ShowHealthBar = new Bindable<bool>(true);
|
||||||
|
|
||||||
private readonly DrawableRuleset drawableRuleset;
|
private readonly DrawableRuleset drawableRuleset;
|
||||||
@ -104,6 +108,8 @@ namespace osu.Game.Screens.Play
|
|||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
CreateFailingLayer(),
|
CreateFailingLayer(),
|
||||||
|
//Needs to be initialized before skinnable drawables.
|
||||||
|
tally = new JudgementTally(),
|
||||||
mainComponents = new MainComponentsContainer
|
mainComponents = new MainComponentsContainer
|
||||||
{
|
{
|
||||||
AlwaysPresent = true,
|
AlwaysPresent = true,
|
||||||
|
@ -309,6 +309,8 @@ namespace osu.Game.Screens.Play
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies.CacheAs(DrawableRuleset.FrameStableClock);
|
||||||
|
|
||||||
// add the overlay components as a separate step as they proxy some elements from the above underlay/gameplay components.
|
// add the overlay components as a separate step as they proxy some elements from the above underlay/gameplay components.
|
||||||
// also give the overlays the ruleset skin provider to allow rulesets to potentially override HUD elements (used to disable combo counters etc.)
|
// also give the overlays the ruleset skin provider to allow rulesets to potentially override HUD elements (used to disable combo counters etc.)
|
||||||
// we may want to limit this in the future to disallow rulesets from outright replacing elements the user expects to be there.
|
// we may want to limit this in the future to disallow rulesets from outright replacing elements the user expects to be there.
|
||||||
|
@ -596,6 +596,9 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
public void FlushPendingFilterOperations()
|
public void FlushPendingFilterOperations()
|
||||||
{
|
{
|
||||||
|
if (!IsLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
if (PendingFilter?.Completed == false)
|
if (PendingFilter?.Completed == false)
|
||||||
{
|
{
|
||||||
applyActiveCriteria(false);
|
applyActiveCriteria(false);
|
||||||
|
@ -863,6 +863,7 @@ namespace osu.Game.Screens.Select
|
|||||||
// if we have a pending filter operation, we want to run it now.
|
// if we have a pending filter operation, we want to run it now.
|
||||||
// it could change selection (ie. if the ruleset has been changed).
|
// it could change selection (ie. if the ruleset has been changed).
|
||||||
Carousel.FlushPendingFilterOperations();
|
Carousel.FlushPendingFilterOperations();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user