mirror of
https://github.com/ppy/osu.git
synced 2024-11-06 06:57:39 +08:00
Merge remote-tracking branch 'origin/master' into rearrangeable-playlist
This commit is contained in:
commit
e4e0a26b62
@ -135,7 +135,7 @@ csharp_preferred_modifier_order = public,private,protected,internal,new,abstract
|
||||
csharp_style_expression_bodied_accessors = true:warning
|
||||
csharp_style_expression_bodied_constructors = false:none
|
||||
csharp_style_expression_bodied_indexers = true:warning
|
||||
csharp_style_expression_bodied_methods = true:silent
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_operators = true:warning
|
||||
csharp_style_expression_bodied_properties = true:warning
|
||||
csharp_style_expression_bodied_local_functions = true:silent
|
||||
|
@ -54,6 +54,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1230.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.125.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.131.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -20,7 +20,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
internal readonly CatcherArea CatcherArea;
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) || CatcherArea.ReceivePositionalInputAt(screenSpacePos);
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) =>
|
||||
// only check the X position; handle all vertical space.
|
||||
base.ReceivePositionalInputAt(new Vector2(screenSpacePos.X, ScreenSpaceDrawQuad.Centre.Y));
|
||||
|
||||
public CatchPlayfield(BeatmapDifficulty difficulty, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation)
|
||||
{
|
||||
|
@ -7,12 +7,10 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
@ -21,7 +19,7 @@ using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class TestSceneLegacyBeatmapSkin : OsuTestScene
|
||||
public class TestSceneLegacyBeatmapSkin : ScreenTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private AudioManager audio { get; set; }
|
||||
@ -65,7 +63,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
ExposedPlayer player;
|
||||
|
||||
Beatmap.Value = new CustomSkinWorkingBeatmap(audio, beatmapHasColours);
|
||||
Child = new OsuScreenStack(player = new ExposedPlayer(userHasCustomColours)) { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
LoadScreen(player = new ExposedPlayer(userHasCustomColours));
|
||||
|
||||
return player;
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
private const double time_during_slide_2 = 3000;
|
||||
private const double time_during_slide_3 = 3500;
|
||||
private const double time_during_slide_4 = 3800;
|
||||
private const double time_slider_end = 4000;
|
||||
|
||||
private List<JudgementResult> judgementResults;
|
||||
private bool allJudgedFired;
|
||||
@ -284,6 +285,48 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
AddAssert("Tracking acquired", assertMidSliderJudgements);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scenario:
|
||||
/// - Press a key on the slider head
|
||||
/// - While holding the key, move cursor close to the edge of tracking area
|
||||
/// - Keep the cursor on the edge of tracking area until the slider ends
|
||||
/// Expected Result:
|
||||
/// A passing test case will have the slider track the cursor throughout the whole test.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestTrackingAreaEdge()
|
||||
{
|
||||
performTest(new List<ReplayFrame>
|
||||
{
|
||||
new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_slider_start },
|
||||
new OsuReplayFrame { Position = new Vector2(0, OsuHitObject.OBJECT_RADIUS * 1.19f), Actions = { OsuAction.LeftButton }, Time = time_slider_start + 250 },
|
||||
new OsuReplayFrame { Position = new Vector2(slider_path_length, OsuHitObject.OBJECT_RADIUS * 1.199f), Actions = { OsuAction.LeftButton }, Time = time_slider_end },
|
||||
});
|
||||
|
||||
AddAssert("Tracking kept", assertGreatJudge);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scenario:
|
||||
/// - Press a key on the slider head
|
||||
/// - While holding the key, move cursor just outside the tracking area
|
||||
/// - Keep the cursor just outside the tracking area until the slider ends
|
||||
/// Expected Result:
|
||||
/// A passing test case will have the slider drop the tracking on frame 2.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestTrackingAreaOutsideEdge()
|
||||
{
|
||||
performTest(new List<ReplayFrame>
|
||||
{
|
||||
new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_slider_start },
|
||||
new OsuReplayFrame { Position = new Vector2(0, OsuHitObject.OBJECT_RADIUS * 1.21f), Actions = { OsuAction.LeftButton }, Time = time_slider_start + 250 },
|
||||
new OsuReplayFrame { Position = new Vector2(slider_path_length, OsuHitObject.OBJECT_RADIUS * 1.201f), Actions = { OsuAction.LeftButton }, Time = time_slider_end },
|
||||
});
|
||||
|
||||
AddAssert("Tracking dropped", assertMidSliderJudgementFail);
|
||||
}
|
||||
|
||||
private bool assertGreatJudge() => judgementResults.Last().Type == HitResult.Great;
|
||||
|
||||
private bool assertHeadMissTailTracked() => judgementResults[^2].Type == HitResult.Great && judgementResults.First().Type == HitResult.Miss;
|
||||
@ -294,6 +337,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
|
||||
private ScoreAccessibleReplayPlayer currentPlayer;
|
||||
|
||||
private const float slider_path_length = 25;
|
||||
|
||||
private void performTest(List<ReplayFrame> frames)
|
||||
{
|
||||
AddStep("load player", () =>
|
||||
@ -309,8 +354,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
Path = new SliderPath(PathType.PerfectCurve, new[]
|
||||
{
|
||||
Vector2.Zero,
|
||||
new Vector2(25, 0),
|
||||
}, 25),
|
||||
new Vector2(slider_path_length, 0),
|
||||
}, slider_path_length),
|
||||
}
|
||||
},
|
||||
BeatmapInfo =
|
||||
|
@ -4,7 +4,7 @@
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.16.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
/// <summary>
|
||||
/// The start time of <see cref="Start"/>.
|
||||
/// </summary>
|
||||
public readonly Bindable<double> StartTime = new Bindable<double>();
|
||||
public readonly Bindable<double> StartTime = new BindableDouble();
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="DrawableOsuHitObject"/> which <see cref="FollowPoint"/>s will exit from.
|
||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
|
||||
private readonly IBindable<int> stackHeightBindable = new Bindable<int>();
|
||||
private readonly IBindable<float> scaleBindable = new Bindable<float>();
|
||||
private readonly IBindable<float> scaleBindable = new BindableFloat();
|
||||
|
||||
public OsuAction? HitAction => HitArea.HitAction;
|
||||
|
||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
InternalChild = scaleContainer = new ReverseArrowPiece();
|
||||
}
|
||||
|
||||
private readonly IBindable<float> scaleBindable = new Bindable<float>();
|
||||
private readonly IBindable<float> scaleBindable = new BindableFloat();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
|
||||
private readonly IBindable<int> stackHeightBindable = new Bindable<int>();
|
||||
private readonly IBindable<float> scaleBindable = new Bindable<float>();
|
||||
private readonly IBindable<float> scaleBindable = new BindableFloat();
|
||||
|
||||
public DrawableSlider(Slider s)
|
||||
: base(s)
|
||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
};
|
||||
}
|
||||
|
||||
private readonly IBindable<float> scaleBindable = new Bindable<float>();
|
||||
private readonly IBindable<float> scaleBindable = new BindableFloat();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
public Func<OsuAction?> GetInitialHitAction;
|
||||
|
||||
private readonly Slider slider;
|
||||
public readonly Drawable FollowCircle;
|
||||
private readonly Drawable followCircle;
|
||||
private readonly DrawableSlider drawableSlider;
|
||||
|
||||
public SliderBall(Slider slider, DrawableSlider drawableSlider = null)
|
||||
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
|
||||
Children = new[]
|
||||
{
|
||||
FollowCircle = new FollowCircleContainer
|
||||
followCircle = new FollowCircleContainer
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
@ -95,8 +95,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
|
||||
tracking = value;
|
||||
|
||||
FollowCircle.ScaleTo(tracking ? 2f : 1, 300, Easing.OutQuint);
|
||||
FollowCircle.FadeTo(tracking ? 1f : 0, 300, Easing.OutQuint);
|
||||
followCircle.ScaleTo(tracking ? 2.4f : 1f, 300, Easing.OutQuint);
|
||||
followCircle.FadeTo(tracking ? 1f : 0, 300, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,7 +149,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
// in valid time range
|
||||
Time.Current >= slider.StartTime && Time.Current < slider.EndTime &&
|
||||
// in valid position range
|
||||
lastScreenSpaceMousePosition.HasValue && FollowCircle.ReceivePositionalInputAt(lastScreenSpaceMousePosition.Value) &&
|
||||
lastScreenSpaceMousePosition.HasValue && followCircle.ReceivePositionalInputAt(lastScreenSpaceMousePosition.Value) &&
|
||||
// valid action
|
||||
(actions?.Any(isValidTrackingAction) ?? false);
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
|
||||
public double Radius => OBJECT_RADIUS * Scale;
|
||||
|
||||
public readonly Bindable<float> ScaleBindable = new Bindable<float>(1);
|
||||
public readonly Bindable<float> ScaleBindable = new BindableFloat(1);
|
||||
|
||||
public float Scale
|
||||
{
|
||||
|
@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
autoCursorScale = config.GetBindable<bool>(OsuSetting.AutoCursorSize);
|
||||
autoCursorScale.ValueChanged += _ => calculateScale();
|
||||
|
||||
CursorScale = new Bindable<float>();
|
||||
CursorScale = new BindableFloat();
|
||||
CursorScale.ValueChanged += e => ActiveCursor.Scale = cursorTrail.Scale = new Vector2(e.NewValue);
|
||||
|
||||
calculateScale();
|
||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
{
|
||||
Add(localCursorContainer = new OsuCursorContainer());
|
||||
|
||||
localCursorScale = new Bindable<float>();
|
||||
localCursorScale = new BindableFloat();
|
||||
localCursorScale.BindTo(localCursorContainer.CursorScale);
|
||||
localCursorScale.BindValueChanged(scale => cursorScaleContainer.Scale = new Vector2(scale.NewValue), true);
|
||||
}
|
||||
|
@ -118,17 +118,19 @@ namespace osu.Game.Tests.Editor
|
||||
[Test]
|
||||
public void TestGetSnappedDurationFromDistance()
|
||||
{
|
||||
assertSnappedDuration(50, 0);
|
||||
assertSnappedDuration(0, 0);
|
||||
assertSnappedDuration(50, 1000);
|
||||
assertSnappedDuration(100, 1000);
|
||||
assertSnappedDuration(150, 1000);
|
||||
assertSnappedDuration(150, 2000);
|
||||
assertSnappedDuration(200, 2000);
|
||||
assertSnappedDuration(250, 2000);
|
||||
assertSnappedDuration(250, 3000);
|
||||
|
||||
AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2);
|
||||
|
||||
assertSnappedDuration(0, 0);
|
||||
assertSnappedDuration(50, 0);
|
||||
assertSnappedDuration(100, 0);
|
||||
assertSnappedDuration(150, 0);
|
||||
assertSnappedDuration(100, 1000);
|
||||
assertSnappedDuration(150, 1000);
|
||||
assertSnappedDuration(200, 1000);
|
||||
assertSnappedDuration(250, 1000);
|
||||
|
||||
@ -139,8 +141,8 @@ namespace osu.Game.Tests.Editor
|
||||
});
|
||||
|
||||
assertSnappedDuration(50, 0);
|
||||
assertSnappedDuration(100, 0);
|
||||
assertSnappedDuration(150, 0);
|
||||
assertSnappedDuration(100, 500);
|
||||
assertSnappedDuration(150, 500);
|
||||
assertSnappedDuration(200, 500);
|
||||
assertSnappedDuration(250, 500);
|
||||
assertSnappedDuration(400, 1000);
|
||||
@ -149,17 +151,17 @@ namespace osu.Game.Tests.Editor
|
||||
[Test]
|
||||
public void GetSnappedDistanceFromDistance()
|
||||
{
|
||||
assertSnappedDistance(50, 0);
|
||||
assertSnappedDistance(50, 100);
|
||||
assertSnappedDistance(100, 100);
|
||||
assertSnappedDistance(150, 100);
|
||||
assertSnappedDistance(150, 200);
|
||||
assertSnappedDistance(200, 200);
|
||||
assertSnappedDistance(250, 200);
|
||||
assertSnappedDistance(250, 300);
|
||||
|
||||
AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2);
|
||||
|
||||
assertSnappedDistance(50, 0);
|
||||
assertSnappedDistance(100, 0);
|
||||
assertSnappedDistance(150, 0);
|
||||
assertSnappedDistance(100, 200);
|
||||
assertSnappedDistance(150, 200);
|
||||
assertSnappedDistance(200, 200);
|
||||
assertSnappedDistance(250, 200);
|
||||
|
||||
@ -170,8 +172,8 @@ namespace osu.Game.Tests.Editor
|
||||
});
|
||||
|
||||
assertSnappedDistance(50, 0);
|
||||
assertSnappedDistance(100, 0);
|
||||
assertSnappedDistance(150, 0);
|
||||
assertSnappedDistance(100, 200);
|
||||
assertSnappedDistance(150, 200);
|
||||
assertSnappedDistance(200, 200);
|
||||
assertSnappedDistance(250, 200);
|
||||
assertSnappedDistance(400, 400);
|
||||
|
@ -68,10 +68,10 @@ namespace osu.Game.Tests.Visual.Background
|
||||
[SetUp]
|
||||
public virtual void SetUp() => Schedule(() =>
|
||||
{
|
||||
Child = new OsuScreenStack(songSelect = new DummySongSelect())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
};
|
||||
var stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both };
|
||||
Child = stack;
|
||||
|
||||
stack.Push(songSelect = new DummySongSelect());
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
@ -277,7 +277,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
private void setupUserSettings()
|
||||
{
|
||||
AddUntilStep("Song select has selection", () => songSelect.Carousel.SelectedBeatmap != null);
|
||||
AddUntilStep("Song select has selection", () => songSelect.Carousel?.SelectedBeatmap != null);
|
||||
AddStep("Set default user settings", () =>
|
||||
{
|
||||
SelectedMods.Value = SelectedMods.Value.Concat(new[] { new OsuModNoFail() }).ToArray();
|
||||
@ -302,8 +302,8 @@ namespace osu.Game.Tests.Visual.Background
|
||||
}
|
||||
|
||||
public readonly Bindable<bool> DimEnabled = new Bindable<bool>();
|
||||
public readonly Bindable<double> DimLevel = new Bindable<double>();
|
||||
public readonly Bindable<double> BlurLevel = new Bindable<double>();
|
||||
public readonly Bindable<double> DimLevel = new BindableDouble();
|
||||
public readonly Bindable<double> BlurLevel = new BindableDouble();
|
||||
|
||||
public new BeatmapCarousel Carousel => base.Carousel;
|
||||
|
||||
|
@ -85,64 +85,64 @@ namespace osu.Game.Tests.Visual.Editor
|
||||
{
|
||||
}
|
||||
|
||||
protected override void CreateContent(Vector2 startPosition)
|
||||
protected override void CreateContent()
|
||||
{
|
||||
AddInternal(new Circle
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(5),
|
||||
Position = startPosition
|
||||
Position = StartPosition
|
||||
});
|
||||
|
||||
int beatIndex = 0;
|
||||
int indexFromPlacement = 0;
|
||||
|
||||
for (float s = startPosition.X + DistanceSpacing; s <= DrawWidth && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++)
|
||||
for (float s = StartPosition.X + DistanceSpacing; s <= DrawWidth && indexFromPlacement < MaxIntervals; s += DistanceSpacing, indexFromPlacement++)
|
||||
{
|
||||
AddInternal(new Circle
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(5, 10),
|
||||
Position = new Vector2(s, startPosition.Y),
|
||||
Colour = GetColourForBeatIndex(beatIndex)
|
||||
Position = new Vector2(s, StartPosition.Y),
|
||||
Colour = GetColourForIndexFromPlacement(indexFromPlacement)
|
||||
});
|
||||
}
|
||||
|
||||
beatIndex = 0;
|
||||
indexFromPlacement = 0;
|
||||
|
||||
for (float s = startPosition.X - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++)
|
||||
for (float s = StartPosition.X - DistanceSpacing; s >= 0 && indexFromPlacement < MaxIntervals; s -= DistanceSpacing, indexFromPlacement++)
|
||||
{
|
||||
AddInternal(new Circle
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(5, 10),
|
||||
Position = new Vector2(s, startPosition.Y),
|
||||
Colour = GetColourForBeatIndex(beatIndex)
|
||||
Position = new Vector2(s, StartPosition.Y),
|
||||
Colour = GetColourForIndexFromPlacement(indexFromPlacement)
|
||||
});
|
||||
}
|
||||
|
||||
beatIndex = 0;
|
||||
indexFromPlacement = 0;
|
||||
|
||||
for (float s = startPosition.Y + DistanceSpacing; s <= DrawHeight && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++)
|
||||
for (float s = StartPosition.Y + DistanceSpacing; s <= DrawHeight && indexFromPlacement < MaxIntervals; s += DistanceSpacing, indexFromPlacement++)
|
||||
{
|
||||
AddInternal(new Circle
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(10, 5),
|
||||
Position = new Vector2(startPosition.X, s),
|
||||
Colour = GetColourForBeatIndex(beatIndex)
|
||||
Position = new Vector2(StartPosition.X, s),
|
||||
Colour = GetColourForIndexFromPlacement(indexFromPlacement)
|
||||
});
|
||||
}
|
||||
|
||||
beatIndex = 0;
|
||||
indexFromPlacement = 0;
|
||||
|
||||
for (float s = startPosition.Y - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++)
|
||||
for (float s = StartPosition.Y - DistanceSpacing; s >= 0 && indexFromPlacement < MaxIntervals; s -= DistanceSpacing, indexFromPlacement++)
|
||||
{
|
||||
AddInternal(new Circle
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(10, 5),
|
||||
Position = new Vector2(startPosition.X, s),
|
||||
Colour = GetColourForBeatIndex(beatIndex)
|
||||
Position = new Vector2(StartPosition.X, s),
|
||||
Colour = GetColourForIndexFromPlacement(indexFromPlacement)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,146 +1,15 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editor
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneTimelineBlueprintContainer : EditorClockTestScene
|
||||
public class TestSceneTimelineBlueprintContainer : TimelineTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(TimelineArea),
|
||||
typeof(Timeline),
|
||||
typeof(TimelineButton),
|
||||
typeof(CentreMarker)
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
Beatmap.Value = new WaveformTestBeatmap(audio);
|
||||
|
||||
var editorBeatmap = new EditorBeatmap((Beatmap<HitObject>)Beatmap.Value.Beatmap, BeatDivisor);
|
||||
|
||||
Dependencies.Cache(editorBeatmap);
|
||||
Dependencies.CacheAs<IBeatSnapProvider>(editorBeatmap);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 5),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new StartStopButton(),
|
||||
new AudioVisualiser(),
|
||||
}
|
||||
},
|
||||
new TimelineArea
|
||||
{
|
||||
Child = new TimelineBlueprintContainer(),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Size = new Vector2(0.8f, 100)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private class AudioVisualiser : CompositeDrawable
|
||||
{
|
||||
private readonly Drawable marker;
|
||||
|
||||
[Resolved]
|
||||
private IBindable<WorkingBeatmap> beatmap { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IAdjustableClock adjustableClock { get; set; }
|
||||
|
||||
public AudioVisualiser()
|
||||
{
|
||||
Size = new Vector2(250, 25);
|
||||
|
||||
InternalChildren = new[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.25f,
|
||||
},
|
||||
marker = new Box
|
||||
{
|
||||
RelativePositionAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 2,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (beatmap.Value.Track.IsLoaded)
|
||||
marker.X = (float)(adjustableClock.CurrentTime / beatmap.Value.Track.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private class StartStopButton : OsuButton
|
||||
{
|
||||
private IAdjustableClock adjustableClock;
|
||||
private bool started;
|
||||
|
||||
public StartStopButton()
|
||||
{
|
||||
BackgroundColour = Color4.SlateGray;
|
||||
Size = new Vector2(100, 50);
|
||||
Text = "Start";
|
||||
|
||||
Action = onClick;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IAdjustableClock adjustableClock)
|
||||
{
|
||||
this.adjustableClock = adjustableClock;
|
||||
}
|
||||
|
||||
private void onClick()
|
||||
{
|
||||
if (started)
|
||||
{
|
||||
adjustableClock.Stop();
|
||||
Text = "Start";
|
||||
}
|
||||
else
|
||||
{
|
||||
adjustableClock.Start();
|
||||
Text = "Stop";
|
||||
}
|
||||
|
||||
started = !started;
|
||||
}
|
||||
}
|
||||
public override Drawable CreateTestComponent() => new TimelineBlueprintContainer();
|
||||
}
|
||||
}
|
||||
|
32
osu.Game.Tests/Visual/Editor/TestSceneTimelineTickDisplay.cs
Normal file
32
osu.Game.Tests/Visual/Editor/TestSceneTimelineTickDisplay.cs
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Screens.Edit.Compose.Components;
|
||||
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editor
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneTimelineTickDisplay : TimelineTestScene
|
||||
{
|
||||
public override Drawable CreateTestComponent() => new TimelineTickDisplay();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
BeatDivisor.Value = 4;
|
||||
|
||||
Add(new BeatDivisorControl(BeatDivisor)
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Margin = new MarginPadding(30),
|
||||
Size = new Vector2(90)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
148
osu.Game.Tests/Visual/Editor/TimelineTestScene.cs
Normal file
148
osu.Game.Tests/Visual/Editor/TimelineTestScene.cs
Normal file
@ -0,0 +1,148 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editor
|
||||
{
|
||||
public abstract class TimelineTestScene : EditorClockTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(TimelineArea),
|
||||
typeof(Timeline),
|
||||
typeof(TimelineButton),
|
||||
typeof(CentreMarker)
|
||||
};
|
||||
|
||||
protected TimelineArea TimelineArea { get; private set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
Beatmap.Value = new WaveformTestBeatmap(audio);
|
||||
|
||||
var editorBeatmap = new EditorBeatmap((Beatmap<HitObject>)Beatmap.Value.Beatmap, BeatDivisor);
|
||||
|
||||
Dependencies.Cache(editorBeatmap);
|
||||
Dependencies.CacheAs<IBeatSnapProvider>(editorBeatmap);
|
||||
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 5),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new StartStopButton(),
|
||||
new AudioVisualiser(),
|
||||
}
|
||||
},
|
||||
TimelineArea = new TimelineArea
|
||||
{
|
||||
Child = CreateTestComponent(),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Size = new Vector2(0.8f, 100),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public abstract Drawable CreateTestComponent();
|
||||
|
||||
private class AudioVisualiser : CompositeDrawable
|
||||
{
|
||||
private readonly Drawable marker;
|
||||
|
||||
[Resolved]
|
||||
private IBindable<WorkingBeatmap> beatmap { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IAdjustableClock adjustableClock { get; set; }
|
||||
|
||||
public AudioVisualiser()
|
||||
{
|
||||
Size = new Vector2(250, 25);
|
||||
|
||||
InternalChildren = new[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.25f,
|
||||
},
|
||||
marker = new Box
|
||||
{
|
||||
RelativePositionAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 2,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (beatmap.Value.Track.IsLoaded)
|
||||
marker.X = (float)(adjustableClock.CurrentTime / beatmap.Value.Track.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private class StartStopButton : OsuButton
|
||||
{
|
||||
private IAdjustableClock adjustableClock;
|
||||
private bool started;
|
||||
|
||||
public StartStopButton()
|
||||
{
|
||||
BackgroundColour = Color4.SlateGray;
|
||||
Size = new Vector2(100, 50);
|
||||
Text = "Start";
|
||||
|
||||
Action = onClick;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IAdjustableClock adjustableClock)
|
||||
{
|
||||
this.adjustableClock = adjustableClock;
|
||||
}
|
||||
|
||||
private void onClick()
|
||||
{
|
||||
if (started)
|
||||
{
|
||||
adjustableClock.Stop();
|
||||
Text = "Start";
|
||||
}
|
||||
else
|
||||
{
|
||||
adjustableClock.Start();
|
||||
Text = "Stop";
|
||||
}
|
||||
|
||||
started = !started;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,49 +2,66 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Taiko;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class which runs <see cref="Player"/> test for all available rulesets.
|
||||
/// Steps to be run for each ruleset should be added via <see cref="AddCheckSteps"/>.
|
||||
/// </summary>
|
||||
public abstract class AllPlayersTestScene : RateAdjustedBeatmapTestScene
|
||||
public abstract class TestSceneAllRulesetPlayers : RateAdjustedBeatmapTestScene
|
||||
{
|
||||
protected Player Player;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
foreach (var r in rulesets.AvailableRulesets)
|
||||
{
|
||||
Player p = null;
|
||||
AddStep(r.Name, () => p = loadPlayerFor(r));
|
||||
AddUntilStep("player loaded", () =>
|
||||
{
|
||||
if (p?.IsLoaded == true)
|
||||
{
|
||||
p = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
AddCheckSteps();
|
||||
}
|
||||
|
||||
OsuConfigManager manager;
|
||||
Dependencies.Cache(manager = new OsuConfigManager(LocalStorage));
|
||||
manager.GetBindable<double>(OsuSetting.DimLevel).Value = 1.0;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOsu() => runForRuleset(new OsuRuleset().RulesetInfo);
|
||||
|
||||
[Test]
|
||||
public void TestTaiko() => runForRuleset(new TaikoRuleset().RulesetInfo);
|
||||
|
||||
[Test]
|
||||
public void TestCatch() => runForRuleset(new CatchRuleset().RulesetInfo);
|
||||
|
||||
[Test]
|
||||
public void TestMania() => runForRuleset(new ManiaRuleset().RulesetInfo);
|
||||
|
||||
private void runForRuleset(RulesetInfo ruleset)
|
||||
{
|
||||
Player p = null;
|
||||
AddStep($"load {ruleset.Name} player", () => p = loadPlayerFor(ruleset));
|
||||
AddUntilStep("player loaded", () =>
|
||||
{
|
||||
if (p?.IsLoaded == true)
|
||||
{
|
||||
p = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
AddCheckSteps();
|
||||
}
|
||||
|
||||
protected abstract void AddCheckSteps();
|
||||
|
||||
private Player loadPlayerFor(RulesetInfo rulesetInfo)
|
@ -12,7 +12,7 @@ using osu.Game.Storyboards;
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
[Description("Player instantiated with an autoplay mod.")]
|
||||
public class TestSceneAutoplay : AllPlayersTestScene
|
||||
public class TestSceneAutoplay : TestSceneAllRulesetPlayers
|
||||
{
|
||||
private ClockBackedTestWorkingBeatmap.TrackVirtualManual track;
|
||||
|
||||
|
@ -10,7 +10,7 @@ using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneFailAnimation : AllPlayersTestScene
|
||||
public class TestSceneFailAnimation : TestSceneAllRulesetPlayers
|
||||
{
|
||||
protected override Player CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(AllPlayersTestScene),
|
||||
typeof(TestSceneAllRulesetPlayers),
|
||||
typeof(TestPlayer),
|
||||
typeof(Player),
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneFailJudgement : AllPlayersTestScene
|
||||
public class TestSceneFailJudgement : TestSceneAllRulesetPlayers
|
||||
{
|
||||
protected override Player CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
|
@ -2,12 +2,16 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Play;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
@ -15,7 +19,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
private HUDOverlay hudOverlay;
|
||||
|
||||
private Drawable hideTarget => hudOverlay.KeyCounter; // best way of checking hideTargets without exposing.
|
||||
// best way to check without exposing.
|
||||
private Drawable hideTarget => hudOverlay.KeyCounter;
|
||||
private FillFlowContainer<KeyCounter> keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType<FillFlowContainer<KeyCounter>>().First();
|
||||
|
||||
[Resolved]
|
||||
private OsuConfigManager config { get; set; }
|
||||
@ -28,6 +34,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("showhud is set", () => hudOverlay.ShowHud.Value);
|
||||
|
||||
AddAssert("hidetarget is visible", () => hideTarget.IsPresent);
|
||||
AddAssert("key counter flow is visible", () => keyCounterFlow.IsPresent);
|
||||
AddAssert("pause button is visible", () => hudOverlay.HoldToQuit.IsPresent);
|
||||
}
|
||||
|
||||
@ -50,6 +57,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
AddUntilStep("hidetarget is hidden", () => !hideTarget.IsPresent);
|
||||
AddAssert("pause button is still visible", () => hudOverlay.HoldToQuit.IsPresent);
|
||||
|
||||
// Key counter flow container should not be affected by this, only the key counter display will be hidden as checked above.
|
||||
AddAssert("key counter flow not affected", () => keyCounterFlow.IsPresent);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -68,12 +78,40 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("config unchanged", () => originalConfigValue == config.Get<bool>(OsuSetting.ShowInterface));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChangeHUDVisibilityOnHiddenKeyCounter()
|
||||
{
|
||||
bool keyCounterVisibleValue = false;
|
||||
|
||||
createNew();
|
||||
AddStep("save keycounter visible value", () => keyCounterVisibleValue = config.Get<bool>(OsuSetting.KeyOverlay));
|
||||
|
||||
AddStep("set keycounter visible false", () =>
|
||||
{
|
||||
config.Set<bool>(OsuSetting.KeyOverlay, false);
|
||||
hudOverlay.KeyCounter.AlwaysVisible.Value = false;
|
||||
});
|
||||
|
||||
AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false);
|
||||
AddUntilStep("hidetarget is hidden", () => !hideTarget.IsPresent);
|
||||
AddAssert("key counters hidden", () => !keyCounterFlow.IsPresent);
|
||||
|
||||
AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true);
|
||||
AddUntilStep("hidetarget is visible", () => hideTarget.IsPresent);
|
||||
AddAssert("key counters still hidden", () => !keyCounterFlow.IsPresent);
|
||||
|
||||
AddStep("return value", () => config.Set<bool>(OsuSetting.KeyOverlay, keyCounterVisibleValue));
|
||||
}
|
||||
|
||||
private void createNew(Action<HUDOverlay> action = null)
|
||||
{
|
||||
AddStep("create overlay", () =>
|
||||
{
|
||||
Child = hudOverlay = new HUDOverlay(null, null, null, Array.Empty<Mod>());
|
||||
|
||||
// Add any key just to display the key counter visually.
|
||||
hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
|
||||
|
||||
action?.Invoke(hudOverlay);
|
||||
});
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
base.SetUpSteps();
|
||||
|
||||
AddStep("resume player", () => Player.GameplayClockContainer.Start());
|
||||
confirmClockRunning(true);
|
||||
}
|
||||
|
@ -207,9 +207,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
OsuScreenStack stack;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new OsuScreenStack(screen)
|
||||
stack = new OsuScreenStack
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
@ -224,6 +226,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
Origin = Anchor.TopLeft,
|
||||
}
|
||||
};
|
||||
|
||||
stack.Push(screen);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ using osu.Game.Storyboards;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestScenePlayerReferenceLeaking : AllPlayersTestScene
|
||||
public class TestScenePlayerReferenceLeaking : TestSceneAllRulesetPlayers
|
||||
{
|
||||
private readonly WeakList<WorkingBeatmap> workingWeakReferences = new WeakList<WorkingBeatmap>();
|
||||
|
||||
|
@ -13,7 +13,7 @@ using osu.Game.Screens.Play;
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
[Description("Player instantiated with a replay.")]
|
||||
public class TestSceneReplay : AllPlayersTestScene
|
||||
public class TestSceneReplay : TestSceneAllRulesetPlayers
|
||||
{
|
||||
protected override Player CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
|
@ -75,10 +75,16 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
public void ResultsWithoutPlayer()
|
||||
{
|
||||
TestSoloResults screen = null;
|
||||
OsuScreenStack stack;
|
||||
|
||||
AddStep("load results", () => Child = new OsuScreenStack(screen = createResultsScreen())
|
||||
AddStep("load results", () =>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
Child = stack = new OsuScreenStack
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
};
|
||||
|
||||
stack.Push(screen = createResultsScreen());
|
||||
});
|
||||
AddUntilStep("wait for loaded", () => screen.IsLoaded);
|
||||
AddAssert("retry overlay not present", () => screen.RetryOverlay == null);
|
||||
@ -102,11 +108,14 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
public TestResultsContainer(IScreen screen)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
OsuScreenStack stack;
|
||||
|
||||
InternalChild = new OsuScreenStack(screen)
|
||||
InternalChild = stack = new OsuScreenStack
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
};
|
||||
|
||||
stack.Push(screen);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
|
||||
protected IntroTestScene()
|
||||
{
|
||||
Drawable introStack = null;
|
||||
OsuScreenStack introStack = null;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -57,10 +57,12 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
|
||||
introStack?.Expire();
|
||||
|
||||
Add(introStack = new OsuScreenStack(CreateScreen())
|
||||
Add(introStack = new OsuScreenStack
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
});
|
||||
|
||||
introStack.Push(CreateScreen());
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
OsuScreenStack screenStack = new OsuScreenStack(new TestMultiplayerSubScreen(index)) { RelativeSizeAxes = Axes.Both };
|
||||
OsuScreenStack screenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
screenStack.Push(new TestMultiplayerSubScreen(index));
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
|
133
osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs
Normal file
133
osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs
Normal file
@ -0,0 +1,133 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osuTK.Graphics;
|
||||
using IntroSequence = osu.Game.Configuration.IntroSequence;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Navigation
|
||||
{
|
||||
/// <summary>
|
||||
/// A scene which tests full game flow.
|
||||
/// </summary>
|
||||
public abstract class OsuGameTestScene : ManualInputManagerTestScene
|
||||
{
|
||||
private GameHost host;
|
||||
|
||||
protected TestOsuGame Game;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host)
|
||||
{
|
||||
this.host = host;
|
||||
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
};
|
||||
}
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
AddStep("Create new game instance", () =>
|
||||
{
|
||||
if (Game != null)
|
||||
{
|
||||
Remove(Game);
|
||||
Game.Dispose();
|
||||
}
|
||||
|
||||
RecycleLocalStorage();
|
||||
|
||||
// see MouseSettings
|
||||
var frameworkConfig = host.Dependencies.Get<FrameworkConfigManager>();
|
||||
frameworkConfig.GetBindable<double>(FrameworkSetting.CursorSensitivity).Disabled = false;
|
||||
|
||||
Game = new TestOsuGame(LocalStorage, API);
|
||||
Game.SetHost(host);
|
||||
|
||||
// todo: this can be removed once we can run audio tracks without a device present
|
||||
// see https://github.com/ppy/osu/issues/1302
|
||||
Game.LocalConfig.Set(OsuSetting.IntroSequence, IntroSequence.Circles);
|
||||
|
||||
Add(Game);
|
||||
});
|
||||
|
||||
AddUntilStep("Wait for load", () => Game.IsLoaded);
|
||||
AddUntilStep("Wait for intro", () => Game.ScreenStack.CurrentScreen is IntroScreen);
|
||||
|
||||
ConfirmAtMainMenu();
|
||||
}
|
||||
|
||||
protected void PushAndConfirm(Func<Screen> newScreen)
|
||||
{
|
||||
Screen screen = null;
|
||||
AddStep("Push new screen", () => Game.ScreenStack.Push(screen = newScreen()));
|
||||
AddUntilStep("Wait for new screen", () => Game.ScreenStack.CurrentScreen == screen && screen.IsLoaded);
|
||||
}
|
||||
|
||||
protected void ConfirmAtMainMenu() => AddUntilStep("Wait for main menu", () => Game.ScreenStack.CurrentScreen is MainMenu menu && menu.IsLoaded);
|
||||
|
||||
public class TestOsuGame : OsuGame
|
||||
{
|
||||
public new ScreenStack ScreenStack => base.ScreenStack;
|
||||
|
||||
public new BackButton BackButton => base.BackButton;
|
||||
|
||||
public new BeatmapManager BeatmapManager => base.BeatmapManager;
|
||||
|
||||
public new SettingsPanel Settings => base.Settings;
|
||||
|
||||
public new OsuConfigManager LocalConfig => base.LocalConfig;
|
||||
|
||||
public new Bindable<WorkingBeatmap> Beatmap => base.Beatmap;
|
||||
|
||||
public new Bindable<RulesetInfo> Ruleset => base.Ruleset;
|
||||
|
||||
protected override Loader CreateLoader() => new TestLoader();
|
||||
|
||||
public new void PerformFromScreen(Action<IScreen> action, IEnumerable<Type> validScreens = null) => base.PerformFromScreen(action, validScreens);
|
||||
|
||||
public TestOsuGame(Storage storage, IAPIProvider api)
|
||||
{
|
||||
Storage = storage;
|
||||
API = api;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
API.Login("Rhythm Champion", "osu!");
|
||||
}
|
||||
}
|
||||
|
||||
public class TestLoader : Loader
|
||||
{
|
||||
protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler();
|
||||
|
||||
private class TestShaderPrecompiler : ShaderPrecompiler
|
||||
{
|
||||
protected override bool AllLoaded => true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
// 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.Screens.Menu;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Select;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Navigation
|
||||
{
|
||||
public class TestScenePerformFromScreen : OsuGameTestScene
|
||||
{
|
||||
[Test]
|
||||
public void TestPerformAtMenu()
|
||||
{
|
||||
AddAssert("could perform immediately", () =>
|
||||
{
|
||||
bool actionPerformed = false;
|
||||
Game.PerformFromScreen(_ => actionPerformed = true);
|
||||
return actionPerformed;
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPerformAtSongSelect()
|
||||
{
|
||||
PushAndConfirm(() => new PlaySongSelect());
|
||||
|
||||
AddAssert("could perform immediately", () =>
|
||||
{
|
||||
bool actionPerformed = false;
|
||||
Game.PerformFromScreen(_ => actionPerformed = true, new[] { typeof(PlaySongSelect) });
|
||||
return actionPerformed;
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPerformAtMenuFromSongSelect()
|
||||
{
|
||||
PushAndConfirm(() => new PlaySongSelect());
|
||||
|
||||
bool actionPerformed = false;
|
||||
AddStep("try to perform", () => Game.PerformFromScreen(_ => actionPerformed = true));
|
||||
AddUntilStep("returned to menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
|
||||
AddAssert("did perform", () => actionPerformed);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPerformAtSongSelectFromPlayerLoader()
|
||||
{
|
||||
PushAndConfirm(() => new PlaySongSelect());
|
||||
PushAndConfirm(() => new PlayerLoader(() => new Player()));
|
||||
|
||||
bool actionPerformed = false;
|
||||
AddStep("try to perform", () => Game.PerformFromScreen(_ => actionPerformed = true, new[] { typeof(PlaySongSelect) }));
|
||||
AddUntilStep("returned to song select", () => Game.ScreenStack.CurrentScreen is PlaySongSelect);
|
||||
AddAssert("did perform", () => actionPerformed);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPerformAtMenuFromPlayerLoader()
|
||||
{
|
||||
PushAndConfirm(() => new PlaySongSelect());
|
||||
PushAndConfirm(() => new PlayerLoader(() => new Player()));
|
||||
|
||||
bool actionPerformed = false;
|
||||
AddStep("try to perform", () => Game.PerformFromScreen(_ => actionPerformed = true));
|
||||
AddUntilStep("returned to song select", () => Game.ScreenStack.CurrentScreen is MainMenu);
|
||||
AddAssert("did perform", () => actionPerformed);
|
||||
}
|
||||
}
|
||||
}
|
110
osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs
Normal file
110
osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Menu;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Navigation
|
||||
{
|
||||
public class TestScenePresentBeatmap : OsuGameTestScene
|
||||
{
|
||||
[Test]
|
||||
public void TestFromMainMenu()
|
||||
{
|
||||
var firstImport = importBeatmap(1);
|
||||
presentAndConfirm(firstImport);
|
||||
|
||||
AddStep("return to menu", () => Game.ScreenStack.CurrentScreen.Exit());
|
||||
AddUntilStep("wait for menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
|
||||
|
||||
var secondimport = importBeatmap(2);
|
||||
presentAndConfirm(secondimport);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFromMainMenuDifferentRuleset()
|
||||
{
|
||||
var firstImport = importBeatmap(1);
|
||||
presentAndConfirm(firstImport);
|
||||
|
||||
AddStep("return to menu", () => Game.ScreenStack.CurrentScreen.Exit());
|
||||
AddUntilStep("wait for menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
|
||||
|
||||
var secondimport = importBeatmap(2, new ManiaRuleset().RulesetInfo);
|
||||
presentAndConfirm(secondimport);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFromSongSelect()
|
||||
{
|
||||
var firstImport = importBeatmap(1);
|
||||
presentAndConfirm(firstImport);
|
||||
|
||||
var secondimport = importBeatmap(2);
|
||||
presentAndConfirm(secondimport);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFromSongSelectDifferentRuleset()
|
||||
{
|
||||
var firstImport = importBeatmap(1);
|
||||
presentAndConfirm(firstImport);
|
||||
|
||||
var secondimport = importBeatmap(2, new ManiaRuleset().RulesetInfo);
|
||||
presentAndConfirm(secondimport);
|
||||
}
|
||||
|
||||
private Func<BeatmapSetInfo> importBeatmap(int i, RulesetInfo ruleset = null)
|
||||
{
|
||||
BeatmapSetInfo imported = null;
|
||||
AddStep($"import beatmap {i}", () =>
|
||||
{
|
||||
var difficulty = new BeatmapDifficulty();
|
||||
var metadata = new BeatmapMetadata
|
||||
{
|
||||
Artist = "SomeArtist",
|
||||
AuthorString = "SomeAuthor",
|
||||
Title = $"import {i}"
|
||||
};
|
||||
|
||||
imported = Game.BeatmapManager.Import(new BeatmapSetInfo
|
||||
{
|
||||
Hash = Guid.NewGuid().ToString(),
|
||||
OnlineBeatmapSetID = i,
|
||||
Metadata = metadata,
|
||||
Beatmaps = new List<BeatmapInfo>
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
OnlineBeatmapID = i * 1024,
|
||||
Metadata = metadata,
|
||||
BaseDifficulty = difficulty,
|
||||
Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
|
||||
},
|
||||
}
|
||||
}).Result;
|
||||
});
|
||||
|
||||
AddAssert($"import {i} succeeded", () => imported != null);
|
||||
|
||||
return () => imported;
|
||||
}
|
||||
|
||||
private void presentAndConfirm(Func<BeatmapSetInfo> getImport)
|
||||
{
|
||||
AddStep("present beatmap", () => Game.PresentBeatmap(getImport()));
|
||||
|
||||
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
|
||||
AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapSetInfo.ID == getImport().ID);
|
||||
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Beatmaps.First().Ruleset.ID);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,90 +1,36 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Tests.Beatmaps.IO;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Input;
|
||||
using IntroSequence = osu.Game.Configuration.IntroSequence;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Menus
|
||||
namespace osu.Game.Tests.Visual.Navigation
|
||||
{
|
||||
public class TestSceneScreenNavigation : ManualInputManagerTestScene
|
||||
public class TestSceneScreenNavigation : OsuGameTestScene
|
||||
{
|
||||
private const float click_padding = 25;
|
||||
|
||||
private GameHost host;
|
||||
private TestOsuGame game;
|
||||
private Vector2 backButtonPosition => Game.ToScreenSpace(new Vector2(click_padding, Game.LayoutRectangle.Bottom - click_padding));
|
||||
|
||||
private Vector2 backButtonPosition => game.ToScreenSpace(new Vector2(click_padding, game.LayoutRectangle.Bottom - click_padding));
|
||||
|
||||
private Vector2 optionsButtonPosition => game.ToScreenSpace(new Vector2(click_padding, click_padding));
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host)
|
||||
{
|
||||
this.host = host;
|
||||
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
};
|
||||
}
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
AddStep("Create new game instance", () =>
|
||||
{
|
||||
if (game != null)
|
||||
{
|
||||
Remove(game);
|
||||
game.Dispose();
|
||||
}
|
||||
|
||||
game = new TestOsuGame(LocalStorage, API);
|
||||
game.SetHost(host);
|
||||
|
||||
// todo: this can be removed once we can run audio trakcs without a device present
|
||||
// see https://github.com/ppy/osu/issues/1302
|
||||
game.LocalConfig.Set(OsuSetting.IntroSequence, IntroSequence.Circles);
|
||||
|
||||
Add(game);
|
||||
});
|
||||
AddUntilStep("Wait for load", () => game.IsLoaded);
|
||||
AddUntilStep("Wait for intro", () => game.ScreenStack.CurrentScreen is IntroScreen);
|
||||
confirmAtMainMenu();
|
||||
}
|
||||
private Vector2 optionsButtonPosition => Game.ToScreenSpace(new Vector2(click_padding, click_padding));
|
||||
|
||||
[Test]
|
||||
public void TestExitSongSelectWithEscape()
|
||||
{
|
||||
TestSongSelect songSelect = null;
|
||||
|
||||
pushAndConfirm(() => songSelect = new TestSongSelect());
|
||||
PushAndConfirm(() => songSelect = new TestSongSelect());
|
||||
AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show());
|
||||
AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible);
|
||||
pushEscape();
|
||||
@ -98,21 +44,21 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
Player player = null;
|
||||
|
||||
WorkingBeatmap beatmap() => game.Beatmap.Value;
|
||||
WorkingBeatmap beatmap() => Game.Beatmap.Value;
|
||||
Track track() => beatmap().Track;
|
||||
|
||||
pushAndConfirm(() => new TestSongSelect());
|
||||
PushAndConfirm(() => new TestSongSelect());
|
||||
|
||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Wait());
|
||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(Game, virtualTrack: true).Wait());
|
||||
|
||||
AddUntilStep("wait for selected", () => !game.Beatmap.IsDefault);
|
||||
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
|
||||
|
||||
if (withUserPause)
|
||||
AddStep("pause", () => game.Dependencies.Get<MusicController>().Stop());
|
||||
AddStep("pause", () => Game.Dependencies.Get<MusicController>().Stop());
|
||||
|
||||
AddStep("press enter", () => pressAndRelease(Key.Enter));
|
||||
|
||||
AddUntilStep("wait for player", () => (player = game.ScreenStack.CurrentScreen as Player) != null);
|
||||
AddUntilStep("wait for player", () => (player = Game.ScreenStack.CurrentScreen as Player) != null);
|
||||
AddUntilStep("wait for fail", () => player.HasFailed);
|
||||
|
||||
AddUntilStep("wait for track stop", () => !track().IsRunning);
|
||||
@ -129,13 +75,13 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
TestSongSelect songSelect = null;
|
||||
|
||||
pushAndConfirm(() => songSelect = new TestSongSelect());
|
||||
PushAndConfirm(() => songSelect = new TestSongSelect());
|
||||
AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show());
|
||||
AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible);
|
||||
AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(backButtonPosition));
|
||||
|
||||
// BackButton handles hover using its child button, so this checks whether or not any of BackButton's children are hovered.
|
||||
AddUntilStep("Back button is hovered", () => InputManager.HoveredDrawables.Any(d => d.Parent == game.BackButton));
|
||||
AddUntilStep("Back button is hovered", () => InputManager.HoveredDrawables.Any(d => d.Parent == Game.BackButton));
|
||||
|
||||
AddStep("Click back button", () => InputManager.Click(MouseButton.Left));
|
||||
AddUntilStep("Overlay was hidden", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden);
|
||||
@ -145,34 +91,27 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
[Test]
|
||||
public void TestExitMultiWithEscape()
|
||||
{
|
||||
pushAndConfirm(() => new Screens.Multi.Multiplayer());
|
||||
PushAndConfirm(() => new Screens.Multi.Multiplayer());
|
||||
exitViaEscapeAndConfirm();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExitMultiWithBackButton()
|
||||
{
|
||||
pushAndConfirm(() => new Screens.Multi.Multiplayer());
|
||||
PushAndConfirm(() => new Screens.Multi.Multiplayer());
|
||||
exitViaBackButtonAndConfirm();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOpenOptionsAndExitWithEscape()
|
||||
{
|
||||
AddUntilStep("Wait for options to load", () => game.Settings.IsLoaded);
|
||||
AddUntilStep("Wait for options to load", () => Game.Settings.IsLoaded);
|
||||
AddStep("Enter menu", () => pressAndRelease(Key.Enter));
|
||||
AddStep("Move mouse to options overlay", () => InputManager.MoveMouseTo(optionsButtonPosition));
|
||||
AddStep("Click options overlay", () => InputManager.Click(MouseButton.Left));
|
||||
AddAssert("Options overlay was opened", () => game.Settings.State.Value == Visibility.Visible);
|
||||
AddAssert("Options overlay was opened", () => Game.Settings.State.Value == Visibility.Visible);
|
||||
AddStep("Hide options overlay using escape", () => pressAndRelease(Key.Escape));
|
||||
AddAssert("Options overlay was closed", () => game.Settings.State.Value == Visibility.Hidden);
|
||||
}
|
||||
|
||||
private void pushAndConfirm(Func<Screen> newScreen)
|
||||
{
|
||||
Screen screen = null;
|
||||
AddStep("Push new screen", () => game.ScreenStack.Push(screen = newScreen()));
|
||||
AddUntilStep("Wait for new screen", () => game.ScreenStack.CurrentScreen == screen && screen.IsLoaded);
|
||||
AddAssert("Options overlay was closed", () => Game.Settings.State.Value == Visibility.Hidden);
|
||||
}
|
||||
|
||||
private void pushEscape() =>
|
||||
@ -181,64 +120,25 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
private void exitViaEscapeAndConfirm()
|
||||
{
|
||||
pushEscape();
|
||||
confirmAtMainMenu();
|
||||
ConfirmAtMainMenu();
|
||||
}
|
||||
|
||||
private void exitViaBackButtonAndConfirm()
|
||||
{
|
||||
AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(backButtonPosition));
|
||||
AddStep("Click back button", () => InputManager.Click(MouseButton.Left));
|
||||
confirmAtMainMenu();
|
||||
ConfirmAtMainMenu();
|
||||
}
|
||||
|
||||
private void confirmAtMainMenu() => AddUntilStep("Wait for main menu", () => game.ScreenStack.CurrentScreen is MainMenu menu && menu.IsLoaded);
|
||||
|
||||
private void pressAndRelease(Key key)
|
||||
{
|
||||
InputManager.PressKey(key);
|
||||
InputManager.ReleaseKey(key);
|
||||
}
|
||||
|
||||
private class TestOsuGame : OsuGame
|
||||
{
|
||||
public new ScreenStack ScreenStack => base.ScreenStack;
|
||||
|
||||
public new BackButton BackButton => base.BackButton;
|
||||
|
||||
public new SettingsPanel Settings => base.Settings;
|
||||
|
||||
public new OsuConfigManager LocalConfig => base.LocalConfig;
|
||||
|
||||
public new Bindable<WorkingBeatmap> Beatmap => base.Beatmap;
|
||||
|
||||
protected override Loader CreateLoader() => new TestLoader();
|
||||
|
||||
public TestOsuGame(Storage storage, IAPIProvider api)
|
||||
{
|
||||
Storage = storage;
|
||||
API = api;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
API.Login("Rhythm Champion", "osu!");
|
||||
}
|
||||
}
|
||||
|
||||
private class TestSongSelect : PlaySongSelect
|
||||
{
|
||||
public ModSelectOverlay ModSelectOverlay => ModSelect;
|
||||
}
|
||||
|
||||
private class TestLoader : Loader
|
||||
{
|
||||
protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler();
|
||||
|
||||
private class TestShaderPrecompiler : ShaderPrecompiler
|
||||
{
|
||||
protected override bool AllLoaded => true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using osu.Game.Rulesets;
|
||||
using System;
|
||||
@ -21,6 +22,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(BeatmapRulesetTabItem),
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||
|
||||
private readonly TestRulesetSelector selector;
|
||||
|
||||
public TestSceneBeatmapRulesetSelector()
|
||||
|
@ -3,12 +3,15 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.Chat;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Chat;
|
||||
@ -35,8 +38,21 @@ namespace osu.Game.Tests.Visual.Online
|
||||
private TestChatOverlay chatOverlay;
|
||||
private ChannelManager channelManager;
|
||||
|
||||
private readonly Channel channel1 = new Channel(new User()) { Name = "test really long username" };
|
||||
private readonly Channel channel2 = new Channel(new User()) { Name = "test2" };
|
||||
private readonly List<Channel> channels;
|
||||
|
||||
private Channel channel1 => channels[0];
|
||||
private Channel channel2 => channels[1];
|
||||
|
||||
public TestSceneChatOverlay()
|
||||
{
|
||||
channels = Enumerable.Range(1, 10)
|
||||
.Select(index => new Channel(new User())
|
||||
{
|
||||
Name = $"Channel no. {index}",
|
||||
Topic = index == 3 ? null : $"We talk about the number {index} here"
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
@ -45,7 +61,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
ChannelManagerContainer container;
|
||||
|
||||
Child = container = new ChannelManagerContainer(new List<Channel> { channel1, channel2 })
|
||||
Child = container = new ChannelManagerContainer(channels)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
};
|
||||
@ -96,6 +112,47 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSearchInSelector()
|
||||
{
|
||||
AddStep("search for 'no. 2'", () => chatOverlay.ChildrenOfType<SearchTextBox>().First().Text = "no. 2");
|
||||
AddUntilStep("only channel 2 visible", () =>
|
||||
{
|
||||
var listItems = chatOverlay.ChildrenOfType<ChannelListItem>().Where(c => c.IsPresent);
|
||||
return listItems.Count() == 1 && listItems.Single().Channel == channel2;
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChannelShortcutKeys()
|
||||
{
|
||||
AddStep("join 10 channels", () => channels.ForEach(channel => channelManager.JoinChannel(channel)));
|
||||
AddStep("close channel selector", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.Escape);
|
||||
InputManager.ReleaseKey(Key.Escape);
|
||||
});
|
||||
AddUntilStep("wait for close", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||
|
||||
for (int zeroBasedIndex = 0; zeroBasedIndex < 10; ++zeroBasedIndex)
|
||||
{
|
||||
var oneBasedIndex = zeroBasedIndex + 1;
|
||||
var targetNumberKey = oneBasedIndex % 10;
|
||||
var targetChannel = channels[zeroBasedIndex];
|
||||
AddStep($"press Alt+{targetNumberKey}", () => pressChannelHotkey(targetNumberKey));
|
||||
AddAssert($"channel #{oneBasedIndex} is selected", () => channelManager.CurrentChannel.Value == targetChannel);
|
||||
}
|
||||
}
|
||||
|
||||
private void pressChannelHotkey(int number)
|
||||
{
|
||||
var channelKey = Key.Number0 + number;
|
||||
InputManager.PressKey(Key.AltLeft);
|
||||
InputManager.PressKey(channelKey);
|
||||
InputManager.ReleaseKey(Key.AltLeft);
|
||||
InputManager.ReleaseKey(channelKey);
|
||||
}
|
||||
|
||||
private void clickDrawable(Drawable d)
|
||||
{
|
||||
InputManager.MoveMouseTo(d);
|
||||
|
@ -24,8 +24,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(HeaderButton),
|
||||
typeof(SortTabControl),
|
||||
typeof(ShowChildrenButton),
|
||||
typeof(DeletedChildrenPlaceholder),
|
||||
typeof(VotePill)
|
||||
typeof(DeletedCommentsCounter),
|
||||
typeof(VotePill),
|
||||
typeof(CommentsPage),
|
||||
};
|
||||
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
162
osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs
Normal file
162
osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs
Normal file
@ -0,0 +1,162 @@
|
||||
// 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.Game.Overlays.Comments;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneCommentsPage : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(DrawableComment),
|
||||
typeof(CommentsPage),
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||
|
||||
private readonly BindableBool showDeleted = new BindableBool();
|
||||
private readonly Container content;
|
||||
|
||||
public TestSceneCommentsPage()
|
||||
{
|
||||
Add(new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 10),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Width = 200,
|
||||
Child = new OsuCheckbox
|
||||
{
|
||||
Current = showDeleted,
|
||||
LabelText = @"Show Deleted"
|
||||
}
|
||||
},
|
||||
content = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
AddStep("load comments", () => createPage(comment_bundle));
|
||||
AddStep("load empty comments", () => createPage(empty_comment_bundle));
|
||||
}
|
||||
|
||||
private void createPage(CommentBundle commentBundle)
|
||||
{
|
||||
content.Clear();
|
||||
content.Add(new CommentsPage(commentBundle)
|
||||
{
|
||||
ShowDeleted = { BindTarget = showDeleted }
|
||||
});
|
||||
}
|
||||
|
||||
private static readonly CommentBundle empty_comment_bundle = new CommentBundle
|
||||
{
|
||||
Comments = new List<Comment>(),
|
||||
Total = 0,
|
||||
};
|
||||
|
||||
private static readonly CommentBundle comment_bundle = new CommentBundle
|
||||
{
|
||||
Comments = new List<Comment>
|
||||
{
|
||||
new Comment
|
||||
{
|
||||
Id = 1,
|
||||
Message = "Simple test comment",
|
||||
LegacyName = "TestUser1",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 5
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 2,
|
||||
Message = "This comment has been deleted :( but visible for admins",
|
||||
LegacyName = "TestUser2",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
DeletedAt = DateTimeOffset.Now,
|
||||
VotesCount = 5
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 3,
|
||||
Message = "This comment is a top level",
|
||||
LegacyName = "TestUser3",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
RepliesCount = 2,
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 4,
|
||||
ParentId = 3,
|
||||
Message = "And this is a reply",
|
||||
RepliesCount = 1,
|
||||
LegacyName = "TestUser1",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 15,
|
||||
ParentId = 4,
|
||||
Message = "Reply to reply",
|
||||
LegacyName = "TestUser1",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 6,
|
||||
ParentId = 3,
|
||||
LegacyName = "TestUser11515",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
DeletedAt = DateTimeOffset.Now,
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 5,
|
||||
Message = "This comment is voted and edited",
|
||||
LegacyName = "BigBrainUser",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
EditedAt = DateTimeOffset.Now,
|
||||
VotesCount = 1000,
|
||||
EditedById = 1,
|
||||
}
|
||||
},
|
||||
IncludedComments = new List<Comment>(),
|
||||
UserVotes = new List<long>
|
||||
{
|
||||
5
|
||||
},
|
||||
Users = new List<User>
|
||||
{
|
||||
new User
|
||||
{
|
||||
Id = 1,
|
||||
Username = "Good_Admin"
|
||||
}
|
||||
},
|
||||
TopLevelCount = 4,
|
||||
Total = 7
|
||||
};
|
||||
}
|
||||
}
|
@ -4,10 +4,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Profile.Sections;
|
||||
using osu.Game.Overlays.Profile.Sections.Historical;
|
||||
using osu.Game.Users;
|
||||
@ -24,9 +26,11 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(HistoricalSection),
|
||||
typeof(PaginatedMostPlayedBeatmapContainer),
|
||||
typeof(DrawableMostPlayedBeatmap),
|
||||
typeof(DrawableProfileRow)
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink);
|
||||
|
||||
public TestSceneHistoricalSection()
|
||||
{
|
||||
HistoricalSection section;
|
||||
|
@ -11,6 +11,8 @@ using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Taiko;
|
||||
using osu.Game.Users;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
@ -22,10 +24,13 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(ProfileRulesetTabItem),
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||
|
||||
public TestSceneProfileRulesetSelector()
|
||||
{
|
||||
ProfileRulesetSelector selector;
|
||||
Bindable<User> user = new Bindable<User>();
|
||||
var user = new Bindable<User>();
|
||||
|
||||
Child = selector = new ProfileRulesetSelector
|
||||
{
|
||||
|
@ -4,11 +4,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Profile.Header.Components;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
@ -24,6 +26,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(LineGraph)
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink);
|
||||
|
||||
public TestSceneRankGraph()
|
||||
{
|
||||
RankGraph graph;
|
||||
|
@ -0,0 +1,87 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Rankings;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneRankingsSpotlightSelector : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(SpotlightSelector),
|
||||
};
|
||||
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
private readonly SpotlightSelector selector;
|
||||
|
||||
public TestSceneRankingsSpotlightSelector()
|
||||
{
|
||||
Add(selector = new SpotlightSelector());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLocalSpotlights()
|
||||
{
|
||||
var spotlights = new[]
|
||||
{
|
||||
new APISpotlight
|
||||
{
|
||||
Name = "Spotlight 1",
|
||||
StartDate = DateTimeOffset.Now,
|
||||
EndDate = DateTimeOffset.Now,
|
||||
},
|
||||
new APISpotlight
|
||||
{
|
||||
Name = "Spotlight 2",
|
||||
StartDate = DateTimeOffset.Now,
|
||||
EndDate = DateTimeOffset.Now,
|
||||
},
|
||||
new APISpotlight
|
||||
{
|
||||
Name = "Spotlight 3",
|
||||
StartDate = DateTimeOffset.Now,
|
||||
EndDate = DateTimeOffset.Now,
|
||||
},
|
||||
};
|
||||
|
||||
AddStep("load spotlights", () => selector.Spotlights = spotlights);
|
||||
AddStep("change to spotlight 3", () => selector.Current.Value = spotlights[2]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOnlineSpotlights()
|
||||
{
|
||||
List<APISpotlight> spotlights = null;
|
||||
|
||||
AddStep("retrieve spotlights", () =>
|
||||
{
|
||||
var req = new GetSpotlightsRequest();
|
||||
req.Success += res => spotlights = res.Spotlights;
|
||||
|
||||
api.Perform(req);
|
||||
});
|
||||
|
||||
AddStep("set spotlights", () =>
|
||||
{
|
||||
if (spotlights != null)
|
||||
selector.Spotlights = spotlights;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
@ -12,6 +13,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Profile.Sections;
|
||||
using osu.Game.Overlays.Profile.Sections.Recent;
|
||||
|
||||
@ -28,6 +30,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(MedalIcon)
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||
|
||||
public TestSceneUserProfileRecentSection()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
@ -131,6 +136,22 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Beatmap = dummyBeatmap,
|
||||
},
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.Rank,
|
||||
Rank = 1,
|
||||
Mode = "vitaru",
|
||||
Beatmap = dummyBeatmap,
|
||||
},
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.Rank,
|
||||
Rank = 1,
|
||||
Mode = "fruits",
|
||||
Beatmap = dummyBeatmap,
|
||||
},
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.RankLost,
|
||||
|
101
osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs
Normal file
101
osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs
Normal file
@ -0,0 +1,101 @@
|
||||
// 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.Game.Overlays.Profile.Sections;
|
||||
using osu.Game.Overlays.Profile.Sections.Ranks;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osuTK;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneUserProfileScores : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(DrawableProfileScore),
|
||||
typeof(DrawableProfileWeightedScore),
|
||||
typeof(ProfileItemContainer),
|
||||
};
|
||||
|
||||
public TestSceneUserProfileScores()
|
||||
{
|
||||
var score = new ScoreInfo
|
||||
{
|
||||
PP = 134.32,
|
||||
Rank = ScoreRank.A,
|
||||
Beatmap = new BeatmapInfo
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = "Triumph & Regret",
|
||||
Artist = "typeMARS"
|
||||
},
|
||||
Version = "[4K] Regret"
|
||||
},
|
||||
Date = DateTimeOffset.Now,
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new OsuModHardRock(),
|
||||
new OsuModDoubleTime(),
|
||||
},
|
||||
Accuracy = 0.998546
|
||||
};
|
||||
|
||||
var noPPScore = new ScoreInfo
|
||||
{
|
||||
Rank = ScoreRank.B,
|
||||
Beatmap = new BeatmapInfo
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = "C18H27NO3(extend)",
|
||||
Artist = "Team Grimoire"
|
||||
},
|
||||
Version = "[4K] Cataclysmic Hypernova"
|
||||
},
|
||||
Date = DateTimeOffset.Now,
|
||||
Accuracy = 0.55879
|
||||
};
|
||||
|
||||
Add(new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 10),
|
||||
Children = new[]
|
||||
{
|
||||
new ColourProvidedContainer(OverlayColourScheme.Green, new DrawableProfileScore(score)),
|
||||
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(noPPScore)),
|
||||
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(score, 0.85))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class ColourProvidedContainer : Container
|
||||
{
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider;
|
||||
|
||||
public ColourProvidedContainer(OverlayColourScheme colourScheme, DrawableProfileScore score)
|
||||
{
|
||||
colourProvider = new OverlayColourProvider(colourScheme);
|
||||
|
||||
AutoSizeAxes = Axes.Y;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Add(score);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,11 +4,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Profile.Sections;
|
||||
using osu.Game.Overlays.Profile.Sections.Ranks;
|
||||
using osu.Game.Users;
|
||||
@ -20,7 +22,15 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(DrawableProfileScore), typeof(RanksSection) };
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(DrawableProfileScore),
|
||||
typeof(DrawableProfileWeightedScore),
|
||||
typeof(RanksSection)
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||
|
||||
public TestSceneUserRanks()
|
||||
{
|
||||
|
175
osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs
Normal file
175
osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs
Normal file
@ -0,0 +1,175 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Select.Details;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.SongSelect
|
||||
{
|
||||
[System.ComponentModel.Description("Advanced beatmap statistics display")]
|
||||
public class TestSceneAdvancedStats : OsuTestScene
|
||||
{
|
||||
private TestAdvancedStats advancedStats;
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() => Child = advancedStats = new TestAdvancedStats
|
||||
{
|
||||
Width = 500
|
||||
});
|
||||
|
||||
private BeatmapInfo exampleBeatmapInfo => new BeatmapInfo
|
||||
{
|
||||
RulesetID = 0,
|
||||
Ruleset = rulesets.AvailableRulesets.First(),
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 7.2f,
|
||||
DrainRate = 3,
|
||||
OverallDifficulty = 5.7f,
|
||||
ApproachRate = 3.5f
|
||||
},
|
||||
StarDifficulty = 4.5f
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestNoMod()
|
||||
{
|
||||
AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
|
||||
|
||||
AddStep("no mods selected", () => SelectedMods.Value = Array.Empty<Mod>());
|
||||
|
||||
AddAssert("first bar text is Circle Size", () => advancedStats.ChildrenOfType<SpriteText>().First().Text == "Circle Size");
|
||||
AddAssert("circle size bar is white", () => barIsWhite(advancedStats.FirstValue));
|
||||
AddAssert("HP drain bar is white", () => barIsWhite(advancedStats.HpDrain));
|
||||
AddAssert("accuracy bar is white", () => barIsWhite(advancedStats.Accuracy));
|
||||
AddAssert("approach rate bar is white", () => barIsWhite(advancedStats.ApproachRate));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestManiaFirstBarText()
|
||||
{
|
||||
AddStep("set beatmap", () => advancedStats.Beatmap = new BeatmapInfo
|
||||
{
|
||||
Ruleset = rulesets.GetRuleset(3),
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 5,
|
||||
DrainRate = 4.3f,
|
||||
OverallDifficulty = 4.5f,
|
||||
ApproachRate = 3.1f
|
||||
},
|
||||
StarDifficulty = 8
|
||||
});
|
||||
|
||||
AddAssert("first bar text is Key Count", () => advancedStats.ChildrenOfType<SpriteText>().First().Text == "Key Count");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEasyMod()
|
||||
{
|
||||
AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
|
||||
|
||||
AddStep("select EZ mod", () =>
|
||||
{
|
||||
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
|
||||
SelectedMods.Value = new[] { ruleset.GetAllMods().OfType<ModEasy>().Single() };
|
||||
});
|
||||
|
||||
AddAssert("circle size bar is blue", () => barIsBlue(advancedStats.FirstValue));
|
||||
AddAssert("HP drain bar is blue", () => barIsBlue(advancedStats.HpDrain));
|
||||
AddAssert("accuracy bar is blue", () => barIsBlue(advancedStats.Accuracy));
|
||||
AddAssert("approach rate bar is blue", () => barIsBlue(advancedStats.ApproachRate));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHardRockMod()
|
||||
{
|
||||
AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
|
||||
|
||||
AddStep("select HR mod", () =>
|
||||
{
|
||||
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
|
||||
SelectedMods.Value = new[] { ruleset.GetAllMods().OfType<ModHardRock>().Single() };
|
||||
});
|
||||
|
||||
AddAssert("circle size bar is red", () => barIsRed(advancedStats.FirstValue));
|
||||
AddAssert("HP drain bar is red", () => barIsRed(advancedStats.HpDrain));
|
||||
AddAssert("accuracy bar is red", () => barIsRed(advancedStats.Accuracy));
|
||||
AddAssert("approach rate bar is red", () => barIsRed(advancedStats.ApproachRate));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUnchangedDifficultyAdjustMod()
|
||||
{
|
||||
AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
|
||||
|
||||
AddStep("select unchanged Difficulty Adjust mod", () =>
|
||||
{
|
||||
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
|
||||
var difficultyAdjustMod = ruleset.GetAllMods().OfType<ModDifficultyAdjust>().Single();
|
||||
difficultyAdjustMod.ReadFromDifficulty(advancedStats.Beatmap.BaseDifficulty);
|
||||
SelectedMods.Value = new[] { difficultyAdjustMod };
|
||||
});
|
||||
|
||||
AddAssert("circle size bar is white", () => barIsWhite(advancedStats.FirstValue));
|
||||
AddAssert("HP drain bar is white", () => barIsWhite(advancedStats.HpDrain));
|
||||
AddAssert("accuracy bar is white", () => barIsWhite(advancedStats.Accuracy));
|
||||
AddAssert("approach rate bar is white", () => barIsWhite(advancedStats.ApproachRate));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChangedDifficultyAdjustMod()
|
||||
{
|
||||
AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
|
||||
|
||||
AddStep("select changed Difficulty Adjust mod", () =>
|
||||
{
|
||||
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
|
||||
var difficultyAdjustMod = ruleset.GetAllMods().OfType<ModDifficultyAdjust>().Single();
|
||||
var originalDifficulty = advancedStats.Beatmap.BaseDifficulty;
|
||||
var adjustedDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = originalDifficulty.CircleSize,
|
||||
DrainRate = originalDifficulty.DrainRate - 0.5f,
|
||||
OverallDifficulty = originalDifficulty.OverallDifficulty,
|
||||
ApproachRate = originalDifficulty.ApproachRate + 2.2f,
|
||||
};
|
||||
difficultyAdjustMod.ReadFromDifficulty(adjustedDifficulty);
|
||||
SelectedMods.Value = new[] { difficultyAdjustMod };
|
||||
});
|
||||
|
||||
AddAssert("circle size bar is white", () => barIsWhite(advancedStats.FirstValue));
|
||||
AddAssert("drain rate bar is blue", () => barIsBlue(advancedStats.HpDrain));
|
||||
AddAssert("accuracy bar is white", () => barIsWhite(advancedStats.Accuracy));
|
||||
AddAssert("approach rate bar is red", () => barIsRed(advancedStats.ApproachRate));
|
||||
}
|
||||
|
||||
private bool barIsWhite(AdvancedStats.StatisticRow row) => row.ModBar.AccentColour == Color4.White;
|
||||
private bool barIsBlue(AdvancedStats.StatisticRow row) => row.ModBar.AccentColour == colours.BlueDark;
|
||||
private bool barIsRed(AdvancedStats.StatisticRow row) => row.ModBar.AccentColour == colours.Red;
|
||||
|
||||
private class TestAdvancedStats : AdvancedStats
|
||||
{
|
||||
public new StatisticRow FirstValue => base.FirstValue;
|
||||
public new StatisticRow HpDrain => base.HpDrain;
|
||||
public new StatisticRow Accuracy => base.Accuracy;
|
||||
public new StatisticRow ApproachRate => base.ApproachRate;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,14 +3,8 @@
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Select;
|
||||
|
||||
namespace osu.Game.Tests.Visual.SongSelect
|
||||
@ -180,27 +174,5 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
OnlineBeatmapID = 162,
|
||||
});
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
|
||||
[Test]
|
||||
public void TestModAdjustments()
|
||||
{
|
||||
TestAllMetrics();
|
||||
|
||||
Ruleset ruleset = rulesets.AvailableRulesets.First().CreateInstance();
|
||||
|
||||
AddStep("with EZ mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModEasy) });
|
||||
|
||||
AddAssert("first bar coloured blue", () => details.ChildrenOfType<Bar>().Skip(1).First().AccentColour == colours.BlueDark);
|
||||
|
||||
AddStep("with HR mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModHardRock) });
|
||||
|
||||
AddAssert("first bar coloured red", () => details.ChildrenOfType<Bar>().Skip(1).First().AccentColour == colours.Red);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Taiko;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Screens.Select.Carousel;
|
||||
using osu.Game.Screens.Select.Filter;
|
||||
@ -72,19 +73,23 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
// required to get bindables attached
|
||||
Add(music);
|
||||
|
||||
Beatmap.SetDefault();
|
||||
|
||||
Dependencies.Cache(config = new OsuConfigManager(LocalStorage));
|
||||
}
|
||||
|
||||
private OsuConfigManager config;
|
||||
|
||||
[SetUp]
|
||||
public virtual void SetUp() => Schedule(() =>
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
Ruleset.Value = new OsuRuleset().RulesetInfo;
|
||||
manager?.Delete(manager.GetAllUsableBeatmapSets());
|
||||
});
|
||||
base.SetUpSteps();
|
||||
|
||||
AddStep("delete all beatmaps", () =>
|
||||
{
|
||||
Ruleset.Value = new OsuRuleset().RulesetInfo;
|
||||
manager?.Delete(manager.GetAllUsableBeatmapSets());
|
||||
|
||||
Beatmap.SetDefault();
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSingleFilterOnEnter()
|
||||
@ -118,10 +123,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
InputManager.ReleaseKey(Key.Enter);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
|
||||
AddAssert("ensure selection changed", () => selected != Beatmap.Value);
|
||||
|
||||
AddUntilStep("wait for return to song select", () => songSelect.IsCurrentScreen());
|
||||
AddUntilStep("bindable lease returned", () => !Beatmap.Disabled);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -145,10 +148,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
InputManager.ReleaseKey(Key.Down);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
|
||||
AddAssert("ensure selection didn't change", () => selected == Beatmap.Value);
|
||||
|
||||
AddUntilStep("wait for return to song select", () => songSelect.IsCurrentScreen());
|
||||
AddUntilStep("bindable lease returned", () => !Beatmap.Disabled);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -176,10 +177,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
InputManager.ReleaseKey(Key.Enter);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
|
||||
AddAssert("ensure selection changed", () => selected != Beatmap.Value);
|
||||
|
||||
AddUntilStep("wait for return to song select", () => songSelect.IsCurrentScreen());
|
||||
AddUntilStep("bindable lease returned", () => !Beatmap.Disabled);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -208,10 +207,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
InputManager.ReleaseButton(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
|
||||
AddAssert("ensure selection didn't change", () => selected == Beatmap.Value);
|
||||
|
||||
AddUntilStep("wait for return to song select", () => songSelect.IsCurrentScreen());
|
||||
AddUntilStep("bindable lease returned", () => !Beatmap.Disabled);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -429,6 +426,31 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddAssert("start not requested", () => !startRequested);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAutoplayViaCtrlEnter()
|
||||
{
|
||||
addRulesetImportStep(0);
|
||||
|
||||
createSongSelect();
|
||||
|
||||
AddStep("press ctrl+enter", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.ControlLeft);
|
||||
InputManager.PressKey(Key.Enter);
|
||||
|
||||
InputManager.ReleaseKey(Key.ControlLeft);
|
||||
InputManager.ReleaseKey(Key.Enter);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for player", () => Stack.CurrentScreen is PlayerLoader);
|
||||
|
||||
AddAssert("autoplay enabled", () => songSelect.Mods.Value.FirstOrDefault() is ModAutoplay);
|
||||
|
||||
AddUntilStep("wait for return to ss", () => songSelect.IsCurrentScreen());
|
||||
|
||||
AddAssert("mod disabled", () => songSelect.Mods.Value.Count == 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHideSetSelectsCorrectBeatmap()
|
||||
{
|
||||
|
@ -16,7 +16,8 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(FooterButtonMods)
|
||||
typeof(FooterButtonMods),
|
||||
typeof(FooterButton)
|
||||
};
|
||||
|
||||
private readonly TestFooterButtonMods footerButtonMods;
|
||||
|
@ -60,9 +60,9 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
modSelect = new TestModSelectOverlay
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Origin = Anchor.BottomCentre,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
SelectedMods = { BindTarget = SelectedMods }
|
||||
},
|
||||
|
||||
modDisplay = new ModDisplay
|
||||
|
@ -27,6 +27,13 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
private readonly Mod testCustomisableAutoOpenMod = new TestModCustomisable2();
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
SelectedMods.Value = Array.Empty<Mod>();
|
||||
Ruleset.Value = new TestRulesetInfo();
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestButtonShowsOnCustomisableMod()
|
||||
{
|
||||
@ -70,13 +77,11 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
AddStep("create mod select", () =>
|
||||
{
|
||||
Ruleset.Value = new TestRulesetInfo();
|
||||
|
||||
Child = modSelect = new TestModSelectOverlay
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Origin = Anchor.BottomCentre,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
SelectedMods = { BindTarget = SelectedMods }
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
addHeader("Orange OverlayHeader (no background)", new TestNoBackgroundHeader(), OverlayColourScheme.Orange);
|
||||
addHeader("Blue OverlayHeader", new TestNoControlHeader(), OverlayColourScheme.Blue);
|
||||
addHeader("Green TabControlOverlayHeader (string)", new TestStringTabControlHeader(), OverlayColourScheme.Green);
|
||||
addHeader("Green TabControlOverlayHeader (string) with ruleset selector", new TestStringTabControlHeader(), OverlayColourScheme.Green);
|
||||
addHeader("Pink TabControlOverlayHeader (enum)", new TestEnumTabControlHeader(), OverlayColourScheme.Pink);
|
||||
addHeader("Red BreadcrumbControlOverlayHeader (no background)", new TestBreadcrumbControlHeader(), OverlayColourScheme.Red);
|
||||
}
|
||||
@ -116,6 +116,8 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
protected override ScreenTitle CreateTitle() => new TestTitle();
|
||||
|
||||
protected override Drawable CreateTitleContent() => new OverlayRulesetSelector();
|
||||
|
||||
public TestStringTabControlHeader()
|
||||
{
|
||||
TabControl.AddItem("tab1");
|
||||
|
@ -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.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Taiko;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osuTK;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneOverlayRulesetSelector : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(OverlayRulesetSelector),
|
||||
typeof(OverlayRulesetTabItem),
|
||||
};
|
||||
|
||||
private readonly OverlayRulesetSelector selector;
|
||||
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
|
||||
|
||||
public TestSceneOverlayRulesetSelector()
|
||||
{
|
||||
Add(new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 5),
|
||||
Children = new[]
|
||||
{
|
||||
new ColourProvidedContainer(OverlayColourScheme.Green, selector = new OverlayRulesetSelector { Current = ruleset }),
|
||||
new ColourProvidedContainer(OverlayColourScheme.Blue, new OverlayRulesetSelector { Current = ruleset }),
|
||||
new ColourProvidedContainer(OverlayColourScheme.Orange, new OverlayRulesetSelector { Current = ruleset }),
|
||||
new ColourProvidedContainer(OverlayColourScheme.Pink, new OverlayRulesetSelector { Current = ruleset }),
|
||||
new ColourProvidedContainer(OverlayColourScheme.Purple, new OverlayRulesetSelector { Current = ruleset }),
|
||||
new ColourProvidedContainer(OverlayColourScheme.Red, new OverlayRulesetSelector { Current = ruleset }),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class ColourProvidedContainer : Container
|
||||
{
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider;
|
||||
|
||||
public ColourProvidedContainer(OverlayColourScheme colourScheme, OverlayRulesetSelector rulesetSelector)
|
||||
{
|
||||
colourProvider = new OverlayColourProvider(colourScheme);
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Add(rulesetSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSelection()
|
||||
{
|
||||
AddStep("Select osu!", () => ruleset.Value = new OsuRuleset().RulesetInfo);
|
||||
AddAssert("Check osu! selected", () => selector.Current.Value.Equals(new OsuRuleset().RulesetInfo));
|
||||
|
||||
AddStep("Select mania", () => ruleset.Value = new ManiaRuleset().RulesetInfo);
|
||||
AddAssert("Check mania selected", () => selector.Current.Value.Equals(new ManiaRuleset().RulesetInfo));
|
||||
|
||||
AddStep("Select taiko", () => ruleset.Value = new TaikoRuleset().RulesetInfo);
|
||||
AddAssert("Check taiko selected", () => selector.Current.Value.Equals(new TaikoRuleset().RulesetInfo));
|
||||
|
||||
AddStep("Select catch", () => ruleset.Value = new CatchRuleset().RulesetInfo);
|
||||
AddAssert("Check catch selected", () => selector.Current.Value.Equals(new CatchRuleset().RulesetInfo));
|
||||
}
|
||||
}
|
||||
}
|
@ -25,7 +25,9 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
OsuSpriteText titleText;
|
||||
|
||||
IScreen startScreen = new TestScreenOne();
|
||||
screenStack = new OsuScreenStack(startScreen) { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
screenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both };
|
||||
screenStack.Push(startScreen);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
|
@ -29,9 +29,9 @@ namespace osu.Game.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
public DrawableDate(DateTimeOffset date)
|
||||
public DrawableDate(DateTimeOffset date, float textSize = OsuFont.DEFAULT_FONT_SIZE, bool italic = true)
|
||||
{
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Regular, italics: true);
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Regular, size: textSize, italics: italic);
|
||||
Date = date;
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,11 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
public virtual string TooltipText { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to format the tooltip as a percentage or the actual value.
|
||||
/// </summary>
|
||||
public bool DisplayAsPercentage { get; set; }
|
||||
|
||||
private Color4 accentColour;
|
||||
|
||||
public Color4 AccentColour
|
||||
@ -169,11 +174,11 @@ namespace osu.Game.Graphics.UserInterface
|
||||
else
|
||||
{
|
||||
double floatValue = value.ToDouble(NumberFormatInfo.InvariantInfo);
|
||||
double floatMinValue = CurrentNumber.MinValue.ToDouble(NumberFormatInfo.InvariantInfo);
|
||||
double floatMaxValue = CurrentNumber.MaxValue.ToDouble(NumberFormatInfo.InvariantInfo);
|
||||
|
||||
if (floatMaxValue == 1 && floatMinValue >= -1)
|
||||
TooltipText = floatValue.ToString("P0");
|
||||
if (DisplayAsPercentage)
|
||||
{
|
||||
TooltipText = floatValue.ToString("0%");
|
||||
}
|
||||
else
|
||||
{
|
||||
var decimalPrecision = normalise(CurrentNumber.Precision.ToDecimal(NumberFormatInfo.InvariantInfo), max_decimal_digits);
|
||||
|
@ -17,7 +17,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
stack.ScreenPushed += onPushed;
|
||||
stack.ScreenExited += onExited;
|
||||
|
||||
onPushed(null, stack.CurrentScreen);
|
||||
if (stack.CurrentScreen != null)
|
||||
onPushed(null, stack.CurrentScreen);
|
||||
|
||||
Current.ValueChanged += current => current.NewValue.MakeCurrent();
|
||||
}
|
||||
|
@ -40,13 +40,14 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
public ShowMoreButton()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Height = 30;
|
||||
Width = 140;
|
||||
}
|
||||
|
||||
protected override Drawable CreateContent() => new CircularContainer
|
||||
{
|
||||
Masking = true,
|
||||
Size = new Vector2(140, 30),
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
|
20
osu.Game/Online/API/Requests/GetSpotlightsRequest.cs
Normal file
20
osu.Game/Online/API/Requests/GetSpotlightsRequest.cs
Normal file
@ -0,0 +1,20 @@
|
||||
// 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 Newtonsoft.Json;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetSpotlightsRequest : APIRequest<SpotlightsCollection>
|
||||
{
|
||||
protected override string Target => "spotlights";
|
||||
}
|
||||
|
||||
public class SpotlightsCollection
|
||||
{
|
||||
[JsonProperty("spotlights")]
|
||||
public List<APISpotlight> Spotlights;
|
||||
}
|
||||
}
|
31
osu.Game/Online/API/Requests/Responses/APISpotlight.cs
Normal file
31
osu.Game/Online/API/Requests/Responses/APISpotlight.cs
Normal file
@ -0,0 +1,31 @@
|
||||
// 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 Newtonsoft.Json;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APISpotlight
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public int Id;
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name;
|
||||
|
||||
[JsonProperty("type")]
|
||||
public string Type;
|
||||
|
||||
[JsonProperty("mode_specific")]
|
||||
public bool ModeSpecific;
|
||||
|
||||
[JsonProperty(@"start_date")]
|
||||
public DateTimeOffset StartDate;
|
||||
|
||||
[JsonProperty(@"end_date")]
|
||||
public DateTimeOffset EndDate;
|
||||
|
||||
public override string ToString() => Name;
|
||||
}
|
||||
}
|
@ -6,8 +6,6 @@ using osu.Game.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
@ -70,12 +68,10 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
|
||||
public bool IsDeleted => DeletedAt.HasValue;
|
||||
|
||||
public bool HasMessage => !string.IsNullOrEmpty(MessageHtml);
|
||||
public bool HasMessage => !string.IsNullOrEmpty(Message);
|
||||
|
||||
public bool IsVoted { get; set; }
|
||||
|
||||
public string GetMessage => HasMessage ? WebUtility.HtmlDecode(Regex.Replace(MessageHtml, @"<(.|\n)*?>", string.Empty)) : string.Empty;
|
||||
|
||||
public int DeletedChildrenCount => ChildComments.Count(c => c.IsDeleted);
|
||||
}
|
||||
}
|
||||
|
@ -47,17 +47,18 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
[JsonProperty(@"included_comments")]
|
||||
public List<Comment> IncludedComments { get; set; }
|
||||
|
||||
private List<long> userVotes;
|
||||
|
||||
[JsonProperty(@"user_votes")]
|
||||
private List<long> userVotes
|
||||
public List<long> UserVotes
|
||||
{
|
||||
set => value.ForEach(v =>
|
||||
get => userVotes;
|
||||
set
|
||||
{
|
||||
Comments.ForEach(c =>
|
||||
{
|
||||
if (v == c.Id)
|
||||
c.IsVoted = true;
|
||||
});
|
||||
});
|
||||
userVotes = value;
|
||||
|
||||
Comments.ForEach(c => c.IsVoted = value.Contains(c.Id));
|
||||
}
|
||||
}
|
||||
|
||||
private List<User> users;
|
||||
|
@ -277,7 +277,7 @@ namespace osu.Game.Online.Leaderboards
|
||||
protected virtual IEnumerable<LeaderboardScoreStatistic> GetStatistics(ScoreInfo model) => new[]
|
||||
{
|
||||
new LeaderboardScoreStatistic(FontAwesome.Solid.Link, "Max Combo", model.MaxCombo.ToString()),
|
||||
new LeaderboardScoreStatistic(FontAwesome.Solid.Crosshairs, "Accuracy", string.Format(model.Accuracy % 1 == 0 ? @"{0:P0}" : @"{0:P2}", model.Accuracy))
|
||||
new LeaderboardScoreStatistic(FontAwesome.Solid.Crosshairs, "Accuracy", model.DisplayAccuracy)
|
||||
};
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
|
@ -327,10 +327,10 @@ namespace osu.Game
|
||||
return;
|
||||
}
|
||||
|
||||
performFromMainMenu(() =>
|
||||
PerformFromScreen(screen =>
|
||||
{
|
||||
// we might already be at song select, so a check is required before performing the load to solo.
|
||||
if (menuScreen.IsCurrentScreen())
|
||||
if (screen is MainMenu)
|
||||
menuScreen.LoadToSolo();
|
||||
|
||||
// we might even already be at the song
|
||||
@ -344,7 +344,7 @@ namespace osu.Game
|
||||
|
||||
Ruleset.Value = first.Ruleset;
|
||||
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(first);
|
||||
}, $"load {beatmap}", bypassScreenAllowChecks: true, targetScreen: typeof(PlaySongSelect));
|
||||
}, validScreens: new[] { typeof(PlaySongSelect) });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -381,12 +381,12 @@ namespace osu.Game
|
||||
return;
|
||||
}
|
||||
|
||||
performFromMainMenu(() =>
|
||||
PerformFromScreen(screen =>
|
||||
{
|
||||
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap);
|
||||
|
||||
menuScreen.Push(new ReplayPlayerLoader(databasedScore));
|
||||
}, $"watch {databasedScoreInfo}", bypassScreenAllowChecks: true);
|
||||
screen.Push(new ReplayPlayerLoader(databasedScore));
|
||||
}, validScreens: new[] { typeof(PlaySongSelect) });
|
||||
}
|
||||
|
||||
protected virtual Loader CreateLoader() => new Loader();
|
||||
@ -441,53 +441,42 @@ namespace osu.Game
|
||||
private ScheduledDelegate performFromMainMenuTask;
|
||||
|
||||
/// <summary>
|
||||
/// Perform an action only after returning to the main menu.
|
||||
/// Perform an action only after returning to a specific screen as indicated by <paramref name="validScreens"/>.
|
||||
/// Eagerly tries to exit the current screen until it succeeds.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to perform once we are in the correct state.</param>
|
||||
/// <param name="taskName">The task name to display in a notification (if we can't immediately reach the main menu state).</param>
|
||||
/// <param name="targetScreen">An optional target screen type. If this screen is already current we can immediately perform the action without returning to the menu.</param>
|
||||
/// <param name="bypassScreenAllowChecks">Whether checking <see cref="IOsuScreen.AllowExternalScreenChange"/> should be bypassed.</param>
|
||||
private void performFromMainMenu(Action action, string taskName, Type targetScreen = null, bool bypassScreenAllowChecks = false)
|
||||
/// <param name="validScreens">An optional collection of valid screen types. If any of these screens are already current we can perform the action immediately, else the first valid parent will be made current before performing the action. <see cref="MainMenu"/> is used if not specified.</param>
|
||||
protected void PerformFromScreen(Action<IScreen> action, IEnumerable<Type> validScreens = null)
|
||||
{
|
||||
performFromMainMenuTask?.Cancel();
|
||||
|
||||
// if the current screen does not allow screen changing, give the user an option to try again later.
|
||||
if (!bypassScreenAllowChecks && (ScreenStack.CurrentScreen as IOsuScreen)?.AllowExternalScreenChange == false)
|
||||
{
|
||||
notifications.Post(new SimpleNotification
|
||||
{
|
||||
Text = $"Click here to {taskName}",
|
||||
Activated = () =>
|
||||
{
|
||||
performFromMainMenu(action, taskName, targetScreen, true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
validScreens ??= Enumerable.Empty<Type>();
|
||||
validScreens = validScreens.Append(typeof(MainMenu));
|
||||
|
||||
CloseAllOverlays(false);
|
||||
|
||||
// we may already be at the target screen type.
|
||||
if (targetScreen != null && ScreenStack.CurrentScreen?.GetType() == targetScreen)
|
||||
if (validScreens.Contains(ScreenStack.CurrentScreen?.GetType()) && !Beatmap.Disabled)
|
||||
{
|
||||
action();
|
||||
action(ScreenStack.CurrentScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
// all conditions have been met to continue with the action.
|
||||
if (menuScreen?.IsCurrentScreen() == true && !Beatmap.Disabled)
|
||||
// find closest valid target
|
||||
IScreen screen = ScreenStack.CurrentScreen;
|
||||
|
||||
while (screen != null)
|
||||
{
|
||||
action();
|
||||
return;
|
||||
if (validScreens.Contains(screen.GetType()))
|
||||
{
|
||||
screen.MakeCurrent();
|
||||
break;
|
||||
}
|
||||
|
||||
screen = screen.GetParentScreen();
|
||||
}
|
||||
|
||||
// menuScreen may not be initialised yet (null check required).
|
||||
menuScreen?.MakeCurrent();
|
||||
|
||||
performFromMainMenuTask = Schedule(() => performFromMainMenu(action, taskName));
|
||||
performFromMainMenuTask = Schedule(() => PerformFromScreen(action, validScreens));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -2,17 +2,14 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
public class BeatmapRulesetSelector : RulesetSelector
|
||||
public class BeatmapRulesetSelector : OverlayRulesetSelector
|
||||
{
|
||||
private readonly Bindable<BeatmapSetInfo> beatmapSet = new Bindable<BeatmapSetInfo>();
|
||||
|
||||
@ -28,21 +25,9 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
}
|
||||
}
|
||||
|
||||
public BeatmapRulesetSelector()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
protected override TabItem<RulesetInfo> CreateTabItem(RulesetInfo value) => new BeatmapRulesetTabItem(value)
|
||||
{
|
||||
BeatmapSet = { BindTarget = beatmapSet }
|
||||
};
|
||||
|
||||
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10, 0),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -3,143 +3,74 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
public class BeatmapRulesetTabItem : TabItem<RulesetInfo>
|
||||
public class BeatmapRulesetTabItem : OverlayRulesetTabItem
|
||||
{
|
||||
private readonly OsuSpriteText name, count;
|
||||
private readonly Box bar;
|
||||
|
||||
public readonly Bindable<BeatmapSetInfo> BeatmapSet = new Bindable<BeatmapSetInfo>();
|
||||
|
||||
public override bool PropagatePositionalInputSubTree => Enabled.Value && !Active.Value && base.PropagatePositionalInputSubTree;
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
private OsuSpriteText count;
|
||||
private Container countContainer;
|
||||
|
||||
public BeatmapRulesetTabItem(RulesetInfo value)
|
||||
: base(value)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
FillFlowContainer nameContainer;
|
||||
|
||||
Children = new Drawable[]
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Add(countContainer = new Container
|
||||
{
|
||||
nameContainer = new FillFlowContainer
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Masking = true,
|
||||
CornerRadius = 4f,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Margin = new MarginPadding { Bottom = 7.5f },
|
||||
Spacing = new Vector2(2.5f),
|
||||
Children = new Drawable[]
|
||||
new Box
|
||||
{
|
||||
name = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Text = value.Name,
|
||||
Font = OsuFont.Default.With(size: 18),
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
CornerRadius = 4f,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black.Opacity(0.5f),
|
||||
},
|
||||
count = new OsuSpriteText
|
||||
{
|
||||
Alpha = 0,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Margin = new MarginPadding { Horizontal = 5f },
|
||||
Font = OsuFont.Default.With(weight: FontWeight.SemiBold),
|
||||
}
|
||||
}
|
||||
}
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background6
|
||||
},
|
||||
count = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Margin = new MarginPadding { Horizontal = 5f },
|
||||
Font = OsuFont.Default.With(weight: FontWeight.SemiBold),
|
||||
Colour = colourProvider.Foreground1,
|
||||
}
|
||||
},
|
||||
bar = new Box
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
},
|
||||
new HoverClickSounds(),
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
BeatmapSet.BindValueChanged(setInfo =>
|
||||
{
|
||||
var beatmapsCount = setInfo.NewValue?.Beatmaps.Count(b => b.Ruleset.Equals(Value)) ?? 0;
|
||||
|
||||
count.Text = beatmapsCount.ToString();
|
||||
count.Alpha = beatmapsCount > 0 ? 1f : 0f;
|
||||
countContainer.FadeTo(beatmapsCount > 0 ? 1 : 0);
|
||||
|
||||
Enabled.Value = beatmapsCount > 0;
|
||||
}, true);
|
||||
|
||||
Enabled.BindValueChanged(v => nameContainer.Alpha = v.NewValue ? 1f : 0.5f, true);
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colour { get; set; }
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
count.Colour = colour.Gray9;
|
||||
bar.Colour = colour.Blue;
|
||||
|
||||
updateState();
|
||||
}
|
||||
|
||||
private void updateState()
|
||||
{
|
||||
var isHoveredOrActive = IsHovered || Active.Value;
|
||||
|
||||
bar.ResizeHeightTo(isHoveredOrActive ? 4 : 0, 200, Easing.OutQuint);
|
||||
|
||||
name.Colour = isHoveredOrActive ? colour.GrayE : colour.GrayC;
|
||||
name.Font = name.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Regular);
|
||||
}
|
||||
|
||||
#region Hovering and activation logic
|
||||
|
||||
protected override void OnActivated() => updateState();
|
||||
|
||||
protected override void OnDeactivated() => updateState();
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
updateState();
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e) => updateState();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
35
osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs
Normal file
35
osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs
Normal file
@ -0,0 +1,35 @@
|
||||
// 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.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
public class BeatmapSetHeader : OverlayHeader
|
||||
{
|
||||
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||
|
||||
public BeatmapRulesetSelector RulesetSelector { get; private set; }
|
||||
|
||||
protected override ScreenTitle CreateTitle() => new BeatmapHeaderTitle();
|
||||
|
||||
protected override Drawable CreateTitleContent() => RulesetSelector = new BeatmapRulesetSelector
|
||||
{
|
||||
Current = Ruleset
|
||||
};
|
||||
|
||||
private class BeatmapHeaderTitle : ScreenTitle
|
||||
{
|
||||
public BeatmapHeaderTitle()
|
||||
{
|
||||
Title = @"beatmap";
|
||||
Section = @"info";
|
||||
}
|
||||
|
||||
protected override Drawable CreateIcon() => new ScreenTitleTextureIcon(@"Icons/changelog");
|
||||
}
|
||||
}
|
||||
}
|
@ -26,11 +26,9 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
public class Header : BeatmapDownloadTrackingComposite
|
||||
{
|
||||
private const float transition_duration = 200;
|
||||
private const float tabs_height = 50;
|
||||
private const float buttons_height = 45;
|
||||
private const float buttons_spacing = 5;
|
||||
|
||||
private readonly Box tabsBg;
|
||||
private readonly UpdateableBeatmapSetCover cover;
|
||||
private readonly OsuSpriteText title, artist;
|
||||
private readonly AuthorInfo author;
|
||||
@ -41,14 +39,13 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
public bool DownloadButtonsVisible => downloadButtonsContainer.Any();
|
||||
|
||||
public readonly BeatmapRulesetSelector RulesetSelector;
|
||||
public BeatmapRulesetSelector RulesetSelector => beatmapSetHeader.RulesetSelector;
|
||||
public readonly BeatmapPicker Picker;
|
||||
|
||||
private readonly FavouriteButton favouriteButton;
|
||||
|
||||
private readonly FillFlowContainer fadeContent;
|
||||
|
||||
private readonly LoadingAnimation loading;
|
||||
private readonly BeatmapSetHeader beatmapSetHeader;
|
||||
|
||||
[Cached(typeof(IBindable<RulesetInfo>))]
|
||||
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
|
||||
@ -69,154 +66,145 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
InternalChild = new FillFlowContainer
|
||||
{
|
||||
new Container
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = tabs_height,
|
||||
Children = new Drawable[]
|
||||
beatmapSetHeader = new BeatmapSetHeader
|
||||
{
|
||||
tabsBg = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
RulesetSelector = new BeatmapRulesetSelector
|
||||
{
|
||||
Current = ruleset,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
}
|
||||
Ruleset = { BindTarget = ruleset },
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Top = tabs_height },
|
||||
Children = new Drawable[]
|
||||
new Container
|
||||
{
|
||||
new Container
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
new Container
|
||||
{
|
||||
cover = new UpdateableBeatmapSetCover
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
},
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.3f), Color4.Black.Opacity(0.8f)),
|
||||
},
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Top = 20,
|
||||
Bottom = 30,
|
||||
Left = BeatmapSetOverlay.X_PADDING,
|
||||
Right = BeatmapSetOverlay.X_PADDING + BeatmapSetOverlay.RIGHT_WIDTH,
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
fadeContent = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
cover = new UpdateableBeatmapSetCover
|
||||
{
|
||||
new Container
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
},
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.3f), Color4.Black.Opacity(0.8f)),
|
||||
},
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Top = 20,
|
||||
Bottom = 30,
|
||||
Left = BeatmapSetOverlay.X_PADDING,
|
||||
Right = BeatmapSetOverlay.X_PADDING + BeatmapSetOverlay.RIGHT_WIDTH,
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
fadeContent = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Child = Picker = new BeatmapPicker(),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Horizontal,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
new Container
|
||||
{
|
||||
title = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 37, weight: FontWeight.Bold, italics: true)
|
||||
},
|
||||
externalLink = new ExternalLinkButton
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Margin = new MarginPadding { Left = 3, Bottom = 4 }, //To better lineup with the font
|
||||
},
|
||||
}
|
||||
},
|
||||
artist = new OsuSpriteText { Font = OsuFont.GetFont(size: 25, weight: FontWeight.SemiBold, italics: true) },
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Top = 20 },
|
||||
Child = author = new AuthorInfo(),
|
||||
},
|
||||
beatmapAvailability = new BeatmapAvailability(),
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = buttons_height,
|
||||
Margin = new MarginPadding { Top = 10 },
|
||||
Children = new Drawable[]
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Child = Picker = new BeatmapPicker(),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
favouriteButton = new FavouriteButton
|
||||
Direction = FillDirection.Horizontal,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
BeatmapSet = { BindTarget = BeatmapSet }
|
||||
},
|
||||
downloadButtonsContainer = new FillFlowContainer
|
||||
title = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 37, weight: FontWeight.Bold, italics: true)
|
||||
},
|
||||
externalLink = new ExternalLinkButton
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Margin = new MarginPadding { Left = 3, Bottom = 4 }, //To better lineup with the font
|
||||
},
|
||||
}
|
||||
},
|
||||
artist = new OsuSpriteText { Font = OsuFont.GetFont(size: 25, weight: FontWeight.SemiBold, italics: true) },
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Top = 20 },
|
||||
Child = author = new AuthorInfo(),
|
||||
},
|
||||
beatmapAvailability = new BeatmapAvailability(),
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = buttons_height,
|
||||
Margin = new MarginPadding { Top = 10 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = buttons_height + buttons_spacing },
|
||||
Spacing = new Vector2(buttons_spacing),
|
||||
favouriteButton = new FavouriteButton
|
||||
{
|
||||
BeatmapSet = { BindTarget = BeatmapSet }
|
||||
},
|
||||
downloadButtonsContainer = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = buttons_height + buttons_spacing },
|
||||
Spacing = new Vector2(buttons_spacing),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
loading = new LoadingAnimation
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Scale = new Vector2(1.5f),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding { Top = BeatmapSetOverlay.TOP_PADDING, Right = BeatmapSetOverlay.X_PADDING },
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(10),
|
||||
Children = new Drawable[]
|
||||
}
|
||||
},
|
||||
loading = new LoadingAnimation
|
||||
{
|
||||
onlineStatusPill = new BeatmapSetOnlineStatusPill
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Scale = new Vector2(1.5f),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding { Top = BeatmapSetOverlay.TOP_PADDING, Right = BeatmapSetOverlay.X_PADDING },
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(10),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
TextSize = 14,
|
||||
TextPadding = new MarginPadding { Horizontal = 25, Vertical = 8 }
|
||||
onlineStatusPill = new BeatmapSetOnlineStatusPill
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
TextSize = 14,
|
||||
TextPadding = new MarginPadding { Horizontal = 25, Vertical = 8 }
|
||||
},
|
||||
Details = new Details(),
|
||||
},
|
||||
Details = new Details(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
Picker.Beatmap.ValueChanged += b =>
|
||||
@ -229,8 +217,6 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
tabsBg.Colour = colours.Gray3;
|
||||
|
||||
State.BindValueChanged(_ => updateDownloadButtons());
|
||||
|
||||
BeatmapSet.BindValueChanged(setInfo =>
|
||||
|
@ -116,7 +116,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
new OsuSpriteText
|
||||
{
|
||||
Margin = new MarginPadding { Right = horizontal_inset },
|
||||
Text = $@"{score.Accuracy:P2}",
|
||||
Text = score.DisplayAccuracy,
|
||||
Font = OsuFont.GetFont(size: text_size),
|
||||
Colour = score.Accuracy == 1 ? highAccuracyColour : Color4.White
|
||||
},
|
||||
|
@ -92,7 +92,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
set
|
||||
{
|
||||
totalScoreColumn.Text = $@"{value.TotalScore:N0}";
|
||||
accuracyColumn.Text = $@"{value.Accuracy:P2}";
|
||||
accuracyColumn.Text = value.DisplayAccuracy;
|
||||
maxComboColumn.Text = $@"{value.MaxCombo:N0}x";
|
||||
ppColumn.Text = $@"{value.PP:N0}";
|
||||
|
||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
int playCount = beatmap?.OnlineInfo?.PlayCount ?? 0;
|
||||
|
||||
var rate = playCount != 0 ? (float)passCount / playCount : 0;
|
||||
successPercent.Text = rate.ToString("P0");
|
||||
successPercent.Text = rate.ToString("0%");
|
||||
successRate.Length = rate;
|
||||
percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic);
|
||||
|
||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
public class ChangelogHeader : BreadcrumbControlOverlayHeader
|
||||
{
|
||||
public readonly Bindable<APIChangelogBuild> Current = new Bindable<APIChangelogBuild>();
|
||||
public readonly Bindable<APIChangelogBuild> Build = new Bindable<APIChangelogBuild>();
|
||||
|
||||
public Action ListingSelected;
|
||||
|
||||
@ -25,18 +25,18 @@ namespace osu.Game.Overlays.Changelog
|
||||
public ChangelogHeader()
|
||||
{
|
||||
TabControl.AddItem(listing_string);
|
||||
TabControl.Current.ValueChanged += e =>
|
||||
Current.ValueChanged += e =>
|
||||
{
|
||||
if (e.NewValue == listing_string)
|
||||
ListingSelected?.Invoke();
|
||||
};
|
||||
|
||||
Current.ValueChanged += showBuild;
|
||||
Build.ValueChanged += showBuild;
|
||||
|
||||
Streams.Current.ValueChanged += e =>
|
||||
{
|
||||
if (e.NewValue?.LatestBuild != null && !e.NewValue.Equals(Current.Value?.UpdateStream))
|
||||
Current.Value = e.NewValue.LatestBuild;
|
||||
if (e.NewValue?.LatestBuild != null && !e.NewValue.Equals(Build.Value?.UpdateStream))
|
||||
Build.Value = e.NewValue.LatestBuild;
|
||||
};
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
if (e.NewValue != null)
|
||||
{
|
||||
TabControl.AddItem(e.NewValue.ToString());
|
||||
TabControl.Current.Value = e.NewValue.ToString();
|
||||
Current.Value = e.NewValue.ToString();
|
||||
|
||||
updateCurrentStream();
|
||||
|
||||
@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
}
|
||||
else
|
||||
{
|
||||
TabControl.Current.Value = listing_string;
|
||||
Current.Value = listing_string;
|
||||
Streams.Current.Value = null;
|
||||
title.Version = null;
|
||||
}
|
||||
@ -86,10 +86,10 @@ namespace osu.Game.Overlays.Changelog
|
||||
|
||||
private void updateCurrentStream()
|
||||
{
|
||||
if (Current.Value == null)
|
||||
if (Build.Value == null)
|
||||
return;
|
||||
|
||||
Streams.Current.Value = Streams.Items.FirstOrDefault(s => s.Name == Current.Value.UpdateStream.Name);
|
||||
Streams.Current.Value = Streams.Items.FirstOrDefault(s => s.Name == Build.Value.UpdateStream.Name);
|
||||
}
|
||||
|
||||
private class ChangelogHeaderTitle : ScreenTitle
|
||||
|
@ -78,7 +78,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
sampleBack = audio.Samples.Get(@"UI/generic-select-soft");
|
||||
|
||||
Header.Current.BindTo(Current);
|
||||
Header.Build.BindTo(Current);
|
||||
|
||||
Current.BindValueChanged(e =>
|
||||
{
|
||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
private const float text_size = 15;
|
||||
private const float transition_duration = 100;
|
||||
|
||||
private readonly Channel channel;
|
||||
public readonly Channel Channel;
|
||||
|
||||
private readonly Bindable<bool> joinedBind = new Bindable<bool>();
|
||||
private readonly OsuSpriteText name;
|
||||
@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
private Color4 topicColour;
|
||||
private Color4 hoverColour;
|
||||
|
||||
public IEnumerable<string> FilterTerms => new[] { channel.Name, channel.Topic };
|
||||
public IEnumerable<string> FilterTerms => new[] { Channel.Name, Channel.Topic ?? string.Empty };
|
||||
|
||||
public bool MatchingFilter
|
||||
{
|
||||
@ -50,7 +50,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
|
||||
public ChannelListItem(Channel channel)
|
||||
{
|
||||
this.channel = channel;
|
||||
Channel = channel;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
@ -148,7 +148,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
hoverColour = colours.Yellow;
|
||||
|
||||
joinedBind.ValueChanged += joined => updateColour(joined.NewValue);
|
||||
joinedBind.BindTo(channel.Joined);
|
||||
joinedBind.BindTo(Channel.Joined);
|
||||
|
||||
joinedBind.TriggerChange();
|
||||
FinishTransforms(true);
|
||||
@ -156,7 +156,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
if (!channel.Joined.Value)
|
||||
if (!Channel.Joined.Value)
|
||||
name.FadeColour(hoverColour, 50, Easing.OutQuint);
|
||||
|
||||
return base.OnHover(e);
|
||||
@ -164,7 +164,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
if (!channel.Joined.Value)
|
||||
if (!Channel.Joined.Value)
|
||||
name.FadeColour(Color4.White, transition_duration);
|
||||
}
|
||||
|
||||
|
@ -321,8 +321,10 @@ namespace osu.Game.Overlays
|
||||
|
||||
private void selectTab(int index)
|
||||
{
|
||||
var channel = ChannelTabControl.Items.Skip(index).FirstOrDefault();
|
||||
if (channel != null && !(channel is ChannelSelectorTabItem.ChannelSelectorTabChannel))
|
||||
var channel = ChannelTabControl.Items
|
||||
.Where(tab => !(tab is ChannelSelectorTabItem.ChannelSelectorTabChannel))
|
||||
.ElementAtOrDefault(index);
|
||||
if (channel != null)
|
||||
ChannelTabControl.Current.Value = channel;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Comments
|
||||
private int currentPage;
|
||||
|
||||
private FillFlowContainer content;
|
||||
private DeletedChildrenPlaceholder deletedChildrenPlaceholder;
|
||||
private DeletedCommentsCounter deletedCommentsCounter;
|
||||
private CommentsShowMoreButton moreButton;
|
||||
private TotalCommentsCounter commentCounter;
|
||||
|
||||
@ -68,6 +68,7 @@ namespace osu.Game.Overlays.Comments
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = @"Footer",
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
@ -84,7 +85,7 @@ namespace osu.Game.Overlays.Comments
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
deletedChildrenPlaceholder = new DeletedChildrenPlaceholder
|
||||
deletedCommentsCounter = new DeletedCommentsCounter
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted }
|
||||
},
|
||||
@ -153,7 +154,8 @@ namespace osu.Game.Overlays.Comments
|
||||
private void clearComments()
|
||||
{
|
||||
currentPage = 1;
|
||||
deletedChildrenPlaceholder.DeletedCount.Value = 0;
|
||||
deletedCommentsCounter.Count.Value = 0;
|
||||
moreButton.Show();
|
||||
moreButton.IsLoading = true;
|
||||
content.Clear();
|
||||
}
|
||||
@ -162,29 +164,14 @@ namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
loadCancellation = new CancellationTokenSource();
|
||||
|
||||
var page = new FillFlowContainer
|
||||
LoadComponentAsync(new CommentsPage(response)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
};
|
||||
|
||||
foreach (var c in response.Comments)
|
||||
{
|
||||
if (c.IsTopLevel)
|
||||
{
|
||||
page.Add(new DrawableComment(c)
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
LoadComponentAsync(page, loaded =>
|
||||
ShowDeleted = { BindTarget = ShowDeleted }
|
||||
}, loaded =>
|
||||
{
|
||||
content.Add(loaded);
|
||||
|
||||
deletedChildrenPlaceholder.DeletedCount.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel);
|
||||
deletedCommentsCounter.Count.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel);
|
||||
|
||||
if (response.HasMore)
|
||||
{
|
||||
@ -194,10 +181,12 @@ namespace osu.Game.Overlays.Comments
|
||||
moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments;
|
||||
moreButton.IsLoading = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
moreButton.Hide();
|
||||
}
|
||||
|
||||
commentCounter.Current.Value = response.Total;
|
||||
|
||||
moreButton.FadeTo(response.HasMore ? 1 : 0);
|
||||
}, loadCancellation.Token);
|
||||
}
|
||||
|
||||
|
92
osu.Game/Overlays/Comments/CommentsPage.cs
Normal file
92
osu.Game/Overlays/Comments/CommentsPage.cs
Normal file
@ -0,0 +1,92 @@
|
||||
// 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.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
public class CommentsPage : CompositeDrawable
|
||||
{
|
||||
public readonly BindableBool ShowDeleted = new BindableBool();
|
||||
|
||||
private readonly CommentBundle commentBundle;
|
||||
|
||||
public CommentsPage(CommentBundle commentBundle)
|
||||
{
|
||||
this.commentBundle = commentBundle;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
FillFlowContainer flow;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background5
|
||||
},
|
||||
flow = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
}
|
||||
});
|
||||
|
||||
if (!commentBundle.Comments.Any())
|
||||
{
|
||||
flow.Add(new NoCommentsPlaceholder());
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var c in commentBundle.Comments)
|
||||
{
|
||||
if (c.IsTopLevel)
|
||||
{
|
||||
flow.Add(new DrawableComment(c)
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class NoCommentsPlaceholder : CompositeDrawable
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
Height = 80;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background4
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Margin = new MarginPadding { Left = 50 },
|
||||
Text = @"No comments yet."
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -14,6 +14,8 @@ namespace osu.Game.Overlays.Comments
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
Height = 20;
|
||||
|
||||
IdleColour = colourProvider.Background2;
|
||||
HoverColour = colourProvider.Background1;
|
||||
ChevronIconColour = colourProvider.Foreground1;
|
||||
|
@ -12,51 +12,56 @@ using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
public class DeletedChildrenPlaceholder : FillFlowContainer
|
||||
public class DeletedCommentsCounter : CompositeDrawable
|
||||
{
|
||||
public readonly BindableBool ShowDeleted = new BindableBool();
|
||||
public readonly BindableInt DeletedCount = new BindableInt();
|
||||
|
||||
public readonly BindableInt Count = new BindableInt();
|
||||
|
||||
private readonly SpriteText countText;
|
||||
|
||||
public DeletedChildrenPlaceholder()
|
||||
public DeletedCommentsCounter()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Direction = FillDirection.Horizontal;
|
||||
Spacing = new Vector2(3, 0);
|
||||
Margin = new MarginPadding { Vertical = 10, Left = 80 };
|
||||
Children = new Drawable[]
|
||||
|
||||
InternalChild = new FillFlowContainer
|
||||
{
|
||||
new SpriteIcon
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(3, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Icon = FontAwesome.Solid.Trash,
|
||||
Size = new Vector2(14),
|
||||
},
|
||||
countText = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
|
||||
new SpriteIcon
|
||||
{
|
||||
Icon = FontAwesome.Solid.Trash,
|
||||
Size = new Vector2(14),
|
||||
},
|
||||
countText = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
DeletedCount.BindValueChanged(_ => updateDisplay(), true);
|
||||
ShowDeleted.BindValueChanged(_ => updateDisplay(), true);
|
||||
base.LoadComplete();
|
||||
|
||||
Count.BindValueChanged(_ => updateDisplay(), true);
|
||||
ShowDeleted.BindValueChanged(_ => updateDisplay(), true);
|
||||
}
|
||||
|
||||
private void updateDisplay()
|
||||
{
|
||||
if (DeletedCount.Value != 0)
|
||||
if (!ShowDeleted.Value && Count.Value != 0)
|
||||
{
|
||||
countText.Text = @"deleted comment".ToQuantity(DeletedCount.Value);
|
||||
this.FadeTo(ShowDeleted.Value ? 0 : 1);
|
||||
countText.Text = @"deleted comment".ToQuantity(Count.Value);
|
||||
Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
Hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
LinkFlowContainer username;
|
||||
FillFlowContainer childCommentsContainer;
|
||||
DeletedChildrenPlaceholder deletedChildrenPlaceholder;
|
||||
DeletedCommentsCounter deletedCommentsCounter;
|
||||
FillFlowContainer info;
|
||||
LinkFlowContainer message;
|
||||
GridContainer content;
|
||||
@ -184,7 +184,7 @@ namespace osu.Game.Overlays.Comments
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical
|
||||
},
|
||||
deletedChildrenPlaceholder = new DeletedChildrenPlaceholder
|
||||
deletedCommentsCounter = new DeletedCommentsCounter
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted }
|
||||
}
|
||||
@ -193,7 +193,7 @@ namespace osu.Game.Overlays.Comments
|
||||
}
|
||||
};
|
||||
|
||||
deletedChildrenPlaceholder.DeletedCount.Value = comment.DeletedChildrenCount;
|
||||
deletedCommentsCounter.Count.Value = comment.DeletedChildrenCount;
|
||||
|
||||
if (comment.UserId.HasValue)
|
||||
username.AddUserLink(comment.User);
|
||||
@ -213,7 +213,7 @@ namespace osu.Game.Overlays.Comments
|
||||
|
||||
if (comment.HasMessage)
|
||||
{
|
||||
var formattedSource = MessageFormatter.FormatText(comment.GetMessage);
|
||||
var formattedSource = MessageFormatter.FormatText(comment.Message);
|
||||
message.AddLinks(formattedSource.Text, formattedSource.Links);
|
||||
}
|
||||
|
||||
@ -343,7 +343,7 @@ namespace osu.Game.Overlays.Comments
|
||||
if (parentComment == null)
|
||||
return string.Empty;
|
||||
|
||||
return parentComment.HasMessage ? parentComment.GetMessage : parentComment.IsDeleted ? @"deleted" : string.Empty;
|
||||
return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? @"deleted" : string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,11 +18,11 @@ namespace osu.Game.Overlays
|
||||
protected IAPIProvider API { get; private set; }
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider;
|
||||
protected readonly OverlayColourProvider ColourProvider;
|
||||
|
||||
protected FullscreenOverlay(OverlayColourScheme colourScheme)
|
||||
{
|
||||
colourProvider = new OverlayColourProvider(colourScheme);
|
||||
ColourProvider = new OverlayColourProvider(colourScheme);
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
RelativePositionAxes = Axes.Both;
|
||||
@ -43,10 +43,10 @@ namespace osu.Game.Overlays
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Waves.FirstWaveColour = colourProvider.Light4;
|
||||
Waves.SecondWaveColour = colourProvider.Light3;
|
||||
Waves.ThirdWaveColour = colourProvider.Dark4;
|
||||
Waves.FourthWaveColour = colourProvider.Dark3;
|
||||
Waves.FirstWaveColour = ColourProvider.Light4;
|
||||
Waves.SecondWaveColour = ColourProvider.Light3;
|
||||
Waves.ThirdWaveColour = ColourProvider.Dark4;
|
||||
Waves.FourthWaveColour = ColourProvider.Dark3;
|
||||
}
|
||||
|
||||
public override void Show()
|
||||
|
@ -30,6 +30,8 @@ namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
public class ModSelectOverlay : WaveOverlayContainer
|
||||
{
|
||||
public const float HEIGHT = 510;
|
||||
|
||||
protected readonly TriangleButton DeselectAllButton;
|
||||
protected readonly TriangleButton CustomiseButton;
|
||||
protected readonly TriangleButton CloseButton;
|
||||
@ -47,7 +49,7 @@ namespace osu.Game.Overlays.Mods
|
||||
|
||||
protected readonly Container ModSettingsContainer;
|
||||
|
||||
protected readonly Bindable<IReadOnlyList<Mod>> SelectedMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||
public readonly Bindable<IReadOnlyList<Mod>> SelectedMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||
|
||||
private Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> availableMods;
|
||||
|
||||
@ -66,7 +68,8 @@ namespace osu.Game.Overlays.Mods
|
||||
Waves.ThirdWaveColour = OsuColour.FromHex(@"005774");
|
||||
Waves.FourthWaveColour = OsuColour.FromHex(@"003a4e");
|
||||
|
||||
Height = 510;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Padding = new MarginPadding { Horizontal = -OsuScreen.HORIZONTAL_OVERFLOW_PADDING };
|
||||
|
||||
Children = new Drawable[]
|
||||
@ -85,8 +88,7 @@ namespace osu.Game.Overlays.Mods
|
||||
new Triangles
|
||||
{
|
||||
TriangleScale = 5,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = Height, //set the height from the start to ensure correct triangle density.
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ColourLight = new Color4(53, 66, 82, 255),
|
||||
ColourDark = new Color4(41, 54, 70, 255),
|
||||
},
|
||||
@ -321,14 +323,13 @@ namespace osu.Game.Overlays.Mods
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuColour colours, AudioManager audio, Bindable<IReadOnlyList<Mod>> selectedMods, OsuGameBase osu)
|
||||
private void load(OsuColour colours, AudioManager audio, OsuGameBase osu)
|
||||
{
|
||||
LowMultiplierColour = colours.Red;
|
||||
HighMultiplierColour = colours.Green;
|
||||
UnrankedLabel.Colour = colours.Blue;
|
||||
|
||||
availableMods = osu.AvailableMods.GetBoundCopy();
|
||||
SelectedMods.BindTo(selectedMods);
|
||||
|
||||
sampleOn = audio.Samples.Get(@"UI/check-on");
|
||||
sampleOff = audio.Samples.Get(@"UI/check-off");
|
||||
|
@ -196,7 +196,7 @@ namespace osu.Game.Overlays
|
||||
if (!instant)
|
||||
queuedDirection = TrackChangeDirection.Next;
|
||||
|
||||
var playable = BeatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).Skip(1).FirstOrDefault() ?? BeatmapSets.FirstOrDefault();
|
||||
var playable = BeatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).ElementAtOrDefault(1) ?? BeatmapSets.FirstOrDefault();
|
||||
|
||||
if (playable != null)
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Overlays.News
|
||||
|
||||
private NewsHeaderTitle title;
|
||||
|
||||
public readonly Bindable<string> Current = new Bindable<string>(null);
|
||||
public readonly Bindable<string> Post = new Bindable<string>(null);
|
||||
|
||||
public Action ShowFrontPage;
|
||||
|
||||
@ -22,13 +22,13 @@ namespace osu.Game.Overlays.News
|
||||
{
|
||||
TabControl.AddItem(front_page_string);
|
||||
|
||||
TabControl.Current.ValueChanged += e =>
|
||||
Current.ValueChanged += e =>
|
||||
{
|
||||
if (e.NewValue == front_page_string)
|
||||
ShowFrontPage?.Invoke();
|
||||
};
|
||||
|
||||
Current.ValueChanged += showPost;
|
||||
Post.ValueChanged += showPost;
|
||||
}
|
||||
|
||||
private void showPost(ValueChangedEvent<string> e)
|
||||
@ -39,13 +39,13 @@ namespace osu.Game.Overlays.News
|
||||
if (e.NewValue != null)
|
||||
{
|
||||
TabControl.AddItem(e.NewValue);
|
||||
TabControl.Current.Value = e.NewValue;
|
||||
Current.Value = e.NewValue;
|
||||
|
||||
title.IsReadingPost = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
TabControl.Current.Value = front_page_string;
|
||||
Current.Value = front_page_string;
|
||||
title.IsReadingPost = false;
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ namespace osu.Game.Overlays
|
||||
},
|
||||
};
|
||||
|
||||
header.Current.BindTo(Current);
|
||||
header.Post.BindTo(Current);
|
||||
Current.TriggerChange();
|
||||
}
|
||||
|
||||
|
@ -50,14 +50,29 @@ namespace osu.Game.Overlays
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Gray,
|
||||
},
|
||||
title = CreateTitle().With(title =>
|
||||
new Container
|
||||
{
|
||||
title.Margin = new MarginPadding
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Horizontal = UserProfileOverlay.CONTENT_X_MARGIN,
|
||||
Vertical = 10,
|
||||
Left = UserProfileOverlay.CONTENT_X_MARGIN
|
||||
};
|
||||
})
|
||||
},
|
||||
Children = new[]
|
||||
{
|
||||
title = CreateTitle().With(title =>
|
||||
{
|
||||
title.Anchor = Anchor.CentreLeft;
|
||||
title.Origin = Anchor.CentreLeft;
|
||||
}),
|
||||
CreateTitleContent().With(content =>
|
||||
{
|
||||
content.Anchor = Anchor.CentreRight;
|
||||
content.Origin = Anchor.CentreRight;
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -75,10 +90,16 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
protected virtual Drawable CreateContent() => Drawable.Empty();
|
||||
protected virtual Drawable CreateContent() => Empty();
|
||||
|
||||
[NotNull]
|
||||
protected virtual Drawable CreateBackground() => Drawable.Empty();
|
||||
protected virtual Drawable CreateBackground() => Empty();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="Drawable"/> on the opposite side of the <see cref="ScreenTitle"/>. Used mostly to create <see cref="OverlayRulesetSelector"/>.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
protected virtual Drawable CreateTitleContent() => Empty();
|
||||
|
||||
protected abstract ScreenTitle CreateTitle();
|
||||
}
|
||||
|
28
osu.Game/Overlays/OverlayRulesetSelector.cs
Normal file
28
osu.Game/Overlays/OverlayRulesetSelector.cs
Normal file
@ -0,0 +1,28 @@
|
||||
// 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.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
public class OverlayRulesetSelector : RulesetSelector
|
||||
{
|
||||
public OverlayRulesetSelector()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
protected override TabItem<RulesetInfo> CreateTabItem(RulesetInfo value) => new OverlayRulesetTabItem(value);
|
||||
|
||||
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(25, 0),
|
||||
};
|
||||
}
|
||||
}
|
97
osu.Game/Overlays/OverlayRulesetTabItem.cs
Normal file
97
osu.Game/Overlays/OverlayRulesetTabItem.cs
Normal file
@ -0,0 +1,97 @@
|
||||
// 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.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK.Graphics;
|
||||
using osuTK;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
public class OverlayRulesetTabItem : TabItem<RulesetInfo>
|
||||
{
|
||||
private Color4 accentColour;
|
||||
|
||||
protected virtual Color4 AccentColour
|
||||
{
|
||||
get => accentColour;
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
text.FadeColour(value, 120, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
protected override Container<Drawable> Content { get; }
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
private readonly OsuSpriteText text;
|
||||
|
||||
public OverlayRulesetTabItem(RulesetInfo value)
|
||||
: base(value)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
Content = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(3, 0),
|
||||
Child = text = new OsuSpriteText
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Text = value.Name,
|
||||
}
|
||||
},
|
||||
new HoverClickSounds()
|
||||
});
|
||||
|
||||
Enabled.Value = true;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
Enabled.BindValueChanged(_ => updateState(), true);
|
||||
}
|
||||
|
||||
public override bool PropagatePositionalInputSubTree => Enabled.Value && !Active.Value && base.PropagatePositionalInputSubTree;
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
base.OnHover(e);
|
||||
updateState();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
base.OnHoverLost(e);
|
||||
updateState();
|
||||
}
|
||||
|
||||
protected override void OnActivated() => updateState();
|
||||
|
||||
protected override void OnDeactivated() => updateState();
|
||||
|
||||
private void updateState()
|
||||
{
|
||||
text.Font = text.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Medium);
|
||||
AccentColour = Enabled.Value ? getActiveColour() : colourProvider.Foreground1;
|
||||
}
|
||||
|
||||
private Color4 getActiveColour() => IsHovered || Active.Value ? Color4.White : colourProvider.Highlight1;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
|
||||
using System;
|
||||
@ -33,16 +33,16 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
iconColour = colours.GreySeafoamLighter;
|
||||
iconColour = colourProvider.Foreground1;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colours.GreySeafoamDark,
|
||||
Colour = colourProvider.Background4
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
@ -82,7 +82,7 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
else
|
||||
{
|
||||
topLinkContainer.AddText("Joined ");
|
||||
topLinkContainer.AddText(new DrawableDate(user.JoinDate), embolden);
|
||||
topLinkContainer.AddText(new DrawableDate(user.JoinDate, italic: false), embolden);
|
||||
}
|
||||
|
||||
addSpacer(topLinkContainer);
|
||||
@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
else if (user.LastVisit.HasValue)
|
||||
{
|
||||
topLinkContainer.AddText("Last seen ");
|
||||
topLinkContainer.AddText(new DrawableDate(user.LastVisit.Value), embolden);
|
||||
topLinkContainer.AddText(new DrawableDate(user.LastVisit.Value, italic: false), embolden);
|
||||
|
||||
addSpacer(topLinkContainer);
|
||||
}
|
||||
@ -111,34 +111,42 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
topLinkContainer.AddText("Contributed ");
|
||||
topLinkContainer.AddLink($@"{user.PostCount:#,##0} forum posts", $"https://osu.ppy.sh/users/{user.Id}/posts", creationParameters: embolden);
|
||||
|
||||
string websiteWithoutProtcol = user.Website;
|
||||
string websiteWithoutProtocol = user.Website;
|
||||
|
||||
if (!string.IsNullOrEmpty(websiteWithoutProtcol))
|
||||
if (!string.IsNullOrEmpty(websiteWithoutProtocol))
|
||||
{
|
||||
if (Uri.TryCreate(websiteWithoutProtcol, UriKind.Absolute, out var uri))
|
||||
if (Uri.TryCreate(websiteWithoutProtocol, UriKind.Absolute, out var uri))
|
||||
{
|
||||
websiteWithoutProtcol = uri.Host + uri.PathAndQuery + uri.Fragment;
|
||||
websiteWithoutProtcol = websiteWithoutProtcol.TrimEnd('/');
|
||||
websiteWithoutProtocol = uri.Host + uri.PathAndQuery + uri.Fragment;
|
||||
websiteWithoutProtocol = websiteWithoutProtocol.TrimEnd('/');
|
||||
}
|
||||
}
|
||||
|
||||
tryAddInfo(FontAwesome.Solid.MapMarker, user.Location);
|
||||
tryAddInfo(OsuIcon.Heart, user.Interests);
|
||||
tryAddInfo(FontAwesome.Solid.Suitcase, user.Occupation);
|
||||
bottomLinkContainer.NewLine();
|
||||
bool anyInfoAdded = false;
|
||||
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.MapMarker, user.Location);
|
||||
anyInfoAdded |= tryAddInfo(OsuIcon.Heart, user.Interests);
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.Suitcase, user.Occupation);
|
||||
|
||||
if (anyInfoAdded)
|
||||
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);
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Twitter, "@" + user.Twitter, $@"https://twitter.com/{user.Twitter}");
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Discord, user.Discord);
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Skype, user.Skype, @"skype:" + user.Skype + @"?chat");
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Lastfm, user.Lastfm, $@"https://last.fm/users/{user.Lastfm}");
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.Link, websiteWithoutProtocol, user.Website);
|
||||
|
||||
// If no information was added to the bottomLinkContainer, hide it to avoid unwanted padding
|
||||
bottomLinkContainer.Alpha = anyInfoAdded ? 1 : 0;
|
||||
}
|
||||
|
||||
private void addSpacer(OsuTextFlowContainer textFlow) => textFlow.AddArbitraryDrawable(new Container { Width = 15 });
|
||||
|
||||
private void tryAddInfo(IconUsage icon, string content, string link = null)
|
||||
private bool tryAddInfo(IconUsage icon, string content, string link = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(content)) return;
|
||||
if (string.IsNullOrEmpty(content)) return false;
|
||||
|
||||
// newlines could be contained in API returned user content.
|
||||
content = content.Replace("\n", " ");
|
||||
@ -155,6 +163,7 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
bottomLinkContainer.AddText(" " + content, embolden);
|
||||
|
||||
addSpacer(bottomLinkContainer);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void embolden(SpriteText text) => text.Font = text.Font.With(weight: FontWeight.Bold);
|
||||
|
@ -7,7 +7,6 @@ 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;
|
||||
@ -28,7 +27,7 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, TextureStore textures)
|
||||
private void load(OverlayColourProvider colourProvider, TextureStore textures)
|
||||
{
|
||||
Container<Drawable> hiddenDetailContainer;
|
||||
Container<Drawable> expandedDetailContainer;
|
||||
@ -38,7 +37,7 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colours.GreySeafoam
|
||||
Colour = colourProvider.Background4
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
@ -119,12 +118,12 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
hiddenDetailGlobal = new OverlinedInfoContainer
|
||||
{
|
||||
Title = "Global Ranking",
|
||||
LineColour = colours.Yellow
|
||||
LineColour = colourProvider.Highlight1
|
||||
},
|
||||
hiddenDetailCountry = new OverlinedInfoContainer
|
||||
{
|
||||
Title = "Country Ranking",
|
||||
LineColour = colours.Yellow
|
||||
LineColour = colourProvider.Highlight1
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ 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
|
||||
@ -25,10 +24,10 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
IdleColour = colours.GreySeafoamLight;
|
||||
HoverColour = colours.GreySeafoamLight.Darken(0.2f);
|
||||
IdleColour = colourProvider.Background2;
|
||||
HoverColour = colourProvider.Background2.Lighten(0.2f);
|
||||
|
||||
Child = icon = new SpriteIcon
|
||||
{
|
||||
|
@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
BackgroundColour = Color4.Black,
|
||||
Direction = BarDirection.LeftToRight,
|
||||
AccentColour = colours.Yellow
|
||||
AccentColour = colourProvider.Highlight1
|
||||
}
|
||||
},
|
||||
levelProgressText = new OsuSpriteText
|
||||
|
@ -43,7 +43,8 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
||||
line = new Circle
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 4,
|
||||
Height = 2,
|
||||
Margin = new MarginPadding { Bottom = 2 }
|
||||
},
|
||||
title = new OsuSpriteText
|
||||
{
|
||||
|
@ -6,7 +6,6 @@ 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
|
||||
@ -27,12 +26,12 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
InternalChild = info = new OverlinedInfoContainer
|
||||
{
|
||||
Title = "Total Play Time",
|
||||
LineColour = colours.Yellow,
|
||||
LineColour = colourProvider.Highlight1,
|
||||
};
|
||||
|
||||
User.BindValueChanged(updateTime, true);
|
||||
|
@ -2,12 +2,11 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Header.Components
|
||||
{
|
||||
@ -24,9 +23,6 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
||||
{
|
||||
AutoSizeAxes = Axes.X;
|
||||
|
||||
IdleColour = Color4.Black;
|
||||
HoverColour = OsuColour.Gray(0.1f);
|
||||
|
||||
base.Content.Add(new CircularContainer
|
||||
{
|
||||
Masking = true,
|
||||
@ -47,5 +43,12 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
IdleColour = colourProvider.Background6;
|
||||
HoverColour = colourProvider.Background5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,63 +1,29 @@
|
||||
// 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.UserInterface;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Header.Components
|
||||
{
|
||||
public class ProfileRulesetSelector : RulesetSelector
|
||||
public class ProfileRulesetSelector : OverlayRulesetSelector
|
||||
{
|
||||
private Color4 accentColour = Color4.White;
|
||||
|
||||
public readonly Bindable<User> User = new Bindable<User>();
|
||||
|
||||
public ProfileRulesetSelector()
|
||||
{
|
||||
TabContainer.Masking = false;
|
||||
TabContainer.Spacing = new Vector2(10, 0);
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
accentColour = colours.Seafoam;
|
||||
|
||||
foreach (TabItem<RulesetInfo> tabItem in TabContainer)
|
||||
((ProfileRulesetTabItem)tabItem).AccentColour = accentColour;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
User.BindValueChanged(u => SetDefaultRuleset(Rulesets.GetRuleset(u.NewValue?.PlayMode ?? "osu")), true);
|
||||
}
|
||||
|
||||
public void SetDefaultRuleset(RulesetInfo ruleset)
|
||||
{
|
||||
foreach (TabItem<RulesetInfo> tabItem in TabContainer)
|
||||
foreach (var tabItem in TabContainer)
|
||||
((ProfileRulesetTabItem)tabItem).IsDefault = ((ProfileRulesetTabItem)tabItem).Value.ID == ruleset.ID;
|
||||
}
|
||||
|
||||
protected override TabItem<RulesetInfo> CreateTabItem(RulesetInfo value) => new ProfileRulesetTabItem(value)
|
||||
{
|
||||
AccentColour = accentColour
|
||||
};
|
||||
|
||||
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Horizontal,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
};
|
||||
protected override TabItem<RulesetInfo> CreateTabItem(RulesetInfo value) => new ProfileRulesetTabItem(value);
|
||||
}
|
||||
}
|
||||
|
@ -2,40 +2,15 @@
|
||||
// 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.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Header.Components
|
||||
{
|
||||
public class ProfileRulesetTabItem : TabItem<RulesetInfo>, IHasAccentColour
|
||||
public class ProfileRulesetTabItem : OverlayRulesetTabItem
|
||||
{
|
||||
private readonly OsuSpriteText text;
|
||||
private readonly SpriteIcon icon;
|
||||
|
||||
private Color4 accentColour;
|
||||
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get => accentColour;
|
||||
set
|
||||
{
|
||||
if (accentColour == value)
|
||||
return;
|
||||
|
||||
accentColour = value;
|
||||
|
||||
updateState();
|
||||
}
|
||||
}
|
||||
|
||||
private bool isDefault;
|
||||
|
||||
public bool IsDefault
|
||||
@ -52,74 +27,30 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
||||
}
|
||||
}
|
||||
|
||||
protected override Color4 AccentColour
|
||||
{
|
||||
get => base.AccentColour;
|
||||
set
|
||||
{
|
||||
base.AccentColour = value;
|
||||
icon.FadeColour(value, 120, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly SpriteIcon icon;
|
||||
|
||||
public ProfileRulesetTabItem(RulesetInfo value)
|
||||
: base(value)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
Children = new Drawable[]
|
||||
Add(icon = new SpriteIcon
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(3, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
text = new OsuSpriteText
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Text = value.Name,
|
||||
},
|
||||
icon = new SpriteIcon
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true,
|
||||
Icon = FontAwesome.Solid.Star,
|
||||
Size = new Vector2(12),
|
||||
},
|
||||
}
|
||||
},
|
||||
new HoverClickSounds()
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
base.OnHover(e);
|
||||
updateState();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
base.OnHoverLost(e);
|
||||
updateState();
|
||||
}
|
||||
|
||||
protected override void OnActivated() => updateState();
|
||||
|
||||
protected override void OnDeactivated() => updateState();
|
||||
|
||||
private void updateState()
|
||||
{
|
||||
text.Font = text.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Medium);
|
||||
|
||||
if (IsHovered || Active.Value)
|
||||
{
|
||||
text.FadeColour(Color4.White, 120, Easing.InQuad);
|
||||
icon.FadeColour(Color4.White, 120, Easing.InQuad);
|
||||
}
|
||||
else
|
||||
{
|
||||
text.FadeColour(AccentColour, 120, Easing.InQuad);
|
||||
icon.FadeColour(AccentColour, 120, Easing.InQuad);
|
||||
}
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true,
|
||||
Icon = FontAwesome.Solid.Star,
|
||||
Size = new Vector2(12),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user