mirror of
https://github.com/ppy/osu.git
synced 2025-01-28 09:02:58 +08:00
Merge branch 'master' into multiplayer-team-vs-results
This commit is contained in:
commit
70005cb39d
@ -51,8 +51,8 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.808.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.810.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.809.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.811.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||||
|
120
osu.Game.Rulesets.Catch.Tests/Mods/CatchModMirrorTest.cs
Normal file
120
osu.Game.Rulesets.Catch.Tests/Mods/CatchModMirrorTest.cs
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Catch.Mods;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Tests.Mods
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class CatchModMirrorTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestModMirror()
|
||||||
|
{
|
||||||
|
IBeatmap original = createBeatmap(false);
|
||||||
|
IBeatmap mirrored = createBeatmap(true);
|
||||||
|
|
||||||
|
assertEffectivePositionsMirrored(original, mirrored);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IBeatmap createBeatmap(bool withMirrorMod)
|
||||||
|
{
|
||||||
|
var beatmap = createRawBeatmap();
|
||||||
|
var mirrorMod = new CatchModMirror();
|
||||||
|
|
||||||
|
var beatmapProcessor = new CatchBeatmapProcessor(beatmap);
|
||||||
|
beatmapProcessor.PreProcess();
|
||||||
|
|
||||||
|
foreach (var hitObject in beatmap.HitObjects)
|
||||||
|
hitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
|
beatmapProcessor.PostProcess();
|
||||||
|
|
||||||
|
if (withMirrorMod)
|
||||||
|
mirrorMod.ApplyToBeatmap(beatmap);
|
||||||
|
|
||||||
|
return beatmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IBeatmap createRawBeatmap() => new Beatmap
|
||||||
|
{
|
||||||
|
HitObjects = new List<HitObject>
|
||||||
|
{
|
||||||
|
new Fruit
|
||||||
|
{
|
||||||
|
OriginalX = 150,
|
||||||
|
StartTime = 0
|
||||||
|
},
|
||||||
|
new Fruit
|
||||||
|
{
|
||||||
|
OriginalX = 450,
|
||||||
|
StartTime = 500
|
||||||
|
},
|
||||||
|
new JuiceStream
|
||||||
|
{
|
||||||
|
OriginalX = 250,
|
||||||
|
Path = new SliderPath
|
||||||
|
{
|
||||||
|
ControlPoints =
|
||||||
|
{
|
||||||
|
new PathControlPoint(new Vector2(-100, 1)),
|
||||||
|
new PathControlPoint(new Vector2(0, 2)),
|
||||||
|
new PathControlPoint(new Vector2(100, 3)),
|
||||||
|
new PathControlPoint(new Vector2(0, 4))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
StartTime = 1000,
|
||||||
|
},
|
||||||
|
new BananaShower
|
||||||
|
{
|
||||||
|
StartTime = 5000,
|
||||||
|
Duration = 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static void assertEffectivePositionsMirrored(IBeatmap original, IBeatmap mirrored)
|
||||||
|
{
|
||||||
|
if (original.HitObjects.Count != mirrored.HitObjects.Count)
|
||||||
|
Assert.Fail($"Top-level object count mismatch (original: {original.HitObjects.Count}, mirrored: {mirrored.HitObjects.Count})");
|
||||||
|
|
||||||
|
for (int i = 0; i < original.HitObjects.Count; ++i)
|
||||||
|
{
|
||||||
|
var originalObject = (CatchHitObject)original.HitObjects[i];
|
||||||
|
var mirroredObject = (CatchHitObject)mirrored.HitObjects[i];
|
||||||
|
|
||||||
|
// banana showers themselves are exempt, as we only really care about their nested bananas' positions.
|
||||||
|
if (!effectivePositionMirrored(originalObject, mirroredObject) && !(originalObject is BananaShower))
|
||||||
|
Assert.Fail($"{originalObject.GetType().Name} at time {originalObject.StartTime} is not mirrored ({printEffectivePositions(originalObject, mirroredObject)})");
|
||||||
|
|
||||||
|
if (originalObject.NestedHitObjects.Count != mirroredObject.NestedHitObjects.Count)
|
||||||
|
Assert.Fail($"{originalObject.GetType().Name} nested object count mismatch (original: {originalObject.NestedHitObjects.Count}, mirrored: {mirroredObject.NestedHitObjects.Count})");
|
||||||
|
|
||||||
|
for (int j = 0; j < originalObject.NestedHitObjects.Count; ++j)
|
||||||
|
{
|
||||||
|
var originalNested = (CatchHitObject)originalObject.NestedHitObjects[j];
|
||||||
|
var mirroredNested = (CatchHitObject)mirroredObject.NestedHitObjects[j];
|
||||||
|
|
||||||
|
if (!effectivePositionMirrored(originalNested, mirroredNested))
|
||||||
|
Assert.Fail($"{originalObject.GetType().Name}'s nested {originalNested.GetType().Name} at time {originalObject.StartTime} is not mirrored ({printEffectivePositions(originalNested, mirroredNested)})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string printEffectivePositions(CatchHitObject original, CatchHitObject mirrored)
|
||||||
|
=> $"original X: {original.EffectiveX}, mirrored X is: {mirrored.EffectiveX}, mirrored X should be: {CatchPlayfield.WIDTH - original.EffectiveX}";
|
||||||
|
|
||||||
|
private static bool effectivePositionMirrored(CatchHitObject original, CatchHitObject mirrored)
|
||||||
|
=> Precision.AlmostEquals(original.EffectiveX, CatchPlayfield.WIDTH - mirrored.EffectiveX);
|
||||||
|
}
|
||||||
|
}
|
@ -117,6 +117,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
{
|
{
|
||||||
new CatchModDifficultyAdjust(),
|
new CatchModDifficultyAdjust(),
|
||||||
new CatchModClassic(),
|
new CatchModClassic(),
|
||||||
|
new CatchModMirror(),
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.Automation:
|
case ModType.Automation:
|
||||||
|
87
osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs
Normal file
87
osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Mods
|
||||||
|
{
|
||||||
|
public class CatchModMirror : ModMirror, IApplicableToBeatmap
|
||||||
|
{
|
||||||
|
public override string Description => "Fruits are flipped horizontally.";
|
||||||
|
|
||||||
|
/// <remarks>
|
||||||
|
/// <see cref="IApplicableToBeatmap"/> is used instead of <see cref="IApplicableToHitObject"/>,
|
||||||
|
/// as <see cref="CatchBeatmapProcessor"/> applies offsets in <see cref="CatchBeatmapProcessor.PostProcess"/>.
|
||||||
|
/// <see cref="IApplicableToBeatmap"/> runs after post-processing, while <see cref="IApplicableToHitObject"/> runs before it.
|
||||||
|
/// </remarks>
|
||||||
|
public void ApplyToBeatmap(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
foreach (var hitObject in beatmap.HitObjects)
|
||||||
|
applyToHitObject(hitObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyToHitObject(HitObject hitObject)
|
||||||
|
{
|
||||||
|
var catchObject = (CatchHitObject)hitObject;
|
||||||
|
|
||||||
|
switch (catchObject)
|
||||||
|
{
|
||||||
|
case Fruit fruit:
|
||||||
|
mirrorEffectiveX(fruit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JuiceStream juiceStream:
|
||||||
|
mirrorEffectiveX(juiceStream);
|
||||||
|
mirrorJuiceStreamPath(juiceStream);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BananaShower bananaShower:
|
||||||
|
mirrorBananaShower(bananaShower);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mirrors the effective X position of <paramref name="catchObject"/> and its nested hit objects.
|
||||||
|
/// </summary>
|
||||||
|
private static void mirrorEffectiveX(CatchHitObject catchObject)
|
||||||
|
{
|
||||||
|
catchObject.OriginalX = CatchPlayfield.WIDTH - catchObject.OriginalX;
|
||||||
|
catchObject.XOffset = -catchObject.XOffset;
|
||||||
|
|
||||||
|
foreach (var nested in catchObject.NestedHitObjects.Cast<CatchHitObject>())
|
||||||
|
{
|
||||||
|
nested.OriginalX = CatchPlayfield.WIDTH - nested.OriginalX;
|
||||||
|
nested.XOffset = -nested.XOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mirrors the path of the <paramref name="juiceStream"/>.
|
||||||
|
/// </summary>
|
||||||
|
private static void mirrorJuiceStreamPath(JuiceStream juiceStream)
|
||||||
|
{
|
||||||
|
var controlPoints = juiceStream.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray();
|
||||||
|
foreach (var point in controlPoints)
|
||||||
|
point.Position.Value = new Vector2(-point.Position.Value.X, point.Position.Value.Y);
|
||||||
|
|
||||||
|
juiceStream.Path = new SliderPath(controlPoints, juiceStream.Path.ExpectedDistance.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mirrors X positions of all bananas in the <paramref name="bananaShower"/>.
|
||||||
|
/// </summary>
|
||||||
|
private static void mirrorBananaShower(BananaShower bananaShower)
|
||||||
|
{
|
||||||
|
foreach (var banana in bananaShower.NestedHitObjects.OfType<Banana>())
|
||||||
|
banana.XOffset = CatchPlayfield.WIDTH - banana.XOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -41,6 +41,11 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
|
|
||||||
protected override GameplayCursorContainer CreateCursor() => null;
|
protected override GameplayCursorContainer CreateCursor() => null;
|
||||||
|
|
||||||
|
public OsuEditorPlayfield()
|
||||||
|
{
|
||||||
|
HitPolicy = new AnyOrderHitPolicy();
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuConfigManager config)
|
private void load(OsuConfigManager config)
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
// Roughly matches osu!stable's slider border portions.
|
// Roughly matches osu!stable's slider border portions.
|
||||||
=> base.CalculatedBorderPortion * 0.77f;
|
=> base.CalculatedBorderPortion * 0.77f;
|
||||||
|
|
||||||
public new Color4 AccentColour => new Color4(base.AccentColour.R, base.AccentColour.G, base.AccentColour.B, base.AccentColour.A * 0.70f);
|
public new Color4 AccentColour => new Color4(base.AccentColour.R, base.AccentColour.G, base.AccentColour.B, 0.7f);
|
||||||
|
|
||||||
protected override Color4 ColourAt(float position)
|
protected override Color4 ColourAt(float position)
|
||||||
{
|
{
|
||||||
|
22
osu.Game.Rulesets.Osu/UI/AnyOrderHitPolicy.cs
Normal file
22
osu.Game.Rulesets.Osu/UI/AnyOrderHitPolicy.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 osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.UI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An <see cref="IHitPolicy"/> which allows hitobjects to be hit in any order.
|
||||||
|
/// </summary>
|
||||||
|
public class AnyOrderHitPolicy : IHitPolicy
|
||||||
|
{
|
||||||
|
public IHitObjectContainer HitObjectContainer { get; set; }
|
||||||
|
|
||||||
|
public bool IsHittable(DrawableHitObject hitObject, double time) => true;
|
||||||
|
|
||||||
|
public void HandleHit(DrawableHitObject hitObject)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,11 +2,13 @@
|
|||||||
// 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 NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Gameplay
|
namespace osu.Game.Tests.Gameplay
|
||||||
@ -121,6 +123,18 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
AddAssert("Drawable lifetime is restored", () => dho.LifetimeStart == 666 && dho.LifetimeEnd == 999);
|
AddAssert("Drawable lifetime is restored", () => dho.LifetimeStart == 666 && dho.LifetimeEnd == 999);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestStateChangeBeforeLoadComplete()
|
||||||
|
{
|
||||||
|
TestDrawableHitObject dho = null;
|
||||||
|
AddStep("Add DHO and apply result", () =>
|
||||||
|
{
|
||||||
|
Child = dho = new TestDrawableHitObject(new HitObject { StartTime = Time.Current });
|
||||||
|
dho.MissForcefully();
|
||||||
|
});
|
||||||
|
AddAssert("DHO state is correct", () => dho.State.Value == ArmedState.Miss);
|
||||||
|
}
|
||||||
|
|
||||||
private class TestDrawableHitObject : DrawableHitObject
|
private class TestDrawableHitObject : DrawableHitObject
|
||||||
{
|
{
|
||||||
public const double INITIAL_LIFETIME_OFFSET = 100;
|
public const double INITIAL_LIFETIME_OFFSET = 100;
|
||||||
@ -141,6 +155,19 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
if (SetLifetimeStartOnApply)
|
if (SetLifetimeStartOnApply)
|
||||||
LifetimeStart = LIFETIME_ON_APPLY;
|
LifetimeStart = LIFETIME_ON_APPLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void MissForcefully() => ApplyResult(r => r.Type = HitResult.Miss);
|
||||||
|
|
||||||
|
protected override void UpdateHitStateTransforms(ArmedState state)
|
||||||
|
{
|
||||||
|
if (state != ArmedState.Miss)
|
||||||
|
{
|
||||||
|
base.UpdateHitStateTransforms(state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.FadeOut(1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestLifetimeEntry : HitObjectLifetimeEntry
|
private class TestLifetimeEntry : HitObjectLifetimeEntry
|
||||||
|
@ -24,6 +24,8 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
|
|||||||
AddRepeatStep("add some users", () => Client.AddUser(new User { Id = id++ }), 5);
|
AddRepeatStep("add some users", () => Client.AddUser(new User { Id = id++ }), 5);
|
||||||
checkPlayingUserCount(0);
|
checkPlayingUserCount(0);
|
||||||
|
|
||||||
|
AddAssert("playlist item is available", () => Client.CurrentMatchPlayingItem.Value != null);
|
||||||
|
|
||||||
changeState(3, MultiplayerUserState.WaitingForLoad);
|
changeState(3, MultiplayerUserState.WaitingForLoad);
|
||||||
checkPlayingUserCount(3);
|
checkPlayingUserCount(3);
|
||||||
|
|
||||||
@ -41,6 +43,8 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
|
|||||||
|
|
||||||
AddStep("leave room", () => Client.LeaveRoom());
|
AddStep("leave room", () => Client.LeaveRoom());
|
||||||
checkPlayingUserCount(0);
|
checkPlayingUserCount(0);
|
||||||
|
|
||||||
|
AddAssert("playlist item is null", () => Client.CurrentMatchPlayingItem.Value == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Online;
|
using osu.Game.Online;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -15,6 +16,7 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Components
|
namespace osu.Game.Tests.Visual.Components
|
||||||
{
|
{
|
||||||
|
[HeadlessTest]
|
||||||
public class TestScenePollingComponent : OsuTestScene
|
public class TestScenePollingComponent : OsuTestScene
|
||||||
{
|
{
|
||||||
private Container pollBox;
|
private Container pollBox;
|
||||||
|
168
osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs
Normal file
168
osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Online.Rooms;
|
||||||
|
using osu.Game.Online.Rooms.RoomStatuses;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Multiplayer
|
||||||
|
{
|
||||||
|
public class TestSceneDrawableRoom : OsuTestScene
|
||||||
|
{
|
||||||
|
[Cached]
|
||||||
|
private readonly Bindable<Room> selectedRoom = new Bindable<Room>();
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum);
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMultipleStatuses()
|
||||||
|
{
|
||||||
|
AddStep("create rooms", () =>
|
||||||
|
{
|
||||||
|
Child = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Size = new Vector2(0.9f),
|
||||||
|
Spacing = new Vector2(10),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
createDrawableRoom(new Room
|
||||||
|
{
|
||||||
|
Name = { Value = "Flyte's Trash Playlist" },
|
||||||
|
Status = { Value = new RoomStatusOpen() },
|
||||||
|
EndDate = { Value = DateTimeOffset.Now.AddDays(1) },
|
||||||
|
Playlist =
|
||||||
|
{
|
||||||
|
new PlaylistItem
|
||||||
|
{
|
||||||
|
Beatmap =
|
||||||
|
{
|
||||||
|
Value = new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
StarDifficulty = 2.5
|
||||||
|
}
|
||||||
|
}.BeatmapInfo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
createDrawableRoom(new Room
|
||||||
|
{
|
||||||
|
Name = { Value = "Room 2" },
|
||||||
|
Status = { Value = new RoomStatusPlaying() },
|
||||||
|
EndDate = { Value = DateTimeOffset.Now.AddDays(1) },
|
||||||
|
Playlist =
|
||||||
|
{
|
||||||
|
new PlaylistItem
|
||||||
|
{
|
||||||
|
Beatmap =
|
||||||
|
{
|
||||||
|
Value = new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
StarDifficulty = 2.5
|
||||||
|
}
|
||||||
|
}.BeatmapInfo,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new PlaylistItem
|
||||||
|
{
|
||||||
|
Beatmap =
|
||||||
|
{
|
||||||
|
Value = new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
StarDifficulty = 4.5
|
||||||
|
}
|
||||||
|
}.BeatmapInfo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
createDrawableRoom(new Room
|
||||||
|
{
|
||||||
|
Name = { Value = "Room 3" },
|
||||||
|
Status = { Value = new RoomStatusEnded() },
|
||||||
|
EndDate = { Value = DateTimeOffset.Now },
|
||||||
|
}),
|
||||||
|
createDrawableRoom(new Room
|
||||||
|
{
|
||||||
|
Name = { Value = "Room 4 (realtime)" },
|
||||||
|
Status = { Value = new RoomStatusOpen() },
|
||||||
|
Category = { Value = RoomCategory.Realtime },
|
||||||
|
}),
|
||||||
|
createDrawableRoom(new Room
|
||||||
|
{
|
||||||
|
Name = { Value = "Room 4 (spotlight)" },
|
||||||
|
Status = { Value = new RoomStatusOpen() },
|
||||||
|
Category = { Value = RoomCategory.Spotlight },
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestEnableAndDisablePassword()
|
||||||
|
{
|
||||||
|
DrawableRoom drawableRoom = null;
|
||||||
|
Room room = null;
|
||||||
|
|
||||||
|
AddStep("create room", () => Child = drawableRoom = createDrawableRoom(room = new Room
|
||||||
|
{
|
||||||
|
Name = { Value = "Room with password" },
|
||||||
|
Status = { Value = new RoomStatusOpen() },
|
||||||
|
Category = { Value = RoomCategory.Realtime },
|
||||||
|
}));
|
||||||
|
|
||||||
|
AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType<DrawableRoom.PasswordProtectedIcon>().Single().Alpha));
|
||||||
|
|
||||||
|
AddStep("set password", () => room.Password.Value = "password");
|
||||||
|
AddAssert("password icon visible", () => Precision.AlmostEquals(1, drawableRoom.ChildrenOfType<DrawableRoom.PasswordProtectedIcon>().Single().Alpha));
|
||||||
|
|
||||||
|
AddStep("unset password", () => room.Password.Value = string.Empty);
|
||||||
|
AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType<DrawableRoom.PasswordProtectedIcon>().Single().Alpha));
|
||||||
|
}
|
||||||
|
|
||||||
|
private DrawableRoom createDrawableRoom(Room room)
|
||||||
|
{
|
||||||
|
room.Host.Value ??= new User { Username = "peppy", Id = 2 };
|
||||||
|
|
||||||
|
if (room.RecentParticipants.Count == 0)
|
||||||
|
{
|
||||||
|
room.RecentParticipants.AddRange(Enumerable.Range(0, 20).Select(i => new User
|
||||||
|
{
|
||||||
|
Id = i,
|
||||||
|
Username = $"User {i}"
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
var drawableRoom = new DrawableRoom(room) { MatchingFilter = true };
|
||||||
|
drawableRoom.Action = () => drawableRoom.State = drawableRoom.State == SelectionState.Selected ? SelectionState.NotSelected : SelectionState.Selected;
|
||||||
|
|
||||||
|
return drawableRoom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,7 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Beatmaps.Drawables;
|
using osu.Game.Beatmaps.Drawables;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays.BeatmapListing.Panels;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
@ -215,7 +215,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
assertDownloadButtonVisible(false);
|
assertDownloadButtonVisible(false);
|
||||||
|
|
||||||
void assertDownloadButtonVisible(bool visible) => AddUntilStep($"download button {(visible ? "shown" : "hidden")}",
|
void assertDownloadButtonVisible(bool visible) => AddUntilStep($"download button {(visible ? "shown" : "hidden")}",
|
||||||
() => playlist.ChildrenOfType<BeatmapDownloadTrackingComposite>().Single().Alpha == (visible ? 1 : 0));
|
() => playlist.ChildrenOfType<BeatmapPanelDownloadButton>().Single().Alpha == (visible ? 1 : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -229,7 +229,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
|
|
||||||
createPlaylist(byOnlineId, byChecksum);
|
createPlaylist(byOnlineId, byChecksum);
|
||||||
|
|
||||||
AddAssert("download buttons shown", () => playlist.ChildrenOfType<BeatmapDownloadTrackingComposite>().All(d => d.IsPresent));
|
AddAssert("download buttons shown", () => playlist.ChildrenOfType<BeatmapPanelDownloadButton>().All(d => d.IsPresent));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Online.Rooms;
|
|
||||||
using osu.Game.Online.Rooms.RoomStatuses;
|
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
|
||||||
using osu.Game.Tests.Visual.OnlinePlay;
|
|
||||||
using osu.Game.Users;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Multiplayer
|
|
||||||
{
|
|
||||||
public class TestSceneLoungeRoomInfo : OnlinePlayTestScene
|
|
||||||
{
|
|
||||||
[SetUp]
|
|
||||||
public new void Setup() => Schedule(() =>
|
|
||||||
{
|
|
||||||
SelectedRoom.Value = new Room();
|
|
||||||
|
|
||||||
Child = new RoomInfo
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Width = 500
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestNonSelectedRoom()
|
|
||||||
{
|
|
||||||
AddStep("set null room", () => SelectedRoom.Value.RoomID.Value = null);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestOpenRoom()
|
|
||||||
{
|
|
||||||
AddStep("set open room", () =>
|
|
||||||
{
|
|
||||||
SelectedRoom.Value.RoomID.Value = 0;
|
|
||||||
SelectedRoom.Value.Name.Value = "Room 0";
|
|
||||||
SelectedRoom.Value.Host.Value = new User { Username = "peppy", Id = 2 };
|
|
||||||
SelectedRoom.Value.EndDate.Value = DateTimeOffset.Now.AddMonths(1);
|
|
||||||
SelectedRoom.Value.Status.Value = new RoomStatusOpen();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -97,11 +97,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
TeamID = 1,
|
TeamID = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
SpectatorClient.StartPlay(PLAYER_1_ID, importedBeatmapId);
|
SpectatorClient.StartPlay(player1.UserID, importedBeatmapId);
|
||||||
SpectatorClient.StartPlay(PLAYER_2_ID, importedBeatmapId);
|
SpectatorClient.StartPlay(player2.UserID, importedBeatmapId);
|
||||||
|
|
||||||
playingUsers.Add(new MultiplayerRoomUser(PLAYER_1_ID));
|
playingUsers.Add(player1);
|
||||||
playingUsers.Add(new MultiplayerRoomUser(PLAYER_2_ID));
|
playingUsers.Add(player2);
|
||||||
});
|
});
|
||||||
|
|
||||||
loadSpectateScreen();
|
loadSpectateScreen();
|
||||||
|
@ -423,10 +423,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
|
|
||||||
private void createRoom(Func<Room> room)
|
private void createRoom(Func<Room> room)
|
||||||
{
|
{
|
||||||
AddStep("open room", () =>
|
AddUntilStep("wait for lounge", () => multiplayerScreen.ChildrenOfType<LoungeSubScreen>().SingleOrDefault()?.IsLoaded == true);
|
||||||
{
|
AddStep("open room", () => multiplayerScreen.ChildrenOfType<LoungeSubScreen>().Single().Open(room()));
|
||||||
multiplayerScreen.OpenNewRoom(room());
|
|
||||||
});
|
|
||||||
|
|
||||||
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
|
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
|
||||||
AddWaitStep("wait for transition", 2);
|
AddWaitStep("wait for transition", 2);
|
||||||
|
@ -12,6 +12,7 @@ using osu.Framework.Testing;
|
|||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Online.Spectator;
|
using osu.Game.Online.Spectator;
|
||||||
using osu.Game.Replays.Legacy;
|
using osu.Game.Replays.Legacy;
|
||||||
using osu.Game.Rulesets.Osu.Scoring;
|
using osu.Game.Rulesets.Osu.Scoring;
|
||||||
@ -51,12 +52,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
OsuScoreProcessor scoreProcessor;
|
OsuScoreProcessor scoreProcessor;
|
||||||
Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value);
|
Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value);
|
||||||
|
|
||||||
var playable = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value);
|
var playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value);
|
||||||
|
var multiplayerUsers = new List<MultiplayerRoomUser>();
|
||||||
|
|
||||||
foreach (var user in users)
|
foreach (var user in users)
|
||||||
{
|
{
|
||||||
SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0);
|
SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0);
|
||||||
OnlinePlayDependencies.Client.AddUser(new User { Id = user }, true);
|
multiplayerUsers.Add(OnlinePlayDependencies.Client.AddUser(new User { Id = user }, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -64,9 +66,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
scoreProcessor = new OsuScoreProcessor(),
|
scoreProcessor = new OsuScoreProcessor(),
|
||||||
};
|
};
|
||||||
|
|
||||||
scoreProcessor.ApplyBeatmap(playable);
|
scoreProcessor.ApplyBeatmap(playableBeatmap);
|
||||||
|
|
||||||
LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(scoreProcessor, Client.Room?.Users.ToArray())
|
LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(scoreProcessor, multiplayerUsers.ToArray())
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
|
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Rulesets.Osu.Scoring;
|
using osu.Game.Rulesets.Osu.Scoring;
|
||||||
@ -55,7 +56,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
OsuScoreProcessor scoreProcessor;
|
OsuScoreProcessor scoreProcessor;
|
||||||
Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value);
|
Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value);
|
||||||
|
|
||||||
var playable = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value);
|
var playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value);
|
||||||
|
var multiplayerUsers = new List<MultiplayerRoomUser>();
|
||||||
|
|
||||||
foreach (var user in users)
|
foreach (var user in users)
|
||||||
{
|
{
|
||||||
@ -66,6 +68,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
TeamID = RNG.Next(0, 2)
|
TeamID = RNG.Next(0, 2)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
multiplayerUsers.Add(roomUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -73,9 +77,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
scoreProcessor = new OsuScoreProcessor(),
|
scoreProcessor = new OsuScoreProcessor(),
|
||||||
};
|
};
|
||||||
|
|
||||||
scoreProcessor.ApplyBeatmap(playable);
|
scoreProcessor.ApplyBeatmap(playableBeatmap);
|
||||||
|
|
||||||
LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(scoreProcessor, Client.Room?.Users.ToArray())
|
LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(scoreProcessor, multiplayerUsers.ToArray())
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
@ -155,6 +155,42 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddUntilStep("second user crown visible", () => this.ChildrenOfType<ParticipantPanel>().ElementAt(1).ChildrenOfType<SpriteIcon>().First().Alpha == 1);
|
AddUntilStep("second user crown visible", () => this.ChildrenOfType<ParticipantPanel>().ElementAt(1).ChildrenOfType<SpriteIcon>().First().Alpha == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestKickButtonOnlyPresentWhenHost()
|
||||||
|
{
|
||||||
|
AddStep("add user", () => Client.AddUser(new User
|
||||||
|
{
|
||||||
|
Id = 3,
|
||||||
|
Username = "Second",
|
||||||
|
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
|
||||||
|
}));
|
||||||
|
|
||||||
|
AddUntilStep("kick buttons visible", () => this.ChildrenOfType<ParticipantPanel.KickButton>().Count(d => d.IsPresent) == 1);
|
||||||
|
|
||||||
|
AddStep("make second user host", () => Client.TransferHost(3));
|
||||||
|
|
||||||
|
AddUntilStep("kick buttons not visible", () => this.ChildrenOfType<ParticipantPanel.KickButton>().Count(d => d.IsPresent) == 0);
|
||||||
|
|
||||||
|
AddStep("make local user host again", () => Client.TransferHost(API.LocalUser.Value.Id));
|
||||||
|
|
||||||
|
AddUntilStep("kick buttons visible", () => this.ChildrenOfType<ParticipantPanel.KickButton>().Count(d => d.IsPresent) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestKickButtonKicks()
|
||||||
|
{
|
||||||
|
AddStep("add user", () => Client.AddUser(new User
|
||||||
|
{
|
||||||
|
Id = 3,
|
||||||
|
Username = "Second",
|
||||||
|
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
|
||||||
|
}));
|
||||||
|
|
||||||
|
AddStep("kick second user", () => this.ChildrenOfType<ParticipantPanel.KickButton>().Single(d => d.IsPresent).TriggerClick());
|
||||||
|
|
||||||
|
AddAssert("second user kicked", () => Client.Room?.Users.Single().UserID == API.LocalUser.Value.Id);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestManyUsers()
|
public void TestManyUsers()
|
||||||
{
|
{
|
||||||
|
95
osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs
Normal file
95
osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// 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.Screens.OnlinePlay.Lounge.Components;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Multiplayer
|
||||||
|
{
|
||||||
|
public class TestSceneRankRangePill : MultiplayerTestScene
|
||||||
|
{
|
||||||
|
[SetUp]
|
||||||
|
public new void Setup() => Schedule(() =>
|
||||||
|
{
|
||||||
|
Child = new RankRangePill
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSingleUser()
|
||||||
|
{
|
||||||
|
AddStep("add user", () =>
|
||||||
|
{
|
||||||
|
Client.AddUser(new User
|
||||||
|
{
|
||||||
|
Id = 2,
|
||||||
|
Statistics = { GlobalRank = 1234 }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove the local user so only the one above is displayed.
|
||||||
|
Client.RemoveUser(API.LocalUser.Value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMultipleUsers()
|
||||||
|
{
|
||||||
|
AddStep("add users", () =>
|
||||||
|
{
|
||||||
|
Client.AddUser(new User
|
||||||
|
{
|
||||||
|
Id = 2,
|
||||||
|
Statistics = { GlobalRank = 1234 }
|
||||||
|
});
|
||||||
|
|
||||||
|
Client.AddUser(new User
|
||||||
|
{
|
||||||
|
Id = 3,
|
||||||
|
Statistics = { GlobalRank = 3333 }
|
||||||
|
});
|
||||||
|
|
||||||
|
Client.AddUser(new User
|
||||||
|
{
|
||||||
|
Id = 4,
|
||||||
|
Statistics = { GlobalRank = 4321 }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove the local user so only the ones above are displayed.
|
||||||
|
Client.RemoveUser(API.LocalUser.Value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(1, 10)]
|
||||||
|
[TestCase(10, 100)]
|
||||||
|
[TestCase(100, 1000)]
|
||||||
|
[TestCase(1000, 10000)]
|
||||||
|
[TestCase(10000, 100000)]
|
||||||
|
[TestCase(100000, 1000000)]
|
||||||
|
[TestCase(1000000, 10000000)]
|
||||||
|
public void TestRange(int min, int max)
|
||||||
|
{
|
||||||
|
AddStep("add users", () =>
|
||||||
|
{
|
||||||
|
Client.AddUser(new User
|
||||||
|
{
|
||||||
|
Id = 2,
|
||||||
|
Statistics = { GlobalRank = min }
|
||||||
|
});
|
||||||
|
|
||||||
|
Client.AddUser(new User
|
||||||
|
{
|
||||||
|
Id = 3,
|
||||||
|
Statistics = { GlobalRank = max }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove the local user so only the ones above are displayed.
|
||||||
|
Client.RemoveUser(API.LocalUser.Value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,143 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Online.Rooms;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||||
|
using osu.Game.Tests.Visual.OnlinePlay;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osu.Game.Users.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Multiplayer
|
||||||
|
{
|
||||||
|
public class TestSceneRecentParticipantsList : OnlinePlayTestScene
|
||||||
|
{
|
||||||
|
private RecentParticipantsList list;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public new void Setup() => Schedule(() =>
|
||||||
|
{
|
||||||
|
SelectedRoom.Value = new Room { Name = { Value = "test room" } };
|
||||||
|
|
||||||
|
Child = list = new RecentParticipantsList
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
NumberOfCircles = 4
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCircleCountNearLimit()
|
||||||
|
{
|
||||||
|
AddStep("add 8 users", () =>
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
addUser(i);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("set 8 circles", () => list.NumberOfCircles = 8);
|
||||||
|
AddAssert("0 hidden users", () => list.ChildrenOfType<RecentParticipantsList.HiddenUserCount>().Single().Count == 0);
|
||||||
|
|
||||||
|
AddStep("add one more user", () => addUser(9));
|
||||||
|
AddAssert("2 hidden users", () => list.ChildrenOfType<RecentParticipantsList.HiddenUserCount>().Single().Count == 2);
|
||||||
|
|
||||||
|
AddStep("remove first user", () => removeUserAt(0));
|
||||||
|
AddAssert("0 hidden users", () => list.ChildrenOfType<RecentParticipantsList.HiddenUserCount>().Single().Count == 0);
|
||||||
|
|
||||||
|
AddStep("add one more user", () => addUser(9));
|
||||||
|
AddAssert("2 hidden users", () => list.ChildrenOfType<RecentParticipantsList.HiddenUserCount>().Single().Count == 2);
|
||||||
|
|
||||||
|
AddStep("remove last user", () => removeUserAt(8));
|
||||||
|
AddAssert("0 hidden users", () => list.ChildrenOfType<RecentParticipantsList.HiddenUserCount>().Single().Count == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHiddenUsersBecomeDisplayed()
|
||||||
|
{
|
||||||
|
AddStep("add 8 users", () =>
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
addUser(i);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("set 3 circles", () => list.NumberOfCircles = 3);
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
AddStep("remove user", () => removeUserAt(0));
|
||||||
|
int remainingUsers = 7 - i;
|
||||||
|
|
||||||
|
int displayedUsers = remainingUsers > 3 ? 2 : remainingUsers;
|
||||||
|
AddAssert($"{displayedUsers} avatars displayed", () => list.ChildrenOfType<UpdateableAvatar>().Count() == displayedUsers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCircleCount()
|
||||||
|
{
|
||||||
|
AddStep("add 50 users", () =>
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 50; i++)
|
||||||
|
addUser(i);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("set 3 circles", () => list.NumberOfCircles = 3);
|
||||||
|
AddAssert("2 users displayed", () => list.ChildrenOfType<UpdateableAvatar>().Count() == 2);
|
||||||
|
AddAssert("48 hidden users", () => list.ChildrenOfType<RecentParticipantsList.HiddenUserCount>().Single().Count == 48);
|
||||||
|
|
||||||
|
AddStep("set 10 circles", () => list.NumberOfCircles = 10);
|
||||||
|
AddAssert("9 users displayed", () => list.ChildrenOfType<UpdateableAvatar>().Count() == 9);
|
||||||
|
AddAssert("41 hidden users", () => list.ChildrenOfType<RecentParticipantsList.HiddenUserCount>().Single().Count == 41);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAddAndRemoveUsers()
|
||||||
|
{
|
||||||
|
AddStep("add 50 users", () =>
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 50; i++)
|
||||||
|
addUser(i);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("remove from start", () => removeUserAt(0));
|
||||||
|
AddAssert("3 circles displayed", () => list.ChildrenOfType<UpdateableAvatar>().Count() == 3);
|
||||||
|
AddAssert("46 hidden users", () => list.ChildrenOfType<RecentParticipantsList.HiddenUserCount>().Single().Count == 46);
|
||||||
|
|
||||||
|
AddStep("remove from end", () => removeUserAt(SelectedRoom.Value.RecentParticipants.Count - 1));
|
||||||
|
AddAssert("3 circles displayed", () => list.ChildrenOfType<UpdateableAvatar>().Count() == 3);
|
||||||
|
AddAssert("45 hidden users", () => list.ChildrenOfType<RecentParticipantsList.HiddenUserCount>().Single().Count == 45);
|
||||||
|
|
||||||
|
AddRepeatStep("remove 45 users", () => removeUserAt(0), 45);
|
||||||
|
AddAssert("3 circles displayed", () => list.ChildrenOfType<UpdateableAvatar>().Count() == 3);
|
||||||
|
AddAssert("0 hidden users", () => list.ChildrenOfType<RecentParticipantsList.HiddenUserCount>().Single().Count == 0);
|
||||||
|
AddAssert("hidden users bubble hidden", () => list.ChildrenOfType<RecentParticipantsList.HiddenUserCount>().Single().Alpha < 0.5f);
|
||||||
|
|
||||||
|
AddStep("remove another user", () => removeUserAt(0));
|
||||||
|
AddAssert("2 circles displayed", () => list.ChildrenOfType<UpdateableAvatar>().Count() == 2);
|
||||||
|
AddAssert("0 hidden users", () => list.ChildrenOfType<RecentParticipantsList.HiddenUserCount>().Single().Count == 0);
|
||||||
|
|
||||||
|
AddRepeatStep("remove the remaining two users", () => removeUserAt(0), 2);
|
||||||
|
AddAssert("0 circles displayed", () => !list.ChildrenOfType<UpdateableAvatar>().Any());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addUser(int id)
|
||||||
|
{
|
||||||
|
SelectedRoom.Value.RecentParticipants.Add(new User
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
Username = $"User {id}"
|
||||||
|
});
|
||||||
|
SelectedRoom.Value.ParticipantCount.Value++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeUserAt(int index)
|
||||||
|
{
|
||||||
|
SelectedRoom.Value.RecentParticipants.RemoveAt(index);
|
||||||
|
SelectedRoom.Value.ParticipantCount.Value--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,81 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Online.Rooms;
|
|
||||||
using osu.Game.Online.Rooms.RoomStatuses;
|
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Multiplayer
|
|
||||||
{
|
|
||||||
public class TestSceneRoomStatus : OsuTestScene
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public void TestMultipleStatuses()
|
|
||||||
{
|
|
||||||
AddStep("create rooms", () =>
|
|
||||||
{
|
|
||||||
Child = new FillFlowContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Width = 0.5f,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new DrawableRoom(new Room
|
|
||||||
{
|
|
||||||
Name = { Value = "Open - ending in 1 day" },
|
|
||||||
Status = { Value = new RoomStatusOpen() },
|
|
||||||
EndDate = { Value = DateTimeOffset.Now.AddDays(1) }
|
|
||||||
}) { MatchingFilter = true },
|
|
||||||
new DrawableRoom(new Room
|
|
||||||
{
|
|
||||||
Name = { Value = "Playing - ending in 1 day" },
|
|
||||||
Status = { Value = new RoomStatusPlaying() },
|
|
||||||
EndDate = { Value = DateTimeOffset.Now.AddDays(1) }
|
|
||||||
}) { MatchingFilter = true },
|
|
||||||
new DrawableRoom(new Room
|
|
||||||
{
|
|
||||||
Name = { Value = "Ended" },
|
|
||||||
Status = { Value = new RoomStatusEnded() },
|
|
||||||
EndDate = { Value = DateTimeOffset.Now }
|
|
||||||
}) { MatchingFilter = true },
|
|
||||||
new DrawableRoom(new Room
|
|
||||||
{
|
|
||||||
Name = { Value = "Open" },
|
|
||||||
Status = { Value = new RoomStatusOpen() },
|
|
||||||
Category = { Value = RoomCategory.Realtime }
|
|
||||||
}) { MatchingFilter = true },
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestEnableAndDisablePassword()
|
|
||||||
{
|
|
||||||
DrawableRoom drawableRoom = null;
|
|
||||||
Room room = null;
|
|
||||||
|
|
||||||
AddStep("create room", () => Child = drawableRoom = new DrawableRoom(room = new Room
|
|
||||||
{
|
|
||||||
Name = { Value = "Room with password" },
|
|
||||||
Status = { Value = new RoomStatusOpen() },
|
|
||||||
Category = { Value = RoomCategory.Realtime },
|
|
||||||
}) { MatchingFilter = true });
|
|
||||||
|
|
||||||
AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType<DrawableRoom.PasswordProtectedIcon>().Single().Alpha));
|
|
||||||
|
|
||||||
AddStep("set password", () => room.Password.Value = "password");
|
|
||||||
AddAssert("password icon visible", () => Precision.AlmostEquals(1, drawableRoom.ChildrenOfType<DrawableRoom.PasswordProtectedIcon>().Single().Alpha));
|
|
||||||
|
|
||||||
AddStep("unset password", () => room.Password.Value = string.Empty);
|
|
||||||
AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType<DrawableRoom.PasswordProtectedIcon>().Single().Alpha));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,6 +17,7 @@ using osu.Game.Rulesets;
|
|||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Screens;
|
using osu.Game.Screens;
|
||||||
using osu.Game.Screens.OnlinePlay.Components;
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||||
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
|
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
|
||||||
using osu.Game.Screens.OnlinePlay.Multiplayer.Participants;
|
using osu.Game.Screens.OnlinePlay.Multiplayer.Participants;
|
||||||
@ -150,10 +151,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
|
|
||||||
private void createRoom(Func<Room> room)
|
private void createRoom(Func<Room> room)
|
||||||
{
|
{
|
||||||
AddStep("open room", () =>
|
AddStep("open room", () => multiplayerScreen.ChildrenOfType<LoungeSubScreen>().Single().Open(room()));
|
||||||
{
|
|
||||||
multiplayerScreen.OpenNewRoom(room());
|
|
||||||
});
|
|
||||||
|
|
||||||
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
|
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
|
||||||
AddWaitStep("wait for transition", 2);
|
AddWaitStep("wait for transition", 2);
|
||||||
|
@ -10,7 +10,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
@ -30,10 +29,9 @@ using osu.Game.Skinning;
|
|||||||
using osu.Game.Utils;
|
using osu.Game.Utils;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual.Navigation
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
[HeadlessTest]
|
|
||||||
public class TestSceneOsuGame : OsuTestScene
|
public class TestSceneOsuGame : OsuTestScene
|
||||||
{
|
{
|
||||||
private IReadOnlyList<Type> requiredGameDependencies => new[]
|
private IReadOnlyList<Type> requiredGameDependencies => new[]
|
@ -16,6 +16,7 @@ using osu.Game.Overlays.Toolbar;
|
|||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Screens.OnlinePlay.Components;
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
@ -316,7 +317,8 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
|
|
||||||
PushAndConfirm(() => multiplayer = new TestMultiplayer());
|
PushAndConfirm(() => multiplayer = new TestMultiplayer());
|
||||||
|
|
||||||
AddStep("open room", () => multiplayer.OpenNewRoom());
|
AddUntilStep("wait for lounge", () => multiplayer.ChildrenOfType<LoungeSubScreen>().SingleOrDefault()?.IsLoaded == true);
|
||||||
|
AddStep("open room", () => multiplayer.ChildrenOfType<LoungeSubScreen>().Single().Open());
|
||||||
AddStep("press back button", () => Game.ChildrenOfType<BackButton>().First().Action());
|
AddStep("press back button", () => Game.ChildrenOfType<BackButton>().First().Action());
|
||||||
AddWaitStep("wait two frames", 2);
|
AddWaitStep("wait two frames", 2);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
@ -95,9 +96,11 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddAssert(@"no stream selected", () => changelog.Header.Streams.Current.Value == null);
|
AddAssert(@"no stream selected", () => changelog.Header.Streams.Current.Value == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[TestCase(false)]
|
||||||
public void ShowWithBuild()
|
[TestCase(true)]
|
||||||
|
public void ShowWithBuild(bool isSupporter)
|
||||||
{
|
{
|
||||||
|
AddStep(@"set supporter", () => dummyAPI.LocalUser.Value.IsSupporter = isSupporter);
|
||||||
showBuild(() => new APIChangelogBuild
|
showBuild(() => new APIChangelogBuild
|
||||||
{
|
{
|
||||||
Version = "2018.712.0",
|
Version = "2018.712.0",
|
||||||
@ -155,6 +158,8 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddUntilStep(@"wait for streams", () => changelog.Streams?.Count > 0);
|
AddUntilStep(@"wait for streams", () => changelog.Streams?.Count > 0);
|
||||||
AddAssert(@"correct build displayed", () => changelog.Current.Value.Version == "2018.712.0");
|
AddAssert(@"correct build displayed", () => changelog.Current.Value.Version == "2018.712.0");
|
||||||
AddAssert(@"correct stream selected", () => changelog.Header.Streams.Current.Value.Id == 5);
|
AddAssert(@"correct stream selected", () => changelog.Header.Streams.Current.Value.Id == 5);
|
||||||
|
AddUntilStep(@"wait for content load", () => changelog.ChildrenOfType<ChangelogSupporterPromo>().Any());
|
||||||
|
AddAssert(@"supporter promo showed", () => changelog.ChildrenOfType<ChangelogSupporterPromo>().First().Alpha == (isSupporter ? 0 : 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.Changelog;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Online
|
||||||
|
{
|
||||||
|
public class TestSceneChangelogSupporterPromo : OsuTestScene
|
||||||
|
{
|
||||||
|
[Cached]
|
||||||
|
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||||
|
|
||||||
|
public TestSceneChangelogSupporterPromo()
|
||||||
|
{
|
||||||
|
Child = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colourProvider.Background4,
|
||||||
|
},
|
||||||
|
new ChangelogSupporterPromo(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -68,13 +70,40 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MyContextMenuContainer : Container, IHasContextMenu
|
private static MenuItem[] makeMenu()
|
||||||
{
|
{
|
||||||
public MenuItem[] ContextMenuItems => new MenuItem[]
|
return new MenuItem[]
|
||||||
{
|
{
|
||||||
new OsuMenuItem(@"Some option"),
|
new OsuMenuItem(@"Some option"),
|
||||||
new OsuMenuItem(@"Highlighted option", MenuItemType.Highlighted),
|
new OsuMenuItem(@"Highlighted option", MenuItemType.Highlighted),
|
||||||
new OsuMenuItem(@"Another option"),
|
new OsuMenuItem(@"Another option"),
|
||||||
|
new OsuMenuItem(@"Nested option >")
|
||||||
|
{
|
||||||
|
Items = new MenuItem[]
|
||||||
|
{
|
||||||
|
new OsuMenuItem(@"Sub-One"),
|
||||||
|
new OsuMenuItem(@"Sub-Two"),
|
||||||
|
new OsuMenuItem(@"Sub-Three"),
|
||||||
|
new OsuMenuItem(@"Sub-Nested option >")
|
||||||
|
{
|
||||||
|
Items = new MenuItem[]
|
||||||
|
{
|
||||||
|
new OsuMenuItem(@"Double Sub-One"),
|
||||||
|
new OsuMenuItem(@"Double Sub-Two"),
|
||||||
|
new OsuMenuItem(@"Double Sub-Three"),
|
||||||
|
new OsuMenuItem(@"Sub-Sub-Nested option >")
|
||||||
|
{
|
||||||
|
Items = new MenuItem[]
|
||||||
|
{
|
||||||
|
new OsuMenuItem(@"Too Deep One"),
|
||||||
|
new OsuMenuItem(@"Too Deep Two"),
|
||||||
|
new OsuMenuItem(@"Too Deep Three"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
new OsuMenuItem(@"Choose me please"),
|
new OsuMenuItem(@"Choose me please"),
|
||||||
new OsuMenuItem(@"And me too"),
|
new OsuMenuItem(@"And me too"),
|
||||||
new OsuMenuItem(@"Trying to fill"),
|
new OsuMenuItem(@"Trying to fill"),
|
||||||
@ -82,17 +111,29 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class MyContextMenuContainer : Container, IHasContextMenu
|
||||||
|
{
|
||||||
|
public MenuItem[] ContextMenuItems => makeMenu();
|
||||||
|
}
|
||||||
|
|
||||||
private class AnotherContextMenuContainer : Container, IHasContextMenu
|
private class AnotherContextMenuContainer : Container, IHasContextMenu
|
||||||
{
|
{
|
||||||
public MenuItem[] ContextMenuItems => new MenuItem[]
|
public MenuItem[] ContextMenuItems
|
||||||
{
|
{
|
||||||
new OsuMenuItem(@"Simple option"),
|
get
|
||||||
new OsuMenuItem(@"Simple very very long option"),
|
{
|
||||||
new OsuMenuItem(@"Change width", MenuItemType.Highlighted, () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint)),
|
List<MenuItem> items = makeMenu().ToList();
|
||||||
new OsuMenuItem(@"Change height", MenuItemType.Highlighted, () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint)),
|
items.AddRange(new MenuItem[]
|
||||||
new OsuMenuItem(@"Change width back", MenuItemType.Destructive, () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint)),
|
{
|
||||||
new OsuMenuItem(@"Change height back", MenuItemType.Destructive, () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint)),
|
new OsuMenuItem(@"Change width", MenuItemType.Highlighted, () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint)),
|
||||||
};
|
new OsuMenuItem(@"Change height", MenuItemType.Highlighted, () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint)),
|
||||||
|
new OsuMenuItem(@"Change width back", MenuItemType.Destructive, () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint)),
|
||||||
|
new OsuMenuItem(@"Change height back", MenuItemType.Destructive, () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint)),
|
||||||
|
});
|
||||||
|
|
||||||
|
return items.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,16 @@ namespace osu.Game.Database
|
|||||||
public interface IModelManager<TModel>
|
public interface IModelManager<TModel>
|
||||||
where TModel : class
|
where TModel : class
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A bindable which contains a weak reference to the last item that was updated.
|
||||||
|
/// This is not thread-safe and should be scheduled locally if consumed from a drawable component.
|
||||||
|
/// </summary>
|
||||||
IBindable<WeakReference<TModel>> ItemUpdated { get; }
|
IBindable<WeakReference<TModel>> ItemUpdated { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A bindable which contains a weak reference to the last item that was removed.
|
||||||
|
/// This is not thread-safe and should be scheduled locally if consumed from a drawable component.
|
||||||
|
/// </summary>
|
||||||
IBindable<WeakReference<TModel>> ItemRemoved { get; }
|
IBindable<WeakReference<TModel>> ItemRemoved { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
@ -9,6 +10,14 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
{
|
{
|
||||||
public class OsuContextMenuContainer : ContextMenuContainer
|
public class OsuContextMenuContainer : ContextMenuContainer
|
||||||
{
|
{
|
||||||
protected override Menu CreateMenu() => new OsuContextMenu();
|
[Cached]
|
||||||
|
private OsuContextMenuSamples samples = new OsuContextMenuSamples();
|
||||||
|
|
||||||
|
public OsuContextMenuContainer()
|
||||||
|
{
|
||||||
|
AddInternal(samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Menu CreateMenu() => new OsuContextMenu(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
Background = new Box
|
Background = new Box
|
||||||
{
|
{
|
||||||
@ -42,7 +42,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
Size = new Vector2(13),
|
Size = new Vector2(13),
|
||||||
Icon = icon,
|
Icon = icon,
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,9 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
private const float border_width = 3;
|
private const float border_width = 3;
|
||||||
|
|
||||||
|
private const double animate_in_duration = 150;
|
||||||
|
private const double animate_out_duration = 500;
|
||||||
|
|
||||||
public Nub()
|
public Nub()
|
||||||
{
|
{
|
||||||
Box fill;
|
Box fill;
|
||||||
@ -77,20 +80,26 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
this.FadeColour(GlowingAccentColour, 500, Easing.OutQuint);
|
this.FadeColour(GlowingAccentColour, animate_in_duration, Easing.OutQuint);
|
||||||
FadeEdgeEffectTo(1, 500, Easing.OutQuint);
|
FadeEdgeEffectTo(1, animate_in_duration, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FadeEdgeEffectTo(0, 500);
|
FadeEdgeEffectTo(0, animate_out_duration);
|
||||||
this.FadeColour(AccentColour, 500);
|
this.FadeColour(AccentColour, animate_out_duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Expanded
|
public bool Expanded
|
||||||
{
|
{
|
||||||
set => this.ResizeTo(new Vector2(value ? EXPANDED_SIZE : COLLAPSED_SIZE, 12), 500, Easing.OutQuint);
|
set
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
this.ResizeTo(new Vector2(EXPANDED_SIZE, 12), animate_in_duration, Easing.OutQuint);
|
||||||
|
else
|
||||||
|
this.ResizeTo(new Vector2(COLLAPSED_SIZE, 12), animate_out_duration, Easing.OutQuint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Bindable<bool> current = new Bindable<bool>();
|
private readonly Bindable<bool> current = new Bindable<bool>();
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
@ -14,7 +15,14 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
private const int fade_duration = 250;
|
private const int fade_duration = 250;
|
||||||
|
|
||||||
public OsuContextMenu()
|
[Resolved]
|
||||||
|
private OsuContextMenuSamples samples { get; set; }
|
||||||
|
|
||||||
|
// todo: this shouldn't be required after https://github.com/ppy/osu-framework/issues/4519 is fixed.
|
||||||
|
private bool wasOpened;
|
||||||
|
private readonly bool playClickSample;
|
||||||
|
|
||||||
|
public OsuContextMenu(bool playClickSample = false)
|
||||||
: base(Direction.Vertical)
|
: base(Direction.Vertical)
|
||||||
{
|
{
|
||||||
MaskingContainer.CornerRadius = 5;
|
MaskingContainer.CornerRadius = 5;
|
||||||
@ -28,16 +36,38 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
ItemsContainer.Padding = new MarginPadding { Vertical = DrawableOsuMenuItem.MARGIN_VERTICAL };
|
ItemsContainer.Padding = new MarginPadding { Vertical = DrawableOsuMenuItem.MARGIN_VERTICAL };
|
||||||
|
|
||||||
MaxHeight = 250;
|
MaxHeight = 250;
|
||||||
|
|
||||||
|
this.playClickSample = playClickSample;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours, AudioManager audio)
|
||||||
{
|
{
|
||||||
BackgroundColour = colours.ContextMenuGray;
|
BackgroundColour = colours.ContextMenuGray;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint);
|
protected override void AnimateOpen()
|
||||||
protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint);
|
{
|
||||||
|
this.FadeIn(fade_duration, Easing.OutQuint);
|
||||||
|
|
||||||
|
if (playClickSample)
|
||||||
|
samples.PlayClickSample();
|
||||||
|
|
||||||
|
if (!wasOpened)
|
||||||
|
samples.PlayOpenSample();
|
||||||
|
|
||||||
|
wasOpened = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AnimateClose()
|
||||||
|
{
|
||||||
|
this.FadeOut(fade_duration, Easing.OutQuint);
|
||||||
|
|
||||||
|
if (wasOpened)
|
||||||
|
samples.PlayCloseSample();
|
||||||
|
|
||||||
|
wasOpened = false;
|
||||||
|
}
|
||||||
|
|
||||||
protected override Menu CreateSubMenu() => new OsuContextMenu();
|
protected override Menu CreateSubMenu() => new OsuContextMenu();
|
||||||
}
|
}
|
||||||
|
35
osu.Game/Graphics/UserInterface/OsuContextMenuSamples.cs
Normal file
35
osu.Game/Graphics/UserInterface/OsuContextMenuSamples.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Audio.Sample;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface
|
||||||
|
{
|
||||||
|
public class OsuContextMenuSamples : Component
|
||||||
|
{
|
||||||
|
private Sample sampleClick;
|
||||||
|
private Sample sampleOpen;
|
||||||
|
private Sample sampleClose;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours, AudioManager audio)
|
||||||
|
{
|
||||||
|
sampleClick = audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select");
|
||||||
|
sampleOpen = audio.Samples.Get(@"UI/dropdown-open");
|
||||||
|
sampleClose = audio.Samples.Get(@"UI/dropdown-close");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PlayClickSample() => Scheduler.AddOnce(playClickSample);
|
||||||
|
private void playClickSample() => sampleClick.Play();
|
||||||
|
|
||||||
|
public void PlayOpenSample() => Scheduler.AddOnce(playOpenSample);
|
||||||
|
private void playOpenSample() => sampleOpen.Play();
|
||||||
|
|
||||||
|
public void PlayCloseSample() => Scheduler.AddOnce(playCloseSample);
|
||||||
|
private void playCloseSample() => sampleClose.Play();
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,14 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
/// <exception cref="NotJoinedRoomException">If the user is not in a room.</exception>
|
/// <exception cref="NotJoinedRoomException">If the user is not in a room.</exception>
|
||||||
Task TransferHost(int userId);
|
Task TransferHost(int userId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// As the host, kick another user from the room.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId">The user to kick..</param>
|
||||||
|
/// <exception cref="NotHostException">A user other than the current host is attempting to kick a user.</exception>
|
||||||
|
/// <exception cref="NotJoinedRoomException">If the user is not in a room.</exception>
|
||||||
|
Task KickUser(int userId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// As the host, update the settings of the currently joined room.
|
/// As the host, update the settings of the currently joined room.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -181,6 +181,7 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
{
|
{
|
||||||
APIRoom = null;
|
APIRoom = null;
|
||||||
Room = null;
|
Room = null;
|
||||||
|
CurrentMatchPlayingItem.Value = null;
|
||||||
PlayingUserIds.Clear();
|
PlayingUserIds.Clear();
|
||||||
|
|
||||||
RoomUpdated?.Invoke();
|
RoomUpdated?.Invoke();
|
||||||
@ -292,6 +293,8 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
|
|
||||||
public abstract Task TransferHost(int userId);
|
public abstract Task TransferHost(int userId);
|
||||||
|
|
||||||
|
public abstract Task KickUser(int userId);
|
||||||
|
|
||||||
public abstract Task ChangeSettings(MultiplayerRoomSettings settings);
|
public abstract Task ChangeSettings(MultiplayerRoomSettings settings);
|
||||||
|
|
||||||
public abstract Task ChangeState(MultiplayerUserState newState);
|
public abstract Task ChangeState(MultiplayerUserState newState);
|
||||||
|
@ -91,6 +91,14 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
return connection.InvokeAsync(nameof(IMultiplayerServer.TransferHost), userId);
|
return connection.InvokeAsync(nameof(IMultiplayerServer.TransferHost), userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Task KickUser(int userId)
|
||||||
|
{
|
||||||
|
if (!IsConnected.Value)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
return connection.InvokeAsync(nameof(IMultiplayerServer.KickUser), userId);
|
||||||
|
}
|
||||||
|
|
||||||
public override Task ChangeSettings(MultiplayerRoomSettings settings)
|
public override Task ChangeSettings(MultiplayerRoomSettings settings)
|
||||||
{
|
{
|
||||||
if (!IsConnected.Value)
|
if (!IsConnected.Value)
|
||||||
|
@ -59,8 +59,8 @@ namespace osu.Game.Online.Rooms
|
|||||||
|
|
||||||
protected override bool VerifyDatabasedModel(BeatmapSetInfo databasedSet)
|
protected override bool VerifyDatabasedModel(BeatmapSetInfo databasedSet)
|
||||||
{
|
{
|
||||||
int? beatmapId = SelectedItem.Value.Beatmap.Value.OnlineBeatmapID;
|
int? beatmapId = SelectedItem.Value?.Beatmap.Value.OnlineBeatmapID;
|
||||||
string checksum = SelectedItem.Value.Beatmap.Value.MD5Hash;
|
string checksum = SelectedItem.Value?.Beatmap.Value.MD5Hash;
|
||||||
|
|
||||||
var matchingBeatmap = databasedSet.Beatmaps.FirstOrDefault(b => b.OnlineBeatmapID == beatmapId && b.MD5Hash == checksum);
|
var matchingBeatmap = databasedSet.Beatmaps.FirstOrDefault(b => b.OnlineBeatmapID == beatmapId && b.MD5Hash == checksum);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ namespace osu.Game.Online.Rooms.RoomStatuses
|
|||||||
{
|
{
|
||||||
public class RoomStatusEnded : RoomStatus
|
public class RoomStatusEnded : RoomStatus
|
||||||
{
|
{
|
||||||
public override string Message => @"Ended";
|
public override string Message => "Ended";
|
||||||
public override Color4 GetAppropriateColour(OsuColour colours) => colours.YellowDarker;
|
public override Color4 GetAppropriateColour(OsuColour colours) => colours.YellowDarker;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ namespace osu.Game.Online.Rooms.RoomStatuses
|
|||||||
{
|
{
|
||||||
public class RoomStatusOpen : RoomStatus
|
public class RoomStatusOpen : RoomStatus
|
||||||
{
|
{
|
||||||
public override string Message => @"Welcoming Players";
|
public override string Message => "Open";
|
||||||
public override Color4 GetAppropriateColour(OsuColour colours) => colours.GreenLight;
|
public override Color4 GetAppropriateColour(OsuColour colours) => colours.GreenLight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ namespace osu.Game.Online.Rooms.RoomStatuses
|
|||||||
{
|
{
|
||||||
public class RoomStatusPlaying : RoomStatus
|
public class RoomStatusPlaying : RoomStatus
|
||||||
{
|
{
|
||||||
public override string Message => @"Now Playing";
|
public override string Message => "Playing";
|
||||||
public override Color4 GetAppropriateColour(OsuColour colours) => colours.Purple;
|
public override Color4 GetAppropriateColour(OsuColour colours) => colours.Purple;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,13 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
button.Add(new DownloadProgressBar(beatmapSet)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
Depth = -1,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
|
@ -71,6 +71,17 @@ namespace osu.Game.Overlays.Changelog
|
|||||||
Colour = colourProvider.Background6,
|
Colour = colourProvider.Background6,
|
||||||
Margin = new MarginPadding { Top = 30 },
|
Margin = new MarginPadding { Top = 30 },
|
||||||
},
|
},
|
||||||
|
new ChangelogSupporterPromo
|
||||||
|
{
|
||||||
|
Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1,
|
||||||
|
},
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 2,
|
||||||
|
Colour = colourProvider.Background6,
|
||||||
|
Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1,
|
||||||
|
},
|
||||||
comments = new CommentsContainer()
|
comments = new CommentsContainer()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
187
osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs
Normal file
187
osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Online.Chat;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Changelog
|
||||||
|
{
|
||||||
|
public class ChangelogSupporterPromo : CompositeDrawable
|
||||||
|
{
|
||||||
|
private const float image_container_width = 164;
|
||||||
|
|
||||||
|
private readonly FillFlowContainer textContainer;
|
||||||
|
private readonly Container imageContainer;
|
||||||
|
|
||||||
|
public ChangelogSupporterPromo()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
Padding = new MarginPadding
|
||||||
|
{
|
||||||
|
Vertical = 20,
|
||||||
|
Horizontal = 50,
|
||||||
|
};
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Masking = true,
|
||||||
|
CornerRadius = 6,
|
||||||
|
EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Shadow,
|
||||||
|
Colour = Color4.Black.Opacity(0.25f),
|
||||||
|
Offset = new Vector2(0, 1),
|
||||||
|
Radius = 3,
|
||||||
|
},
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.Black.Opacity(0.3f),
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 200,
|
||||||
|
Padding = new MarginPadding { Horizontal = 75 },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
textContainer = new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Padding = new MarginPadding { Right = 50 + image_container_width },
|
||||||
|
},
|
||||||
|
imageContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = image_container_width,
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colour, TextureStore textures)
|
||||||
|
{
|
||||||
|
SupporterPromoLinkFlowContainer supportLinkText;
|
||||||
|
textContainer.Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = ChangelogStrings.SupportHeading,
|
||||||
|
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Light),
|
||||||
|
Margin = new MarginPadding { Bottom = 20 },
|
||||||
|
},
|
||||||
|
supportLinkText = new SupporterPromoLinkFlowContainer(t =>
|
||||||
|
{
|
||||||
|
t.Font = t.Font.With(size: 14);
|
||||||
|
t.Colour = colour.PinkLighter;
|
||||||
|
})
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
},
|
||||||
|
new OsuTextFlowContainer(t =>
|
||||||
|
{
|
||||||
|
t.Font = t.Font.With(size: 12);
|
||||||
|
t.Colour = colour.PinkLighter;
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Text = ChangelogStrings.SupportText2.ToString(),
|
||||||
|
Margin = new MarginPadding { Top = 10 },
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
supportLinkText.AddText("Support further development of osu! and ");
|
||||||
|
supportLinkText.AddLink("become and osu!supporter", "https://osu.ppy.sh/home/support", t => t.Font = t.Font.With(weight: FontWeight.Bold));
|
||||||
|
supportLinkText.AddText(" today!");
|
||||||
|
|
||||||
|
imageContainer.Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Sprite
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
FillMode = FillMode.Fill,
|
||||||
|
Texture = textures.Get(@"Online/supporter-pippi"),
|
||||||
|
},
|
||||||
|
new Sprite
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Width = 75,
|
||||||
|
Height = 75,
|
||||||
|
Margin = new MarginPadding { Top = 70 },
|
||||||
|
Texture = textures.Get(@"Online/supporter-heart"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SupporterPromoLinkFlowContainer : LinkFlowContainer
|
||||||
|
{
|
||||||
|
public SupporterPromoLinkFlowContainer(Action<SpriteText> defaultCreationParameters)
|
||||||
|
: base(defaultCreationParameters)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void AddLink(string text, string url, Action<SpriteText> creationParameters) =>
|
||||||
|
AddInternal(new SupporterPromoLinkCompiler(AddText(text, creationParameters)) { Url = url });
|
||||||
|
|
||||||
|
private class SupporterPromoLinkCompiler : DrawableLinkCompiler
|
||||||
|
{
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
private OsuGame game { get; set; }
|
||||||
|
|
||||||
|
public string Url;
|
||||||
|
|
||||||
|
public SupporterPromoLinkCompiler(IEnumerable<Drawable> parts)
|
||||||
|
: base(parts)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colour)
|
||||||
|
{
|
||||||
|
TooltipText = Url;
|
||||||
|
Action = () => game?.HandleLink(Url);
|
||||||
|
IdleColour = colour.PinkDark;
|
||||||
|
HoverColour = Color4.White;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ namespace osu.Game.Overlays
|
|||||||
public static OverlayColourProvider Green { get; } = new OverlayColourProvider(OverlayColourScheme.Green);
|
public static OverlayColourProvider Green { get; } = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||||
public static OverlayColourProvider Purple { get; } = new OverlayColourProvider(OverlayColourScheme.Purple);
|
public static OverlayColourProvider Purple { get; } = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||||
public static OverlayColourProvider Blue { get; } = new OverlayColourProvider(OverlayColourScheme.Blue);
|
public static OverlayColourProvider Blue { get; } = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||||
|
public static OverlayColourProvider Plum { get; } = new OverlayColourProvider(OverlayColourScheme.Plum);
|
||||||
|
|
||||||
public OverlayColourProvider(OverlayColourScheme colourScheme)
|
public OverlayColourProvider(OverlayColourScheme colourScheme)
|
||||||
{
|
{
|
||||||
@ -80,6 +81,9 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
case OverlayColourScheme.Blue:
|
case OverlayColourScheme.Blue:
|
||||||
return 200 / 360f;
|
return 200 / 360f;
|
||||||
|
|
||||||
|
case OverlayColourScheme.Plum:
|
||||||
|
return 320 / 360f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,6 +96,7 @@ namespace osu.Game.Overlays
|
|||||||
Lime,
|
Lime,
|
||||||
Green,
|
Green,
|
||||||
Purple,
|
Purple,
|
||||||
Blue
|
Blue,
|
||||||
|
Plum,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
comboIndexBindable.BindValueChanged(_ => UpdateComboColour());
|
comboIndexBindable.BindValueChanged(_ => UpdateComboColour());
|
||||||
comboIndexWithOffsetsBindable.BindValueChanged(_ => UpdateComboColour(), true);
|
comboIndexWithOffsetsBindable.BindValueChanged(_ => UpdateComboColour(), true);
|
||||||
|
|
||||||
updateState(ArmedState.Idle, true);
|
// Apply transforms
|
||||||
|
updateState(State.Value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,117 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Online.Rooms;
|
|
||||||
using osu.Game.Online.Rooms.RoomStatuses;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Components
|
|
||||||
{
|
|
||||||
public class RoomStatusInfo : OnlinePlayComposite
|
|
||||||
{
|
|
||||||
public RoomStatusInfo()
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
StatusPart statusPart;
|
|
||||||
EndDatePart endDatePart;
|
|
||||||
|
|
||||||
InternalChild = new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
statusPart = new StatusPart
|
|
||||||
{
|
|
||||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 14)
|
|
||||||
},
|
|
||||||
endDatePart = new EndDatePart { Font = OsuFont.GetFont(size: 14) }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
statusPart.EndDate.BindTo(EndDate);
|
|
||||||
statusPart.Status.BindTo(Status);
|
|
||||||
statusPart.Availability.BindTo(Availability);
|
|
||||||
endDatePart.EndDate.BindTo(EndDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class EndDatePart : DrawableDate
|
|
||||||
{
|
|
||||||
public readonly IBindable<DateTimeOffset?> EndDate = new Bindable<DateTimeOffset?>();
|
|
||||||
|
|
||||||
public EndDatePart()
|
|
||||||
: base(DateTimeOffset.UtcNow)
|
|
||||||
{
|
|
||||||
EndDate.BindValueChanged(date =>
|
|
||||||
{
|
|
||||||
// If null, set a very large future date to prevent unnecessary schedules.
|
|
||||||
Date = date.NewValue ?? DateTimeOffset.Now.AddYears(1);
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override string Format()
|
|
||||||
{
|
|
||||||
if (EndDate.Value == null)
|
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
var diffToNow = Date.Subtract(DateTimeOffset.Now);
|
|
||||||
|
|
||||||
if (diffToNow.TotalSeconds < -5)
|
|
||||||
return $"Closed {base.Format()}";
|
|
||||||
|
|
||||||
if (diffToNow.TotalSeconds < 0)
|
|
||||||
return "Closed";
|
|
||||||
|
|
||||||
if (diffToNow.TotalSeconds < 5)
|
|
||||||
return "Closing soon";
|
|
||||||
|
|
||||||
return $"Closing {base.Format()}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class StatusPart : EndDatePart
|
|
||||||
{
|
|
||||||
public readonly IBindable<RoomStatus> Status = new Bindable<RoomStatus>();
|
|
||||||
public readonly IBindable<RoomAvailability> Availability = new Bindable<RoomAvailability>();
|
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private OsuColour colours { get; set; }
|
|
||||||
|
|
||||||
public StatusPart()
|
|
||||||
{
|
|
||||||
EndDate.BindValueChanged(_ => Format());
|
|
||||||
Status.BindValueChanged(_ => Format());
|
|
||||||
Availability.BindValueChanged(_ => Format());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
Text = Format();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override string Format()
|
|
||||||
{
|
|
||||||
if (!IsLoaded)
|
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
RoomStatus status = Date < DateTimeOffset.Now ? new RoomStatusEnded() : Status.Value ?? new RoomStatusOpen();
|
|
||||||
|
|
||||||
this.FadeColour(status.GetAppropriateColour(colours), 100);
|
|
||||||
return $"{Availability.Value.GetDescription()}, {status.Message}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +1,14 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Screens.Ranking.Expanded;
|
using osu.Game.Screens.Ranking.Expanded;
|
||||||
@ -85,6 +87,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
|||||||
|
|
||||||
minDisplay.Current.Value = minDifficulty;
|
minDisplay.Current.Value = minDifficulty;
|
||||||
maxDisplay.Current.Value = maxDifficulty;
|
maxDisplay.Current.Value = maxDifficulty;
|
||||||
|
maxDisplay.Alpha = Precision.AlmostEquals(Math.Round(minDifficulty.Stars, 2), Math.Round(maxDifficulty.Stars, 2)) ? 0 : 1;
|
||||||
|
|
||||||
minBackground.Colour = colours.ForStarDifficulty(minDifficulty.Stars);
|
minBackground.Colour = colours.ForStarDifficulty(minDifficulty.Stars);
|
||||||
maxBackground.Colour = colours.ForStarDifficulty(maxDifficulty.Stars);
|
maxBackground.Colour = colours.ForStarDifficulty(maxDifficulty.Stars);
|
||||||
|
@ -11,6 +11,7 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
@ -20,7 +21,6 @@ using osu.Framework.Graphics.UserInterface;
|
|||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.Drawables;
|
|
||||||
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;
|
||||||
@ -28,6 +28,7 @@ using osu.Game.Graphics.UserInterface;
|
|||||||
using osu.Game.Graphics.UserInterfaceV2;
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Screens.OnlinePlay.Components;
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -37,21 +38,18 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
public class DrawableRoom : OsuClickableContainer, IStateful<SelectionState>, IFilterable, IHasContextMenu, IHasPopover, IKeyBindingHandler<GlobalAction>
|
public class DrawableRoom : OsuClickableContainer, IStateful<SelectionState>, IFilterable, IHasContextMenu, IHasPopover, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
public const float SELECTION_BORDER_WIDTH = 4;
|
public const float SELECTION_BORDER_WIDTH = 4;
|
||||||
private const float corner_radius = 5;
|
private const float corner_radius = 10;
|
||||||
private const float transition_duration = 60;
|
private const float transition_duration = 60;
|
||||||
private const float content_padding = 10;
|
private const float height = 100;
|
||||||
private const float height = 110;
|
|
||||||
private const float side_strip_width = 5;
|
|
||||||
private const float cover_width = 145;
|
|
||||||
|
|
||||||
public event Action<SelectionState> StateChanged;
|
public event Action<SelectionState> StateChanged;
|
||||||
|
|
||||||
protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds();
|
protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds();
|
||||||
|
|
||||||
private readonly Box selectionBox;
|
private Drawable selectionBox;
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private OnlinePlayScreen parentScreen { get; set; }
|
private LoungeSubScreen loungeScreen { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private BeatmapManager beatmaps { get; set; }
|
private BeatmapManager beatmaps { get; set; }
|
||||||
@ -74,14 +72,18 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
get => state;
|
get => state;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == state) return;
|
if (value == state)
|
||||||
|
return;
|
||||||
|
|
||||||
state = value;
|
state = value;
|
||||||
|
|
||||||
if (state == SelectionState.Selected)
|
if (selectionBox != null)
|
||||||
selectionBox.FadeIn(transition_duration);
|
{
|
||||||
else
|
if (state == SelectionState.Selected)
|
||||||
selectionBox.FadeOut(transition_duration);
|
selectionBox.FadeIn(transition_duration);
|
||||||
|
else
|
||||||
|
selectionBox.FadeOut(transition_duration);
|
||||||
|
}
|
||||||
|
|
||||||
StateChanged?.Invoke(State);
|
StateChanged?.Invoke(State);
|
||||||
}
|
}
|
||||||
@ -108,6 +110,25 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int numberOfAvatars = 7;
|
||||||
|
|
||||||
|
public int NumberOfAvatars
|
||||||
|
{
|
||||||
|
get => numberOfAvatars;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
numberOfAvatars = value;
|
||||||
|
|
||||||
|
if (recentParticipantsList != null)
|
||||||
|
recentParticipantsList.NumberOfCircles = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Bindable<RoomCategory> roomCategory = new Bindable<RoomCategory>();
|
||||||
|
|
||||||
|
private RecentParticipantsList recentParticipantsList;
|
||||||
|
private RoomSpecialCategoryPill specialCategoryPill;
|
||||||
|
|
||||||
public bool FilteringActive { get; set; }
|
public bool FilteringActive { get; set; }
|
||||||
|
|
||||||
private PasswordProtectedIcon passwordIcon;
|
private PasswordProtectedIcon passwordIcon;
|
||||||
@ -119,114 +140,208 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
Room = room;
|
Room = room;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Height = height + SELECTION_BORDER_WIDTH * 2;
|
Height = height;
|
||||||
CornerRadius = corner_radius + SELECTION_BORDER_WIDTH / 2;
|
|
||||||
Masking = true;
|
|
||||||
|
|
||||||
// create selectionBox here so State can be set before being loaded
|
Masking = true;
|
||||||
selectionBox = new Box
|
CornerRadius = corner_radius + SELECTION_BORDER_WIDTH / 2;
|
||||||
|
EdgeEffect = new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
Type = EdgeEffectType.Shadow,
|
||||||
Alpha = 0f,
|
Colour = Color4.Black.Opacity(40),
|
||||||
|
Radius = 5,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours, AudioManager audio)
|
private void load(OverlayColourProvider colours, AudioManager audio)
|
||||||
{
|
{
|
||||||
float stripWidth = side_strip_width * (Room.Category.Value == RoomCategory.Spotlight ? 2 : 1);
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new StatusColouredContainer(transition_duration)
|
// This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites.
|
||||||
|
new BufferedContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = selectionBox
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colours.Background5,
|
||||||
|
},
|
||||||
|
new OnlinePlayBackgroundSprite
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
|
Name = @"Room content",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding(SELECTION_BORDER_WIDTH),
|
// This negative padding resolves 1px gaps between this background and the background above.
|
||||||
|
Padding = new MarginPadding { Left = 20, Vertical = -0.5f },
|
||||||
Child = new Container
|
Child = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
CornerRadius = corner_radius,
|
CornerRadius = corner_radius,
|
||||||
EdgeEffect = new EdgeEffectParameters
|
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Shadow,
|
|
||||||
Colour = Color4.Black.Opacity(40),
|
|
||||||
Radius = 5,
|
|
||||||
},
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
// This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites.
|
||||||
|
new BufferedContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4Extensions.FromHex(@"212121"),
|
Children = new Drawable[]
|
||||||
},
|
{
|
||||||
new StatusColouredContainer(transition_duration)
|
new GridContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Width = stripWidth,
|
ColumnDimensions = new[]
|
||||||
Child = new Box { RelativeSizeAxes = Axes.Both }
|
{
|
||||||
},
|
new Dimension(GridSizeMode.Relative, 0.2f)
|
||||||
new Container
|
},
|
||||||
{
|
Content = new[]
|
||||||
RelativeSizeAxes = Axes.Y,
|
{
|
||||||
Width = cover_width,
|
new Drawable[]
|
||||||
Masking = true,
|
{
|
||||||
Margin = new MarginPadding { Left = stripWidth },
|
new Box
|
||||||
Child = new OnlinePlayBackgroundSprite(BeatmapSetCoverType.List) { RelativeSizeAxes = Axes.Both }
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colours.Background5,
|
||||||
|
},
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = ColourInfo.GradientHorizontal(colours.Background5, colours.Background5.Opacity(0.3f))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
|
Name = @"Left details",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding
|
Padding = new MarginPadding
|
||||||
{
|
{
|
||||||
Vertical = content_padding,
|
Left = 20,
|
||||||
Left = stripWidth + cover_width + content_padding,
|
Vertical = 5
|
||||||
Right = content_padding,
|
|
||||||
},
|
},
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
AutoSizeAxes = Axes.Both,
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(5f),
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new RoomName { Font = OsuFont.GetFont(size: 18) },
|
new FillFlowContainer
|
||||||
new ParticipantInfo(),
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(5),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new RoomStatusPill
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft
|
||||||
|
},
|
||||||
|
specialCategoryPill = new RoomSpecialCategoryPill
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft
|
||||||
|
},
|
||||||
|
new EndDateInfo
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding { Top = 3 },
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new RoomNameText(),
|
||||||
|
new RoomHostText(),
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
Origin = Anchor.BottomLeft,
|
Origin = Anchor.BottomLeft,
|
||||||
RelativeSizeAxes = Axes.X,
|
AutoSizeAxes = Axes.Both,
|
||||||
AutoSizeAxes = Axes.Y,
|
Direction = FillDirection.Horizontal,
|
||||||
Direction = FillDirection.Vertical,
|
Spacing = new Vector2(5),
|
||||||
Spacing = new Vector2(0, 5),
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new RoomStatusInfo(),
|
new PlaylistCountPill
|
||||||
new BeatmapTitle { TextSize = 14 },
|
{
|
||||||
},
|
Anchor = Anchor.CentreLeft,
|
||||||
},
|
Origin = Anchor.CentreLeft,
|
||||||
new ModeTypeInfo
|
},
|
||||||
{
|
new StarRatingRangeDisplay
|
||||||
Anchor = Anchor.BottomRight,
|
{
|
||||||
Origin = Anchor.BottomRight,
|
Anchor = Anchor.CentreLeft,
|
||||||
},
|
Origin = Anchor.CentreLeft,
|
||||||
|
Scale = new Vector2(0.8f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Name = "Right content",
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Padding = new MarginPadding
|
||||||
|
{
|
||||||
|
Right = 10,
|
||||||
|
Vertical = 5
|
||||||
},
|
},
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
recentParticipantsList = new RecentParticipantsList
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
NumberOfCircles = NumberOfAvatars
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
passwordIcon = new PasswordProtectedIcon { Alpha = 0 }
|
passwordIcon = new PasswordProtectedIcon { Alpha = 0 }
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
new StatusColouredContainer(transition_duration)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Child = selectionBox = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = state == SelectionState.Selected ? 1 : 0,
|
||||||
|
Masking = true,
|
||||||
|
CornerRadius = corner_radius,
|
||||||
|
BorderThickness = SELECTION_BORDER_WIDTH,
|
||||||
|
BorderColour = Color4.White,
|
||||||
|
Child = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
AlwaysPresent = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
sampleSelect = audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select");
|
sampleSelect = audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select");
|
||||||
@ -250,6 +365,15 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
else
|
else
|
||||||
Alpha = 0;
|
Alpha = 0;
|
||||||
|
|
||||||
|
roomCategory.BindTo(Room.Category);
|
||||||
|
roomCategory.BindValueChanged(c =>
|
||||||
|
{
|
||||||
|
if (c.NewValue == RoomCategory.Spotlight)
|
||||||
|
specialCategoryPill.Show();
|
||||||
|
else
|
||||||
|
specialCategoryPill.Hide();
|
||||||
|
}, true);
|
||||||
|
|
||||||
hasPassword.BindTo(Room.HasPassword);
|
hasPassword.BindTo(Room.HasPassword);
|
||||||
hasPassword.BindValueChanged(v => passwordIcon.Alpha = v.NewValue ? 1 : 0, true);
|
hasPassword.BindValueChanged(v => passwordIcon.Alpha = v.NewValue ? 1 : 0, true);
|
||||||
}
|
}
|
||||||
@ -260,7 +384,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
{
|
{
|
||||||
new OsuMenuItem("Create copy", MenuItemType.Standard, () =>
|
new OsuMenuItem("Create copy", MenuItemType.Standard, () =>
|
||||||
{
|
{
|
||||||
parentScreen?.OpenNewRoom(Room.DeepClone());
|
lounge?.Open(Room.DeepClone());
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -307,11 +431,16 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
return base.OnClick(e);
|
return base.OnClick(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class RoomName : OsuSpriteText
|
private class RoomNameText : OsuSpriteText
|
||||||
{
|
{
|
||||||
[Resolved(typeof(Room), nameof(Online.Rooms.Room.Name))]
|
[Resolved(typeof(Room), nameof(Online.Rooms.Room.Name))]
|
||||||
private Bindable<string> name { get; set; }
|
private Bindable<string> name { get; set; }
|
||||||
|
|
||||||
|
public RoomNameText()
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 28);
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
@ -319,6 +448,41 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class RoomHostText : OnlinePlayComposite
|
||||||
|
{
|
||||||
|
private LinkFlowContainer hostText;
|
||||||
|
|
||||||
|
public RoomHostText()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
InternalChild = hostText = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 16))
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Host.BindValueChanged(host =>
|
||||||
|
{
|
||||||
|
hostText.Clear();
|
||||||
|
|
||||||
|
if (host.NewValue != null)
|
||||||
|
{
|
||||||
|
hostText.AddText("hosted by ");
|
||||||
|
hostText.AddUserLink(host.NewValue);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class PasswordProtectedIcon : CompositeDrawable
|
public class PasswordProtectedIcon : CompositeDrawable
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -366,7 +530,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
private OsuPasswordTextBox passwordTextbox;
|
private OsuPasswordTextBox passwordTextbox;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load()
|
||||||
{
|
{
|
||||||
Child = new FillFlowContainer
|
Child = new FillFlowContainer
|
||||||
{
|
{
|
||||||
|
65
osu.Game/Screens/OnlinePlay/Lounge/Components/EndDateInfo.cs
Normal file
65
osu.Game/Screens/OnlinePlay/Lounge/Components/EndDateInfo.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||||
|
{
|
||||||
|
public class EndDateInfo : OnlinePlayComposite
|
||||||
|
{
|
||||||
|
public EndDateInfo()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
InternalChild = new EndDatePart
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 12),
|
||||||
|
EndDate = { BindTarget = EndDate }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private class EndDatePart : DrawableDate
|
||||||
|
{
|
||||||
|
public readonly IBindable<DateTimeOffset?> EndDate = new Bindable<DateTimeOffset?>();
|
||||||
|
|
||||||
|
public EndDatePart()
|
||||||
|
: base(DateTimeOffset.UtcNow)
|
||||||
|
{
|
||||||
|
EndDate.BindValueChanged(date =>
|
||||||
|
{
|
||||||
|
// If null, set a very large future date to prevent unnecessary schedules.
|
||||||
|
Date = date.NewValue ?? DateTimeOffset.Now.AddYears(1);
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string Format()
|
||||||
|
{
|
||||||
|
if (EndDate.Value == null)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var diffToNow = Date.Subtract(DateTimeOffset.Now);
|
||||||
|
|
||||||
|
if (diffToNow.TotalSeconds < -5)
|
||||||
|
return $"Closed {base.Format()}";
|
||||||
|
|
||||||
|
if (diffToNow.TotalSeconds < 0)
|
||||||
|
return "Closed";
|
||||||
|
|
||||||
|
if (diffToNow.TotalSeconds < 5)
|
||||||
|
return "Closing soon";
|
||||||
|
|
||||||
|
return $"Closing {base.Format()}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,19 +5,18 @@ 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.UserInterface;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osuTK.Graphics;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||||
{
|
{
|
||||||
public abstract class FilterControl : CompositeDrawable
|
public abstract class FilterControl : CompositeDrawable
|
||||||
{
|
{
|
||||||
protected const float VERTICAL_PADDING = 10;
|
protected readonly FillFlowContainer Filters;
|
||||||
protected const float HORIZONTAL_PADDING = 80;
|
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private Bindable<FilterCriteria> filter { get; set; }
|
private Bindable<FilterCriteria> filter { get; set; }
|
||||||
@ -25,60 +24,51 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IBindable<RulesetInfo> ruleset { get; set; }
|
private IBindable<RulesetInfo> ruleset { get; set; }
|
||||||
|
|
||||||
private readonly Box tabStrip;
|
|
||||||
private readonly SearchTextBox search;
|
private readonly SearchTextBox search;
|
||||||
private readonly PageTabControl<RoomStatusFilter> tabs;
|
private readonly Dropdown<RoomStatusFilter> statusDropdown;
|
||||||
|
|
||||||
protected FilterControl()
|
protected FilterControl()
|
||||||
{
|
{
|
||||||
InternalChildren = new Drawable[]
|
RelativeSizeAxes = Axes.X;
|
||||||
|
Height = 70;
|
||||||
|
|
||||||
|
InternalChild = new FillFlowContainer
|
||||||
{
|
{
|
||||||
new Box
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(10),
|
||||||
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
search = new FilterSearchTextBox
|
||||||
Colour = Color4.Black,
|
|
||||||
Alpha = 0.25f,
|
|
||||||
},
|
|
||||||
tabStrip = new Box
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 1,
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Padding = new MarginPadding
|
|
||||||
{
|
{
|
||||||
Top = VERTICAL_PADDING,
|
Anchor = Anchor.TopRight,
|
||||||
Horizontal = HORIZONTAL_PADDING
|
Origin = Anchor.TopRight,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Width = 0.6f,
|
||||||
},
|
},
|
||||||
Children = new Drawable[]
|
Filters = new FillFlowContainer
|
||||||
{
|
{
|
||||||
search = new FilterSearchTextBox
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(10),
|
||||||
|
Child = statusDropdown = new SlimEnumDropdown<RoomStatusFilter>
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
Anchor = Anchor.TopRight,
|
||||||
},
|
Origin = Anchor.TopRight,
|
||||||
tabs = new PageTabControl<RoomStatusFilter>
|
RelativeSizeAxes = Axes.None,
|
||||||
{
|
Width = 160,
|
||||||
Anchor = Anchor.BottomLeft,
|
}
|
||||||
Origin = Anchor.BottomLeft,
|
},
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
tabs.Current.Value = RoomStatusFilter.Open;
|
|
||||||
tabs.Current.TriggerChange();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
filter ??= new Bindable<FilterCriteria>();
|
filter ??= new Bindable<FilterCriteria>();
|
||||||
tabStrip.Colour = colours.Yellow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -87,7 +77,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
|
|
||||||
search.Current.BindValueChanged(_ => updateFilterDebounced());
|
search.Current.BindValueChanged(_ => updateFilterDebounced());
|
||||||
ruleset.BindValueChanged(_ => UpdateFilter());
|
ruleset.BindValueChanged(_ => UpdateFilter());
|
||||||
tabs.Current.BindValueChanged(_ => UpdateFilter(), true);
|
statusDropdown.Current.BindValueChanged(_ => UpdateFilter(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScheduledDelegate scheduledFilterUpdate;
|
private ScheduledDelegate scheduledFilterUpdate;
|
||||||
@ -106,7 +96,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
|
|
||||||
var criteria = CreateCriteria();
|
var criteria = CreateCriteria();
|
||||||
criteria.SearchString = search.Current.Value;
|
criteria.SearchString = search.Current.Value;
|
||||||
criteria.Status = tabs.Current.Value;
|
criteria.Status = statusDropdown.Current.Value;
|
||||||
criteria.Ruleset = ruleset.Value;
|
criteria.Ruleset = ruleset.Value;
|
||||||
|
|
||||||
filter.Value = criteria;
|
filter.Value = criteria;
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using Humanizer;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Containers;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using osu.Game.Users.Drawables;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|
||||||
{
|
|
||||||
public class ParticipantInfo : OnlinePlayComposite
|
|
||||||
{
|
|
||||||
public ParticipantInfo()
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X;
|
|
||||||
Height = 15f;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
OsuSpriteText summary;
|
|
||||||
Container flagContainer;
|
|
||||||
LinkFlowContainer hostText;
|
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
|
||||||
{
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.X,
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Spacing = new Vector2(5f, 0f),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
flagContainer = new Container
|
|
||||||
{
|
|
||||||
Width = 22f,
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
},
|
|
||||||
hostText = new LinkFlowContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
AutoSizeAxes = Axes.Both
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreRight,
|
|
||||||
Origin = Anchor.CentreRight,
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Colour = colours.Gray9,
|
|
||||||
Children = new[]
|
|
||||||
{
|
|
||||||
summary = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Text = "0 participants",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Host.BindValueChanged(host =>
|
|
||||||
{
|
|
||||||
hostText.Clear();
|
|
||||||
flagContainer.Clear();
|
|
||||||
|
|
||||||
if (host.NewValue != null)
|
|
||||||
{
|
|
||||||
hostText.AddText("hosted by ");
|
|
||||||
hostText.AddUserLink(host.NewValue, s => s.Font = s.Font.With(Typeface.Torus, weight: FontWeight.Bold, italics: true));
|
|
||||||
|
|
||||||
flagContainer.Child = new UpdateableFlag(host.NewValue.Country) { RelativeSizeAxes = Axes.Both };
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
ParticipantCount.BindValueChanged(count => summary.Text = "participant".ToQuantity(count.NewValue), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Displays contents in a "pill".
|
||||||
|
/// </summary>
|
||||||
|
public class PillContainer : Container
|
||||||
|
{
|
||||||
|
private const float padding = 8;
|
||||||
|
|
||||||
|
public readonly Drawable Background;
|
||||||
|
|
||||||
|
protected override Container<Drawable> Content => content;
|
||||||
|
private readonly Container content;
|
||||||
|
|
||||||
|
public PillContainer()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.X;
|
||||||
|
Height = 16;
|
||||||
|
|
||||||
|
InternalChild = new CircularContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Masking = true,
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
Background = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.Black,
|
||||||
|
Alpha = 0.5f
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding { Horizontal = padding },
|
||||||
|
Child = new GridContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
ColumnDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(GridSizeMode.AutoSize, minSize: 80 - 2 * padding)
|
||||||
|
},
|
||||||
|
Content = new[]
|
||||||
|
{
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Padding = new MarginPadding { Bottom = 2 },
|
||||||
|
Child = content = new Container
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using Humanizer;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A pill that displays the playlist item count.
|
||||||
|
/// </summary>
|
||||||
|
public class PlaylistCountPill : OnlinePlayComposite
|
||||||
|
{
|
||||||
|
private OsuTextFlowContainer count;
|
||||||
|
|
||||||
|
public PlaylistCountPill()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
InternalChild = new PillContainer
|
||||||
|
{
|
||||||
|
Child = count = new OsuTextFlowContainer(s => s.Font = OsuFont.GetFont(size: 12))
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Playlist.BindCollectionChanged(updateCount, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateCount(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
count.Clear();
|
||||||
|
count.AddText(Playlist.Count.ToString(), s => s.Font = s.Font.With(weight: FontWeight.Bold));
|
||||||
|
count.AddText(" ");
|
||||||
|
count.AddText("Beatmap".ToQuantity(Playlist.Count, ShowQuantityAs.None));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,18 +9,16 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
{
|
{
|
||||||
public class PlaylistsFilterControl : FilterControl
|
public class PlaylistsFilterControl : FilterControl
|
||||||
{
|
{
|
||||||
private readonly Dropdown<PlaylistsCategory> dropdown;
|
private readonly Dropdown<PlaylistsCategory> categoryDropdown;
|
||||||
|
|
||||||
public PlaylistsFilterControl()
|
public PlaylistsFilterControl()
|
||||||
{
|
{
|
||||||
AddInternal(dropdown = new SlimEnumDropdown<PlaylistsCategory>
|
Filters.Add(categoryDropdown = new SlimEnumDropdown<PlaylistsCategory>
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
RelativeSizeAxes = Axes.None,
|
RelativeSizeAxes = Axes.None,
|
||||||
Width = 160,
|
Width = 160,
|
||||||
X = -HORIZONTAL_PADDING,
|
|
||||||
Y = -30
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,14 +26,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
dropdown.Current.BindValueChanged(_ => UpdateFilter());
|
categoryDropdown.Current.BindValueChanged(_ => UpdateFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override FilterCriteria CreateCriteria()
|
protected override FilterCriteria CreateCriteria()
|
||||||
{
|
{
|
||||||
var criteria = base.CreateCriteria();
|
var criteria = base.CreateCriteria();
|
||||||
|
|
||||||
switch (dropdown.Current.Value)
|
switch (categoryDropdown.Current.Value)
|
||||||
{
|
{
|
||||||
case PlaylistsCategory.Normal:
|
case PlaylistsCategory.Normal:
|
||||||
criteria.Category = "normal";
|
criteria.Category = "normal";
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
// 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 osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||||
|
{
|
||||||
|
public class RankRangePill : MultiplayerRoomComposite
|
||||||
|
{
|
||||||
|
private OsuTextFlowContainer rankFlow;
|
||||||
|
|
||||||
|
public RankRangePill()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
InternalChild = new PillContainer
|
||||||
|
{
|
||||||
|
Child = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Spacing = new Vector2(4),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new SpriteIcon
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Size = new Vector2(8),
|
||||||
|
Icon = FontAwesome.Solid.User
|
||||||
|
},
|
||||||
|
rankFlow = new OsuTextFlowContainer(s => s.Font = OsuFont.GetFont(size: 12))
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnRoomUpdated()
|
||||||
|
{
|
||||||
|
base.OnRoomUpdated();
|
||||||
|
|
||||||
|
rankFlow.Clear();
|
||||||
|
|
||||||
|
if (Room == null || Room.Users.All(u => u.User == null))
|
||||||
|
{
|
||||||
|
rankFlow.AddText("-");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minRank = Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Min();
|
||||||
|
int maxRank = Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Max();
|
||||||
|
|
||||||
|
rankFlow.AddText("#");
|
||||||
|
rankFlow.AddText(minRank.ToString("#,0"), s => s.Font = s.Font.With(weight: FontWeight.Bold));
|
||||||
|
|
||||||
|
rankFlow.AddText(" - ");
|
||||||
|
|
||||||
|
rankFlow.AddText("#");
|
||||||
|
rankFlow.AddText(maxRank.ToString("#,0"), s => s.Font = s.Font.With(weight: FontWeight.Bold));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,278 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osu.Game.Users.Drawables;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||||
|
{
|
||||||
|
public class RecentParticipantsList : OnlinePlayComposite
|
||||||
|
{
|
||||||
|
private const float avatar_size = 36;
|
||||||
|
|
||||||
|
private FillFlowContainer<CircularAvatar> avatarFlow;
|
||||||
|
|
||||||
|
private HiddenUserCount hiddenUsers;
|
||||||
|
private OsuSpriteText totalCount;
|
||||||
|
|
||||||
|
public RecentParticipantsList()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.X;
|
||||||
|
Height = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OverlayColourProvider colours)
|
||||||
|
{
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
CornerRadius = 10,
|
||||||
|
Shear = new Vector2(0.2f, 0),
|
||||||
|
Child = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colours.Background4,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(4),
|
||||||
|
Padding = new MarginPadding { Right = 16 },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new SpriteIcon
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Size = new Vector2(16),
|
||||||
|
Margin = new MarginPadding { Left = 8 },
|
||||||
|
Icon = FontAwesome.Solid.User,
|
||||||
|
},
|
||||||
|
totalCount = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.Default.With(weight: FontWeight.Bold),
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
},
|
||||||
|
avatarFlow = new FillFlowContainer<CircularAvatar>
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(4),
|
||||||
|
Margin = new MarginPadding { Left = 4 },
|
||||||
|
},
|
||||||
|
hiddenUsers = new HiddenUserCount
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
RecentParticipants.BindCollectionChanged(onParticipantsChanged, true);
|
||||||
|
ParticipantCount.BindValueChanged(_ =>
|
||||||
|
{
|
||||||
|
updateHiddenUsers();
|
||||||
|
totalCount.Text = ParticipantCount.Value.ToString();
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int numberOfCircles = 4;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum number of circles visible (including the "hidden count" circle in the overflow case).
|
||||||
|
/// </summary>
|
||||||
|
public int NumberOfCircles
|
||||||
|
{
|
||||||
|
get => numberOfCircles;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
numberOfCircles = value;
|
||||||
|
|
||||||
|
if (LoadState < LoadState.Loaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Reinitialising the list looks janky, but this is unlikely to be used in a setting where it's visible.
|
||||||
|
clearUsers();
|
||||||
|
foreach (var u in RecentParticipants)
|
||||||
|
addUser(u);
|
||||||
|
|
||||||
|
updateHiddenUsers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onParticipantsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
switch (e.Action)
|
||||||
|
{
|
||||||
|
case NotifyCollectionChangedAction.Add:
|
||||||
|
foreach (var added in e.NewItems.OfType<User>())
|
||||||
|
addUser(added);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotifyCollectionChangedAction.Remove:
|
||||||
|
foreach (var removed in e.OldItems.OfType<User>())
|
||||||
|
removeUser(removed);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotifyCollectionChangedAction.Reset:
|
||||||
|
clearUsers();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotifyCollectionChangedAction.Replace:
|
||||||
|
case NotifyCollectionChangedAction.Move:
|
||||||
|
// Easiest is to just reinitialise the whole list. These are unlikely to ever be use cases.
|
||||||
|
clearUsers();
|
||||||
|
foreach (var u in RecentParticipants)
|
||||||
|
addUser(u);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHiddenUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int displayedCircles => avatarFlow.Count + (hiddenUsers.Count > 0 ? 1 : 0);
|
||||||
|
|
||||||
|
private void addUser(User user)
|
||||||
|
{
|
||||||
|
if (displayedCircles < NumberOfCircles)
|
||||||
|
avatarFlow.Add(new CircularAvatar { User = user });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeUser(User user)
|
||||||
|
{
|
||||||
|
avatarFlow.RemoveAll(a => a.User == user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearUsers()
|
||||||
|
{
|
||||||
|
avatarFlow.Clear();
|
||||||
|
updateHiddenUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateHiddenUsers()
|
||||||
|
{
|
||||||
|
int hiddenCount = 0;
|
||||||
|
if (RecentParticipants.Count > NumberOfCircles)
|
||||||
|
hiddenCount = ParticipantCount.Value - NumberOfCircles + 1;
|
||||||
|
|
||||||
|
hiddenUsers.Count = hiddenCount;
|
||||||
|
|
||||||
|
if (displayedCircles > NumberOfCircles)
|
||||||
|
avatarFlow.Remove(avatarFlow.Last());
|
||||||
|
else if (displayedCircles < NumberOfCircles)
|
||||||
|
{
|
||||||
|
var nextUser = RecentParticipants.FirstOrDefault(u => avatarFlow.All(a => a.User != u));
|
||||||
|
if (nextUser != null) addUser(nextUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CircularAvatar : CompositeDrawable
|
||||||
|
{
|
||||||
|
public User User
|
||||||
|
{
|
||||||
|
get => avatar.User;
|
||||||
|
set => avatar.User = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly UpdateableAvatar avatar = new UpdateableAvatar(showUsernameTooltip: true) { RelativeSizeAxes = Axes.Both };
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OverlayColourProvider colours)
|
||||||
|
{
|
||||||
|
Size = new Vector2(avatar_size);
|
||||||
|
|
||||||
|
InternalChild = new CircularContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Colour = colours.Background5,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
avatar
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HiddenUserCount : CompositeDrawable
|
||||||
|
{
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get => count;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
count = value;
|
||||||
|
countText.Text = $"+{count}";
|
||||||
|
|
||||||
|
if (count > 0)
|
||||||
|
Show();
|
||||||
|
else
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int count;
|
||||||
|
|
||||||
|
private readonly SpriteText countText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Font = OsuFont.Default.With(weight: FontWeight.Bold),
|
||||||
|
};
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OverlayColourProvider colours)
|
||||||
|
{
|
||||||
|
Size = new Vector2(avatar_size);
|
||||||
|
Alpha = 0;
|
||||||
|
|
||||||
|
InternalChild = new CircularContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colours.Background5,
|
||||||
|
},
|
||||||
|
countText
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,86 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Containers;
|
|
||||||
using osu.Game.Screens.OnlinePlay.Components;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|
||||||
{
|
|
||||||
public class RoomInfo : OnlinePlayComposite
|
|
||||||
{
|
|
||||||
private readonly List<Drawable> statusElements = new List<Drawable>();
|
|
||||||
private readonly OsuTextFlowContainer roomName;
|
|
||||||
|
|
||||||
public RoomInfo()
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Y;
|
|
||||||
|
|
||||||
RoomLocalUserInfo localUserInfo;
|
|
||||||
RoomStatusInfo statusInfo;
|
|
||||||
ModeTypeInfo typeInfo;
|
|
||||||
ParticipantInfo participantInfo;
|
|
||||||
|
|
||||||
InternalChild = new FillFlowContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Spacing = new Vector2(0, 10),
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
roomName = new OsuTextFlowContainer(t => t.Font = OsuFont.GetFont(size: 30))
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
},
|
|
||||||
participantInfo = new ParticipantInfo(),
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
statusInfo = new RoomStatusInfo(),
|
|
||||||
typeInfo = new ModeTypeInfo
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomRight,
|
|
||||||
Origin = Anchor.BottomRight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
localUserInfo = new RoomLocalUserInfo(),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
statusElements.AddRange(new Drawable[]
|
|
||||||
{
|
|
||||||
statusInfo, typeInfo, participantInfo, localUserInfo
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
if (RoomID.Value == null)
|
|
||||||
statusElements.ForEach(e => e.FadeOut());
|
|
||||||
RoomID.BindValueChanged(id =>
|
|
||||||
{
|
|
||||||
if (id.NewValue == null)
|
|
||||||
statusElements.ForEach(e => e.FadeOut(100));
|
|
||||||
else
|
|
||||||
statusElements.ForEach(e => e.FadeIn(100));
|
|
||||||
}, true);
|
|
||||||
RoomName.BindValueChanged(name =>
|
|
||||||
{
|
|
||||||
roomName.Text = name.NewValue ?? "No room selected";
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,91 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Screens.OnlinePlay.Components;
|
|
||||||
using osuTK.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|
||||||
{
|
|
||||||
public class RoomInspector : OnlinePlayComposite
|
|
||||||
{
|
|
||||||
private const float transition_duration = 100;
|
|
||||||
|
|
||||||
private readonly MarginPadding contentPadding = new MarginPadding { Horizontal = 20, Vertical = 10 };
|
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private BeatmapManager beatmaps { get; set; }
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
OverlinedHeader participantsHeader;
|
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = Color4.Black,
|
|
||||||
Alpha = 0.25f
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Padding = new MarginPadding { Horizontal = 30 },
|
|
||||||
Child = new GridContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Content = new[]
|
|
||||||
{
|
|
||||||
new Drawable[]
|
|
||||||
{
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new RoomInfo
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Margin = new MarginPadding { Vertical = 60 },
|
|
||||||
},
|
|
||||||
participantsHeader = new OverlinedHeader("Recent Participants"),
|
|
||||||
new ParticipantsDisplay(Direction.Vertical)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = ParticipantsList.TILE_SIZE * 3,
|
|
||||||
Details = { BindTarget = participantsHeader.Details }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new Drawable[] { new OverlinedPlaylistHeader(), },
|
|
||||||
new Drawable[]
|
|
||||||
{
|
|
||||||
new DrawableRoomPlaylist(false, false)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Items = { BindTarget = Playlist }
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
RowDimensions = new[]
|
|
||||||
{
|
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
|
||||||
new Dimension(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,49 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||||
|
{
|
||||||
|
public class RoomSpecialCategoryPill : OnlinePlayComposite
|
||||||
|
{
|
||||||
|
private SpriteText text;
|
||||||
|
|
||||||
|
public RoomSpecialCategoryPill()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
InternalChild = new PillContainer
|
||||||
|
{
|
||||||
|
Background =
|
||||||
|
{
|
||||||
|
Colour = colours.Pink,
|
||||||
|
Alpha = 1
|
||||||
|
},
|
||||||
|
Child = text = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 12),
|
||||||
|
Colour = Color4.Black
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Category.BindValueChanged(c => text.Text = c.NewValue.ToString(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Online.Rooms;
|
||||||
|
using osu.Game.Online.Rooms.RoomStatuses;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A pill that displays the room's current status.
|
||||||
|
/// </summary>
|
||||||
|
public class RoomStatusPill : OnlinePlayComposite
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private OsuColour colours { get; set; }
|
||||||
|
|
||||||
|
private PillContainer pill;
|
||||||
|
private SpriteText statusText;
|
||||||
|
|
||||||
|
public RoomStatusPill()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
InternalChild = pill = new PillContainer
|
||||||
|
{
|
||||||
|
Child = statusText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 12),
|
||||||
|
Colour = Color4.Black
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
EndDate.BindValueChanged(_ => updateDisplay());
|
||||||
|
Status.BindValueChanged(_ => updateDisplay(), true);
|
||||||
|
|
||||||
|
FinishTransforms(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDisplay()
|
||||||
|
{
|
||||||
|
RoomStatus status = getDisplayStatus();
|
||||||
|
|
||||||
|
pill.Background.Alpha = 1;
|
||||||
|
pill.Background.FadeColour(status.GetAppropriateColour(colours), 100);
|
||||||
|
statusText.Text = status.Message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RoomStatus getDisplayStatus()
|
||||||
|
{
|
||||||
|
if (EndDate.Value < DateTimeOffset.Now)
|
||||||
|
return new RoomStatusEnded();
|
||||||
|
|
||||||
|
return Status.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -50,6 +50,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
|
// account for the fact we are in a scroll container and want a bit of spacing from the scroll bar.
|
||||||
|
Padding = new MarginPadding { Right = 5 };
|
||||||
|
|
||||||
InternalChild = new OsuContextMenuContainer
|
InternalChild = new OsuContextMenuContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
@ -59,7 +62,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(2),
|
Spacing = new Vector2(10),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
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.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
@ -18,6 +19,8 @@ using osu.Game.Overlays;
|
|||||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||||
using osu.Game.Screens.OnlinePlay.Match;
|
using osu.Game.Screens.OnlinePlay.Match;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Lounge
|
namespace osu.Game.Screens.OnlinePlay.Lounge
|
||||||
{
|
{
|
||||||
@ -28,11 +31,17 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
|
|
||||||
protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby();
|
protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby();
|
||||||
|
|
||||||
|
protected Container<OsuButton> Buttons { get; } = new Container<OsuButton>
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
AutoSizeAxes = Axes.Both
|
||||||
|
};
|
||||||
|
|
||||||
private readonly IBindable<bool> initialRoomsReceived = new Bindable<bool>();
|
private readonly IBindable<bool> initialRoomsReceived = new Bindable<bool>();
|
||||||
private readonly IBindable<bool> operationInProgress = new Bindable<bool>();
|
private readonly IBindable<bool> operationInProgress = new Bindable<bool>();
|
||||||
|
|
||||||
private FilterControl filter;
|
private FilterControl filter;
|
||||||
private Container content;
|
|
||||||
private LoadingLayer loadingLayer;
|
private LoadingLayer loadingLayer;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -56,41 +65,71 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
content = new Container
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 100,
|
||||||
|
Colour = Color4.Black,
|
||||||
|
Alpha = 0.5f,
|
||||||
|
},
|
||||||
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Padding = new MarginPadding
|
||||||
{
|
{
|
||||||
new Container
|
Top = 20,
|
||||||
|
Left = WaveOverlayContainer.WIDTH_PADDING,
|
||||||
|
Right = WaveOverlayContainer.WIDTH_PADDING,
|
||||||
|
},
|
||||||
|
Child = new GridContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
RowDimensions = new[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
Width = 0.55f,
|
new Dimension(GridSizeMode.Absolute, 20)
|
||||||
Children = new Drawable[]
|
},
|
||||||
|
Content = new[]
|
||||||
|
{
|
||||||
|
new Drawable[]
|
||||||
{
|
{
|
||||||
scrollContainer = new OsuScrollContainer
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 70,
|
||||||
|
Depth = -1,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
filter = CreateFilterControl(),
|
||||||
|
Buttons.WithChild(CreateNewRoomButton().With(d =>
|
||||||
|
{
|
||||||
|
d.Size = new Vector2(150, 25);
|
||||||
|
d.Action = () => Open();
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
ScrollbarOverlapsContent = false,
|
Children = new Drawable[]
|
||||||
Padding = new MarginPadding(10),
|
{
|
||||||
Child = roomsContainer = new RoomsContainer()
|
scrollContainer = new OsuScrollContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
ScrollbarOverlapsContent = false,
|
||||||
|
Child = roomsContainer = new RoomsContainer()
|
||||||
|
},
|
||||||
|
loadingLayer = new LoadingLayer(true),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
loadingLayer = new LoadingLayer(true),
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
new RoomInspector
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopRight,
|
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Width = 0.45f,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
filter = CreateFilterControl().With(d =>
|
|
||||||
{
|
|
||||||
d.RelativeSizeAxes = Axes.X;
|
|
||||||
d.Height = 80;
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// scroll selected room into view on selection.
|
// scroll selected room into view on selection.
|
||||||
@ -116,18 +155,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateAfterChildren()
|
|
||||||
{
|
|
||||||
base.UpdateAfterChildren();
|
|
||||||
|
|
||||||
content.Padding = new MarginPadding
|
|
||||||
{
|
|
||||||
Top = filter.DrawHeight,
|
|
||||||
Left = WaveOverlayContainer.WIDTH_PADDING - DrawableRoom.SELECTION_BORDER_WIDTH + HORIZONTAL_OVERFLOW_PADDING,
|
|
||||||
Right = WaveOverlayContainer.WIDTH_PADDING + HORIZONTAL_OVERFLOW_PADDING,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnFocus(FocusEvent e)
|
protected override void OnFocus(FocusEvent e)
|
||||||
{
|
{
|
||||||
filter.TakeFocus();
|
filter.TakeFocus();
|
||||||
@ -199,13 +226,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Push a room as a new subscreen.
|
/// Push a room as a new subscreen.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Open(Room room) => Schedule(() =>
|
/// <param name="room">An optional template to use when creating the room.</param>
|
||||||
|
public void Open(Room room = null) => Schedule(() =>
|
||||||
{
|
{
|
||||||
// Handles the case where a room is clicked 3 times in quick succession
|
// Handles the case where a room is clicked 3 times in quick succession
|
||||||
if (!this.IsCurrentScreen())
|
if (!this.IsCurrentScreen())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
OpenNewRoom(room);
|
OpenNewRoom(room ?? CreateNewRoom());
|
||||||
});
|
});
|
||||||
|
|
||||||
protected virtual void OpenNewRoom(Room room)
|
protected virtual void OpenNewRoom(Room room)
|
||||||
@ -217,6 +245,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
|
|
||||||
protected abstract FilterControl CreateFilterControl();
|
protected abstract FilterControl CreateFilterControl();
|
||||||
|
|
||||||
|
protected abstract OsuButton CreateNewRoomButton();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new room.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The created <see cref="Room"/>.</returns>
|
||||||
|
protected abstract Room CreateNewRoom();
|
||||||
|
|
||||||
protected abstract RoomSubScreen CreateRoomSubScreen(Room room);
|
protected abstract RoomSubScreen CreateRoomSubScreen(Room room);
|
||||||
|
|
||||||
private void updateLoadingLayer()
|
private void updateLoadingLayer()
|
||||||
|
@ -12,6 +12,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
SpriteText.Font = SpriteText.Font.With(size: 14);
|
||||||
Triangles.TriangleScale = 1.5f;
|
Triangles.TriangleScale = 1.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,9 +4,7 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Online.Multiplayer;
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Online.Rooms;
|
|
||||||
using osu.Game.Screens.OnlinePlay.Components;
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge;
|
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||||
|
|
||||||
@ -54,20 +52,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
Logger.Log($"Polling adjusted (listing: {multiplayerRoomManager.TimeBetweenListingPolls.Value}, selection: {multiplayerRoomManager.TimeBetweenSelectionPolls.Value})");
|
Logger.Log($"Polling adjusted (listing: {multiplayerRoomManager.TimeBetweenListingPolls.Value}, selection: {multiplayerRoomManager.TimeBetweenSelectionPolls.Value})");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Room CreateNewRoom() =>
|
|
||||||
new Room
|
|
||||||
{
|
|
||||||
Name = { Value = $"{API.LocalUser}'s awesome room" },
|
|
||||||
Category = { Value = RoomCategory.Realtime },
|
|
||||||
Type = { Value = MatchType.HeadToHead },
|
|
||||||
};
|
|
||||||
|
|
||||||
protected override string ScreenTitle => "Multiplayer";
|
protected override string ScreenTitle => "Multiplayer";
|
||||||
|
|
||||||
protected override RoomManager CreateRoomManager() => new MultiplayerRoomManager();
|
protected override RoomManager CreateRoomManager() => new MultiplayerRoomManager();
|
||||||
|
|
||||||
protected override LoungeSubScreen CreateLounge() => new MultiplayerLoungeSubScreen();
|
protected override LoungeSubScreen CreateLounge() => new MultiplayerLoungeSubScreen();
|
||||||
|
|
||||||
protected override OsuButton CreateNewMultiplayerGameButton() => new CreateMultiplayerMatchButton();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.Multiplayer;
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge;
|
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||||
@ -13,13 +15,25 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
{
|
{
|
||||||
public class MultiplayerLoungeSubScreen : LoungeSubScreen
|
public class MultiplayerLoungeSubScreen : LoungeSubScreen
|
||||||
{
|
{
|
||||||
protected override FilterControl CreateFilterControl() => new MultiplayerFilterControl();
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; }
|
||||||
protected override RoomSubScreen CreateRoomSubScreen(Room room) => new MultiplayerMatchSubScreen(room);
|
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private MultiplayerClient client { get; set; }
|
private MultiplayerClient client { get; set; }
|
||||||
|
|
||||||
|
protected override FilterControl CreateFilterControl() => new MultiplayerFilterControl();
|
||||||
|
|
||||||
|
protected override OsuButton CreateNewRoomButton() => new CreateMultiplayerMatchButton();
|
||||||
|
|
||||||
|
protected override Room CreateNewRoom() => new Room
|
||||||
|
{
|
||||||
|
Name = { Value = $"{api.LocalUser}'s awesome room" },
|
||||||
|
Category = { Value = RoomCategory.Realtime },
|
||||||
|
Type = { Value = MatchType.HeadToHead },
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override RoomSubScreen CreateRoomSubScreen(Room room) => new MultiplayerMatchSubScreen(room);
|
||||||
|
|
||||||
protected override void OpenNewRoom(Room room)
|
protected override void OpenNewRoom(Room room)
|
||||||
{
|
{
|
||||||
if (client?.IsConnected.Value != true)
|
if (client?.IsConnected.Value != true)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
@ -42,6 +43,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
|
|||||||
private ModDisplay userModsDisplay;
|
private ModDisplay userModsDisplay;
|
||||||
private StateDisplay userStateDisplay;
|
private StateDisplay userStateDisplay;
|
||||||
|
|
||||||
|
private IconButton kickButton;
|
||||||
|
|
||||||
public ParticipantPanel(MultiplayerRoomUser user)
|
public ParticipantPanel(MultiplayerRoomUser user)
|
||||||
{
|
{
|
||||||
User = user;
|
User = user;
|
||||||
@ -64,7 +67,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
|
|||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.Absolute, 18),
|
new Dimension(GridSizeMode.Absolute, 18),
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
new Dimension()
|
new Dimension(),
|
||||||
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
},
|
},
|
||||||
Content = new[]
|
Content = new[]
|
||||||
{
|
{
|
||||||
@ -157,7 +161,20 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
|
|||||||
Margin = new MarginPadding { Right = 10 },
|
Margin = new MarginPadding { Right = 10 },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
kickButton = new KickButton
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Alpha = 0,
|
||||||
|
Margin = new MarginPadding(4),
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
Debug.Assert(user != null);
|
||||||
|
|
||||||
|
Client.KickUser(user.Id);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -167,7 +184,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
|
|||||||
{
|
{
|
||||||
base.OnRoomUpdated();
|
base.OnRoomUpdated();
|
||||||
|
|
||||||
if (Room == null)
|
if (Room == null || Client.LocalUser == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const double fade_time = 50;
|
const double fade_time = 50;
|
||||||
@ -179,6 +196,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
|
|||||||
|
|
||||||
userStateDisplay.UpdateStatus(User.State, User.BeatmapAvailability);
|
userStateDisplay.UpdateStatus(User.State, User.BeatmapAvailability);
|
||||||
|
|
||||||
|
if (Client.IsHost && !User.Equals(Client.LocalUser))
|
||||||
|
kickButton.FadeIn(fade_time);
|
||||||
|
else
|
||||||
|
kickButton.FadeOut(fade_time);
|
||||||
|
|
||||||
if (Room.Host?.Equals(User) == true)
|
if (Room.Host?.Equals(User) == true)
|
||||||
crown.FadeIn(fade_time);
|
crown.FadeIn(fade_time);
|
||||||
else
|
else
|
||||||
@ -211,13 +233,36 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
|
|||||||
new OsuMenuItem("Give host", MenuItemType.Standard, () =>
|
new OsuMenuItem("Give host", MenuItemType.Standard, () =>
|
||||||
{
|
{
|
||||||
// Ensure the local user is still host.
|
// Ensure the local user is still host.
|
||||||
if (Room.Host?.UserID != api.LocalUser.Value.Id)
|
if (!Client.IsHost)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Client.TransferHost(targetUser);
|
Client.TransferHost(targetUser);
|
||||||
|
}),
|
||||||
|
new OsuMenuItem("Kick", MenuItemType.Destructive, () =>
|
||||||
|
{
|
||||||
|
// Ensure the local user is still host.
|
||||||
|
if (!Client.IsHost)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Client.KickUser(targetUser);
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class KickButton : IconButton
|
||||||
|
{
|
||||||
|
public KickButton()
|
||||||
|
{
|
||||||
|
Icon = FontAwesome.Solid.UserTimes;
|
||||||
|
TooltipText = "Kick";
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
IconHoverColour = colours.Red;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
|
|||||||
public MultiSpectatorScreen(MultiplayerRoomUser[] users)
|
public MultiSpectatorScreen(MultiplayerRoomUser[] users)
|
||||||
: base(users.Select(u => u.UserID).ToArray())
|
: base(users.Select(u => u.UserID).ToArray())
|
||||||
{
|
{
|
||||||
// todo: this is a bit ugly, but not sure on a better way to handle.
|
|
||||||
this.users = users;
|
this.users = users;
|
||||||
|
|
||||||
instances = new PlayerArea[Users.Count];
|
instances = new PlayerArea[Users.Count];
|
||||||
|
@ -35,6 +35,9 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
[Resolved(typeof(Room))]
|
[Resolved(typeof(Room))]
|
||||||
protected BindableList<PlaylistItem> Playlist { get; private set; }
|
protected BindableList<PlaylistItem> Playlist { get; private set; }
|
||||||
|
|
||||||
|
[Resolved(typeof(Room))]
|
||||||
|
protected Bindable<RoomCategory> Category { get; private set; }
|
||||||
|
|
||||||
[Resolved(typeof(Room))]
|
[Resolved(typeof(Room))]
|
||||||
protected BindableList<User> RecentParticipants { get; private set; }
|
protected BindableList<User> RecentParticipants { get; private set; }
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ using osu.Framework.Logging;
|
|||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Beatmaps.Drawables;
|
using osu.Game.Beatmaps.Drawables;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Input;
|
using osu.Game.Input;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
@ -24,13 +23,15 @@ using osu.Game.Screens.OnlinePlay.Lounge;
|
|||||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||||
using osu.Game.Screens.OnlinePlay.Match;
|
using osu.Game.Screens.OnlinePlay.Match;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay
|
namespace osu.Game.Screens.OnlinePlay
|
||||||
{
|
{
|
||||||
[Cached]
|
[Cached]
|
||||||
public abstract class OnlinePlayScreen : OsuScreen, IHasSubScreenStack
|
public abstract class OnlinePlayScreen : OsuScreen, IHasSubScreenStack
|
||||||
{
|
{
|
||||||
|
[Cached]
|
||||||
|
protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum);
|
||||||
|
|
||||||
public override bool CursorVisible => (screenStack?.CurrentScreen as IOnlinePlaySubScreen)?.CursorVisible ?? true;
|
public override bool CursorVisible => (screenStack?.CurrentScreen as IOnlinePlaySubScreen)?.CursorVisible ?? true;
|
||||||
|
|
||||||
// this is required due to PlayerLoader eventually being pushed to the main stack
|
// this is required due to PlayerLoader eventually being pushed to the main stack
|
||||||
@ -38,12 +39,8 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
public override bool DisallowExternalBeatmapRulesetChanges => true;
|
public override bool DisallowExternalBeatmapRulesetChanges => true;
|
||||||
|
|
||||||
private MultiplayerWaveContainer waves;
|
private MultiplayerWaveContainer waves;
|
||||||
|
|
||||||
private OsuButton createButton;
|
|
||||||
|
|
||||||
private ScreenStack screenStack;
|
|
||||||
|
|
||||||
private LoungeSubScreen loungeSubScreen;
|
private LoungeSubScreen loungeSubScreen;
|
||||||
|
private ScreenStack screenStack;
|
||||||
|
|
||||||
private readonly IBindable<bool> isIdle = new BindableBool();
|
private readonly IBindable<bool> isIdle = new BindableBool();
|
||||||
|
|
||||||
@ -146,20 +143,8 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Header(ScreenTitle, screenStack),
|
new Header(ScreenTitle, screenStack),
|
||||||
createButton = CreateNewMultiplayerGameButton().With(button =>
|
|
||||||
{
|
|
||||||
button.Anchor = Anchor.TopRight;
|
|
||||||
button.Origin = Anchor.TopRight;
|
|
||||||
button.Size = new Vector2(150, Header.HEIGHT - 20);
|
|
||||||
button.Margin = new MarginPadding
|
|
||||||
{
|
|
||||||
Top = 10,
|
|
||||||
Right = 10 + HORIZONTAL_OVERFLOW_PADDING,
|
|
||||||
};
|
|
||||||
button.Action = () => OpenNewRoom();
|
|
||||||
}),
|
|
||||||
RoomManager,
|
RoomManager,
|
||||||
ongoingOperationTracker,
|
ongoingOperationTracker
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -292,18 +277,6 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
logo.Delay(WaveContainer.DISAPPEAR_DURATION / 2).FadeOut();
|
logo.Delay(WaveContainer.DISAPPEAR_DURATION / 2).FadeOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates and opens the newly-created room.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="room">An optional template to use when creating the room.</param>
|
|
||||||
public void OpenNewRoom(Room room = null) => loungeSubScreen.Open(room ?? CreateNewRoom());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new room.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The created <see cref="Room"/>.</returns>
|
|
||||||
protected abstract Room CreateNewRoom();
|
|
||||||
|
|
||||||
private void screenPushed(IScreen lastScreen, IScreen newScreen)
|
private void screenPushed(IScreen lastScreen, IScreen newScreen)
|
||||||
{
|
{
|
||||||
subScreenChanged(lastScreen, newScreen);
|
subScreenChanged(lastScreen, newScreen);
|
||||||
@ -339,7 +312,6 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
((IBindable<UserActivity>)Activity).BindTo(newOsuScreen.Activity);
|
((IBindable<UserActivity>)Activity).BindTo(newOsuScreen.Activity);
|
||||||
|
|
||||||
UpdatePollingRate(isIdle.Value);
|
UpdatePollingRate(isIdle.Value);
|
||||||
createButton.FadeTo(newScreen is LoungeSubScreen ? 1 : 0, 200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IScreen CurrentSubScreen => screenStack.CurrentScreen;
|
protected IScreen CurrentSubScreen => screenStack.CurrentScreen;
|
||||||
@ -350,8 +322,6 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
|
|
||||||
protected abstract LoungeSubScreen CreateLounge();
|
protected abstract LoungeSubScreen CreateLounge();
|
||||||
|
|
||||||
protected abstract OsuButton CreateNewMultiplayerGameButton();
|
|
||||||
|
|
||||||
private class MultiplayerWaveContainer : WaveContainer
|
private class MultiplayerWaveContainer : WaveContainer
|
||||||
{
|
{
|
||||||
protected override bool StartHidden => true;
|
protected override bool StartHidden => true;
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Online.Rooms;
|
|
||||||
using osu.Game.Screens.OnlinePlay.Components;
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge;
|
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||||
using osu.Game.Screens.OnlinePlay.Match;
|
using osu.Game.Screens.OnlinePlay.Match;
|
||||||
@ -46,21 +44,10 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
Logger.Log($"Polling adjusted (listing: {playlistsManager.TimeBetweenListingPolls.Value}, selection: {playlistsManager.TimeBetweenSelectionPolls.Value})");
|
Logger.Log($"Polling adjusted (listing: {playlistsManager.TimeBetweenListingPolls.Value}, selection: {playlistsManager.TimeBetweenSelectionPolls.Value})");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Room CreateNewRoom()
|
|
||||||
{
|
|
||||||
return new Room
|
|
||||||
{
|
|
||||||
Name = { Value = $"{API.LocalUser}'s awesome playlist" },
|
|
||||||
Type = { Value = MatchType.Playlists }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override string ScreenTitle => "Playlists";
|
protected override string ScreenTitle => "Playlists";
|
||||||
|
|
||||||
protected override RoomManager CreateRoomManager() => new PlaylistsRoomManager();
|
protected override RoomManager CreateRoomManager() => new PlaylistsRoomManager();
|
||||||
|
|
||||||
protected override LoungeSubScreen CreateLounge() => new PlaylistsLoungeSubScreen();
|
protected override LoungeSubScreen CreateLounge() => new PlaylistsLoungeSubScreen();
|
||||||
|
|
||||||
protected override OsuButton CreateNewMultiplayerGameButton() => new CreatePlaylistsRoomButton();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
// 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.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge;
|
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||||
@ -10,8 +13,22 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
{
|
{
|
||||||
public class PlaylistsLoungeSubScreen : LoungeSubScreen
|
public class PlaylistsLoungeSubScreen : LoungeSubScreen
|
||||||
{
|
{
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
protected override FilterControl CreateFilterControl() => new PlaylistsFilterControl();
|
protected override FilterControl CreateFilterControl() => new PlaylistsFilterControl();
|
||||||
|
|
||||||
|
protected override OsuButton CreateNewRoomButton() => new CreatePlaylistsRoomButton();
|
||||||
|
|
||||||
|
protected override Room CreateNewRoom()
|
||||||
|
{
|
||||||
|
return new Room
|
||||||
|
{
|
||||||
|
Name = { Value = $"{api.LocalUser}'s awesome playlist" },
|
||||||
|
Type = { Value = MatchType.Playlists }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
protected override RoomSubScreen CreateRoomSubScreen(Room room) => new PlaylistsRoomSubScreen(room);
|
protected override RoomSubScreen CreateRoomSubScreen(Room room) => new PlaylistsRoomSubScreen(room);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -962,7 +962,7 @@ namespace osu.Game.Screens.Play
|
|||||||
screenSuspension?.Expire();
|
screenSuspension?.Expire();
|
||||||
|
|
||||||
// if arriving here and the results screen preparation task hasn't run, it's safe to say the user has not completed the beatmap.
|
// if arriving here and the results screen preparation task hasn't run, it's safe to say the user has not completed the beatmap.
|
||||||
if (Score != null && prepareScoreForDisplayTask == null)
|
if (prepareScoreForDisplayTask == null)
|
||||||
{
|
{
|
||||||
Score.ScoreInfo.Passed = false;
|
Score.ScoreInfo.Passed = false;
|
||||||
// potentially should be ScoreRank.F instead? this is the best alternative for now.
|
// potentially should be ScoreRank.F instead? this is the best alternative for now.
|
||||||
|
@ -174,6 +174,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
|
|
||||||
public override Task TransferHost(int userId) => ((IMultiplayerClient)this).HostChanged(userId);
|
public override Task TransferHost(int userId) => ((IMultiplayerClient)this).HostChanged(userId);
|
||||||
|
|
||||||
|
public override Task KickUser(int userId)
|
||||||
|
{
|
||||||
|
Debug.Assert(Room != null);
|
||||||
|
|
||||||
|
return ((IMultiplayerClient)this).UserLeft(Room.Users.Single(u => u.UserID == userId));
|
||||||
|
}
|
||||||
|
|
||||||
public override async Task ChangeSettings(MultiplayerRoomSettings settings)
|
public override async Task ChangeSettings(MultiplayerRoomSettings settings)
|
||||||
{
|
{
|
||||||
Debug.Assert(Room != null);
|
Debug.Assert(Room != null);
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Screens.OnlinePlay;
|
using osu.Game.Screens.OnlinePlay;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||||
|
|
||||||
@ -46,6 +47,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay
|
|||||||
CacheAs(Filter);
|
CacheAs(Filter);
|
||||||
CacheAs(OngoingOperationTracker);
|
CacheAs(OngoingOperationTracker);
|
||||||
CacheAs(AvailabilityTracker);
|
CacheAs(AvailabilityTracker);
|
||||||
|
CacheAs(new OverlayColourProvider(OverlayColourScheme.Plum));
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(Type type)
|
public object Get(Type type)
|
||||||
|
@ -36,8 +36,8 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Realm" Version="10.3.0" />
|
<PackageReference Include="Realm" Version="10.3.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2021.809.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2021.811.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.808.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.810.0" />
|
||||||
<PackageReference Include="Sentry" Version="3.8.3" />
|
<PackageReference Include="Sentry" Version="3.8.3" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.28.3" />
|
<PackageReference Include="SharpCompress" Version="0.28.3" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
|
@ -70,8 +70,8 @@
|
|||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.809.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.811.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.808.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.810.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
@ -93,7 +93,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2021.809.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2021.811.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.28.3" />
|
<PackageReference Include="SharpCompress" Version="0.28.3" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||||
|
Loading…
Reference in New Issue
Block a user