mirror of
https://github.com/ppy/osu.git
synced 2025-02-15 20:43:21 +08:00
Merge branch 'master' into fix-op-non-current-onexiting
This commit is contained in:
commit
54b2fe9df3
@ -1,6 +1,6 @@
|
|||||||
clone_depth: 1
|
clone_depth: 1
|
||||||
version: '{build}'
|
version: '{build}'
|
||||||
image: Visual Studio 2019
|
image: Visual Studio 2022
|
||||||
test: off
|
test: off
|
||||||
skip_non_tags: true
|
skip_non_tags: true
|
||||||
configuration: Release
|
configuration: Release
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.1219.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.1226.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<!-- Fody does not handle Android build well, and warns when unchanged.
|
<!-- Fody does not handle Android build well, and warns when unchanged.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" package="sh.ppy.osulazer" android:installLocation="auto" android:versionName="0.1.0">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="sh.ppy.osulazer" android:installLocation="auto">
|
||||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="31" />
|
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="31" />
|
||||||
<application android:allowBackup="true" android:supportsRtl="true" android:label="osu!" android:icon="@drawable/lazer" />
|
<application android:allowBackup="true" android:supportsRtl="true" android:label="osu!" android:icon="@drawable/lazer" />
|
||||||
</manifest>
|
</manifest>
|
@ -8,6 +8,9 @@
|
|||||||
<UseMauiEssentials>true</UseMauiEssentials>
|
<UseMauiEssentials>true</UseMauiEssentials>
|
||||||
<!-- This currently causes random lockups during gameplay. https://github.com/mono/mono/issues/18973 -->
|
<!-- This currently causes random lockups during gameplay. https://github.com/mono/mono/issues/18973 -->
|
||||||
<EnableLLVM>false</EnableLLVM>
|
<EnableLLVM>false</EnableLLVM>
|
||||||
|
<Version>0.0.0</Version>
|
||||||
|
<ApplicationVersion Condition=" '$(ApplicationVersion)' == '' ">1</ApplicationVersion>
|
||||||
|
<ApplicationDisplayVersion Condition=" '$(ApplicationDisplayVersion)' == '' ">$(Version)</ApplicationDisplayVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
|
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
|
||||||
|
@ -18,6 +18,36 @@ namespace osu.Game.Rulesets.Catch.Tests.Mods
|
|||||||
{
|
{
|
||||||
protected override Ruleset CreatePlayerRuleset() => new CatchRuleset();
|
protected override Ruleset CreatePlayerRuleset() => new CatchRuleset();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAlwaysHidden()
|
||||||
|
{
|
||||||
|
CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new CatchModNoScope
|
||||||
|
{
|
||||||
|
HiddenComboCount = { Value = 0 },
|
||||||
|
},
|
||||||
|
Autoplay = true,
|
||||||
|
PassCondition = () => Player.ScoreProcessor.Combo.Value == 2,
|
||||||
|
Beatmap = new Beatmap
|
||||||
|
{
|
||||||
|
HitObjects = new List<HitObject>
|
||||||
|
{
|
||||||
|
new Fruit
|
||||||
|
{
|
||||||
|
X = CatchPlayfield.CENTER_X * 0.5f,
|
||||||
|
StartTime = 1000,
|
||||||
|
},
|
||||||
|
new Fruit
|
||||||
|
{
|
||||||
|
X = CatchPlayfield.CENTER_X * 1.5f,
|
||||||
|
StartTime = 2000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestVisibleDuringBreak()
|
public void TestVisibleDuringBreak()
|
||||||
{
|
{
|
||||||
|
@ -26,6 +26,9 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
var catchPlayfield = (CatchPlayfield)playfield;
|
var catchPlayfield = (CatchPlayfield)playfield;
|
||||||
bool shouldAlwaysShowCatcher = IsBreakTime.Value;
|
bool shouldAlwaysShowCatcher = IsBreakTime.Value;
|
||||||
float targetAlpha = shouldAlwaysShowCatcher ? 1 : ComboBasedAlpha;
|
float targetAlpha = shouldAlwaysShowCatcher ? 1 : ComboBasedAlpha;
|
||||||
|
|
||||||
|
// AlwaysPresent required for catcher to still act on input when fully hidden.
|
||||||
|
catchPlayfield.CatcherArea.AlwaysPresent = true;
|
||||||
catchPlayfield.CatcherArea.Alpha = (float)Interpolation.Lerp(catchPlayfield.CatcherArea.Alpha, targetAlpha, Math.Clamp(catchPlayfield.Time.Elapsed / TRANSITION_DURATION, 0, 1));
|
catchPlayfield.CatcherArea.Alpha = (float)Interpolation.Lerp(catchPlayfield.CatcherArea.Alpha, targetAlpha, Math.Clamp(catchPlayfield.Time.Elapsed / TRANSITION_DURATION, 0, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -32,7 +31,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ISkinSource skin)
|
private void load(ISkinSource skin)
|
||||||
{
|
{
|
||||||
foreach (var state in Enum.GetValues(typeof(CatcherAnimationState)).Cast<CatcherAnimationState>())
|
foreach (var state in Enum.GetValues<CatcherAnimationState>())
|
||||||
{
|
{
|
||||||
AddInternal(drawables[state] = getDrawableFor(state).With(d =>
|
AddInternal(drawables[state] = getDrawableFor(state).With(d =>
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,6 @@ using osu.Framework.Input.Bindings;
|
|||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Input;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.UI
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
{
|
{
|
||||||
@ -106,41 +105,17 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseDown(MouseDownEvent e)
|
|
||||||
{
|
|
||||||
return updateAction(e.Button, getTouchCatchActionFromInput(e.ScreenSpaceMousePosition));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnTouchDown(TouchDownEvent e)
|
protected override bool OnTouchDown(TouchDownEvent e)
|
||||||
{
|
{
|
||||||
return updateAction(e.Touch.Source, getTouchCatchActionFromInput(e.ScreenSpaceTouch.Position));
|
return updateAction(e.Touch.Source, getTouchCatchActionFromInput(e.ScreenSpaceTouch.Position));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
|
||||||
{
|
|
||||||
Show();
|
|
||||||
|
|
||||||
TouchCatchAction? action = getTouchCatchActionFromInput(e.ScreenSpaceMousePosition);
|
|
||||||
|
|
||||||
// multiple mouse buttons may be pressed and handling the same action.
|
|
||||||
foreach (MouseButton button in e.PressedButtons)
|
|
||||||
updateAction(button, action);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnTouchMove(TouchMoveEvent e)
|
protected override void OnTouchMove(TouchMoveEvent e)
|
||||||
{
|
{
|
||||||
updateAction(e.Touch.Source, getTouchCatchActionFromInput(e.ScreenSpaceTouch.Position));
|
updateAction(e.Touch.Source, getTouchCatchActionFromInput(e.ScreenSpaceTouch.Position));
|
||||||
base.OnTouchMove(e);
|
base.OnTouchMove(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnMouseUp(MouseUpEvent e)
|
|
||||||
{
|
|
||||||
updateAction(e.Button, null);
|
|
||||||
base.OnMouseUp(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnTouchUp(TouchUpEvent e)
|
protected override void OnTouchUp(TouchUpEvent e)
|
||||||
{
|
{
|
||||||
updateAction(e.Touch.Source, null);
|
updateAction(e.Touch.Source, null);
|
||||||
|
@ -209,18 +209,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
keyBindingContainer = maniaInputManager?.KeyBindingContainer;
|
keyBindingContainer = maniaInputManager?.KeyBindingContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseDown(MouseDownEvent e)
|
|
||||||
{
|
|
||||||
keyBindingContainer?.TriggerPressed(column.Action.Value);
|
|
||||||
return base.OnMouseDown(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnMouseUp(MouseUpEvent e)
|
|
||||||
{
|
|
||||||
keyBindingContainer?.TriggerReleased(column.Action.Value);
|
|
||||||
base.OnMouseUp(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnTouchDown(TouchDownEvent e)
|
protected override bool OnTouchDown(TouchDownEvent e)
|
||||||
{
|
{
|
||||||
keyBindingContainer?.TriggerPressed(column.Action.Value);
|
keyBindingContainer?.TriggerPressed(column.Action.Value);
|
||||||
|
@ -160,9 +160,9 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
static bool assertSamples(HitObject hitObject) => hitObject.Samples.All(s => s.Name != HitSampleInfo.HIT_CLAP && s.Name != HitSampleInfo.HIT_WHISTLE);
|
static bool assertSamples(HitObject hitObject) => hitObject.Samples.All(s => s.Name != HitSampleInfo.HIT_CLAP && s.Name != HitSampleInfo.HIT_WHISTLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable testSimpleBig(int repeats = 0) => createSlider(2, repeats: repeats);
|
private Drawable testSimpleBig(int repeats = 0) => createSlider(repeats: repeats);
|
||||||
|
|
||||||
private Drawable testSimpleBigLargeStackOffset(int repeats = 0) => createSlider(2, repeats: repeats, stackHeight: 10);
|
private Drawable testSimpleBigLargeStackOffset(int repeats = 0) => createSlider(repeats: repeats, stackHeight: 10);
|
||||||
|
|
||||||
private Drawable testDistanceOverflow(int repeats = 0)
|
private Drawable testDistanceOverflow(int repeats = 0)
|
||||||
{
|
{
|
||||||
|
@ -1,35 +1,64 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Skinning.Argon
|
namespace osu.Game.Rulesets.Osu.Skinning.Argon
|
||||||
{
|
{
|
||||||
public partial class ArgonFollowCircle : FollowCircle
|
public partial class ArgonFollowCircle : FollowCircle
|
||||||
{
|
{
|
||||||
|
private readonly CircularContainer circleContainer;
|
||||||
|
private readonly Box circleFill;
|
||||||
|
|
||||||
|
private readonly IBindable<Color4> accentColour = new Bindable<Color4>();
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private DrawableHitObject? parentObject { get; set; }
|
||||||
|
|
||||||
public ArgonFollowCircle()
|
public ArgonFollowCircle()
|
||||||
{
|
{
|
||||||
InternalChild = new CircularContainer
|
InternalChild = circleContainer = new CircularContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
BorderThickness = 4,
|
BorderThickness = 4,
|
||||||
BorderColour = ColourInfo.GradientVertical(Colour4.FromHex("FC618F"), Colour4.FromHex("BB1A41")),
|
|
||||||
Blending = BlendingParameters.Additive,
|
Blending = BlendingParameters.Additive,
|
||||||
Child = new Box
|
Child = circleFill = new Box
|
||||||
{
|
{
|
||||||
Colour = ColourInfo.GradientVertical(Colour4.FromHex("FC618F"), Colour4.FromHex("BB1A41")),
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Alpha = 0.3f,
|
Alpha = 0.3f,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
if (parentObject != null)
|
||||||
|
accentColour.BindTo(parentObject.AccentColour);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
accentColour.BindValueChanged(colour =>
|
||||||
|
{
|
||||||
|
circleContainer.BorderColour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.5f));
|
||||||
|
circleFill.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.5f));
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnSliderPress()
|
protected override void OnSliderPress()
|
||||||
{
|
{
|
||||||
const float duration = 300f;
|
const float duration = 300f;
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -21,6 +23,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
|
|||||||
|
|
||||||
private readonly Vector2 defaultIconScale = new Vector2(0.6f, 0.8f);
|
private readonly Vector2 defaultIconScale = new Vector2(0.6f, 0.8f);
|
||||||
|
|
||||||
|
private readonly IBindable<Color4> accentColour = new Bindable<Color4>();
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private DrawableHitObject? parentObject { get; set; }
|
private DrawableHitObject? parentObject { get; set; }
|
||||||
|
|
||||||
@ -37,7 +41,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
|
|||||||
{
|
{
|
||||||
fill = new Box
|
fill = new Box
|
||||||
{
|
{
|
||||||
Colour = ColourInfo.GradientVertical(Colour4.FromHex("FC618F"), Colour4.FromHex("BB1A41")),
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
@ -53,10 +56,22 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
if (parentObject != null)
|
||||||
|
accentColour.BindTo(parentObject.AccentColour);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
|
accentColour.BindValueChanged(colour =>
|
||||||
|
{
|
||||||
|
fill.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.5f));
|
||||||
|
}, true);
|
||||||
|
|
||||||
if (parentObject != null)
|
if (parentObject != null)
|
||||||
{
|
{
|
||||||
parentObject.ApplyCustomUpdateState += updateStateTransforms;
|
parentObject.ApplyCustomUpdateState += updateStateTransforms;
|
||||||
|
@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
HitPolicy = new StartTimeOrderedHitPolicy();
|
HitPolicy = new StartTimeOrderedHitPolicy();
|
||||||
|
|
||||||
var hitWindows = new OsuHitWindows();
|
var hitWindows = new OsuHitWindows();
|
||||||
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r > HitResult.None && hitWindows.IsHitResultAllowed(r)))
|
foreach (var result in Enum.GetValues<HitResult>().Where(r => r > HitResult.None && hitWindows.IsHitResultAllowed(r)))
|
||||||
poolDictionary.Add(result, new DrawableJudgementPool(result, onJudgementLoaded));
|
poolDictionary.Add(result, new DrawableJudgementPool(result, onJudgementLoaded));
|
||||||
|
|
||||||
AddRangeInternal(poolDictionary.Values);
|
AddRangeInternal(poolDictionary.Values);
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
public void ApplyToDrawableRuleset(DrawableRuleset<TaikoHitObject> drawableRuleset)
|
public void ApplyToDrawableRuleset(DrawableRuleset<TaikoHitObject> drawableRuleset)
|
||||||
{
|
{
|
||||||
drawableTaikoRuleset = (DrawableTaikoRuleset)drawableRuleset;
|
drawableTaikoRuleset = (DrawableTaikoRuleset)drawableRuleset;
|
||||||
drawableTaikoRuleset.LockPlayfieldAspect.Value = false;
|
drawableTaikoRuleset.LockPlayfieldMaxAspect.Value = false;
|
||||||
|
|
||||||
var playfield = (TaikoPlayfield)drawableRuleset.Playfield;
|
var playfield = (TaikoPlayfield)drawableRuleset.Playfield;
|
||||||
playfield.ClassicHitTargetPosition.Value = true;
|
playfield.ClassicHitTargetPosition.Value = true;
|
||||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
{
|
{
|
||||||
public new BindableDouble TimeRange => base.TimeRange;
|
public new BindableDouble TimeRange => base.TimeRange;
|
||||||
|
|
||||||
public readonly BindableBool LockPlayfieldAspect = new BindableBool(true);
|
public readonly BindableBool LockPlayfieldMaxAspect = new BindableBool(true);
|
||||||
|
|
||||||
protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping;
|
protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping;
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
|
|
||||||
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new TaikoPlayfieldAdjustmentContainer
|
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new TaikoPlayfieldAdjustmentContainer
|
||||||
{
|
{
|
||||||
LockPlayfieldAspect = { BindTarget = LockPlayfieldAspect }
|
LockPlayfieldMaxAspect = { BindTarget = LockPlayfieldMaxAspect }
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo);
|
protected override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo);
|
||||||
|
@ -107,24 +107,6 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseDown(MouseDownEvent e)
|
|
||||||
{
|
|
||||||
if (!validMouse(e))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
handleDown(e.Button, e.ScreenSpaceMousePosition);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnMouseUp(MouseUpEvent e)
|
|
||||||
{
|
|
||||||
if (!validMouse(e))
|
|
||||||
return;
|
|
||||||
|
|
||||||
handleUp(e.Button);
|
|
||||||
base.OnMouseUp(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnTouchDown(TouchDownEvent e)
|
protected override bool OnTouchDown(TouchDownEvent e)
|
||||||
{
|
{
|
||||||
handleDown(e.Touch.Source, e.ScreenSpaceTouchDownPosition);
|
handleDown(e.Touch.Source, e.ScreenSpaceTouchDownPosition);
|
||||||
|
@ -190,7 +190,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
|
|
||||||
var hitWindows = new TaikoHitWindows();
|
var hitWindows = new TaikoHitWindows();
|
||||||
|
|
||||||
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => hitWindows.IsHitResultAllowed(r)))
|
foreach (var result in Enum.GetValues<HitResult>().Where(r => hitWindows.IsHitResultAllowed(r)))
|
||||||
{
|
{
|
||||||
judgementPools.Add(result, new DrawablePool<DrawableTaikoJudgement>(15));
|
judgementPools.Add(result, new DrawablePool<DrawableTaikoJudgement>(15));
|
||||||
explosionPools.Add(result, new HitExplosionPool(result));
|
explosionPools.Add(result, new HitExplosionPool(result));
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
private const float default_relative_height = TaikoPlayfield.DEFAULT_HEIGHT / 768;
|
private const float default_relative_height = TaikoPlayfield.DEFAULT_HEIGHT / 768;
|
||||||
private const float default_aspect = 16f / 9f;
|
private const float default_aspect = 16f / 9f;
|
||||||
|
|
||||||
public readonly IBindable<bool> LockPlayfieldAspect = new BindableBool(true);
|
public readonly IBindable<bool> LockPlayfieldMaxAspect = new BindableBool(true);
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
@ -21,7 +21,12 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
|
|
||||||
float height = default_relative_height;
|
float height = default_relative_height;
|
||||||
|
|
||||||
if (LockPlayfieldAspect.Value)
|
// Players coming from stable expect to be able to change the aspect ratio regardless of the window size.
|
||||||
|
// We originally wanted to limit this more, but there was considerable pushback from the community.
|
||||||
|
//
|
||||||
|
// As a middle-ground, the aspect ratio can still be adjusted in the downwards direction but has a maximum limit.
|
||||||
|
// This is still a bit weird, because readability changes with window size, but it is what it is.
|
||||||
|
if (LockPlayfieldMaxAspect.Value && Parent.ChildSize.X / Parent.ChildSize.Y > default_aspect)
|
||||||
height *= Math.Clamp(Parent.ChildSize.X / Parent.ChildSize.Y, 0.4f, 4) / default_aspect;
|
height *= Math.Clamp(Parent.ChildSize.X / Parent.ChildSize.Y, 0.4f, 4) / default_aspect;
|
||||||
|
|
||||||
Height = height;
|
Height = height;
|
||||||
|
@ -8,6 +8,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Online.Spectator;
|
using osu.Game.Online.Spectator;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
@ -139,6 +140,29 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
Assert.That(score.MaximumStatistics[HitResult.LargeBonus], Is.EqualTo(1));
|
Assert.That(score.MaximumStatistics[HitResult.LargeBonus], Is.EqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAccuracyModes()
|
||||||
|
{
|
||||||
|
var beatmap = new Beatmap<HitObject>
|
||||||
|
{
|
||||||
|
HitObjects = Enumerable.Range(0, 4).Select(_ => new TestHitObject(HitResult.Great)).ToList<HitObject>()
|
||||||
|
};
|
||||||
|
|
||||||
|
var scoreProcessor = new ScoreProcessor(new OsuRuleset());
|
||||||
|
scoreProcessor.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
|
Assert.That(scoreProcessor.Accuracy.Value, Is.EqualTo(1));
|
||||||
|
Assert.That(scoreProcessor.MinimumAccuracy.Value, Is.EqualTo(0));
|
||||||
|
Assert.That(scoreProcessor.MaximumAccuracy.Value, Is.EqualTo(1));
|
||||||
|
|
||||||
|
scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], beatmap.HitObjects[0].CreateJudgement()) { Type = HitResult.Ok });
|
||||||
|
scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[1], beatmap.HitObjects[1].CreateJudgement()) { Type = HitResult.Great });
|
||||||
|
|
||||||
|
Assert.That(scoreProcessor.Accuracy.Value, Is.EqualTo((double)(100 + 300) / (2 * 300)).Within(Precision.DOUBLE_EPSILON));
|
||||||
|
Assert.That(scoreProcessor.MinimumAccuracy.Value, Is.EqualTo((double)(100 + 300) / (4 * 300)).Within(Precision.DOUBLE_EPSILON));
|
||||||
|
Assert.That(scoreProcessor.MaximumAccuracy.Value, Is.EqualTo((double)(100 + 3 * 300) / (4 * 300)).Within(Precision.DOUBLE_EPSILON));
|
||||||
|
}
|
||||||
|
|
||||||
private class TestJudgement : Judgement
|
private class TestJudgement : Judgement
|
||||||
{
|
{
|
||||||
public override HitResult MaxResult { get; }
|
public override HitResult MaxResult { get; }
|
||||||
|
@ -60,6 +60,6 @@ namespace osu.Game.Tests.Mods
|
|||||||
/// This local helper is used rather than <see cref="Ruleset.CreateAllMods"/>, because the aforementioned method flattens multi mods.
|
/// This local helper is used rather than <see cref="Ruleset.CreateAllMods"/>, because the aforementioned method flattens multi mods.
|
||||||
/// </remarks>>
|
/// </remarks>>
|
||||||
private static IEnumerable<MultiMod> getMultiMods(Ruleset ruleset)
|
private static IEnumerable<MultiMod> getMultiMods(Ruleset ruleset)
|
||||||
=> Enum.GetValues(typeof(ModType)).Cast<ModType>().SelectMany(ruleset.GetModsFor).OfType<MultiMod>();
|
=> Enum.GetValues<ModType>().SelectMany(ruleset.GetModsFor).OfType<MultiMod>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Screens.Edit;
|
using osu.Game.Screens.Edit;
|
||||||
using osu.Game.Screens.Edit.Components.Timelines.Summary;
|
using osu.Game.Screens.Edit.Components.Timelines.Summary;
|
||||||
@ -21,7 +22,13 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
public TestSceneEditorSummaryTimeline()
|
public TestSceneEditorSummaryTimeline()
|
||||||
{
|
{
|
||||||
editorBeatmap = new EditorBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo));
|
var beatmap = CreateBeatmap(new OsuRuleset().RulesetInfo);
|
||||||
|
|
||||||
|
beatmap.ControlPointInfo.Add(100000, new TimingControlPoint { BeatLength = 100 });
|
||||||
|
beatmap.ControlPointInfo.Add(50000, new DifficultyControlPoint { SliderVelocity = 2 });
|
||||||
|
beatmap.BeatmapInfo.Bookmarks = new[] { 75000, 125000 };
|
||||||
|
|
||||||
|
editorBeatmap = new EditorBeatmap(beatmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
|
35
osu.Game.Tests/Visual/Editing/TestScenePreviewTime.cs
Normal file
35
osu.Game.Tests/Visual/Editing/TestScenePreviewTime.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 System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Editing
|
||||||
|
{
|
||||||
|
public partial class TestScenePreviewTime : EditorTestScene
|
||||||
|
{
|
||||||
|
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSceneSetPreviewTimingPoint()
|
||||||
|
{
|
||||||
|
AddStep("seek to 1000", () => EditorClock.Seek(1000));
|
||||||
|
AddAssert("time is 1000", () => EditorClock.CurrentTime == 1000);
|
||||||
|
AddStep("set current time as preview point", () => Editor.SetPreviewPointToCurrentTime());
|
||||||
|
AddAssert("preview time is 1000", () => EditorBeatmap.PreviewTime.Value == 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestScenePreviewTimeline()
|
||||||
|
{
|
||||||
|
AddStep("set preview time to -1", () => EditorBeatmap.PreviewTime.Value = -1);
|
||||||
|
AddAssert("preview time line should not show", () => !Editor.ChildrenOfType<PreviewTimePart>().Single().Children.Any());
|
||||||
|
AddStep("set preview time to 1000", () => EditorBeatmap.PreviewTime.Value = 1000);
|
||||||
|
AddAssert("preview time line should show", () => Editor.ChildrenOfType<PreviewTimePart>().Single().Children.Single().Alpha == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -257,7 +257,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
prepareTestAPI(true);
|
prepareTestAPI(true);
|
||||||
|
|
||||||
createPlayerTest(false, createRuleset: () => new OsuRuleset
|
createPlayerTest(createRuleset: () => new OsuRuleset
|
||||||
{
|
{
|
||||||
RulesetInfo =
|
RulesetInfo =
|
||||||
{
|
{
|
||||||
|
@ -201,6 +201,23 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
AddAssert("volume not changed", () => Audio.Volume.Value == 0.5);
|
AddAssert("volume not changed", () => Audio.Volume.Value == 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRulesetSelectorOverflow()
|
||||||
|
{
|
||||||
|
AddStep("set toolbar width", () =>
|
||||||
|
{
|
||||||
|
toolbar.RelativeSizeAxes = Axes.None;
|
||||||
|
toolbar.Width = 400;
|
||||||
|
});
|
||||||
|
AddStep("move mouse over news toggle button", () =>
|
||||||
|
{
|
||||||
|
var button = toolbar.ChildrenOfType<ToolbarNewsButton>().Single();
|
||||||
|
InputManager.MoveMouseTo(button);
|
||||||
|
});
|
||||||
|
AddAssert("no ruleset toggle buttons hovered", () => !toolbar.ChildrenOfType<ToolbarRulesetTabButton>().Any(button => button.IsHovered));
|
||||||
|
AddUntilStep("toolbar gradient visible", () => toolbar.ChildrenOfType<Toolbar.ToolbarBackground>().Single().Children.All(d => d.Alpha > 0));
|
||||||
|
}
|
||||||
|
|
||||||
public partial class TestToolbar : Toolbar
|
public partial class TestToolbar : Toolbar
|
||||||
{
|
{
|
||||||
public new Bindable<OverlayActivation> OverlayActivationMode => base.OverlayActivationMode as Bindable<OverlayActivation>;
|
public new Bindable<OverlayActivation> OverlayActivationMode => base.OverlayActivationMode as Bindable<OverlayActivation>;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
@ -46,10 +47,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddAssert("item removed", () => !playlist.Items.Contains(selectedItem));
|
AddAssert("item removed", () => !playlist.Items.Contains(selectedItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[TestCase(true)]
|
||||||
public void TestNextItemSelectedAfterDeletion()
|
[TestCase(false)]
|
||||||
|
public void TestNextItemSelectedAfterDeletion(bool allowSelection)
|
||||||
{
|
{
|
||||||
createPlaylist();
|
createPlaylist(p =>
|
||||||
|
{
|
||||||
|
p.AllowSelection = allowSelection;
|
||||||
|
});
|
||||||
|
|
||||||
moveToItem(0);
|
moveToItem(0);
|
||||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||||
@ -57,7 +62,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
moveToDeleteButton(0);
|
moveToDeleteButton(0);
|
||||||
AddStep("click delete button", () => InputManager.Click(MouseButton.Left));
|
AddStep("click delete button", () => InputManager.Click(MouseButton.Left));
|
||||||
|
|
||||||
AddAssert("item 0 is selected", () => playlist.SelectedItem.Value == playlist.Items[0]);
|
AddAssert("item 0 is " + (allowSelection ? "selected" : "not selected"), () => playlist.SelectedItem.Value == (allowSelection ? playlist.Items[0] : null));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -117,7 +122,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
InputManager.MoveMouseTo(item.ChildrenOfType<DrawableRoomPlaylistItem.PlaylistRemoveButton>().ElementAt(0), offset);
|
InputManager.MoveMouseTo(item.ChildrenOfType<DrawableRoomPlaylistItem.PlaylistRemoveButton>().ElementAt(0), offset);
|
||||||
});
|
});
|
||||||
|
|
||||||
private void createPlaylist()
|
private void createPlaylist(Action<TestPlaylist> setupPlaylist = null)
|
||||||
{
|
{
|
||||||
AddStep("create playlist", () =>
|
AddStep("create playlist", () =>
|
||||||
{
|
{
|
||||||
@ -154,6 +159,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupPlaylist?.Invoke(playlist);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded));
|
AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded));
|
||||||
|
@ -54,6 +54,8 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
{
|
{
|
||||||
overlay.ShowBeatmapSet(new APIBeatmapSet
|
overlay.ShowBeatmapSet(new APIBeatmapSet
|
||||||
{
|
{
|
||||||
|
Genre = new BeatmapSetOnlineGenre { Id = 15, Name = "Future genre" },
|
||||||
|
Language = new BeatmapSetOnlineLanguage { Id = 15, Name = "Future language" },
|
||||||
OnlineID = 1235,
|
OnlineID = 1235,
|
||||||
Title = @"an awesome beatmap",
|
Title = @"an awesome beatmap",
|
||||||
Artist = @"naru narusegawa",
|
Artist = @"naru narusegawa",
|
||||||
|
@ -530,6 +530,52 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestTextBoxSavePerChannel()
|
||||||
|
{
|
||||||
|
var testPMChannel = new Channel(testUser);
|
||||||
|
|
||||||
|
AddStep("show overlay", () => chatOverlay.Show());
|
||||||
|
joinTestChannel(0);
|
||||||
|
joinChannel(testPMChannel);
|
||||||
|
|
||||||
|
AddAssert("listing is visible", () => listingIsVisible);
|
||||||
|
AddStep("search for 'number 2'", () => chatOverlayTextBox.Text = "number 2");
|
||||||
|
AddAssert("'number 2' saved to selector", () => channelManager.CurrentChannel.Value.TextBoxMessage.Value == "number 2");
|
||||||
|
|
||||||
|
AddStep("select normal channel", () => clickDrawable(getChannelListItem(testChannel1)));
|
||||||
|
AddAssert("text box cleared on normal channel", () => chatOverlayTextBox.Text == string.Empty);
|
||||||
|
AddAssert("nothing saved on normal channel", () => channelManager.CurrentChannel.Value.TextBoxMessage.Value == string.Empty);
|
||||||
|
AddStep("type '727'", () => chatOverlayTextBox.Text = "727");
|
||||||
|
AddAssert("'727' saved to normal channel", () => channelManager.CurrentChannel.Value.TextBoxMessage.Value == "727");
|
||||||
|
|
||||||
|
AddStep("select PM channel", () => clickDrawable(getChannelListItem(testPMChannel)));
|
||||||
|
AddAssert("text box cleared on PM channel", () => chatOverlayTextBox.Text == string.Empty);
|
||||||
|
AddAssert("nothing saved on PM channel", () => channelManager.CurrentChannel.Value.TextBoxMessage.Value == string.Empty);
|
||||||
|
AddStep("type 'hello'", () => chatOverlayTextBox.Text = "hello");
|
||||||
|
AddAssert("'hello' saved to PM channel", () => channelManager.CurrentChannel.Value.TextBoxMessage.Value == "hello");
|
||||||
|
|
||||||
|
AddStep("select normal channel", () => clickDrawable(getChannelListItem(testChannel1)));
|
||||||
|
AddAssert("text box contains '727'", () => chatOverlayTextBox.Text == "727");
|
||||||
|
|
||||||
|
AddStep("select PM channel", () => clickDrawable(getChannelListItem(testPMChannel)));
|
||||||
|
AddAssert("text box contains 'hello'", () => chatOverlayTextBox.Text == "hello");
|
||||||
|
AddStep("click close button", () =>
|
||||||
|
{
|
||||||
|
ChannelListItemCloseButton closeButton = getChannelListItem(testPMChannel).ChildrenOfType<ChannelListItemCloseButton>().Single();
|
||||||
|
clickDrawable(closeButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("listing is visible", () => listingIsVisible);
|
||||||
|
AddAssert("text box contains 'channel 2'", () => chatOverlayTextBox.Text == "number 2");
|
||||||
|
AddUntilStep("only channel 2 visible", () =>
|
||||||
|
{
|
||||||
|
IEnumerable<ChannelListingItem> listingItems = chatOverlay.ChildrenOfType<ChannelListingItem>()
|
||||||
|
.Where(item => item.IsPresent);
|
||||||
|
return listingItems.Count() == 1 && listingItems.Single().Channel == testChannel2;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void joinTestChannel(int i)
|
private void joinTestChannel(int i)
|
||||||
{
|
{
|
||||||
AddStep($"Join test channel {i}", () => channelManager.JoinChannel(testChannels[i]));
|
AddStep($"Join test channel {i}", () => channelManager.JoinChannel(testChannels[i]));
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Overlays.Profile.Sections.Kudosu;
|
using osu.Game.Overlays.Profile.Sections.Kudosu;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System;
|
using System;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Overlays.Profile.Header.Components;
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
using osu.Game.Rulesets.Catch;
|
using osu.Game.Rulesets.Catch;
|
||||||
@ -24,7 +22,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
public TestSceneProfileRulesetSelector()
|
public TestSceneProfileRulesetSelector()
|
||||||
{
|
{
|
||||||
ProfileRulesetSelector selector;
|
ProfileRulesetSelector selector;
|
||||||
var user = new Bindable<APIUser>();
|
var user = new Bindable<APIUser?>();
|
||||||
|
|
||||||
Child = selector = new ProfileRulesetSelector
|
Child = selector = new ProfileRulesetSelector
|
||||||
{
|
{
|
||||||
|
@ -35,6 +35,8 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
private Action<GetUsersRequest>? handleGetUsersRequest;
|
private Action<GetUsersRequest>? handleGetUsersRequest;
|
||||||
private Action<GetUserRequest>? handleGetUserRequest;
|
private Action<GetUserRequest>? handleGetUserRequest;
|
||||||
|
|
||||||
|
private IDisposable? subscription;
|
||||||
|
|
||||||
private readonly Dictionary<(int userId, string rulesetName), UserStatistics> serverSideStatistics = new Dictionary<(int userId, string rulesetName), UserStatistics>();
|
private readonly Dictionary<(int userId, string rulesetName), UserStatistics> serverSideStatistics = new Dictionary<(int userId, string rulesetName), UserStatistics>();
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
@ -246,6 +248,26 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddAssert("values after are correct", () => update!.After.TotalScore, () => Is.EqualTo(6_000_000));
|
AddAssert("values after are correct", () => update!.After.TotalScore, () => Is.EqualTo(6_000_000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestStatisticsUpdateNotFiredAfterSubscriptionDisposal()
|
||||||
|
{
|
||||||
|
int userId = getUserId();
|
||||||
|
setUpUser(userId);
|
||||||
|
|
||||||
|
long scoreId = getScoreId();
|
||||||
|
var ruleset = new OsuRuleset().RulesetInfo;
|
||||||
|
|
||||||
|
SoloStatisticsUpdate? update = null;
|
||||||
|
registerForUpdates(scoreId, ruleset, receivedUpdate => update = receivedUpdate);
|
||||||
|
AddStep("unsubscribe", () => subscription!.Dispose());
|
||||||
|
|
||||||
|
feignScoreProcessing(userId, ruleset, 5_000_000);
|
||||||
|
|
||||||
|
AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, scoreId));
|
||||||
|
AddWaitStep("wait a bit", 5);
|
||||||
|
AddAssert("update not received", () => update == null);
|
||||||
|
}
|
||||||
|
|
||||||
private int nextUserId = 2000;
|
private int nextUserId = 2000;
|
||||||
private long nextScoreId = 50000;
|
private long nextScoreId = 50000;
|
||||||
|
|
||||||
@ -266,7 +288,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void registerForUpdates(long scoreId, RulesetInfo rulesetInfo, Action<SoloStatisticsUpdate> onUpdateReady) =>
|
private void registerForUpdates(long scoreId, RulesetInfo rulesetInfo, Action<SoloStatisticsUpdate> onUpdateReady) =>
|
||||||
AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter(
|
AddStep("register for updates", () => subscription = watcher.RegisterForStatisticsUpdateAfter(
|
||||||
new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser())
|
new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser())
|
||||||
{
|
{
|
||||||
Ruleset = rulesetInfo,
|
Ruleset = rulesetInfo,
|
||||||
|
@ -50,6 +50,8 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
private ChannelManager channelManager;
|
private ChannelManager channelManager;
|
||||||
|
|
||||||
private TestStandAloneChatDisplay chatDisplay;
|
private TestStandAloneChatDisplay chatDisplay;
|
||||||
|
private TestStandAloneChatDisplay chatWithTextBox;
|
||||||
|
private TestStandAloneChatDisplay chatWithTextBox2;
|
||||||
private int messageIdSequence;
|
private int messageIdSequence;
|
||||||
|
|
||||||
private Channel testChannel;
|
private Channel testChannel;
|
||||||
@ -78,7 +80,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
|
|
||||||
private void reinitialiseDrawableDisplay()
|
private void reinitialiseDrawableDisplay()
|
||||||
{
|
{
|
||||||
Children = new[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
chatDisplay = new TestStandAloneChatDisplay
|
chatDisplay = new TestStandAloneChatDisplay
|
||||||
{
|
{
|
||||||
@ -88,13 +90,28 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
Size = new Vector2(400, 80),
|
Size = new Vector2(400, 80),
|
||||||
Channel = { Value = testChannel },
|
Channel = { Value = testChannel },
|
||||||
},
|
},
|
||||||
new TestStandAloneChatDisplay(true)
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
Origin = Anchor.CentreRight,
|
Origin = Anchor.CentreRight,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Margin = new MarginPadding(20),
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
chatWithTextBox = new TestStandAloneChatDisplay(true)
|
||||||
|
{
|
||||||
Margin = new MarginPadding(20),
|
Margin = new MarginPadding(20),
|
||||||
Size = new Vector2(400, 150),
|
Size = new Vector2(400, 150),
|
||||||
Channel = { Value = testChannel },
|
Channel = { Value = testChannel },
|
||||||
|
},
|
||||||
|
chatWithTextBox2 = new TestStandAloneChatDisplay(true)
|
||||||
|
{
|
||||||
|
Margin = new MarginPadding(20),
|
||||||
|
Size = new Vector2(400, 150),
|
||||||
|
Channel = { Value = testChannel },
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -351,6 +368,13 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
checkScrolledToBottom();
|
checkScrolledToBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestTextBoxSync()
|
||||||
|
{
|
||||||
|
AddStep("type 'hello' to text box 1", () => chatWithTextBox.ChildrenOfType<StandAloneChatDisplay.ChatTextBox>().Single().Text = "hello");
|
||||||
|
AddAssert("text box 2 contains 'hello'", () => chatWithTextBox2.ChildrenOfType<StandAloneChatDisplay.ChatTextBox>().Single().Text == "hello");
|
||||||
|
}
|
||||||
|
|
||||||
private void fillChat(int count = 10)
|
private void fillChat(int count = 10)
|
||||||
{
|
{
|
||||||
AddStep("fill chat", () =>
|
AddStep("fill chat", () =>
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
@ -20,7 +18,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[Cached]
|
[Cached]
|
||||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||||
|
|
||||||
private ProfileHeader header;
|
private ProfileHeader header = null!;
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUpSteps()
|
public void SetUpSteps()
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -14,7 +12,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public partial class TestSceneUserProfilePreviousUsernames : OsuTestScene
|
public partial class TestSceneUserProfilePreviousUsernames : OsuTestScene
|
||||||
{
|
{
|
||||||
private PreviousUsernames container;
|
private PreviousUsernames container = null!;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp() => Schedule(() =>
|
public void SetUp() => Schedule(() =>
|
||||||
@ -50,7 +48,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddUntilStep("Is hidden", () => container.Alpha == 0);
|
AddUntilStep("Is hidden", () => container.Alpha == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly APIUser[] users =
|
private static readonly APIUser?[] users =
|
||||||
{
|
{
|
||||||
new APIUser { Id = 1, PreviousUsernames = new[] { "username1" } },
|
new APIUser { Id = 1, PreviousUsernames = new[] { "username1" } },
|
||||||
new APIUser { Id = 2, PreviousUsernames = new[] { "longusername", "longerusername" } },
|
new APIUser { Id = 2, PreviousUsernames = new[] { "longusername", "longerusername" } },
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
117
osu.Game.Tests/Visual/Ranking/TestSceneOverallRanking.cs
Normal file
117
osu.Game.Tests/Visual/Ranking/TestSceneOverallRanking.cs
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Online.Solo;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Screens.Ranking.Statistics.User;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Ranking
|
||||||
|
{
|
||||||
|
public partial class TestSceneOverallRanking : OsuTestScene
|
||||||
|
{
|
||||||
|
private OverallRanking overallRanking = null!;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUpdatePending()
|
||||||
|
{
|
||||||
|
createDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAllIncreased()
|
||||||
|
{
|
||||||
|
createDisplay();
|
||||||
|
displayUpdate(
|
||||||
|
new UserStatistics
|
||||||
|
{
|
||||||
|
GlobalRank = 12_345,
|
||||||
|
Accuracy = 98.99,
|
||||||
|
MaxCombo = 2_322,
|
||||||
|
RankedScore = 23_123_543_456,
|
||||||
|
TotalScore = 123_123_543_456,
|
||||||
|
PP = 5_072
|
||||||
|
},
|
||||||
|
new UserStatistics
|
||||||
|
{
|
||||||
|
GlobalRank = 1_234,
|
||||||
|
Accuracy = 99.07,
|
||||||
|
MaxCombo = 2_352,
|
||||||
|
RankedScore = 23_124_231_435,
|
||||||
|
TotalScore = 123_124_231_435,
|
||||||
|
PP = 5_434
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAllDecreased()
|
||||||
|
{
|
||||||
|
createDisplay();
|
||||||
|
displayUpdate(
|
||||||
|
new UserStatistics
|
||||||
|
{
|
||||||
|
GlobalRank = 1_234,
|
||||||
|
Accuracy = 99.07,
|
||||||
|
MaxCombo = 2_352,
|
||||||
|
RankedScore = 23_124_231_435,
|
||||||
|
TotalScore = 123_124_231_435,
|
||||||
|
PP = 5_434
|
||||||
|
},
|
||||||
|
new UserStatistics
|
||||||
|
{
|
||||||
|
GlobalRank = 12_345,
|
||||||
|
Accuracy = 98.99,
|
||||||
|
MaxCombo = 2_322,
|
||||||
|
RankedScore = 23_123_543_456,
|
||||||
|
TotalScore = 123_123_543_456,
|
||||||
|
PP = 5_072
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNoChanges()
|
||||||
|
{
|
||||||
|
var statistics = new UserStatistics
|
||||||
|
{
|
||||||
|
GlobalRank = 12_345,
|
||||||
|
Accuracy = 98.99,
|
||||||
|
MaxCombo = 2_322,
|
||||||
|
RankedScore = 23_123_543_456,
|
||||||
|
TotalScore = 123_123_543_456,
|
||||||
|
PP = 5_072
|
||||||
|
};
|
||||||
|
|
||||||
|
createDisplay();
|
||||||
|
displayUpdate(statistics, statistics);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNotRanked()
|
||||||
|
{
|
||||||
|
var statistics = new UserStatistics
|
||||||
|
{
|
||||||
|
GlobalRank = null,
|
||||||
|
Accuracy = 98.99,
|
||||||
|
MaxCombo = 2_322,
|
||||||
|
RankedScore = 23_123_543_456,
|
||||||
|
TotalScore = 123_123_543_456,
|
||||||
|
PP = null
|
||||||
|
};
|
||||||
|
|
||||||
|
createDisplay();
|
||||||
|
displayUpdate(statistics, statistics);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createDisplay() => AddStep("create display", () => Child = overallRanking = new OverallRanking
|
||||||
|
{
|
||||||
|
Width = 400,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre
|
||||||
|
});
|
||||||
|
|
||||||
|
private void displayUpdate(UserStatistics before, UserStatistics after) =>
|
||||||
|
AddStep("display update", () => overallRanking.StatisticsUpdate.Value = new SoloStatisticsUpdate(new ScoreInfo(), before, after));
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Overlays.Profile.Sections;
|
using osu.Game.Overlays.Profile.Sections;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
@ -18,7 +16,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
[Cached]
|
[Cached]
|
||||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink);
|
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink);
|
||||||
|
|
||||||
private ProfileSubsectionHeader header;
|
private ProfileSubsectionHeader header = null!;
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestHiddenCounter()
|
public void TestHiddenCounter()
|
||||||
|
@ -55,6 +55,16 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDisplay()
|
||||||
|
{
|
||||||
|
AddRepeatStep("toggle expanded state", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(group.ChildrenOfType<IconButton>().Single());
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
}, 5);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestClickExpandButtonMultipleTimes()
|
public void TestClickExpandButtonMultipleTimes()
|
||||||
{
|
{
|
||||||
|
@ -127,7 +127,7 @@ namespace osu.Game.Tournament.IPC
|
|||||||
using (var stream = IPCStorage.GetStream(file_ipc_state_filename))
|
using (var stream = IPCStorage.GetStream(file_ipc_state_filename))
|
||||||
using (var sr = new StreamReader(stream))
|
using (var sr = new StreamReader(stream))
|
||||||
{
|
{
|
||||||
State.Value = (TourneyState)Enum.Parse(typeof(TourneyState), sr.ReadLine().AsNonNull());
|
State.Value = Enum.Parse<TourneyState>(sr.ReadLine().AsNonNull());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Tournament.Screens.Drawings.Components
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// ReSharper disable once PossibleNullReferenceException
|
// ReSharper disable once PossibleNullReferenceException
|
||||||
string[] split = line.Split(':');
|
string[] split = line.Split(':', StringSplitOptions.TrimEntries);
|
||||||
|
|
||||||
if (split.Length < 2)
|
if (split.Length < 2)
|
||||||
{
|
{
|
||||||
@ -55,9 +55,9 @@ namespace osu.Game.Tournament.Screens.Drawings.Components
|
|||||||
|
|
||||||
teams.Add(new TournamentTeam
|
teams.Add(new TournamentTeam
|
||||||
{
|
{
|
||||||
FullName = { Value = split[1].Trim(), },
|
FullName = { Value = split[1], },
|
||||||
Acronym = { Value = split.Length >= 3 ? split[2].Trim() : null, },
|
Acronym = { Value = split.Length >= 3 ? split[2] : null, },
|
||||||
FlagName = { Value = split[0].Trim() }
|
FlagName = { Value = split[0] }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
{
|
{
|
||||||
var countries = new List<TournamentTeam>();
|
var countries = new List<TournamentTeam>();
|
||||||
|
|
||||||
foreach (var country in Enum.GetValues(typeof(CountryCode)).Cast<CountryCode>().Skip(1))
|
foreach (var country in Enum.GetValues<CountryCode>().Skip(1))
|
||||||
{
|
{
|
||||||
countries.Add(new TournamentTeam
|
countries.Add(new TournamentTeam
|
||||||
{
|
{
|
||||||
|
22
osu.Game/Beatmaps/BeatmapSetOnlineNomination.cs
Normal file
22
osu.Game/Beatmaps/BeatmapSetOnlineNomination.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// 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 Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps
|
||||||
|
{
|
||||||
|
public struct BeatmapSetOnlineNomination
|
||||||
|
{
|
||||||
|
[JsonProperty(@"beatmapset_id")]
|
||||||
|
public int BeatmapsetId { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(@"reset")]
|
||||||
|
public bool Reset { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(@"rulesets")]
|
||||||
|
public string[]? Rulesets { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(@"user_id")]
|
||||||
|
public int UserId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -5,16 +5,19 @@ using System;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online;
|
using osu.Game.Online;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Drawables.Cards
|
namespace osu.Game.Beatmaps.Drawables.Cards
|
||||||
{
|
{
|
||||||
public abstract partial class BeatmapCard : OsuClickableContainer
|
public abstract partial class BeatmapCard : OsuClickableContainer, IHasContextMenu
|
||||||
{
|
{
|
||||||
public const float TRANSITION_DURATION = 400;
|
public const float TRANSITION_DURATION = 400;
|
||||||
public const float CORNER_RADIUS = 10;
|
public const float CORNER_RADIUS = 10;
|
||||||
@ -96,5 +99,10 @@ namespace osu.Game.Beatmaps.Drawables.Cards
|
|||||||
throw new ArgumentOutOfRangeException(nameof(size), size, @"Unsupported card size");
|
throw new ArgumentOutOfRangeException(nameof(size), size, @"Unsupported card size");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MenuItem[] ContextMenuItems => new MenuItem[]
|
||||||
|
{
|
||||||
|
new OsuMenuItem(ContextMenuStrings.ViewBeatmap, MenuItemType.Highlighted, Action),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,9 +138,18 @@ namespace osu.Game.Beatmaps.Drawables.Cards
|
|||||||
// This avoids depth issues where a hovered (scaled) card to the right of another card would be beneath the card to the left.
|
// This avoids depth issues where a hovered (scaled) card to the right of another card would be beneath the card to the left.
|
||||||
this.ScaleTo(Expanded.Value ? 1.03f : 1, 500, Easing.OutQuint);
|
this.ScaleTo(Expanded.Value ? 1.03f : 1, 500, Easing.OutQuint);
|
||||||
|
|
||||||
background.FadeTo(Expanded.Value ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
if (Expanded.Value)
|
||||||
dropdownContent.FadeTo(Expanded.Value ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
{
|
||||||
borderContainer.FadeTo(Expanded.Value ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
background.FadeIn(BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
dropdownContent.FadeIn(BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
borderContainer.FadeIn(BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
background.FadeOut(BeatmapCard.TRANSITION_DURATION / 3f, Easing.OutQuint);
|
||||||
|
dropdownContent.FadeOut(BeatmapCard.TRANSITION_DURATION / 3f, Easing.OutQuint);
|
||||||
|
borderContainer.FadeOut(BeatmapCard.TRANSITION_DURATION / 3f, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
content.TweenEdgeEffectTo(new EdgeEffectParameters
|
content.TweenEdgeEffectTo(new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
|
@ -160,7 +160,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case @"SampleSet":
|
case @"SampleSet":
|
||||||
defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), pair.Value);
|
defaultSampleBank = Enum.Parse<LegacySampleBank>(pair.Value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case @"SampleVolume":
|
case @"SampleVolume":
|
||||||
@ -218,7 +218,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case @"Countdown":
|
case @"Countdown":
|
||||||
beatmap.BeatmapInfo.Countdown = (CountdownType)Enum.Parse(typeof(CountdownType), pair.Value);
|
beatmap.BeatmapInfo.Countdown = Enum.Parse<CountdownType>(pair.Value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case @"CountdownOffset":
|
case @"CountdownOffset":
|
||||||
|
@ -300,7 +300,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
var comboColour = colours[i];
|
var comboColour = colours[i];
|
||||||
|
|
||||||
writer.Write(FormattableString.Invariant($"Combo{i}: "));
|
writer.Write(FormattableString.Invariant($"Combo{1 + i}: "));
|
||||||
writer.Write(FormattableString.Invariant($"{(byte)(comboColour.R * byte.MaxValue)},"));
|
writer.Write(FormattableString.Invariant($"{(byte)(comboColour.R * byte.MaxValue)},"));
|
||||||
writer.Write(FormattableString.Invariant($"{(byte)(comboColour.G * byte.MaxValue)},"));
|
writer.Write(FormattableString.Invariant($"{(byte)(comboColour.G * byte.MaxValue)},"));
|
||||||
writer.Write(FormattableString.Invariant($"{(byte)(comboColour.B * byte.MaxValue)},"));
|
writer.Write(FormattableString.Invariant($"{(byte)(comboColour.B * byte.MaxValue)},"));
|
||||||
|
@ -132,13 +132,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
protected KeyValuePair<string, string> SplitKeyVal(string line, char separator = ':', bool shouldTrim = true)
|
protected KeyValuePair<string, string> SplitKeyVal(string line, char separator = ':', bool shouldTrim = true)
|
||||||
{
|
{
|
||||||
string[] split = line.Split(separator, 2);
|
string[] split = line.Split(separator, 2, shouldTrim ? StringSplitOptions.TrimEntries : StringSplitOptions.None);
|
||||||
|
|
||||||
if (shouldTrim)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < split.Length; i++)
|
|
||||||
split[i] = split[i].Trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new KeyValuePair<string, string>
|
return new KeyValuePair<string, string>
|
||||||
(
|
(
|
||||||
|
@ -301,11 +301,11 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string parseLayer(string value) => Enum.Parse(typeof(LegacyStoryLayer), value).ToString();
|
private string parseLayer(string value) => Enum.Parse<LegacyStoryLayer>(value).ToString();
|
||||||
|
|
||||||
private Anchor parseOrigin(string value)
|
private Anchor parseOrigin(string value)
|
||||||
{
|
{
|
||||||
var origin = (LegacyOrigins)Enum.Parse(typeof(LegacyOrigins), value);
|
var origin = Enum.Parse<LegacyOrigins>(value);
|
||||||
|
|
||||||
switch (origin)
|
switch (origin)
|
||||||
{
|
{
|
||||||
@ -343,8 +343,8 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
private AnimationLoopType parseAnimationLoopType(string value)
|
private AnimationLoopType parseAnimationLoopType(string value)
|
||||||
{
|
{
|
||||||
var parsed = (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), value);
|
var parsed = Enum.Parse<AnimationLoopType>(value);
|
||||||
return Enum.IsDefined(typeof(AnimationLoopType), parsed) ? parsed : AnimationLoopType.LoopForever;
|
return Enum.IsDefined(parsed) ? parsed : AnimationLoopType.LoopForever;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleVariables(string line)
|
private void handleVariables(string line)
|
||||||
|
@ -34,8 +34,6 @@ namespace osu.Game.Beatmaps
|
|||||||
// TODO: remove once the fallback lookup is not required (and access via `working.BeatmapInfo.Metadata` directly).
|
// TODO: remove once the fallback lookup is not required (and access via `working.BeatmapInfo.Metadata` directly).
|
||||||
public BeatmapMetadata Metadata => BeatmapInfo.Metadata;
|
public BeatmapMetadata Metadata => BeatmapInfo.Metadata;
|
||||||
|
|
||||||
public Waveform Waveform => waveform.Value;
|
|
||||||
|
|
||||||
public Storyboard Storyboard => storyboard.Value;
|
public Storyboard Storyboard => storyboard.Value;
|
||||||
|
|
||||||
public Texture Background => GetBackground(); // Texture uses ref counting, so we want to return a new instance every usage.
|
public Texture Background => GetBackground(); // Texture uses ref counting, so we want to return a new instance every usage.
|
||||||
@ -48,10 +46,11 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
private readonly object beatmapFetchLock = new object();
|
private readonly object beatmapFetchLock = new object();
|
||||||
|
|
||||||
private readonly Lazy<Waveform> waveform;
|
|
||||||
private readonly Lazy<Storyboard> storyboard;
|
private readonly Lazy<Storyboard> storyboard;
|
||||||
private readonly Lazy<ISkin> skin;
|
private readonly Lazy<ISkin> skin;
|
||||||
|
|
||||||
private Track track; // track is not Lazy as we allow transferring and loading multiple times.
|
private Track track; // track is not Lazy as we allow transferring and loading multiple times.
|
||||||
|
private Waveform waveform; // waveform is also not Lazy as the track may change.
|
||||||
|
|
||||||
protected WorkingBeatmap(BeatmapInfo beatmapInfo, AudioManager audioManager)
|
protected WorkingBeatmap(BeatmapInfo beatmapInfo, AudioManager audioManager)
|
||||||
{
|
{
|
||||||
@ -60,7 +59,6 @@ namespace osu.Game.Beatmaps
|
|||||||
BeatmapInfo = beatmapInfo;
|
BeatmapInfo = beatmapInfo;
|
||||||
BeatmapSetInfo = beatmapInfo.BeatmapSet ?? new BeatmapSetInfo();
|
BeatmapSetInfo = beatmapInfo.BeatmapSet ?? new BeatmapSetInfo();
|
||||||
|
|
||||||
waveform = new Lazy<Waveform>(GetWaveform);
|
|
||||||
storyboard = new Lazy<Storyboard>(GetStoryboard);
|
storyboard = new Lazy<Storyboard>(GetStoryboard);
|
||||||
skin = new Lazy<ISkin>(GetSkin);
|
skin = new Lazy<ISkin>(GetSkin);
|
||||||
}
|
}
|
||||||
@ -108,7 +106,16 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public virtual bool TrackLoaded => track != null;
|
public virtual bool TrackLoaded => track != null;
|
||||||
|
|
||||||
public Track LoadTrack() => track = GetBeatmapTrack() ?? GetVirtualTrack(1000);
|
public Track LoadTrack()
|
||||||
|
{
|
||||||
|
track = GetBeatmapTrack() ?? GetVirtualTrack(1000);
|
||||||
|
|
||||||
|
// the track may have changed, recycle the current waveform.
|
||||||
|
waveform?.Dispose();
|
||||||
|
waveform = null;
|
||||||
|
|
||||||
|
return track;
|
||||||
|
}
|
||||||
|
|
||||||
public void PrepareTrackForPreview(bool looping, double offsetFromPreviewPoint = 0)
|
public void PrepareTrackForPreview(bool looping, double offsetFromPreviewPoint = 0)
|
||||||
{
|
{
|
||||||
@ -171,6 +178,12 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Waveform
|
||||||
|
|
||||||
|
public Waveform Waveform => waveform ??= GetWaveform();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Beatmap
|
#region Beatmap
|
||||||
|
|
||||||
public virtual bool BeatmapLoaded => beatmapLoadTask?.IsCompleted ?? false;
|
public virtual bool BeatmapLoaded => beatmapLoadTask?.IsCompleted ?? false;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework;
|
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
@ -63,10 +62,10 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
private void copyToStore(RealmFile file, Stream data, bool preferHardLinks)
|
private void copyToStore(RealmFile file, Stream data, bool preferHardLinks)
|
||||||
{
|
{
|
||||||
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows && data is FileStream fs && preferHardLinks)
|
if (data is FileStream fs && preferHardLinks)
|
||||||
{
|
{
|
||||||
// attempt to do a fast hard link rather than copy.
|
// attempt to do a fast hard link rather than copy.
|
||||||
if (HardLinkHelper.CreateHardLink(Storage.GetFullPath(file.GetStoragePath(), true), fs.Name, IntPtr.Zero))
|
if (HardLinkHelper.TryCreateHardLink(Storage.GetFullPath(file.GetStoragePath(), true), fs.Name))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,38 +22,8 @@ namespace osu.Game.Graphics
|
|||||||
public static Color4 Gray(byte amt) => new Color4(amt, amt, amt, 255);
|
public static Color4 Gray(byte amt) => new Color4(amt, amt, amt, 255);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the colour for a <see cref="DifficultyRating"/>.
|
/// Retrieves the colour for a given point in the star range.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
|
||||||
/// Sourced from the @diff-{rating} variables in https://github.com/ppy/osu-web/blob/71fbab8936d79a7929d13854f5e854b4f383b236/resources/assets/less/variables.less.
|
|
||||||
/// </remarks>
|
|
||||||
public Color4 ForDifficultyRating(DifficultyRating difficulty, bool useLighterColour = false)
|
|
||||||
{
|
|
||||||
switch (difficulty)
|
|
||||||
{
|
|
||||||
case DifficultyRating.Easy:
|
|
||||||
return Color4Extensions.FromHex("4ebfff");
|
|
||||||
|
|
||||||
case DifficultyRating.Normal:
|
|
||||||
return Color4Extensions.FromHex("66ff91");
|
|
||||||
|
|
||||||
case DifficultyRating.Hard:
|
|
||||||
return Color4Extensions.FromHex("f7e85d");
|
|
||||||
|
|
||||||
case DifficultyRating.Insane:
|
|
||||||
return Color4Extensions.FromHex("ff7e68");
|
|
||||||
|
|
||||||
case DifficultyRating.Expert:
|
|
||||||
return Color4Extensions.FromHex("fe3c71");
|
|
||||||
|
|
||||||
case DifficultyRating.ExpertPlus:
|
|
||||||
return Color4Extensions.FromHex("6662dd");
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(difficulty));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color4 ForStarDifficulty(double starDifficulty) => ColourUtils.SampleFromLinearGradient(new[]
|
public Color4 ForStarDifficulty(double starDifficulty) => ColourUtils.SampleFromLinearGradient(new[]
|
||||||
{
|
{
|
||||||
(0.1f, Color4Extensions.FromHex("aaaaaa")),
|
(0.1f, Color4Extensions.FromHex("aaaaaa")),
|
||||||
|
@ -82,7 +82,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
if (Link != null)
|
if (Link != null)
|
||||||
{
|
{
|
||||||
items.Add(new OsuMenuItem("Open", MenuItemType.Standard, () => host.OpenUrlExternally(Link)));
|
items.Add(new OsuMenuItem("Open", MenuItemType.Highlighted, () => host.OpenUrlExternally(Link)));
|
||||||
items.Add(new OsuMenuItem("Copy URL", MenuItemType.Standard, copyUrl));
|
items.Add(new OsuMenuItem("Copy URL", MenuItemType.Standard, copyUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,9 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
protected override bool OnKeyDown(KeyDownEvent e)
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
{
|
{
|
||||||
|
if (e.ControlPressed || e.AltPressed || e.SuperPressed || e.ShiftPressed)
|
||||||
|
return false;
|
||||||
|
|
||||||
switch (e.Key)
|
switch (e.Key)
|
||||||
{
|
{
|
||||||
case Key.Up:
|
case Key.Up:
|
||||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
public OsuEnumDropdown()
|
public OsuEnumDropdown()
|
||||||
{
|
{
|
||||||
Items = (T[])Enum.GetValues(typeof(T));
|
Items = Enum.GetValues<T>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,8 @@ namespace osu.Game.IO
|
|||||||
{
|
{
|
||||||
public static bool CheckAvailability(string testDestinationPath, string testSourcePath)
|
public static bool CheckAvailability(string testDestinationPath, string testSourcePath)
|
||||||
{
|
{
|
||||||
// We can support other operating systems quite easily in the future.
|
// For simplicity, only support desktop operating systems for now.
|
||||||
// Let's handle the most common one for now, though.
|
if (!RuntimeInfo.IsDesktop)
|
||||||
if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const string test_filename = "_hard_link_test";
|
const string test_filename = "_hard_link_test";
|
||||||
@ -31,7 +30,7 @@ namespace osu.Game.IO
|
|||||||
File.WriteAllText(testSourcePath, string.Empty);
|
File.WriteAllText(testSourcePath, string.Empty);
|
||||||
|
|
||||||
// Test availability by creating an arbitrary hard link between the source and destination paths.
|
// Test availability by creating an arbitrary hard link between the source and destination paths.
|
||||||
return CreateHardLink(testDestinationPath, testSourcePath, IntPtr.Zero);
|
return TryCreateHardLink(testDestinationPath, testSourcePath);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -55,10 +54,38 @@ namespace osu.Game.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to create a hard link from <paramref name="sourcePath"/> to <paramref name="destinationPath"/>,
|
||||||
|
/// using platform-specific native methods.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Hard links are only available on desktop platforms.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>Whether the hard link was successfully created.</returns>
|
||||||
|
public static bool TryCreateHardLink(string destinationPath, string sourcePath)
|
||||||
|
{
|
||||||
|
switch (RuntimeInfo.OS)
|
||||||
|
{
|
||||||
|
case RuntimeInfo.Platform.Windows:
|
||||||
|
return CreateHardLink(destinationPath, sourcePath, IntPtr.Zero);
|
||||||
|
|
||||||
|
case RuntimeInfo.Platform.Linux:
|
||||||
|
case RuntimeInfo.Platform.macOS:
|
||||||
|
return link(sourcePath, destinationPath) == 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// For future use (to detect if a file is a hard link with other references existing on disk).
|
// For future use (to detect if a file is a hard link with other references existing on disk).
|
||||||
public static int GetFileLinkCount(string filePath)
|
public static int GetFileLinkCount(string filePath)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
|
switch (RuntimeInfo.OS)
|
||||||
|
{
|
||||||
|
case RuntimeInfo.Platform.Windows:
|
||||||
SafeFileHandle handle = CreateFile(filePath, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, FileAttributes.Archive, IntPtr.Zero);
|
SafeFileHandle handle = CreateFile(filePath, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, FileAttributes.Archive, IntPtr.Zero);
|
||||||
|
|
||||||
ByHandleFileInformation fileInfo;
|
ByHandleFileInformation fileInfo;
|
||||||
@ -66,10 +93,21 @@ namespace osu.Game.IO
|
|||||||
if (GetFileInformationByHandle(handle, out fileInfo))
|
if (GetFileInformationByHandle(handle, out fileInfo))
|
||||||
result = (int)fileInfo.NumberOfLinks;
|
result = (int)fileInfo.NumberOfLinks;
|
||||||
CloseHandle(handle);
|
CloseHandle(handle);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RuntimeInfo.Platform.Linux:
|
||||||
|
case RuntimeInfo.Platform.macOS:
|
||||||
|
if (stat(filePath, out var statbuf) == 0)
|
||||||
|
result = (int)statbuf.st_nlink;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Windows native methods
|
||||||
|
|
||||||
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
public static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes);
|
public static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes);
|
||||||
|
|
||||||
@ -104,5 +142,49 @@ namespace osu.Game.IO
|
|||||||
public readonly uint FileIndexHigh;
|
public readonly uint FileIndexHigh;
|
||||||
public readonly uint FileIndexLow;
|
public readonly uint FileIndexLow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Linux native methods
|
||||||
|
|
||||||
|
#pragma warning disable IDE1006 // Naming rule violation
|
||||||
|
|
||||||
|
[DllImport("libc", SetLastError = true)]
|
||||||
|
public static extern int link(string oldpath, string newpath);
|
||||||
|
|
||||||
|
[DllImport("libc", SetLastError = true)]
|
||||||
|
private static extern int stat(string pathname, out struct_stat statbuf);
|
||||||
|
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
// Struct layout is likely non-portable across unices. Tread with caution.
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct struct_stat
|
||||||
|
{
|
||||||
|
public readonly long st_dev;
|
||||||
|
public readonly long st_ino;
|
||||||
|
public readonly long st_nlink;
|
||||||
|
public readonly int st_mode;
|
||||||
|
public readonly int st_uid;
|
||||||
|
public readonly int st_gid;
|
||||||
|
public readonly long st_rdev;
|
||||||
|
public readonly long st_size;
|
||||||
|
public readonly long st_blksize;
|
||||||
|
public readonly long st_blocks;
|
||||||
|
public readonly timespec st_atim;
|
||||||
|
public readonly timespec st_mtim;
|
||||||
|
public readonly timespec st_ctim;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct timespec
|
||||||
|
{
|
||||||
|
public readonly long tv_sec;
|
||||||
|
public readonly long tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning restore IDE1006
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
osu.Game/Localisation/ContextMenuStrings.cs
Normal file
24
osu.Game/Localisation/ContextMenuStrings.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// 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.Localisation;
|
||||||
|
|
||||||
|
namespace osu.Game.Localisation
|
||||||
|
{
|
||||||
|
public static class ContextMenuStrings
|
||||||
|
{
|
||||||
|
private const string prefix = @"osu.Game.Resources.Localisation.ContextMenu";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "View profile"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ViewProfile => new TranslatableString(getKey(@"view_profile"), @"View profile");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "View beatmap"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ViewBeatmap => new TranslatableString(getKey(@"view_beatmap"), @"View beatmap");
|
||||||
|
|
||||||
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
|
}
|
||||||
|
}
|
@ -259,7 +259,11 @@ namespace osu.Game.Online.API
|
|||||||
|
|
||||||
var friendsReq = new GetFriendsRequest();
|
var friendsReq = new GetFriendsRequest();
|
||||||
friendsReq.Failure += _ => state.Value = APIState.Failing;
|
friendsReq.Failure += _ => state.Value = APIState.Failing;
|
||||||
friendsReq.Success += res => friends.AddRange(res);
|
friendsReq.Success += res =>
|
||||||
|
{
|
||||||
|
friends.Clear();
|
||||||
|
friends.AddRange(res);
|
||||||
|
};
|
||||||
|
|
||||||
if (!handleRequest(friendsReq))
|
if (!handleRequest(friendsReq))
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
@ -11,10 +9,11 @@ using osu.Game.Online.API.Requests.Responses;
|
|||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace osu.Game.Online.API.Requests
|
namespace osu.Game.Online.API.Requests
|
||||||
{
|
{
|
||||||
public class GetScoresRequest : APIRequest<APIScoresCollection>
|
public class GetScoresRequest : APIRequest<APIScoresCollection>, IEquatable<GetScoresRequest>
|
||||||
{
|
{
|
||||||
public const int MAX_SCORES_PER_REQUEST = 50;
|
public const int MAX_SCORES_PER_REQUEST = 50;
|
||||||
|
|
||||||
@ -23,7 +22,7 @@ namespace osu.Game.Online.API.Requests
|
|||||||
private readonly IRulesetInfo ruleset;
|
private readonly IRulesetInfo ruleset;
|
||||||
private readonly IEnumerable<IMod> mods;
|
private readonly IEnumerable<IMod> mods;
|
||||||
|
|
||||||
public GetScoresRequest(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable<IMod> mods = null)
|
public GetScoresRequest(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable<IMod>? mods = null)
|
||||||
{
|
{
|
||||||
if (beatmapInfo.OnlineID <= 0)
|
if (beatmapInfo.OnlineID <= 0)
|
||||||
throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(IBeatmapInfo.OnlineID)}.");
|
throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(IBeatmapInfo.OnlineID)}.");
|
||||||
@ -51,5 +50,16 @@ namespace osu.Game.Online.API.Requests
|
|||||||
|
|
||||||
return query.ToString();
|
return query.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Equals(GetScoresRequest? other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other)) return false;
|
||||||
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
|
||||||
|
return beatmapInfo.Equals(other.beatmapInfo)
|
||||||
|
&& scope == other.scope
|
||||||
|
&& ruleset.Equals(other.ruleset)
|
||||||
|
&& mods.SequenceEqual(other.mods);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,12 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
[JsonProperty(@"language")]
|
[JsonProperty(@"language")]
|
||||||
public BeatmapSetOnlineLanguage Language { get; set; }
|
public BeatmapSetOnlineLanguage Language { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(@"current_nominations")]
|
||||||
|
public BeatmapSetOnlineNomination[]? CurrentNominations { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(@"related_users")]
|
||||||
|
public APIUser[]? RelatedUsers { get; set; }
|
||||||
|
|
||||||
public string Source { get; set; } = string.Empty;
|
public string Source { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonProperty(@"tags")]
|
[JsonProperty(@"tags")]
|
||||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
private string type
|
private string type
|
||||||
{
|
{
|
||||||
set => Type = (RecentActivityType)Enum.Parse(typeof(RecentActivityType), value.ToPascalCase());
|
set => Type = Enum.Parse<RecentActivityType>(value.ToPascalCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecentActivityType Type;
|
public RecentActivityType Type;
|
||||||
@ -29,7 +29,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
private string scoreRank
|
private string scoreRank
|
||||||
{
|
{
|
||||||
set => ScoreRank = (ScoreRank)Enum.Parse(typeof(ScoreRank), value);
|
set => ScoreRank = Enum.Parse<ScoreRank>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScoreRank ScoreRank;
|
public ScoreRank ScoreRank;
|
||||||
|
@ -185,7 +185,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
[JsonProperty(@"playstyle")]
|
[JsonProperty(@"playstyle")]
|
||||||
private string[] playStyle
|
private string[] playStyle
|
||||||
{
|
{
|
||||||
set => PlayStyles = value?.Select(str => Enum.Parse(typeof(APIPlayStyle), str, true)).Cast<APIPlayStyle>().ToArray();
|
set => PlayStyles = value?.Select(str => Enum.Parse<APIPlayStyle>(str, true)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public APIPlayStyle[] PlayStyles;
|
public APIPlayStyle[] PlayStyles;
|
||||||
|
@ -98,6 +98,11 @@ namespace osu.Game.Online.Chat
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Bindable<Message> HighlightedMessage = new Bindable<Message>();
|
public Bindable<Message> HighlightedMessage = new Bindable<Message>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current text box message while in this <see cref="Channel"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Bindable<string> TextBoxMessage = new Bindable<string>(string.Empty);
|
||||||
|
|
||||||
[JsonConstructor]
|
[JsonConstructor]
|
||||||
public Channel()
|
public Channel()
|
||||||
{
|
{
|
||||||
|
@ -341,6 +341,8 @@ namespace osu.Game.Online.Chat
|
|||||||
OpenWiki,
|
OpenWiki,
|
||||||
Custom,
|
Custom,
|
||||||
OpenChangelog,
|
OpenChangelog,
|
||||||
|
FilterBeatmapSetGenre,
|
||||||
|
FilterBeatmapSetLanguage,
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Link : IComparable<Link>
|
public class Link : IComparable<Link>
|
||||||
|
@ -111,8 +111,13 @@ namespace osu.Game.Online.Chat
|
|||||||
{
|
{
|
||||||
drawableChannel?.Expire();
|
drawableChannel?.Expire();
|
||||||
|
|
||||||
|
if (e.OldValue != null)
|
||||||
|
TextBox?.Current.UnbindFrom(e.OldValue.TextBoxMessage);
|
||||||
|
|
||||||
if (e.NewValue == null) return;
|
if (e.NewValue == null) return;
|
||||||
|
|
||||||
|
TextBox?.Current.BindTo(e.NewValue.TextBoxMessage);
|
||||||
|
|
||||||
drawableChannel = CreateDrawableChannel(e.NewValue);
|
drawableChannel = CreateDrawableChannel(e.NewValue);
|
||||||
drawableChannel.CreateChatLineAction = CreateMessage;
|
drawableChannel.CreateChatLineAction = CreateMessage;
|
||||||
drawableChannel.Padding = new MarginPadding { Bottom = postingTextBox ? text_box_height : 0 };
|
drawableChannel.Padding = new MarginPadding { Bottom = postingTextBox ? text_box_height : 0 };
|
||||||
|
@ -9,7 +9,8 @@ namespace osu.Game.Online
|
|||||||
{
|
{
|
||||||
public ProductionEndpointConfiguration()
|
public ProductionEndpointConfiguration()
|
||||||
{
|
{
|
||||||
WebsiteRootUrl = APIEndpointUrl = @"https://osu.ppy.sh";
|
WebsiteRootUrl = @"https://osu.ppy.sh";
|
||||||
|
APIEndpointUrl = @"https://lazer.ppy.sh";
|
||||||
APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk";
|
APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk";
|
||||||
APIClientID = "5";
|
APIClientID = "5";
|
||||||
SpectatorEndpointUrl = "https://spectator.ppy.sh/spectator";
|
SpectatorEndpointUrl = "https://spectator.ppy.sh/spectator";
|
||||||
|
@ -46,12 +46,15 @@ namespace osu.Game.Online.Solo
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="score">The score to listen for the statistics update for.</param>
|
/// <param name="score">The score to listen for the statistics update for.</param>
|
||||||
/// <param name="onUpdateReady">The callback to be invoked once the statistics update has been prepared.</param>
|
/// <param name="onUpdateReady">The callback to be invoked once the statistics update has been prepared.</param>
|
||||||
public void RegisterForStatisticsUpdateAfter(ScoreInfo score, Action<SoloStatisticsUpdate> onUpdateReady) => Schedule(() =>
|
/// <returns>An <see cref="IDisposable"/> representing the subscription. Disposing it is equivalent to unsubscribing from future notifications.</returns>
|
||||||
|
public IDisposable RegisterForStatisticsUpdateAfter(ScoreInfo score, Action<SoloStatisticsUpdate> onUpdateReady)
|
||||||
|
{
|
||||||
|
Schedule(() =>
|
||||||
{
|
{
|
||||||
if (!api.IsLoggedIn)
|
if (!api.IsLoggedIn)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!score.Ruleset.IsLegacyRuleset())
|
if (!score.Ruleset.IsLegacyRuleset() || score.OnlineID <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var callback = new StatisticsUpdateCallback(score, onUpdateReady);
|
var callback = new StatisticsUpdateCallback(score, onUpdateReady);
|
||||||
@ -65,6 +68,9 @@ namespace osu.Game.Online.Solo
|
|||||||
callbacks.Add(score.OnlineID, callback);
|
callbacks.Add(score.OnlineID, callback);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return new InvokeOnDisposal(() => Schedule(() => callbacks.Remove(score.OnlineID)));
|
||||||
|
}
|
||||||
|
|
||||||
private void onUserChanged(APIUser? localUser) => Schedule(() =>
|
private void onUserChanged(APIUser? localUser) => Schedule(() =>
|
||||||
{
|
{
|
||||||
callbacks.Clear();
|
callbacks.Clear();
|
||||||
@ -75,15 +81,27 @@ namespace osu.Game.Online.Solo
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var userRequest = new GetUsersRequest(new[] { localUser.OnlineID });
|
var userRequest = new GetUsersRequest(new[] { localUser.OnlineID });
|
||||||
userRequest.Success += response => Schedule(() =>
|
userRequest.Success += initialiseUserStatistics;
|
||||||
{
|
|
||||||
latestStatistics = new Dictionary<string, UserStatistics>();
|
|
||||||
foreach (var rulesetStats in response.Users.Single().RulesetsStatistics)
|
|
||||||
latestStatistics.Add(rulesetStats.Key, rulesetStats.Value);
|
|
||||||
});
|
|
||||||
api.Queue(userRequest);
|
api.Queue(userRequest);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private void initialiseUserStatistics(GetUsersResponse response) => Schedule(() =>
|
||||||
|
{
|
||||||
|
var user = response.Users.SingleOrDefault();
|
||||||
|
|
||||||
|
// possible if the user is restricted or similar.
|
||||||
|
if (user == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
latestStatistics = new Dictionary<string, UserStatistics>();
|
||||||
|
|
||||||
|
if (user.RulesetsStatistics != null)
|
||||||
|
{
|
||||||
|
foreach (var rulesetStats in user.RulesetsStatistics)
|
||||||
|
latestStatistics.Add(rulesetStats.Key, rulesetStats.Value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
private void userScoreProcessed(int userId, long scoreId)
|
private void userScoreProcessed(int userId, long scoreId)
|
||||||
{
|
{
|
||||||
if (userId != api.LocalUser.Value?.OnlineID)
|
if (userId != api.LocalUser.Value?.OnlineID)
|
||||||
|
@ -46,6 +46,7 @@ using osu.Game.Online;
|
|||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.Chat;
|
using osu.Game.Online.Chat;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.BeatmapListing;
|
||||||
using osu.Game.Overlays.Music;
|
using osu.Game.Overlays.Music;
|
||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Overlays.Toolbar;
|
using osu.Game.Overlays.Toolbar;
|
||||||
@ -353,9 +354,20 @@ namespace osu.Game
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case LinkAction.SearchBeatmapSet:
|
case LinkAction.SearchBeatmapSet:
|
||||||
|
if (link.Argument is RomanisableString romanisable)
|
||||||
|
SearchBeatmapSet(romanisable.GetPreferred(Localisation.CurrentParameters.Value.PreferOriginalScript));
|
||||||
|
else
|
||||||
SearchBeatmapSet(argString);
|
SearchBeatmapSet(argString);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case LinkAction.FilterBeatmapSetGenre:
|
||||||
|
FilterBeatmapSetGenre((SearchGenre)link.Argument);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LinkAction.FilterBeatmapSetLanguage:
|
||||||
|
FilterBeatmapSetLanguage((SearchLanguage)link.Argument);
|
||||||
|
break;
|
||||||
|
|
||||||
case LinkAction.OpenEditorTimestamp:
|
case LinkAction.OpenEditorTimestamp:
|
||||||
case LinkAction.JoinMultiplayerMatch:
|
case LinkAction.JoinMultiplayerMatch:
|
||||||
case LinkAction.Spectate:
|
case LinkAction.Spectate:
|
||||||
@ -460,6 +472,10 @@ namespace osu.Game
|
|||||||
/// <param name="query">The query to search for.</param>
|
/// <param name="query">The query to search for.</param>
|
||||||
public void SearchBeatmapSet(string query) => waitForReady(() => beatmapListing, _ => beatmapListing.ShowWithSearch(query));
|
public void SearchBeatmapSet(string query) => waitForReady(() => beatmapListing, _ => beatmapListing.ShowWithSearch(query));
|
||||||
|
|
||||||
|
public void FilterBeatmapSetGenre(SearchGenre genre) => waitForReady(() => beatmapListing, _ => beatmapListing.ShowWithGenreFilter(genre));
|
||||||
|
|
||||||
|
public void FilterBeatmapSetLanguage(SearchLanguage language) => waitForReady(() => beatmapListing, _ => beatmapListing.ShowWithLanguageFilter(language));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Show a wiki's page as an overlay
|
/// Show a wiki's page as an overlay
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -723,7 +739,7 @@ namespace osu.Game
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
var languages = Enum.GetValues(typeof(Language)).OfType<Language>();
|
var languages = Enum.GetValues<Language>();
|
||||||
|
|
||||||
var mappings = languages.Select(language =>
|
var mappings = languages.Select(language =>
|
||||||
{
|
{
|
||||||
|
@ -46,6 +46,7 @@ using osu.Game.Online.API;
|
|||||||
using osu.Game.Online.Chat;
|
using osu.Game.Online.Chat;
|
||||||
using osu.Game.Online.Metadata;
|
using osu.Game.Online.Metadata;
|
||||||
using osu.Game.Online.Multiplayer;
|
using osu.Game.Online.Multiplayer;
|
||||||
|
using osu.Game.Online.Solo;
|
||||||
using osu.Game.Online.Spectator;
|
using osu.Game.Online.Spectator;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
@ -193,6 +194,7 @@ namespace osu.Game
|
|||||||
protected MultiplayerClient MultiplayerClient { get; private set; }
|
protected MultiplayerClient MultiplayerClient { get; private set; }
|
||||||
|
|
||||||
private MetadataClient metadataClient;
|
private MetadataClient metadataClient;
|
||||||
|
private SoloStatisticsWatcher soloStatisticsWatcher;
|
||||||
|
|
||||||
private RealmAccess realm;
|
private RealmAccess realm;
|
||||||
|
|
||||||
@ -301,6 +303,7 @@ namespace osu.Game
|
|||||||
dependencies.CacheAs(spectatorClient = new OnlineSpectatorClient(endpoints));
|
dependencies.CacheAs(spectatorClient = new OnlineSpectatorClient(endpoints));
|
||||||
dependencies.CacheAs(MultiplayerClient = new OnlineMultiplayerClient(endpoints));
|
dependencies.CacheAs(MultiplayerClient = new OnlineMultiplayerClient(endpoints));
|
||||||
dependencies.CacheAs(metadataClient = new OnlineMetadataClient(endpoints));
|
dependencies.CacheAs(metadataClient = new OnlineMetadataClient(endpoints));
|
||||||
|
dependencies.CacheAs(soloStatisticsWatcher = new SoloStatisticsWatcher());
|
||||||
|
|
||||||
AddInternal(new BeatmapOnlineChangeIngest(beatmapUpdater, realm, metadataClient));
|
AddInternal(new BeatmapOnlineChangeIngest(beatmapUpdater, realm, metadataClient));
|
||||||
|
|
||||||
@ -346,6 +349,7 @@ namespace osu.Game
|
|||||||
AddInternal(spectatorClient);
|
AddInternal(spectatorClient);
|
||||||
AddInternal(MultiplayerClient);
|
AddInternal(MultiplayerClient);
|
||||||
AddInternal(metadataClient);
|
AddInternal(metadataClient);
|
||||||
|
AddInternal(soloStatisticsWatcher);
|
||||||
|
|
||||||
AddInternal(rulesetConfigCache);
|
AddInternal(rulesetConfigCache);
|
||||||
|
|
||||||
@ -603,7 +607,7 @@ namespace osu.Game
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
foreach (ModType type in Enum.GetValues(typeof(ModType)))
|
foreach (ModType type in Enum.GetValues<ModType>())
|
||||||
{
|
{
|
||||||
dict[type] = instance.GetModsFor(type)
|
dict[type] = instance.GetModsFor(type)
|
||||||
// Rulesets should never return null mods, but let's be defensive just in case.
|
// Rulesets should never return null mods, but let's be defensive just in case.
|
||||||
|
@ -145,6 +145,12 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
public void Search(string query)
|
public void Search(string query)
|
||||||
=> Schedule(() => searchControl.Query.Value = query);
|
=> Schedule(() => searchControl.Query.Value = query);
|
||||||
|
|
||||||
|
public void FilterGenre(SearchGenre genre)
|
||||||
|
=> Schedule(() => searchControl.Genre.Value = genre);
|
||||||
|
|
||||||
|
public void FilterLanguage(SearchLanguage language)
|
||||||
|
=> Schedule(() => searchControl.Language.Value = language);
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
@ -12,6 +12,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -100,9 +101,30 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
|
|
||||||
protected partial class MultipleSelectionFilterTabItem : FilterTabItem<T>
|
protected partial class MultipleSelectionFilterTabItem : FilterTabItem<T>
|
||||||
{
|
{
|
||||||
|
private readonly Box selectedUnderline;
|
||||||
|
|
||||||
|
protected override bool HighlightOnHoverWhenActive => true;
|
||||||
|
|
||||||
public MultipleSelectionFilterTabItem(T value)
|
public MultipleSelectionFilterTabItem(T value)
|
||||||
: base(value)
|
: base(value)
|
||||||
{
|
{
|
||||||
|
// This doesn't match any actual design, but should make it easier for the user to understand
|
||||||
|
// that filters are applied until we settle on a final design.
|
||||||
|
AddInternal(selectedUnderline = new Box
|
||||||
|
{
|
||||||
|
Depth = float.MaxValue,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 1.5f,
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateState()
|
||||||
|
{
|
||||||
|
base.UpdateState();
|
||||||
|
selectedUnderline.FadeTo(Active.Value ? 1 : 0, 200, Easing.OutQuint);
|
||||||
|
selectedUnderline.FadeColour(IsHovered ? ColourProvider.Content2 : GetStateColour(), 200, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnClick(ClickEvent e)
|
protected override bool OnClick(ClickEvent e)
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
public partial class FilterTabItem<T> : TabItem<T>
|
public partial class FilterTabItem<T> : TabItem<T>
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OverlayColourProvider colourProvider { get; set; }
|
protected OverlayColourProvider ColourProvider { get; private set; }
|
||||||
|
|
||||||
private OsuSpriteText text;
|
private OsuSpriteText text;
|
||||||
|
|
||||||
@ -52,38 +52,42 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
updateState();
|
UpdateState();
|
||||||
FinishTransforms(true);
|
FinishTransforms(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnHover(HoverEvent e)
|
protected override bool OnHover(HoverEvent e)
|
||||||
{
|
{
|
||||||
base.OnHover(e);
|
base.OnHover(e);
|
||||||
updateState();
|
UpdateState();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHoverLost(HoverLostEvent e)
|
protected override void OnHoverLost(HoverLostEvent e)
|
||||||
{
|
{
|
||||||
base.OnHoverLost(e);
|
base.OnHoverLost(e);
|
||||||
updateState();
|
UpdateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnActivated() => updateState();
|
protected override void OnActivated() => UpdateState();
|
||||||
|
|
||||||
protected override void OnDeactivated() => updateState();
|
protected override void OnDeactivated() => UpdateState();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the label text to be used for the supplied <paramref name="value"/>.
|
/// Returns the label text to be used for the supplied <paramref name="value"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual LocalisableString LabelFor(T value) => (value as Enum)?.GetLocalisableDescription() ?? value.ToString();
|
protected virtual LocalisableString LabelFor(T value) => (value as Enum)?.GetLocalisableDescription() ?? value.ToString();
|
||||||
|
|
||||||
private void updateState()
|
protected virtual bool HighlightOnHoverWhenActive => false;
|
||||||
|
|
||||||
|
protected virtual void UpdateState()
|
||||||
{
|
{
|
||||||
text.FadeColour(IsHovered ? colourProvider.Light1 : GetStateColour(), 200, Easing.OutQuint);
|
bool highlightHover = IsHovered && (!Active.Value || HighlightOnHoverWhenActive);
|
||||||
text.Font = text.Font.With(weight: Active.Value ? FontWeight.SemiBold : FontWeight.Regular);
|
|
||||||
|
text.FadeColour(highlightHover ? ColourProvider.Content2 : GetStateColour(), 200, Easing.OutQuint);
|
||||||
|
text.Font = text.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Regular);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Color4 GetStateColour() => Active.Value ? colourProvider.Content1 : colourProvider.Light2;
|
protected virtual Color4 GetStateColour() => Active.Value ? ColourProvider.Content1 : ColourProvider.Light2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,18 @@ namespace osu.Game.Overlays
|
|||||||
ScrollFlow.ScrollToStart();
|
ScrollFlow.ScrollToStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ShowWithGenreFilter(SearchGenre genre)
|
||||||
|
{
|
||||||
|
ShowWithSearch(string.Empty);
|
||||||
|
filterControl.FilterGenre(genre);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowWithLanguageFilter(SearchLanguage language)
|
||||||
|
{
|
||||||
|
ShowWithSearch(string.Empty);
|
||||||
|
filterControl.FilterLanguage(language);
|
||||||
|
}
|
||||||
|
|
||||||
protected override BeatmapListingHeader CreateHeader() => new BeatmapListingHeader();
|
protected override BeatmapListingHeader CreateHeader() => new BeatmapListingHeader();
|
||||||
|
|
||||||
protected override Color4 BackgroundColour => ColourProvider.Background6;
|
protected override Color4 BackgroundColour => ColourProvider.Background6;
|
||||||
|
@ -3,26 +3,29 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Game.Graphics.Cursor;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.Drawables;
|
using osu.Game.Beatmaps.Drawables;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online;
|
using osu.Game.Online;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Online.Chat;
|
||||||
using osu.Game.Overlays.BeatmapSet.Buttons;
|
using osu.Game.Overlays.BeatmapSet.Buttons;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.BeatmapSet
|
namespace osu.Game.Overlays.BeatmapSet
|
||||||
{
|
{
|
||||||
@ -41,12 +44,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
|
|
||||||
private readonly UpdateableOnlineBeatmapSetCover cover;
|
private readonly UpdateableOnlineBeatmapSetCover cover;
|
||||||
private readonly Box coverGradient;
|
private readonly Box coverGradient;
|
||||||
private readonly OsuSpriteText title, artist;
|
private readonly LinkFlowContainer title, artist;
|
||||||
private readonly AuthorInfo author;
|
private readonly AuthorInfo author;
|
||||||
|
|
||||||
private readonly ExplicitContentBeatmapBadge explicitContent;
|
private ExternalLinkButton externalLink;
|
||||||
private readonly SpotlightBeatmapBadge spotlight;
|
|
||||||
private readonly FeaturedArtistBeatmapBadge featuredArtist;
|
|
||||||
|
|
||||||
private readonly FillFlowContainer downloadButtonsContainer;
|
private readonly FillFlowContainer downloadButtonsContainer;
|
||||||
private readonly BeatmapAvailability beatmapAvailability;
|
private readonly BeatmapAvailability beatmapAvailability;
|
||||||
@ -65,8 +66,6 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
|
|
||||||
public BeatmapSetHeaderContent()
|
public BeatmapSetHeaderContent()
|
||||||
{
|
{
|
||||||
ExternalLinkButton externalLink;
|
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
InternalChild = new Container
|
InternalChild = new Container
|
||||||
@ -91,11 +90,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
new OsuContextMenuContainer
|
new Container
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Child = new Container
|
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
@ -120,58 +115,19 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Child = Picker = new BeatmapPicker(),
|
Child = Picker = new BeatmapPicker(),
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
title = new MetadataFlowContainer(s =>
|
||||||
|
{
|
||||||
|
s.Font = OsuFont.GetFont(size: 30, weight: FontWeight.SemiBold, italics: true);
|
||||||
|
})
|
||||||
{
|
{
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Margin = new MarginPadding { Top = 15 },
|
Margin = new MarginPadding { Top = 15 },
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
title = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Font = OsuFont.GetFont(size: 30, weight: FontWeight.SemiBold, italics: true)
|
|
||||||
},
|
},
|
||||||
externalLink = new ExternalLinkButton
|
artist = new MetadataFlowContainer(s =>
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomLeft,
|
s.Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, italics: true);
|
||||||
Origin = Anchor.BottomLeft,
|
})
|
||||||
Margin = new MarginPadding { Left = 5, Bottom = 4 }, // To better lineup with the font
|
|
||||||
},
|
|
||||||
explicitContent = new ExplicitContentBeatmapBadge
|
|
||||||
{
|
{
|
||||||
Alpha = 0f,
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Margin = new MarginPadding { Left = 10, Bottom = 4 },
|
|
||||||
},
|
|
||||||
spotlight = new SpotlightBeatmapBadge
|
|
||||||
{
|
|
||||||
Alpha = 0f,
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Margin = new MarginPadding { Left = 10, Bottom = 4 },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Margin = new MarginPadding { Bottom = 20 },
|
Margin = new MarginPadding { Bottom = 20 },
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
artist = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, italics: true),
|
|
||||||
},
|
|
||||||
featuredArtist = new FeaturedArtistBeatmapBadge
|
|
||||||
{
|
|
||||||
Alpha = 0f,
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Margin = new MarginPadding { Left = 10 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
@ -197,13 +153,12 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
Padding = new MarginPadding { Left = buttons_height + buttons_spacing },
|
Padding = new MarginPadding { Left = buttons_height + buttons_spacing },
|
||||||
Spacing = new Vector2(buttons_spacing),
|
Spacing = new Vector2(buttons_spacing),
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
|
||||||
loading = new LoadingSpinner
|
loading = new LoadingSpinner
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
@ -237,12 +192,17 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
Picker.Beatmap.ValueChanged += b =>
|
Picker.Beatmap.ValueChanged += b =>
|
||||||
{
|
{
|
||||||
Details.BeatmapInfo = b.NewValue;
|
Details.BeatmapInfo = b.NewValue;
|
||||||
externalLink.Link = $@"{api.WebsiteRootUrl}/beatmapsets/{BeatmapSet.Value?.OnlineID}#{b.NewValue?.Ruleset.ShortName}/{b.NewValue?.OnlineID}";
|
updateExternalLink();
|
||||||
|
|
||||||
onlineStatusPill.Status = b.NewValue?.Status ?? BeatmapOnlineStatus.None;
|
onlineStatusPill.Status = b.NewValue?.Status ?? BeatmapOnlineStatus.None;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateExternalLink()
|
||||||
|
{
|
||||||
|
if (externalLink != null) externalLink.Link = $@"{api.WebsiteRootUrl}/beatmapsets/{BeatmapSet.Value?.OnlineID}#{Picker.Beatmap.Value?.Ruleset.ShortName}/{Picker.Beatmap.Value?.OnlineID}";
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OverlayColourProvider colourProvider)
|
private void load(OverlayColourProvider colourProvider)
|
||||||
{
|
{
|
||||||
@ -275,12 +235,38 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
|
|
||||||
loading.Hide();
|
loading.Hide();
|
||||||
|
|
||||||
title.Text = new RomanisableString(setInfo.NewValue.TitleUnicode, setInfo.NewValue.Title);
|
var titleText = new RomanisableString(setInfo.NewValue.TitleUnicode, setInfo.NewValue.Title);
|
||||||
artist.Text = new RomanisableString(setInfo.NewValue.ArtistUnicode, setInfo.NewValue.Artist);
|
var artistText = new RomanisableString(setInfo.NewValue.ArtistUnicode, setInfo.NewValue.Artist);
|
||||||
|
|
||||||
explicitContent.Alpha = setInfo.NewValue.HasExplicitContent ? 1 : 0;
|
title.Clear();
|
||||||
spotlight.Alpha = setInfo.NewValue.FeaturedInSpotlight ? 1 : 0;
|
artist.Clear();
|
||||||
featuredArtist.Alpha = setInfo.NewValue.TrackId != null ? 1 : 0;
|
|
||||||
|
title.AddLink(titleText, LinkAction.SearchBeatmapSet, titleText);
|
||||||
|
|
||||||
|
title.AddArbitraryDrawable(Empty().With(d => d.Width = 5));
|
||||||
|
title.AddArbitraryDrawable(externalLink = new ExternalLinkButton());
|
||||||
|
|
||||||
|
if (setInfo.NewValue.HasExplicitContent)
|
||||||
|
{
|
||||||
|
title.AddArbitraryDrawable(Empty().With(d => d.Width = 10));
|
||||||
|
title.AddArbitraryDrawable(new ExplicitContentBeatmapBadge());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setInfo.NewValue.FeaturedInSpotlight)
|
||||||
|
{
|
||||||
|
title.AddArbitraryDrawable(Empty().With(d => d.Width = 10));
|
||||||
|
title.AddArbitraryDrawable(new SpotlightBeatmapBadge());
|
||||||
|
}
|
||||||
|
|
||||||
|
artist.AddLink(artistText, LinkAction.SearchBeatmapSet, artistText);
|
||||||
|
|
||||||
|
if (setInfo.NewValue.TrackId != null)
|
||||||
|
{
|
||||||
|
artist.AddArbitraryDrawable(Empty().With(d => d.Width = 10));
|
||||||
|
artist.AddArbitraryDrawable(new FeaturedArtistBeatmapBadge());
|
||||||
|
}
|
||||||
|
|
||||||
|
updateExternalLink();
|
||||||
|
|
||||||
onlineStatusPill.FadeIn(500, Easing.OutQuint);
|
onlineStatusPill.FadeIn(500, Easing.OutQuint);
|
||||||
|
|
||||||
@ -327,5 +313,32 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public partial class MetadataFlowContainer : LinkFlowContainer
|
||||||
|
{
|
||||||
|
public MetadataFlowContainer(Action<SpriteText> defaultCreationParameters = null)
|
||||||
|
: base(defaultCreationParameters)
|
||||||
|
{
|
||||||
|
TextAnchor = Anchor.CentreLeft;
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DrawableLinkCompiler CreateLinkCompiler(ITextPart textPart) => new MetadataLinkCompiler(textPart);
|
||||||
|
|
||||||
|
public partial class MetadataLinkCompiler : DrawableLinkCompiler
|
||||||
|
{
|
||||||
|
public MetadataLinkCompiler(ITextPart part)
|
||||||
|
: base(part)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
IdleColour = Color4.White;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,17 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Overlays.BeatmapListing;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.BeatmapSet
|
namespace osu.Game.Overlays.BeatmapSet
|
||||||
{
|
{
|
||||||
@ -34,7 +37,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
|
|
||||||
public Info()
|
public Info()
|
||||||
{
|
{
|
||||||
MetadataSection source, tags, genre, language;
|
MetadataSectionNominators nominators;
|
||||||
|
MetadataSection source, tags;
|
||||||
|
MetadataSectionGenre genre;
|
||||||
|
MetadataSectionLanguage language;
|
||||||
OsuSpriteText notRankedPlaceholder;
|
OsuSpriteText notRankedPlaceholder;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
@ -59,7 +65,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
Child = new Container
|
Child = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = new MetadataSection(MetadataType.Description),
|
Child = new MetadataSectionDescription(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
@ -76,12 +82,13 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Direction = FillDirection.Full,
|
Direction = FillDirection.Full,
|
||||||
Children = new[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
source = new MetadataSection(MetadataType.Source),
|
nominators = new MetadataSectionNominators(),
|
||||||
genre = new MetadataSection(MetadataType.Genre) { Width = 0.5f },
|
source = new MetadataSectionSource(),
|
||||||
language = new MetadataSection(MetadataType.Language) { Width = 0.5f },
|
genre = new MetadataSectionGenre { Width = 0.5f },
|
||||||
tags = new MetadataSection(MetadataType.Tags),
|
language = new MetadataSectionLanguage { Width = 0.5f },
|
||||||
|
tags = new MetadataSectionTags(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -118,10 +125,11 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
|
|
||||||
BeatmapSet.ValueChanged += b =>
|
BeatmapSet.ValueChanged += b =>
|
||||||
{
|
{
|
||||||
source.Text = b.NewValue?.Source ?? string.Empty;
|
nominators.Metadata = (b.NewValue?.CurrentNominations ?? Array.Empty<BeatmapSetOnlineNomination>(), b.NewValue?.RelatedUsers ?? Array.Empty<APIUser>());
|
||||||
tags.Text = b.NewValue?.Tags ?? string.Empty;
|
source.Metadata = b.NewValue?.Source ?? string.Empty;
|
||||||
genre.Text = b.NewValue?.Genre.Name ?? string.Empty;
|
tags.Metadata = b.NewValue?.Tags ?? string.Empty;
|
||||||
language.Text = b.NewValue?.Language.Name ?? string.Empty;
|
genre.Metadata = b.NewValue?.Genre ?? new BeatmapSetOnlineGenre { Id = (int)SearchGenre.Unspecified };
|
||||||
|
language.Metadata = b.NewValue?.Language ?? new BeatmapSetOnlineLanguage { Id = (int)SearchLanguage.Unspecified };
|
||||||
bool setHasLeaderboard = b.NewValue?.Status > 0;
|
bool setHasLeaderboard = b.NewValue?.Status > 0;
|
||||||
successRate.Alpha = setHasLeaderboard ? 1 : 0;
|
successRate.Alpha = setHasLeaderboard ? 1 : 0;
|
||||||
notRankedPlaceholder.Alpha = setHasLeaderboard ? 0 : 1;
|
notRankedPlaceholder.Alpha = setHasLeaderboard ? 0 : 1;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
@ -11,26 +9,45 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Online.Chat;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.BeatmapSet
|
namespace osu.Game.Overlays.BeatmapSet
|
||||||
{
|
{
|
||||||
public partial class MetadataSection : Container
|
public abstract partial class MetadataSection : MetadataSection<string>
|
||||||
|
{
|
||||||
|
public override string Metadata
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
this.FadeOut(TRANSITION_DURATION);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Metadata = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MetadataSection(MetadataType type, Action<string>? searchAction = null)
|
||||||
|
: base(type, searchAction)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract partial class MetadataSection<T> : Container
|
||||||
{
|
{
|
||||||
private readonly FillFlowContainer textContainer;
|
private readonly FillFlowContainer textContainer;
|
||||||
private readonly MetadataType type;
|
private TextFlowContainer? textFlow;
|
||||||
private TextFlowContainer textFlow;
|
|
||||||
|
|
||||||
private readonly Action<string> searchAction;
|
protected readonly Action<T>? SearchAction;
|
||||||
|
|
||||||
private const float transition_duration = 250;
|
protected const float TRANSITION_DURATION = 250;
|
||||||
|
|
||||||
public MetadataSection(MetadataType type, Action<string> searchAction = null)
|
protected MetadataSection(MetadataType type, Action<T>? searchAction = null)
|
||||||
{
|
{
|
||||||
this.type = type;
|
SearchAction = searchAction;
|
||||||
this.searchAction = searchAction;
|
|
||||||
|
|
||||||
Alpha = 0;
|
Alpha = 0;
|
||||||
|
|
||||||
@ -53,7 +70,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Child = new OsuSpriteText
|
Child = new OsuSpriteText
|
||||||
{
|
{
|
||||||
Text = this.type.GetLocalisableDescription(),
|
Text = type.GetLocalisableDescription(),
|
||||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 14),
|
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 14),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -61,23 +78,23 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text
|
public virtual T Metadata
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(value))
|
if (value == null)
|
||||||
{
|
{
|
||||||
this.FadeOut(transition_duration);
|
this.FadeOut(TRANSITION_DURATION);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.FadeIn(transition_duration);
|
this.FadeIn(TRANSITION_DURATION);
|
||||||
|
|
||||||
setTextAsync(value);
|
setTextFlowAsync(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setTextAsync(string text)
|
private void setTextFlowAsync(T metadata)
|
||||||
{
|
{
|
||||||
LoadComponentAsync(new LinkFlowContainer(s => s.Font = s.Font.With(size: 14))
|
LoadComponentAsync(new LinkFlowContainer(s => s.Font = s.Font.With(size: 14))
|
||||||
{
|
{
|
||||||
@ -88,44 +105,15 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
{
|
{
|
||||||
textFlow?.Expire();
|
textFlow?.Expire();
|
||||||
|
|
||||||
switch (type)
|
AddMetadata(metadata, loaded);
|
||||||
{
|
|
||||||
case MetadataType.Tags:
|
|
||||||
string[] tags = text.Split(" ");
|
|
||||||
|
|
||||||
for (int i = 0; i <= tags.Length - 1; i++)
|
|
||||||
{
|
|
||||||
string tag = tags[i];
|
|
||||||
|
|
||||||
if (searchAction != null)
|
|
||||||
loaded.AddLink(tag, () => searchAction(tag));
|
|
||||||
else
|
|
||||||
loaded.AddLink(tag, LinkAction.SearchBeatmapSet, tag);
|
|
||||||
|
|
||||||
if (i != tags.Length - 1)
|
|
||||||
loaded.AddText(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MetadataType.Source:
|
|
||||||
if (searchAction != null)
|
|
||||||
loaded.AddLink(text, () => searchAction(text));
|
|
||||||
else
|
|
||||||
loaded.AddLink(text, LinkAction.SearchBeatmapSet, text);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
loaded.AddText(text);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
textContainer.Add(textFlow = loaded);
|
textContainer.Add(textFlow = loaded);
|
||||||
|
|
||||||
// fade in if we haven't yet.
|
// fade in if we haven't yet.
|
||||||
textContainer.FadeIn(transition_duration);
|
textContainer.FadeIn(TRANSITION_DURATION);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract void AddMetadata(T metadata, LinkFlowContainer loaded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
21
osu.Game/Overlays/BeatmapSet/MetadataSectionDescription.cs
Normal file
21
osu.Game/Overlays/BeatmapSet/MetadataSectionDescription.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.BeatmapSet
|
||||||
|
{
|
||||||
|
public partial class MetadataSectionDescription : MetadataSection
|
||||||
|
{
|
||||||
|
public MetadataSectionDescription(Action<string>? searchAction = null)
|
||||||
|
: base(MetadataType.Description, searchAction)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AddMetadata(string metadata, LinkFlowContainer loaded)
|
||||||
|
{
|
||||||
|
loaded.AddText(metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
osu.Game/Overlays/BeatmapSet/MetadataSectionGenre.cs
Normal file
30
osu.Game/Overlays/BeatmapSet/MetadataSectionGenre.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Online.Chat;
|
||||||
|
using osu.Game.Overlays.BeatmapListing;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.BeatmapSet
|
||||||
|
{
|
||||||
|
public partial class MetadataSectionGenre : MetadataSection<BeatmapSetOnlineGenre>
|
||||||
|
{
|
||||||
|
public MetadataSectionGenre(Action<BeatmapSetOnlineGenre>? searchAction = null)
|
||||||
|
: base(MetadataType.Genre, searchAction)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AddMetadata(BeatmapSetOnlineGenre metadata, LinkFlowContainer loaded)
|
||||||
|
{
|
||||||
|
var genre = (SearchGenre)metadata.Id;
|
||||||
|
|
||||||
|
if (Enum.IsDefined(genre))
|
||||||
|
loaded.AddLink(genre.GetLocalisableDescription(), LinkAction.FilterBeatmapSetGenre, genre);
|
||||||
|
else
|
||||||
|
loaded.AddText(metadata.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
osu.Game/Overlays/BeatmapSet/MetadataSectionLanguage.cs
Normal file
30
osu.Game/Overlays/BeatmapSet/MetadataSectionLanguage.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Online.Chat;
|
||||||
|
using osu.Game.Overlays.BeatmapListing;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.BeatmapSet
|
||||||
|
{
|
||||||
|
public partial class MetadataSectionLanguage : MetadataSection<BeatmapSetOnlineLanguage>
|
||||||
|
{
|
||||||
|
public MetadataSectionLanguage(Action<BeatmapSetOnlineLanguage>? searchAction = null)
|
||||||
|
: base(MetadataType.Language, searchAction)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AddMetadata(BeatmapSetOnlineLanguage metadata, LinkFlowContainer loaded)
|
||||||
|
{
|
||||||
|
var language = (SearchLanguage)metadata.Id;
|
||||||
|
|
||||||
|
if (Enum.IsDefined(language))
|
||||||
|
loaded.AddLink(language.GetLocalisableDescription(), LinkAction.FilterBeatmapSetLanguage, language);
|
||||||
|
else
|
||||||
|
loaded.AddText(metadata.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
osu.Game/Overlays/BeatmapSet/MetadataSectionNominators.cs
Normal file
63
osu.Game/Overlays/BeatmapSet/MetadataSectionNominators.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.BeatmapSet
|
||||||
|
{
|
||||||
|
public partial class MetadataSectionNominators : MetadataSection<(BeatmapSetOnlineNomination[] CurrentNominations, APIUser[] RelatedUsers)>
|
||||||
|
{
|
||||||
|
public override (BeatmapSetOnlineNomination[] CurrentNominations, APIUser[] RelatedUsers) Metadata
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value.CurrentNominations.Length == 0)
|
||||||
|
{
|
||||||
|
this.FadeOut(TRANSITION_DURATION);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Metadata = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetadataSectionNominators(Action<(BeatmapSetOnlineNomination[] CurrentNominations, APIUser[] RelatedUsers)>? searchAction = null)
|
||||||
|
: base(MetadataType.Nominators, searchAction)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AddMetadata((BeatmapSetOnlineNomination[] CurrentNominations, APIUser[] RelatedUsers) metadata, LinkFlowContainer loaded)
|
||||||
|
{
|
||||||
|
int[] nominatorIds = metadata.CurrentNominations.Select(n => n.UserId).ToArray();
|
||||||
|
|
||||||
|
int nominatorsFound = 0;
|
||||||
|
|
||||||
|
foreach (int nominatorId in nominatorIds)
|
||||||
|
{
|
||||||
|
foreach (var user in metadata.RelatedUsers)
|
||||||
|
{
|
||||||
|
if (nominatorId != user.OnlineID) continue;
|
||||||
|
|
||||||
|
nominatorsFound++;
|
||||||
|
|
||||||
|
loaded.AddUserLink(new APIUser
|
||||||
|
{
|
||||||
|
Username = user.Username,
|
||||||
|
Id = nominatorId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (nominatorsFound < nominatorIds.Length)
|
||||||
|
loaded.AddText(CommonStrings.ArrayAndWordsConnector);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
osu.Game/Overlays/BeatmapSet/MetadataSectionSource.cs
Normal file
25
osu.Game/Overlays/BeatmapSet/MetadataSectionSource.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Online.Chat;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.BeatmapSet
|
||||||
|
{
|
||||||
|
public partial class MetadataSectionSource : MetadataSection
|
||||||
|
{
|
||||||
|
public MetadataSectionSource(Action<string>? searchAction = null)
|
||||||
|
: base(MetadataType.Source, searchAction)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AddMetadata(string metadata, LinkFlowContainer loaded)
|
||||||
|
{
|
||||||
|
if (SearchAction != null)
|
||||||
|
loaded.AddLink(metadata, () => SearchAction(metadata));
|
||||||
|
else
|
||||||
|
loaded.AddLink(metadata, LinkAction.SearchBeatmapSet, metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
osu.Game/Overlays/BeatmapSet/MetadataSectionTags.cs
Normal file
35
osu.Game/Overlays/BeatmapSet/MetadataSectionTags.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 System;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Online.Chat;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.BeatmapSet
|
||||||
|
{
|
||||||
|
public partial class MetadataSectionTags : MetadataSection
|
||||||
|
{
|
||||||
|
public MetadataSectionTags(Action<string>? searchAction = null)
|
||||||
|
: base(MetadataType.Tags, searchAction)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AddMetadata(string metadata, LinkFlowContainer loaded)
|
||||||
|
{
|
||||||
|
string[] tags = metadata.Split(" ");
|
||||||
|
|
||||||
|
for (int i = 0; i <= tags.Length - 1; i++)
|
||||||
|
{
|
||||||
|
string tag = tags[i];
|
||||||
|
|
||||||
|
if (SearchAction != null)
|
||||||
|
loaded.AddLink(tag, () => SearchAction(tag));
|
||||||
|
else
|
||||||
|
loaded.AddLink(tag, LinkAction.SearchBeatmapSet, tag);
|
||||||
|
|
||||||
|
if (i != tags.Length - 1)
|
||||||
|
loaded.AddText(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,9 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
Genre,
|
Genre,
|
||||||
|
|
||||||
[LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowInfoLanguage))]
|
[LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowInfoLanguage))]
|
||||||
Language
|
Language,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowInfoNominators))]
|
||||||
|
Nominators,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,8 +95,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
new TableColumn(BeatmapsetsStrings.ShowScoreboardHeadersScore, Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)),
|
new TableColumn(BeatmapsetsStrings.ShowScoreboardHeadersScore, Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)),
|
||||||
new TableColumn(BeatmapsetsStrings.ShowScoreboardHeadersAccuracy, Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, minSize: 60, maxSize: 70)),
|
new TableColumn(BeatmapsetsStrings.ShowScoreboardHeadersAccuracy, Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, minSize: 60, maxSize: 70)),
|
||||||
new TableColumn("", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 25)), // flag
|
new TableColumn("", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 25)), // flag
|
||||||
new TableColumn(BeatmapsetsStrings.ShowScoreboardHeadersPlayer, Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 125)),
|
new TableColumn(BeatmapsetsStrings.ShowScoreboardHeadersPlayer, Anchor.CentreLeft, new Dimension(minSize: 125)),
|
||||||
new TableColumn(BeatmapsetsStrings.ShowScoreboardHeadersCombo, Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 120))
|
new TableColumn(BeatmapsetsStrings.ShowScoreboardHeadersCombo, Anchor.CentreLeft, new Dimension(minSize: 70, maxSize: 120))
|
||||||
};
|
};
|
||||||
|
|
||||||
// All statistics across all scores, unordered.
|
// All statistics across all scores, unordered.
|
||||||
@ -116,7 +116,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
|
|
||||||
var displayName = ruleset.GetDisplayNameForHitResult(result);
|
var displayName = ruleset.GetDisplayNameForHitResult(result);
|
||||||
|
|
||||||
columns.Add(new TableColumn(displayName, Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 35, maxSize: 60)));
|
columns.Add(new TableColumn(displayName, Anchor.CentreLeft, new Dimension(minSize: 35, maxSize: 60)));
|
||||||
statisticResultTypes.Add((result, displayName));
|
statisticResultTypes.Add((result, displayName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,9 +128,8 @@ namespace osu.Game.Overlays.Chat
|
|||||||
chattingTextContainer.FadeTo(showSearch ? 0 : 1);
|
chattingTextContainer.FadeTo(showSearch ? 0 : 1);
|
||||||
searchIconContainer.FadeTo(showSearch ? 1 : 0);
|
searchIconContainer.FadeTo(showSearch ? 1 : 0);
|
||||||
|
|
||||||
// Clear search terms if any exist when switching back to chat mode
|
if (showSearch)
|
||||||
if (!showSearch)
|
OnSearchTermsChanged?.Invoke(chatTextBox.Current.Value);
|
||||||
OnSearchTermsChanged?.Invoke(string.Empty);
|
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
currentChannel.BindValueChanged(change =>
|
currentChannel.BindValueChanged(change =>
|
||||||
@ -151,6 +150,12 @@ namespace osu.Game.Overlays.Chat
|
|||||||
chattingText.Text = ChatStrings.TalkingIn(newChannel.Name);
|
chattingText.Text = ChatStrings.TalkingIn(newChannel.Name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (change.OldValue != null)
|
||||||
|
chatTextBox.Current.UnbindFrom(change.OldValue.TextBoxMessage);
|
||||||
|
|
||||||
|
if (newChannel != null)
|
||||||
|
chatTextBox.Current.BindTo(newChannel.TextBoxMessage);
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ namespace osu.Game.Overlays.Chat
|
|||||||
bool showSearch = change.NewValue;
|
bool showSearch = change.NewValue;
|
||||||
|
|
||||||
PlaceholderText = showSearch ? HomeStrings.SearchPlaceholder : ChatStrings.InputPlaceholder;
|
PlaceholderText = showSearch ? HomeStrings.SearchPlaceholder : ChatStrings.InputPlaceholder;
|
||||||
Text = string.Empty;
|
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,9 +17,11 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.Chat;
|
using osu.Game.Online.Chat;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -148,11 +150,11 @@ namespace osu.Game.Overlays.Chat
|
|||||||
|
|
||||||
List<MenuItem> items = new List<MenuItem>
|
List<MenuItem> items = new List<MenuItem>
|
||||||
{
|
{
|
||||||
new OsuMenuItem("View Profile", MenuItemType.Highlighted, openUserProfile)
|
new OsuMenuItem(ContextMenuStrings.ViewProfile, MenuItemType.Highlighted, openUserProfile)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!user.Equals(api.LocalUser.Value))
|
if (!user.Equals(api.LocalUser.Value))
|
||||||
items.Add(new OsuMenuItem("Start Chat", MenuItemType.Standard, openUserChannel));
|
items.Add(new OsuMenuItem(UsersStrings.CardSendMessage, MenuItemType.Standard, openUserChannel));
|
||||||
|
|
||||||
return items.ToArray();
|
return items.ToArray();
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Overlays.Chat.Listing
|
|||||||
private Box hoverBox = null!;
|
private Box hoverBox = null!;
|
||||||
private SpriteIcon checkbox = null!;
|
private SpriteIcon checkbox = null!;
|
||||||
private OsuSpriteText channelText = null!;
|
private OsuSpriteText channelText = null!;
|
||||||
private OsuSpriteText topicText = null!;
|
private OsuTextFlowContainer topicText = null!;
|
||||||
private IBindable<bool> channelJoined = null!;
|
private IBindable<bool> channelJoined = null!;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -65,8 +65,8 @@ namespace osu.Game.Overlays.Chat.Listing
|
|||||||
|
|
||||||
Masking = true;
|
Masking = true;
|
||||||
CornerRadius = 5;
|
CornerRadius = 5;
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Content.RelativeSizeAxes = Axes.X;
|
||||||
Height = 20 + (vertical_margin * 2);
|
AutoSizeAxes = Content.AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -79,14 +79,19 @@ namespace osu.Game.Overlays.Chat.Listing
|
|||||||
},
|
},
|
||||||
new GridContainer
|
new GridContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
ColumnDimensions = new[]
|
ColumnDimensions = new[]
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.Absolute, 40),
|
new Dimension(GridSizeMode.Absolute, 40),
|
||||||
new Dimension(GridSizeMode.Absolute, 200),
|
new Dimension(GridSizeMode.Absolute, 200),
|
||||||
new Dimension(GridSizeMode.Absolute, 400),
|
new Dimension(maxSize: 400),
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
new Dimension(),
|
new Dimension(GridSizeMode.Absolute, 50), // enough for any 5 digit user count
|
||||||
|
},
|
||||||
|
RowDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(GridSizeMode.AutoSize, minSize: 20 + (vertical_margin * 2)),
|
||||||
},
|
},
|
||||||
Content = new[]
|
Content = new[]
|
||||||
{
|
{
|
||||||
@ -108,12 +113,13 @@ namespace osu.Game.Overlays.Chat.Listing
|
|||||||
Font = OsuFont.Torus.With(size: text_size, weight: FontWeight.SemiBold),
|
Font = OsuFont.Torus.With(size: text_size, weight: FontWeight.SemiBold),
|
||||||
Margin = new MarginPadding { Bottom = 2 },
|
Margin = new MarginPadding { Bottom = 2 },
|
||||||
},
|
},
|
||||||
topicText = new OsuSpriteText
|
topicText = new OsuTextFlowContainer(t => t.Font = OsuFont.Torus.With(size: text_size))
|
||||||
{
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Text = Channel.Topic,
|
Text = Channel.Topic,
|
||||||
Font = OsuFont.Torus.With(size: text_size),
|
|
||||||
Margin = new MarginPadding { Bottom = 2 },
|
Margin = new MarginPadding { Bottom = 2 },
|
||||||
},
|
},
|
||||||
new SpriteIcon
|
new SpriteIcon
|
||||||
|
@ -22,6 +22,7 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterfaceV2;
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
|
using osu.Game.Online.Chat;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Game.Overlays.Settings.Sections.Maintenance;
|
using osu.Game.Overlays.Settings.Sections.Maintenance;
|
||||||
using osu.Game.Screens.Edit.Setup;
|
using osu.Game.Screens.Edit.Setup;
|
||||||
@ -128,13 +129,16 @@ namespace osu.Game.Overlays.FirstRunSetup
|
|||||||
{
|
{
|
||||||
copyInformation.Text =
|
copyInformation.Text =
|
||||||
"Data migration will use \"hard links\". No extra disk space will be used, and you can delete either data folder at any point without affecting the other installation. ";
|
"Data migration will use \"hard links\". No extra disk space will be used, and you can delete either data folder at any point without affecting the other installation. ";
|
||||||
|
|
||||||
|
copyInformation.AddLink("Learn more about how \"hard links\" work", LinkAction.OpenWiki, @"Client/Release_stream/Lazer/File_storage#via-hard-links");
|
||||||
}
|
}
|
||||||
else if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows)
|
else if (!RuntimeInfo.IsDesktop)
|
||||||
copyInformation.Text = "Lightweight linking of files is not supported on your operating system yet, so a copy of all files will be made during import.";
|
copyInformation.Text = "Lightweight linking of files is not supported on your operating system yet, so a copy of all files will be made during import.";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
copyInformation.Text =
|
copyInformation.Text = RuntimeInfo.OS == RuntimeInfo.Platform.Windows
|
||||||
"A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system is NTFS). ";
|
? "A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system is NTFS). "
|
||||||
|
: "A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system supports hard links). ";
|
||||||
copyInformation.AddLink(GeneralSettingsStrings.ChangeFolderLocation, () =>
|
copyInformation.AddLink(GeneralSettingsStrings.ChangeFolderLocation, () =>
|
||||||
{
|
{
|
||||||
game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen()));
|
game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen()));
|
||||||
|
@ -79,8 +79,7 @@ namespace osu.Game.Overlays.FirstRunSetup
|
|||||||
Direction = FillDirection.Full;
|
Direction = FillDirection.Full;
|
||||||
Spacing = new Vector2(5);
|
Spacing = new Vector2(5);
|
||||||
|
|
||||||
ChildrenEnumerable = Enum.GetValues(typeof(Language))
|
ChildrenEnumerable = Enum.GetValues<Language>()
|
||||||
.Cast<Language>()
|
|
||||||
.Select(l => new LanguageButton(l)
|
.Select(l => new LanguageButton(l)
|
||||||
{
|
{
|
||||||
Action = () => frameworkLocale.Value = l.ToCultureCode()
|
Action = () => frameworkLocale.Value = l.ToCultureCode()
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online;
|
using osu.Game.Online;
|
||||||
|
|
||||||
@ -38,15 +39,23 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
ScrollbarVisible = false,
|
ScrollbarVisible = false,
|
||||||
|
Child = new OsuContextMenuContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Child = new PopoverContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
Child = new FillFlowContainer
|
Child = new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
Header.With(h => h.Depth = float.MinValue),
|
Header.With(h => h.Depth = float.MinValue),
|
||||||
content = new PopoverContainer
|
content = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y
|
AutoSizeAxes = Axes.Y
|
||||||
@ -54,6 +63,8 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
Loading = new LoadingLayer(true)
|
Loading = new LoadingLayer(true)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -25,15 +23,15 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
{
|
{
|
||||||
public partial class BottomHeaderContainer : CompositeDrawable
|
public partial class BottomHeaderContainer : CompositeDrawable
|
||||||
{
|
{
|
||||||
public readonly Bindable<APIUser> User = new Bindable<APIUser>();
|
public readonly Bindable<APIUser?> User = new Bindable<APIUser?>();
|
||||||
|
|
||||||
private LinkFlowContainer topLinkContainer;
|
private LinkFlowContainer topLinkContainer = null!;
|
||||||
private LinkFlowContainer bottomLinkContainer;
|
private LinkFlowContainer bottomLinkContainer = null!;
|
||||||
|
|
||||||
private Color4 iconColour;
|
private Color4 iconColour;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IAPIProvider api { get; set; }
|
private IAPIProvider api { get; set; } = null!;
|
||||||
|
|
||||||
public BottomHeaderContainer()
|
public BottomHeaderContainer()
|
||||||
{
|
{
|
||||||
@ -78,7 +76,7 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
User.BindValueChanged(user => updateDisplay(user.NewValue));
|
User.BindValueChanged(user => updateDisplay(user.NewValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDisplay(APIUser user)
|
private void updateDisplay(APIUser? user)
|
||||||
{
|
{
|
||||||
topLinkContainer.Clear();
|
topLinkContainer.Clear();
|
||||||
bottomLinkContainer.Clear();
|
bottomLinkContainer.Clear();
|
||||||
@ -164,7 +162,7 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
|
|
||||||
private void addSpacer(OsuTextFlowContainer textFlow) => textFlow.AddArbitraryDrawable(new Container { Width = 15 });
|
private void addSpacer(OsuTextFlowContainer textFlow) => textFlow.AddArbitraryDrawable(new Container { Width = 15 });
|
||||||
|
|
||||||
private bool tryAddInfo(IconUsage icon, string content, string link = null)
|
private bool tryAddInfo(IconUsage icon, string content, string? link = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(content)) return false;
|
if (string.IsNullOrEmpty(content)) return false;
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.LocalisationExtensions;
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
@ -20,10 +18,10 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
public partial class CentreHeaderContainer : CompositeDrawable
|
public partial class CentreHeaderContainer : CompositeDrawable
|
||||||
{
|
{
|
||||||
public readonly BindableBool DetailsVisible = new BindableBool(true);
|
public readonly BindableBool DetailsVisible = new BindableBool(true);
|
||||||
public readonly Bindable<APIUser> User = new Bindable<APIUser>();
|
public readonly Bindable<APIUser?> User = new Bindable<APIUser?>();
|
||||||
|
|
||||||
private OverlinedInfoContainer hiddenDetailGlobal;
|
private OverlinedInfoContainer hiddenDetailGlobal = null!;
|
||||||
private OverlinedInfoContainer hiddenDetailCountry;
|
private OverlinedInfoContainer hiddenDetailCountry = null!;
|
||||||
|
|
||||||
public CentreHeaderContainer()
|
public CentreHeaderContainer()
|
||||||
{
|
{
|
||||||
@ -146,7 +144,7 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
User.BindValueChanged(user => updateDisplay(user.NewValue));
|
User.BindValueChanged(user => updateDisplay(user.NewValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDisplay(APIUser user)
|
private void updateDisplay(APIUser? user)
|
||||||
{
|
{
|
||||||
hiddenDetailGlobal.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-";
|
hiddenDetailGlobal.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-";
|
||||||
hiddenDetailCountry.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-";
|
hiddenDetailCountry.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-";
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
@ -23,9 +21,9 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
|||||||
|
|
||||||
public override LocalisableString TooltipText => DetailsVisible.Value ? CommonStrings.ButtonsCollapse : CommonStrings.ButtonsExpand;
|
public override LocalisableString TooltipText => DetailsVisible.Value ? CommonStrings.ButtonsCollapse : CommonStrings.ButtonsExpand;
|
||||||
|
|
||||||
private SpriteIcon icon;
|
private SpriteIcon icon = null!;
|
||||||
private Sample sampleOpen;
|
private Sample? sampleOpen;
|
||||||
private Sample sampleClose;
|
private Sample? sampleClose;
|
||||||
|
|
||||||
protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds();
|
protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds();
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
@ -14,7 +12,7 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
|||||||
{
|
{
|
||||||
public partial class FollowersButton : ProfileHeaderStatisticsButton
|
public partial class FollowersButton : ProfileHeaderStatisticsButton
|
||||||
{
|
{
|
||||||
public readonly Bindable<APIUser> User = new Bindable<APIUser>();
|
public readonly Bindable<APIUser?> User = new Bindable<APIUser?>();
|
||||||
|
|
||||||
public override LocalisableString TooltipText => FriendsStrings.ButtonsDisabled;
|
public override LocalisableString TooltipText => FriendsStrings.ButtonsDisabled;
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -20,11 +18,11 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
|||||||
{
|
{
|
||||||
public partial class LevelBadge : CompositeDrawable, IHasTooltip
|
public partial class LevelBadge : CompositeDrawable, IHasTooltip
|
||||||
{
|
{
|
||||||
public readonly Bindable<APIUser> User = new Bindable<APIUser>();
|
public readonly Bindable<APIUser?> User = new Bindable<APIUser?>();
|
||||||
|
|
||||||
public LocalisableString TooltipText { get; private set; }
|
public LocalisableString TooltipText { get; private set; }
|
||||||
|
|
||||||
private OsuSpriteText levelText;
|
private OsuSpriteText levelText = null!;
|
||||||
|
|
||||||
public LevelBadge()
|
public LevelBadge()
|
||||||
{
|
{
|
||||||
@ -53,10 +51,11 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
|||||||
User.BindValueChanged(user => updateLevel(user.NewValue));
|
User.BindValueChanged(user => updateLevel(user.NewValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateLevel(APIUser user)
|
private void updateLevel(APIUser? user)
|
||||||
{
|
{
|
||||||
levelText.Text = user?.Statistics?.Level.Current.ToString() ?? "0";
|
string level = user?.Statistics?.Level.Current.ToString() ?? "0";
|
||||||
TooltipText = UsersStrings.ShowStatsLevel(user?.Statistics?.Level.Current.ToString());
|
levelText.Text = level;
|
||||||
|
TooltipText = UsersStrings.ShowStatsLevel(level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.LocalisationExtensions;
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
@ -21,12 +19,12 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
|||||||
{
|
{
|
||||||
public partial class LevelProgressBar : CompositeDrawable, IHasTooltip
|
public partial class LevelProgressBar : CompositeDrawable, IHasTooltip
|
||||||
{
|
{
|
||||||
public readonly Bindable<APIUser> User = new Bindable<APIUser>();
|
public readonly Bindable<APIUser?> User = new Bindable<APIUser?>();
|
||||||
|
|
||||||
public LocalisableString TooltipText { get; }
|
public LocalisableString TooltipText { get; }
|
||||||
|
|
||||||
private Bar levelProgressBar;
|
private Bar levelProgressBar = null!;
|
||||||
private OsuSpriteText levelProgressText;
|
private OsuSpriteText levelProgressText = null!;
|
||||||
|
|
||||||
public LevelProgressBar()
|
public LevelProgressBar()
|
||||||
{
|
{
|
||||||
@ -61,7 +59,7 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
|||||||
User.BindValueChanged(user => updateProgress(user.NewValue));
|
User.BindValueChanged(user => updateProgress(user.NewValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateProgress(APIUser user)
|
private void updateProgress(APIUser? user)
|
||||||
{
|
{
|
||||||
levelProgressBar.Length = user?.Statistics?.Level.Progress / 100f ?? 0;
|
levelProgressBar.Length = user?.Statistics?.Level.Progress / 100f ?? 0;
|
||||||
levelProgressText.Text = user?.Statistics?.Level.Progress.ToLocalisableString("0'%'") ?? default;
|
levelProgressText.Text = user?.Statistics?.Level.Progress.ToLocalisableString("0'%'") ?? default;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user