mirror of
https://github.com/ppy/osu.git
synced 2025-02-21 23:59:16 +08:00
Merge branch 'master' into mod-overlay/extension-points
This commit is contained in:
commit
b722ff8dc5
@ -52,7 +52,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.417.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.417.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.415.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.419.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. -->
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Desktop.Security
|
|||||||
public class ElevatedPrivilegesChecker : Component
|
public class ElevatedPrivilegesChecker : Component
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private NotificationOverlay notifications { get; set; }
|
private INotificationOverlay notifications { get; set; }
|
||||||
|
|
||||||
private bool elevated;
|
private bool elevated;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Desktop.Updater
|
|||||||
public class SquirrelUpdateManager : osu.Game.Updater.UpdateManager
|
public class SquirrelUpdateManager : osu.Game.Updater.UpdateManager
|
||||||
{
|
{
|
||||||
private UpdateManager updateManager;
|
private UpdateManager updateManager;
|
||||||
private NotificationOverlay notificationOverlay;
|
private INotificationOverlay notificationOverlay;
|
||||||
|
|
||||||
public Task PrepareUpdateAsync() => UpdateManager.RestartAppWhenExited();
|
public Task PrepareUpdateAsync() => UpdateManager.RestartAppWhenExited();
|
||||||
|
|
||||||
@ -39,9 +39,9 @@ namespace osu.Desktop.Updater
|
|||||||
private readonly SquirrelLogger squirrelLogger = new SquirrelLogger();
|
private readonly SquirrelLogger squirrelLogger = new SquirrelLogger();
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(NotificationOverlay notification)
|
private void load(INotificationOverlay notifications)
|
||||||
{
|
{
|
||||||
notificationOverlay = notification;
|
notificationOverlay = notifications;
|
||||||
|
|
||||||
SquirrelLocator.CurrentMutable.Register(() => squirrelLogger, typeof(ILogger));
|
SquirrelLocator.CurrentMutable.Register(() => squirrelLogger, typeof(ILogger));
|
||||||
}
|
}
|
||||||
|
108
osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs
Normal file
108
osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics.OpenGL.Textures;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Rulesets.Osu.Skinning.Legacy;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
|
{
|
||||||
|
[HeadlessTest]
|
||||||
|
public class LegacyMainCirclePieceTest : OsuTestScene
|
||||||
|
{
|
||||||
|
private static readonly object?[][] texture_priority_cases =
|
||||||
|
{
|
||||||
|
// default priority lookup
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
// available textures
|
||||||
|
new[] { @"hitcircle", @"hitcircleoverlay" },
|
||||||
|
// priority lookup prefix
|
||||||
|
null,
|
||||||
|
// expected circle and overlay
|
||||||
|
@"hitcircle", @"hitcircleoverlay",
|
||||||
|
},
|
||||||
|
// custom priority lookup
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new[] { @"hitcircle", @"hitcircleoverlay", @"sliderstartcircle", @"sliderstartcircleoverlay" },
|
||||||
|
@"sliderstartcircle",
|
||||||
|
@"sliderstartcircle", @"sliderstartcircleoverlay",
|
||||||
|
},
|
||||||
|
// when no sprites are available for the specified prefix, fall back to "hitcircle"/"hitcircleoverlay".
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new[] { @"hitcircle", @"hitcircleoverlay" },
|
||||||
|
@"sliderstartcircle",
|
||||||
|
@"hitcircle", @"hitcircleoverlay",
|
||||||
|
},
|
||||||
|
// when a circle is available for the specified prefix but no overlay exists, no overlay is displayed.
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new[] { @"hitcircle", @"hitcircleoverlay", @"sliderstartcircle" },
|
||||||
|
@"sliderstartcircle",
|
||||||
|
@"sliderstartcircle", null
|
||||||
|
},
|
||||||
|
// when no circle is available for the specified prefix but an overlay exists, the overlay is ignored.
|
||||||
|
new object?[]
|
||||||
|
{
|
||||||
|
new[] { @"hitcircle", @"hitcircleoverlay", @"sliderstartcircleoverlay" },
|
||||||
|
@"sliderstartcircle",
|
||||||
|
@"hitcircle", @"hitcircleoverlay",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(texture_priority_cases))]
|
||||||
|
public void TestTexturePriorities(string[] textureFilenames, string priorityLookup, string? expectedCircle, string? expectedOverlay)
|
||||||
|
{
|
||||||
|
TestLegacyMainCirclePiece piece = null!;
|
||||||
|
|
||||||
|
AddStep("load circle piece", () =>
|
||||||
|
{
|
||||||
|
var skin = new Mock<ISkinSource>();
|
||||||
|
|
||||||
|
// shouldn't be required as GetTexture(string) calls GetTexture(string, WrapMode, WrapMode) by default,
|
||||||
|
// but moq doesn't handle that well, therefore explicitly requiring to use `CallBase`:
|
||||||
|
// https://github.com/moq/moq4/issues/972
|
||||||
|
skin.Setup(s => s.GetTexture(It.IsAny<string>())).CallBase();
|
||||||
|
|
||||||
|
skin.Setup(s => s.GetTexture(It.IsIn(textureFilenames), It.IsAny<WrapMode>(), It.IsAny<WrapMode>()))
|
||||||
|
.Returns((string componentName, WrapMode _, WrapMode __) => new Texture(1, 1) { AssetName = componentName });
|
||||||
|
|
||||||
|
Child = new DependencyProvidingContainer
|
||||||
|
{
|
||||||
|
CachedDependencies = new (Type, object)[] { (typeof(ISkinSource), skin.Object) },
|
||||||
|
Child = piece = new TestLegacyMainCirclePiece(priorityLookup),
|
||||||
|
};
|
||||||
|
|
||||||
|
var sprites = this.ChildrenOfType<Sprite>().Where(s => s.Texture.AssetName != null).DistinctBy(s => s.Texture.AssetName).ToArray();
|
||||||
|
Debug.Assert(sprites.Length <= 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("check circle sprite", () => piece.CircleSprite?.Texture?.AssetName == expectedCircle);
|
||||||
|
AddAssert("check overlay sprite", () => piece.OverlaySprite?.Texture?.AssetName == expectedOverlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestLegacyMainCirclePiece : LegacyMainCirclePiece
|
||||||
|
{
|
||||||
|
public new Sprite? CircleSprite => base.CircleSprite.ChildrenOfType<Sprite>().DistinctBy(s => s.Texture.AssetName).SingleOrDefault();
|
||||||
|
public new Sprite? OverlaySprite => base.OverlaySprite.ChildrenOfType<Sprite>().DistinctBy(s => s.Texture.AssetName).SingleOrDefault();
|
||||||
|
|
||||||
|
public TestLegacyMainCirclePiece(string? priorityLookupPrefix)
|
||||||
|
: base(priorityLookupPrefix, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
@ -16,63 +16,61 @@ using osu.Game.Skinning;
|
|||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyMainCirclePiece : CompositeDrawable
|
public class LegacyMainCirclePiece : CompositeDrawable
|
||||||
{
|
{
|
||||||
public override bool RemoveCompletedTransforms => false;
|
public override bool RemoveCompletedTransforms => false;
|
||||||
|
|
||||||
private readonly string priorityLookup;
|
/// <summary>
|
||||||
|
/// A prioritised prefix to perform texture lookups with.
|
||||||
|
/// </summary>
|
||||||
|
private readonly string? priorityLookupPrefix;
|
||||||
|
|
||||||
private readonly bool hasNumber;
|
private readonly bool hasNumber;
|
||||||
|
|
||||||
public LegacyMainCirclePiece(string priorityLookup = null, bool hasNumber = true)
|
protected Drawable CircleSprite = null!;
|
||||||
|
protected Drawable OverlaySprite = null!;
|
||||||
|
|
||||||
|
protected Container OverlayLayer { get; private set; } = null!;
|
||||||
|
|
||||||
|
private SkinnableSpriteText hitCircleText = null!;
|
||||||
|
|
||||||
|
private readonly Bindable<Color4> accentColour = new Bindable<Color4>();
|
||||||
|
private readonly IBindable<int> indexInCurrentCombo = new Bindable<int>();
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private DrawableHitObject? drawableObject { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private ISkinSource skin { get; set; } = null!;
|
||||||
|
|
||||||
|
public LegacyMainCirclePiece(string? priorityLookupPrefix = null, bool hasNumber = true)
|
||||||
{
|
{
|
||||||
this.priorityLookup = priorityLookup;
|
this.priorityLookupPrefix = priorityLookupPrefix;
|
||||||
this.hasNumber = hasNumber;
|
this.hasNumber = hasNumber;
|
||||||
|
|
||||||
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable hitCircleSprite;
|
|
||||||
|
|
||||||
protected Container OverlayLayer { get; private set; }
|
|
||||||
|
|
||||||
private Drawable hitCircleOverlay;
|
|
||||||
private SkinnableSpriteText hitCircleText;
|
|
||||||
|
|
||||||
private readonly Bindable<Color4> accentColour = new Bindable<Color4>();
|
|
||||||
private readonly IBindable<int> indexInCurrentCombo = new Bindable<int>();
|
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private DrawableHitObject drawableObject { get; set; }
|
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private ISkinSource skin { get; set; }
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
var drawableOsuObject = (DrawableOsuHitObject)drawableObject;
|
var drawableOsuObject = (DrawableOsuHitObject?)drawableObject;
|
||||||
|
|
||||||
bool allowFallback = false;
|
// if a base texture for the specified prefix exists, continue using it for subsequent lookups.
|
||||||
|
// otherwise fall back to the default prefix "hitcircle".
|
||||||
// attempt lookup using priority specification
|
string circleName = (priorityLookupPrefix != null && skin.GetTexture(priorityLookupPrefix) != null) ? priorityLookupPrefix : @"hitcircle";
|
||||||
Texture baseTexture = getTextureWithFallback(string.Empty);
|
|
||||||
|
|
||||||
// if the base texture was not found without a fallback, switch on fallback mode and re-perform the lookup.
|
|
||||||
if (baseTexture == null)
|
|
||||||
{
|
|
||||||
allowFallback = true;
|
|
||||||
baseTexture = getTextureWithFallback(string.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// at this point, any further texture fetches should be correctly using the priority source if the base texture was retrieved using it.
|
// at this point, any further texture fetches should be correctly using the priority source if the base texture was retrieved using it.
|
||||||
// the flow above handles the case where a sliderendcircle.png is retrieved from the skin, but sliderendcircleoverlay.png doesn't exist.
|
// the conditional above handles the case where a sliderendcircle.png is retrieved from the skin, but sliderendcircleoverlay.png doesn't exist.
|
||||||
// expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png (potentially from the default/fall-through skin).
|
// expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png.
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
hitCircleSprite = new KiaiFlashingDrawable(() => new Sprite { Texture = baseTexture })
|
CircleSprite = new KiaiFlashingDrawable(() => new Sprite { Texture = skin.GetTexture(circleName) })
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
@ -81,7 +79,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Child = hitCircleOverlay = new KiaiFlashingDrawable(() => getAnimationWithFallback(@"overlay", 1000 / 2d))
|
Child = OverlaySprite = new KiaiFlashingDrawable(() => skin.GetAnimation(@$"{circleName}overlay", true, true, frameLength: 1000 / 2d))
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
@ -105,39 +103,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
bool overlayAboveNumber = skin.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.HitCircleOverlayAboveNumber)?.Value ?? true;
|
bool overlayAboveNumber = skin.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.HitCircleOverlayAboveNumber)?.Value ?? true;
|
||||||
|
|
||||||
if (overlayAboveNumber)
|
if (overlayAboveNumber)
|
||||||
OverlayLayer.ChangeChildDepth(hitCircleOverlay, float.MinValue);
|
OverlayLayer.ChangeChildDepth(OverlaySprite, float.MinValue);
|
||||||
|
|
||||||
accentColour.BindTo(drawableObject.AccentColour);
|
if (drawableOsuObject != null)
|
||||||
indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable);
|
|
||||||
|
|
||||||
Texture getTextureWithFallback(string name)
|
|
||||||
{
|
{
|
||||||
Texture tex = null;
|
accentColour.BindTo(drawableOsuObject.AccentColour);
|
||||||
|
indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable);
|
||||||
if (!string.IsNullOrEmpty(priorityLookup))
|
|
||||||
{
|
|
||||||
tex = skin.GetTexture($"{priorityLookup}{name}");
|
|
||||||
|
|
||||||
if (!allowFallback)
|
|
||||||
return tex;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tex ?? skin.GetTexture($"hitcircle{name}");
|
|
||||||
}
|
|
||||||
|
|
||||||
Drawable getAnimationWithFallback(string name, double frameLength)
|
|
||||||
{
|
|
||||||
Drawable animation = null;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(priorityLookup))
|
|
||||||
{
|
|
||||||
animation = skin.GetAnimation($"{priorityLookup}{name}", true, true, frameLength: frameLength);
|
|
||||||
|
|
||||||
if (!allowFallback)
|
|
||||||
return animation;
|
|
||||||
}
|
|
||||||
|
|
||||||
return animation ?? skin.GetAnimation($"hitcircle{name}", true, true, frameLength: frameLength);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,28 +116,31 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
accentColour.BindValueChanged(colour => hitCircleSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true);
|
accentColour.BindValueChanged(colour => CircleSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true);
|
||||||
if (hasNumber)
|
if (hasNumber)
|
||||||
indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true);
|
indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true);
|
||||||
|
|
||||||
drawableObject.ApplyCustomUpdateState += updateStateTransforms;
|
if (drawableObject != null)
|
||||||
updateStateTransforms(drawableObject, drawableObject.State.Value);
|
{
|
||||||
|
drawableObject.ApplyCustomUpdateState += updateStateTransforms;
|
||||||
|
updateStateTransforms(drawableObject, drawableObject.State.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state)
|
private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state)
|
||||||
{
|
{
|
||||||
const double legacy_fade_duration = 240;
|
const double legacy_fade_duration = 240;
|
||||||
|
|
||||||
using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime))
|
using (BeginAbsoluteSequence(drawableObject.AsNonNull().HitStateUpdateTime))
|
||||||
{
|
{
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case ArmedState.Hit:
|
case ArmedState.Hit:
|
||||||
hitCircleSprite.FadeOut(legacy_fade_duration, Easing.Out);
|
CircleSprite.FadeOut(legacy_fade_duration, Easing.Out);
|
||||||
hitCircleSprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
|
CircleSprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
|
||||||
|
|
||||||
hitCircleOverlay.FadeOut(legacy_fade_duration, Easing.Out);
|
OverlaySprite.FadeOut(legacy_fade_duration, Easing.Out);
|
||||||
hitCircleOverlay.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
|
OverlaySprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
|
||||||
|
|
||||||
if (hasNumber)
|
if (hasNumber)
|
||||||
{
|
{
|
||||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Tests.Visual.Collections
|
|||||||
});
|
});
|
||||||
|
|
||||||
Dependencies.Cache(manager);
|
Dependencies.Cache(manager);
|
||||||
Dependencies.Cache(dialogOverlay);
|
Dependencies.CacheAs<IDialogOverlay>(dialogOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
|
@ -1,44 +1,71 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
using osu.Game.Screens.Edit;
|
using osu.Game.Screens.Edit;
|
||||||
using osu.Game.Screens.Edit.Compose;
|
using osu.Game.Screens.Edit.Compose;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Editing
|
namespace osu.Game.Tests.Visual.Editing
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneComposeScreen : EditorClockTestScene
|
public class TestSceneComposeScreen : EditorClockTestScene
|
||||||
{
|
{
|
||||||
[Cached(typeof(EditorBeatmap))]
|
private EditorBeatmap editorBeatmap;
|
||||||
[Cached(typeof(IBeatSnapProvider))]
|
|
||||||
private readonly EditorBeatmap editorBeatmap =
|
|
||||||
new EditorBeatmap(new OsuBeatmap
|
|
||||||
{
|
|
||||||
BeatmapInfo =
|
|
||||||
{
|
|
||||||
Ruleset = new OsuRuleset().RulesetInfo
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
private EditorClipboard clipboard = new EditorClipboard();
|
private EditorClipboard clipboard = new EditorClipboard();
|
||||||
|
|
||||||
protected override void LoadComplete()
|
[SetUpSteps]
|
||||||
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
AddStep("setup compose screen", () =>
|
||||||
|
|
||||||
Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap);
|
|
||||||
|
|
||||||
Child = new ComposeScreen
|
|
||||||
{
|
{
|
||||||
State = { Value = Visibility.Visible },
|
var beatmap = new OsuBeatmap
|
||||||
};
|
{
|
||||||
|
BeatmapInfo = { Ruleset = new OsuRuleset().RulesetInfo }
|
||||||
|
};
|
||||||
|
|
||||||
|
editorBeatmap = new EditorBeatmap(beatmap, new LegacyBeatmapSkin(beatmap.BeatmapInfo, null));
|
||||||
|
|
||||||
|
Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap);
|
||||||
|
|
||||||
|
Child = new DependencyProvidingContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
CachedDependencies = new (Type, object)[]
|
||||||
|
{
|
||||||
|
(typeof(EditorBeatmap), editorBeatmap),
|
||||||
|
(typeof(IBeatSnapProvider), editorBeatmap),
|
||||||
|
},
|
||||||
|
Child = new ComposeScreen { State = { Value = Visibility.Visible } },
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for composer", () => this.ChildrenOfType<HitObjectComposer>().SingleOrDefault()?.IsLoaded == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ensures that the skin of the edited beatmap is properly wrapped in a <see cref="LegacySkinTransformer"/>.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestLegacyBeatmapSkinHasTransformer()
|
||||||
|
{
|
||||||
|
AddAssert("legacy beatmap skin has transformer", () =>
|
||||||
|
{
|
||||||
|
var sources = this.ChildrenOfType<BeatmapSkinProvidingContainer>().First().AllSources;
|
||||||
|
return sources.OfType<LegacySkinTransformer>().Count(t => t.Skin == editorBeatmap.BeatmapSkin.AsNonNull().Skin) == 1;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private SessionStatics sessionStatics { get; set; }
|
private SessionStatics sessionStatics { get; set; }
|
||||||
|
|
||||||
[Cached]
|
[Cached(typeof(INotificationOverlay))]
|
||||||
private readonly NotificationOverlay notificationOverlay;
|
private readonly NotificationOverlay notificationOverlay;
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
|
|
||||||
private IntroScreen intro;
|
private IntroScreen intro;
|
||||||
|
|
||||||
[Cached]
|
[Cached(typeof(INotificationOverlay))]
|
||||||
private NotificationOverlay notifications;
|
private NotificationOverlay notifications;
|
||||||
|
|
||||||
private ScheduledDelegate trackResetDelegate;
|
private ScheduledDelegate trackResetDelegate;
|
||||||
|
@ -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.Linq;
|
using System.Linq;
|
||||||
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
@ -22,6 +23,17 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IRulesetStore rulesets { get; set; }
|
private IRulesetStore rulesets { get; set; }
|
||||||
|
|
||||||
|
private readonly Mock<INotificationOverlay> notifications = new Mock<INotificationOverlay>();
|
||||||
|
|
||||||
|
private readonly BindableInt unreadNotificationCount = new BindableInt();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Dependencies.CacheAs(notifications.Object);
|
||||||
|
notifications.SetupGet(n => n.UnreadCount).Returns(unreadNotificationCount);
|
||||||
|
}
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp() => Schedule(() =>
|
public void SetUp() => Schedule(() =>
|
||||||
{
|
{
|
||||||
@ -31,10 +43,6 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestNotificationCounter()
|
public void TestNotificationCounter()
|
||||||
{
|
{
|
||||||
ToolbarNotificationButton notificationButton = null;
|
|
||||||
|
|
||||||
AddStep("retrieve notification button", () => notificationButton = toolbar.ChildrenOfType<ToolbarNotificationButton>().Single());
|
|
||||||
|
|
||||||
setNotifications(1);
|
setNotifications(1);
|
||||||
setNotifications(2);
|
setNotifications(2);
|
||||||
setNotifications(3);
|
setNotifications(3);
|
||||||
@ -43,7 +51,7 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
|
|
||||||
void setNotifications(int count)
|
void setNotifications(int count)
|
||||||
=> AddStep($"set notification count to {count}",
|
=> AddStep($"set notification count to {count}",
|
||||||
() => notificationButton.NotificationCount.Value = count);
|
() => unreadNotificationCount.Value = count);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
typeof(OsuLogo),
|
typeof(OsuLogo),
|
||||||
typeof(IdleTracker),
|
typeof(IdleTracker),
|
||||||
typeof(OnScreenDisplay),
|
typeof(OnScreenDisplay),
|
||||||
typeof(NotificationOverlay),
|
typeof(INotificationOverlay),
|
||||||
typeof(BeatmapListingOverlay),
|
typeof(BeatmapListingOverlay),
|
||||||
typeof(DashboardOverlay),
|
typeof(DashboardOverlay),
|
||||||
typeof(NewsOverlay),
|
typeof(NewsOverlay),
|
||||||
@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
typeof(LoginOverlay),
|
typeof(LoginOverlay),
|
||||||
typeof(MusicController),
|
typeof(MusicController),
|
||||||
typeof(AccountCreationOverlay),
|
typeof(AccountCreationOverlay),
|
||||||
typeof(DialogOverlay),
|
typeof(IDialogOverlay),
|
||||||
typeof(ScreenshotManager)
|
typeof(ScreenshotManager)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
@ -113,12 +114,12 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddAssert("did not perform", () => !actionPerformed);
|
AddAssert("did not perform", () => !actionPerformed);
|
||||||
AddAssert("only one exit attempt", () => blocker.ExitAttempts == 1);
|
AddAssert("only one exit attempt", () => blocker.ExitAttempts == 1);
|
||||||
|
|
||||||
AddUntilStep("wait for dialog display", () => Game.Dependencies.Get<DialogOverlay>().IsLoaded);
|
waitForDialogOverlayLoad();
|
||||||
|
|
||||||
if (confirmed)
|
if (confirmed)
|
||||||
{
|
{
|
||||||
AddStep("accept dialog", () => InputManager.Key(Key.Number1));
|
AddStep("accept dialog", () => InputManager.Key(Key.Number1));
|
||||||
AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog == null);
|
AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get<IDialogOverlay>().CurrentDialog == null);
|
||||||
AddUntilStep("did perform", () => actionPerformed);
|
AddUntilStep("did perform", () => actionPerformed);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -145,7 +146,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
|
|
||||||
AddWaitStep("wait a bit", 10);
|
AddWaitStep("wait a bit", 10);
|
||||||
|
|
||||||
AddUntilStep("wait for dialog display", () => Game.Dependencies.Get<DialogOverlay>().IsLoaded);
|
waitForDialogOverlayLoad();
|
||||||
|
|
||||||
AddAssert("screen didn't change", () => Game.ScreenStack.CurrentScreen == blocker2);
|
AddAssert("screen didn't change", () => Game.ScreenStack.CurrentScreen == blocker2);
|
||||||
AddAssert("did not perform", () => !actionPerformed);
|
AddAssert("did not perform", () => !actionPerformed);
|
||||||
@ -187,7 +188,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
|
|
||||||
AddWaitStep("wait a bit", 10);
|
AddWaitStep("wait a bit", 10);
|
||||||
|
|
||||||
AddUntilStep("wait for dialog display", () => Game.Dependencies.Get<DialogOverlay>().IsLoaded);
|
waitForDialogOverlayLoad();
|
||||||
|
|
||||||
AddAssert("screen didn't change", () => Game.ScreenStack.CurrentScreen == screenWithNestedStack);
|
AddAssert("screen didn't change", () => Game.ScreenStack.CurrentScreen == screenWithNestedStack);
|
||||||
AddAssert("nested screen didn't change", () => screenWithNestedStack.SubScreenStack.CurrentScreen == screenWithNestedStack.Blocker);
|
AddAssert("nested screen didn't change", () => screenWithNestedStack.SubScreenStack.CurrentScreen == screenWithNestedStack.Blocker);
|
||||||
@ -211,6 +212,8 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void waitForDialogOverlayLoad() => AddUntilStep("wait for dialog overlay loaded", () => ((Drawable)Game.Dependencies.Get<IDialogOverlay>()).IsLoaded);
|
||||||
|
|
||||||
private void importAndWaitForSongSelect()
|
private void importAndWaitForSongSelect()
|
||||||
{
|
{
|
||||||
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
|
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
|
||||||
@ -221,7 +224,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
public class DialogBlockingScreen : OsuScreen
|
public class DialogBlockingScreen : OsuScreen
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private DialogOverlay dialogOverlay { get; set; }
|
private IDialogOverlay dialogOverlay { get; set; }
|
||||||
|
|
||||||
private int dialogDisplayCount;
|
private int dialogDisplayCount;
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
@ -200,10 +201,10 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
|
|
||||||
AddStep("choose clear all scores", () => InputManager.Key(Key.Number4));
|
AddStep("choose clear all scores", () => InputManager.Key(Key.Number4));
|
||||||
|
|
||||||
AddUntilStep("wait for dialog display", () => Game.Dependencies.Get<DialogOverlay>().IsLoaded);
|
AddUntilStep("wait for dialog display", () => ((Drawable)Game.Dependencies.Get<IDialogOverlay>()).IsLoaded);
|
||||||
AddUntilStep("wait for dialog", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog != null);
|
AddUntilStep("wait for dialog", () => Game.Dependencies.Get<IDialogOverlay>().CurrentDialog != null);
|
||||||
AddStep("confirm deletion", () => InputManager.Key(Key.Number1));
|
AddStep("confirm deletion", () => InputManager.Key(Key.Number1));
|
||||||
AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog == null);
|
AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get<IDialogOverlay>().CurrentDialog == null);
|
||||||
|
|
||||||
AddUntilStep("ensure score is pending deletion", () => Game.Realm.Run(r => r.Find<ScoreInfo>(score.ID)?.DeletePending == true));
|
AddUntilStep("ensure score is pending deletion", () => Game.Realm.Run(r => r.Find<ScoreInfo>(score.ID)?.DeletePending == true));
|
||||||
|
|
||||||
@ -246,10 +247,10 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
InputManager.Click(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for dialog display", () => Game.Dependencies.Get<DialogOverlay>().IsLoaded);
|
AddUntilStep("wait for dialog display", () => ((Drawable)Game.Dependencies.Get<IDialogOverlay>()).IsLoaded);
|
||||||
AddUntilStep("wait for dialog", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog != null);
|
AddUntilStep("wait for dialog", () => Game.Dependencies.Get<IDialogOverlay>().CurrentDialog != null);
|
||||||
AddStep("confirm deletion", () => InputManager.Key(Key.Number1));
|
AddStep("confirm deletion", () => InputManager.Key(Key.Number1));
|
||||||
AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog == null);
|
AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get<IDialogOverlay>().CurrentDialog == null);
|
||||||
|
|
||||||
AddUntilStep("ensure score is pending deletion", () => Game.Realm.Run(r => r.Find<ScoreInfo>(score.ID)?.DeletePending == true));
|
AddUntilStep("ensure score is pending deletion", () => Game.Realm.Run(r => r.Find<ScoreInfo>(score.ID)?.DeletePending == true));
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
Dependencies.Cache(chatManager);
|
Dependencies.Cache(chatManager);
|
||||||
|
|
||||||
Dependencies.Cache(new ChatOverlay());
|
Dependencies.Cache(new ChatOverlay());
|
||||||
Dependencies.Cache(dialogOverlay);
|
Dependencies.CacheAs<IDialogOverlay>(dialogOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
|
@ -200,7 +200,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[Cached]
|
[Cached]
|
||||||
public ChannelManager ChannelManager { get; } = new ChannelManager();
|
public ChannelManager ChannelManager { get; } = new ChannelManager();
|
||||||
|
|
||||||
[Cached]
|
[Cached(typeof(INotificationOverlay))]
|
||||||
public NotificationOverlay NotificationOverlay { get; } = new NotificationOverlay
|
public NotificationOverlay NotificationOverlay { get; } = new NotificationOverlay
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
{
|
{
|
||||||
public class TestSceneMigrationScreens : ScreenTestScene
|
public class TestSceneMigrationScreens : ScreenTestScene
|
||||||
{
|
{
|
||||||
[Cached]
|
[Cached(typeof(INotificationOverlay))]
|
||||||
private readonly NotificationOverlay notifications;
|
private readonly NotificationOverlay notifications;
|
||||||
|
|
||||||
public TestSceneMigrationScreens()
|
public TestSceneMigrationScreens()
|
||||||
|
@ -97,7 +97,7 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
Depth = -1
|
Depth = -1
|
||||||
});
|
});
|
||||||
|
|
||||||
Dependencies.Cache(dialogOverlay);
|
Dependencies.CacheAs<IDialogOverlay>(dialogOverlay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
private readonly FailableLeaderboard leaderboard;
|
private readonly FailableLeaderboard leaderboard;
|
||||||
|
|
||||||
[Cached]
|
[Cached(typeof(IDialogOverlay))]
|
||||||
private readonly DialogOverlay dialogOverlay;
|
private readonly DialogOverlay dialogOverlay;
|
||||||
|
|
||||||
private ScoreManager scoreManager;
|
private ScoreManager scoreManager;
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
public class TestSceneUserTopScoreContainer : OsuTestScene
|
public class TestSceneUserTopScoreContainer : OsuTestScene
|
||||||
{
|
{
|
||||||
[Cached]
|
[Cached(typeof(IDialogOverlay))]
|
||||||
private readonly DialogOverlay dialogOverlay;
|
private readonly DialogOverlay dialogOverlay;
|
||||||
|
|
||||||
public TestSceneUserTopScoreContainer()
|
public TestSceneUserTopScoreContainer()
|
||||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
private BeatmapInfo beatmapInfo;
|
private BeatmapInfo beatmapInfo;
|
||||||
|
|
||||||
[Cached]
|
[Cached(typeof(IDialogOverlay))]
|
||||||
private readonly DialogOverlay dialogOverlay;
|
private readonly DialogOverlay dialogOverlay;
|
||||||
|
|
||||||
public TestSceneDeleteLocalScore()
|
public TestSceneDeleteLocalScore()
|
||||||
|
@ -10,19 +10,19 @@ using osu.Game.Overlays;
|
|||||||
namespace osu.Game.Tests.Visual.UserInterface
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestScenePopupScreenTitle : OsuTestScene
|
public class TestSceneShearedOverlayHeader : OsuTestScene
|
||||||
{
|
{
|
||||||
[Cached]
|
[Cached]
|
||||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestPopupScreenTitle()
|
public void TestShearedOverlayHeader()
|
||||||
{
|
{
|
||||||
AddStep("create content", () =>
|
AddStep("create content", () =>
|
||||||
{
|
{
|
||||||
Child = new PopupScreenTitle
|
Child = new ShearedOverlayHeader
|
||||||
{
|
{
|
||||||
Title = "Popup Screen Title",
|
Title = "Sheared overlay header",
|
||||||
Description = string.Join(" ", Enumerable.Repeat("This is a description.", 20)),
|
Description = string.Join(" ", Enumerable.Repeat("This is a description.", 20)),
|
||||||
Close = () => { }
|
Close = () => { }
|
||||||
};
|
};
|
||||||
@ -34,9 +34,9 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
AddStep("create content", () =>
|
AddStep("create content", () =>
|
||||||
{
|
{
|
||||||
Child = new PopupScreenTitle
|
Child = new ShearedOverlayHeader
|
||||||
{
|
{
|
||||||
Title = "Popup Screen Title",
|
Title = "Sheared overlay header",
|
||||||
Description = "This is a description."
|
Description = "This is a description."
|
||||||
};
|
};
|
||||||
});
|
});
|
@ -158,7 +158,7 @@ namespace osu.Game.Collections
|
|||||||
public Func<Vector2, bool> IsTextBoxHovered;
|
public Func<Vector2, bool> IsTextBoxHovered;
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private DialogOverlay dialogOverlay { get; set; }
|
private IDialogOverlay dialogOverlay { get; set; }
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private CollectionManager collectionManager { get; set; }
|
private CollectionManager collectionManager { get; set; }
|
||||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Database
|
|||||||
private OsuConfigManager config { get; set; } = null!;
|
private OsuConfigManager config { get; set; } = null!;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private NotificationOverlay notificationOverlay { get; set; } = null!;
|
private INotificationOverlay notificationOverlay { get; set; } = null!;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuGame game { get; set; } = null!;
|
private OsuGame game { get; set; } = null!;
|
||||||
|
@ -40,7 +40,7 @@ namespace osu.Game.Database
|
|||||||
private OsuGame game { get; set; }
|
private OsuGame game { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private DialogOverlay dialogOverlay { get; set; }
|
private IDialogOverlay dialogOverlay { get; set; }
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private DesktopGameHost desktopGameHost { get; set; }
|
private DesktopGameHost desktopGameHost { get; set; }
|
||||||
|
@ -43,7 +43,7 @@ namespace osu.Game.Graphics
|
|||||||
private Storage storage;
|
private Storage storage;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private NotificationOverlay notificationOverlay { get; set; }
|
private INotificationOverlay notificationOverlay { get; set; }
|
||||||
|
|
||||||
private Sample shutter;
|
private Sample shutter;
|
||||||
|
|
||||||
|
@ -19,8 +19,10 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
public class PopupScreenTitle : CompositeDrawable
|
public class ShearedOverlayHeader : CompositeDrawable
|
||||||
{
|
{
|
||||||
|
public const float HEIGHT = main_area_height + 2 * corner_radius;
|
||||||
|
|
||||||
public LocalisableString Title
|
public LocalisableString Title
|
||||||
{
|
{
|
||||||
set => titleSpriteText.Text = value;
|
set => titleSpriteText.Text = value;
|
||||||
@ -48,7 +50,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
private readonly OsuTextFlowContainer descriptionText;
|
private readonly OsuTextFlowContainer descriptionText;
|
||||||
private readonly IconButton closeButton;
|
private readonly IconButton closeButton;
|
||||||
|
|
||||||
public PopupScreenTitle()
|
public ShearedOverlayHeader()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
@ -67,7 +69,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
underlayContainer = new Container
|
underlayContainer = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Height = main_area_height + 2 * corner_radius,
|
Height = HEIGHT,
|
||||||
CornerRadius = corner_radius,
|
CornerRadius = corner_radius,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
BorderThickness = 2,
|
BorderThickness = 2,
|
30
osu.Game/Localisation/DebugLocalisationStore.cs
Normal file
30
osu.Game/Localisation/DebugLocalisationStore.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
|
||||||
|
namespace osu.Game.Localisation
|
||||||
|
{
|
||||||
|
public class DebugLocalisationStore : ILocalisationStore
|
||||||
|
{
|
||||||
|
public string Get(string lookup) => $@"[[{lookup.Substring(lookup.LastIndexOf('.') + 1)}]]";
|
||||||
|
|
||||||
|
public Task<string> GetAsync(string lookup, CancellationToken cancellationToken = default) => Task.FromResult(Get(lookup));
|
||||||
|
|
||||||
|
public Stream GetStream(string name) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public IEnumerable<string> GetAvailableResources() => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public CultureInfo EffectiveCulture { get; } = CultureInfo.CurrentCulture;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -110,6 +110,11 @@ namespace osu.Game.Localisation
|
|||||||
// zh_hk,
|
// zh_hk,
|
||||||
|
|
||||||
[Description(@"繁體中文(台灣)")]
|
[Description(@"繁體中文(台灣)")]
|
||||||
zh_hant
|
zh_hant,
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
[Description(@"Debug (show raw keys)")]
|
||||||
|
debug
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,8 @@ namespace osu.Game.Online.API.Requests
|
|||||||
|
|
||||||
private readonly BeatmapSetType type;
|
private readonly BeatmapSetType type;
|
||||||
|
|
||||||
public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int page = 0, int itemsPerPage = 6)
|
public GetUserBeatmapsRequest(long userId, BeatmapSetType type, PaginationParameters pagination)
|
||||||
: base(page, itemsPerPage)
|
: base(pagination)
|
||||||
{
|
{
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
@ -10,8 +10,8 @@ namespace osu.Game.Online.API.Requests
|
|||||||
{
|
{
|
||||||
private readonly long userId;
|
private readonly long userId;
|
||||||
|
|
||||||
public GetUserKudosuHistoryRequest(long userId, int page = 0, int itemsPerPage = 5)
|
public GetUserKudosuHistoryRequest(long userId, PaginationParameters pagination)
|
||||||
: base(page, itemsPerPage)
|
: base(pagination)
|
||||||
{
|
{
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,8 @@ namespace osu.Game.Online.API.Requests
|
|||||||
{
|
{
|
||||||
private readonly long userId;
|
private readonly long userId;
|
||||||
|
|
||||||
public GetUserMostPlayedBeatmapsRequest(long userId, int page = 0, int itemsPerPage = 5)
|
public GetUserMostPlayedBeatmapsRequest(long userId, PaginationParameters pagination)
|
||||||
: base(page, itemsPerPage)
|
: base(pagination)
|
||||||
{
|
{
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,8 @@ namespace osu.Game.Online.API.Requests
|
|||||||
{
|
{
|
||||||
private readonly long userId;
|
private readonly long userId;
|
||||||
|
|
||||||
public GetUserRecentActivitiesRequest(long userId, int page = 0, int itemsPerPage = 5)
|
public GetUserRecentActivitiesRequest(long userId, PaginationParameters pagination)
|
||||||
: base(page, itemsPerPage)
|
: base(pagination)
|
||||||
{
|
{
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,8 @@ namespace osu.Game.Online.API.Requests
|
|||||||
private readonly ScoreType type;
|
private readonly ScoreType type;
|
||||||
private readonly RulesetInfo ruleset;
|
private readonly RulesetInfo ruleset;
|
||||||
|
|
||||||
public GetUserScoresRequest(long userId, ScoreType type, int page = 0, int itemsPerPage = 5, RulesetInfo ruleset = null)
|
public GetUserScoresRequest(long userId, ScoreType type, PaginationParameters pagination, RulesetInfo ruleset = null)
|
||||||
: base(page, itemsPerPage)
|
: base(pagination)
|
||||||
{
|
{
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
@ -8,21 +8,19 @@ namespace osu.Game.Online.API.Requests
|
|||||||
{
|
{
|
||||||
public abstract class PaginatedAPIRequest<T> : APIRequest<T> where T : class
|
public abstract class PaginatedAPIRequest<T> : APIRequest<T> where T : class
|
||||||
{
|
{
|
||||||
private readonly int page;
|
private readonly PaginationParameters pagination;
|
||||||
private readonly int itemsPerPage;
|
|
||||||
|
|
||||||
protected PaginatedAPIRequest(int page, int itemsPerPage)
|
protected PaginatedAPIRequest(PaginationParameters pagination)
|
||||||
{
|
{
|
||||||
this.page = page;
|
this.pagination = pagination;
|
||||||
this.itemsPerPage = itemsPerPage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override WebRequest CreateWebRequest()
|
protected override WebRequest CreateWebRequest()
|
||||||
{
|
{
|
||||||
var req = base.CreateWebRequest();
|
var req = base.CreateWebRequest();
|
||||||
|
|
||||||
req.AddParameter("offset", (page * itemsPerPage).ToString(CultureInfo.InvariantCulture));
|
req.AddParameter("offset", pagination.Offset.ToString(CultureInfo.InvariantCulture));
|
||||||
req.AddParameter("limit", itemsPerPage.ToString(CultureInfo.InvariantCulture));
|
req.AddParameter("limit", pagination.Limit.ToString(CultureInfo.InvariantCulture));
|
||||||
|
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
38
osu.Game/Online/API/Requests/PaginationParameters.cs
Normal file
38
osu.Game/Online/API/Requests/PaginationParameters.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace osu.Game.Online.API.Requests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a pagination data used for <see cref="PaginatedAPIRequest{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct PaginationParameters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The starting point of the request.
|
||||||
|
/// </summary>
|
||||||
|
public int Offset { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum number of items to return in this request.
|
||||||
|
/// </summary>
|
||||||
|
public int Limit { get; }
|
||||||
|
|
||||||
|
public PaginationParameters(int offset, int limit)
|
||||||
|
{
|
||||||
|
Offset = offset;
|
||||||
|
Limit = limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PaginationParameters(int limit)
|
||||||
|
: this(0, limit)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a <see cref="PaginationParameters"/> of the next number of items defined by <paramref name="limit"/> after this.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="limit">The limit of the next pagination.</param>
|
||||||
|
public PaginationParameters TakeNext(int limit) => new PaginationParameters(Offset + Limit, limit);
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,7 @@ namespace osu.Game.Online.Chat
|
|||||||
private GameHost host { get; set; }
|
private GameHost host { get; set; }
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private DialogOverlay dialogOverlay { get; set; }
|
private IDialogOverlay dialogOverlay { get; set; }
|
||||||
|
|
||||||
private Bindable<bool> externalLinkWarning;
|
private Bindable<bool> externalLinkWarning;
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Online.Chat
|
|||||||
public class MessageNotifier : Component
|
public class MessageNotifier : Component
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private NotificationOverlay notifications { get; set; }
|
private INotificationOverlay notifications { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private ChatOverlay chatOverlay { get; set; }
|
private ChatOverlay chatOverlay { get; set; }
|
||||||
@ -170,7 +170,7 @@ namespace osu.Game.Online.Chat
|
|||||||
public override bool IsImportant => false;
|
public override bool IsImportant => false;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours, ChatOverlay chatOverlay, NotificationOverlay notificationOverlay)
|
private void load(OsuColour colours, ChatOverlay chatOverlay, INotificationOverlay notificationOverlay)
|
||||||
{
|
{
|
||||||
IconBackground.Colour = colours.PurpleDark;
|
IconBackground.Colour = colours.PurpleDark;
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
private List<ScoreComponentLabel> statisticsLabels;
|
private List<ScoreComponentLabel> statisticsLabels;
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private DialogOverlay dialogOverlay { get; set; }
|
private IDialogOverlay dialogOverlay { get; set; }
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private SongSelect songSelect { get; set; }
|
private SongSelect songSelect { get; set; }
|
||||||
|
@ -63,7 +63,7 @@ namespace osu.Game
|
|||||||
/// The full osu! experience. Builds on top of <see cref="OsuGameBase"/> to add menus and binding logic
|
/// The full osu! experience. Builds on top of <see cref="OsuGameBase"/> to add menus and binding logic
|
||||||
/// for initial components that are generally retrieved via DI.
|
/// for initial components that are generally retrieved via DI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OsuGame : OsuGameBase, IKeyBindingHandler<GlobalAction>, ILocalUserPlayInfo
|
public class OsuGame : OsuGameBase, IKeyBindingHandler<GlobalAction>, ILocalUserPlayInfo, IPerformFromScreenRunner
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of global offset to apply when a left/right anchored overlay is displayed (ie. settings or notifications).
|
/// The amount of global offset to apply when a left/right anchored overlay is displayed (ie. settings or notifications).
|
||||||
@ -586,12 +586,6 @@ namespace osu.Game
|
|||||||
|
|
||||||
private PerformFromMenuRunner performFromMainMenuTask;
|
private PerformFromMenuRunner performFromMainMenuTask;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Perform an action only after returning to a specific screen as indicated by <paramref name="validScreens"/>.
|
|
||||||
/// Eagerly tries to exit the current screen until it succeeds.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">The action to perform once we are in the correct state.</param>
|
|
||||||
/// <param name="validScreens">An optional collection of valid screen types. If any of these screens are already current we can perform the action immediately, else the first valid parent will be made current before performing the action. <see cref="MainMenu"/> is used if not specified.</param>
|
|
||||||
public void PerformFromScreen(Action<IScreen> action, IEnumerable<Type> validScreens = null)
|
public void PerformFromScreen(Action<IScreen> action, IEnumerable<Type> validScreens = null)
|
||||||
{
|
{
|
||||||
performFromMainMenuTask?.Cancel();
|
performFromMainMenuTask?.Cancel();
|
||||||
@ -634,6 +628,14 @@ namespace osu.Game
|
|||||||
|
|
||||||
foreach (var language in Enum.GetValues(typeof(Language)).OfType<Language>())
|
foreach (var language in Enum.GetValues(typeof(Language)).OfType<Language>())
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
|
if (language == Language.debug)
|
||||||
|
{
|
||||||
|
Localisation.AddLanguage(Language.debug.ToString(), new DebugLocalisationStore());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
string cultureCode = language.ToCultureCode();
|
string cultureCode = language.ToCultureCode();
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -778,7 +780,7 @@ namespace osu.Game
|
|||||||
|
|
||||||
loadComponentSingleFile(onScreenDisplay, Add, true);
|
loadComponentSingleFile(onScreenDisplay, Add, true);
|
||||||
|
|
||||||
loadComponentSingleFile(Notifications.With(d =>
|
loadComponentSingleFile<INotificationOverlay>(Notifications.With(d =>
|
||||||
{
|
{
|
||||||
d.Anchor = Anchor.TopRight;
|
d.Anchor = Anchor.TopRight;
|
||||||
d.Origin = Anchor.TopRight;
|
d.Origin = Anchor.TopRight;
|
||||||
@ -825,7 +827,7 @@ namespace osu.Game
|
|||||||
}, rightFloatingOverlayContent.Add, true);
|
}, rightFloatingOverlayContent.Add, true);
|
||||||
|
|
||||||
loadComponentSingleFile(new AccountCreationOverlay(), topMostOverlayContent.Add, true);
|
loadComponentSingleFile(new AccountCreationOverlay(), topMostOverlayContent.Add, true);
|
||||||
loadComponentSingleFile(new DialogOverlay(), topMostOverlayContent.Add, true);
|
loadComponentSingleFile<IDialogOverlay>(new DialogOverlay(), topMostOverlayContent.Add, true);
|
||||||
|
|
||||||
loadComponentSingleFile(CreateHighPerformanceSession(), Add);
|
loadComponentSingleFile(CreateHighPerformanceSession(), Add);
|
||||||
|
|
||||||
@ -982,12 +984,14 @@ namespace osu.Game
|
|||||||
/// <param name="component">The component to load.</param>
|
/// <param name="component">The component to load.</param>
|
||||||
/// <param name="loadCompleteAction">An action to invoke on load completion (generally to add the component to the hierarchy).</param>
|
/// <param name="loadCompleteAction">An action to invoke on load completion (generally to add the component to the hierarchy).</param>
|
||||||
/// <param name="cache">Whether to cache the component as type <typeparamref name="T"/> into the game dependencies before any scheduling.</param>
|
/// <param name="cache">Whether to cache the component as type <typeparamref name="T"/> into the game dependencies before any scheduling.</param>
|
||||||
private T loadComponentSingleFile<T>(T component, Action<T> loadCompleteAction, bool cache = false)
|
private T loadComponentSingleFile<T>(T component, Action<Drawable> loadCompleteAction, bool cache = false)
|
||||||
where T : Drawable
|
where T : class
|
||||||
{
|
{
|
||||||
if (cache)
|
if (cache)
|
||||||
dependencies.CacheAs(component);
|
dependencies.CacheAs(component);
|
||||||
|
|
||||||
|
var drawableComponent = component as Drawable ?? throw new ArgumentException($"Component must be a {nameof(Drawable)}", nameof(component));
|
||||||
|
|
||||||
if (component is OsuFocusedOverlayContainer overlay)
|
if (component is OsuFocusedOverlayContainer overlay)
|
||||||
focusedOverlays.Add(overlay);
|
focusedOverlays.Add(overlay);
|
||||||
|
|
||||||
@ -1011,7 +1015,7 @@ namespace osu.Game
|
|||||||
// Since this is running in a separate thread, it is possible for OsuGame to be disposed after LoadComponentAsync has been called
|
// Since this is running in a separate thread, it is possible for OsuGame to be disposed after LoadComponentAsync has been called
|
||||||
// throwing an exception. To avoid this, the call is scheduled on the update thread, which does not run if IsDisposed = true
|
// throwing an exception. To avoid this, the call is scheduled on the update thread, which does not run if IsDisposed = true
|
||||||
Task task = null;
|
Task task = null;
|
||||||
var del = new ScheduledDelegate(() => task = LoadComponentAsync(component, loadCompleteAction));
|
var del = new ScheduledDelegate(() => task = LoadComponentAsync(drawableComponent, loadCompleteAction));
|
||||||
Scheduler.Add(del);
|
Scheduler.Add(del);
|
||||||
|
|
||||||
// The delegate won't complete if OsuGame has been disposed in the meantime
|
// The delegate won't complete if OsuGame has been disposed in the meantime
|
||||||
|
@ -41,7 +41,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(IAPIProvider api, NotificationOverlay notifications)
|
private void load(IAPIProvider api, INotificationOverlay notifications)
|
||||||
{
|
{
|
||||||
SpriteIcon icon;
|
SpriteIcon icon;
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ using osu.Game.Database;
|
|||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.Spectator;
|
using osu.Game.Online.Spectator;
|
||||||
|
using osu.Game.Screens;
|
||||||
using osu.Game.Screens.OnlinePlay.Match.Components;
|
using osu.Game.Screens.OnlinePlay.Match.Components;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
@ -106,7 +107,7 @@ namespace osu.Game.Overlays.Dashboard
|
|||||||
public readonly APIUser User;
|
public readonly APIUser User;
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private OsuGame game { get; set; }
|
private IPerformFromScreenRunner performer { get; set; }
|
||||||
|
|
||||||
public PlayingUserPanel(APIUser user)
|
public PlayingUserPanel(APIUser user)
|
||||||
{
|
{
|
||||||
@ -140,7 +141,7 @@ namespace osu.Game.Overlays.Dashboard
|
|||||||
Text = "Watch",
|
Text = "Watch",
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
Action = () => game?.PerformFromScreen(s => s.Push(new SoloSpectator(User))),
|
Action = () => performer?.PerformFromScreen(s => s.Push(new SoloSpectator(User))),
|
||||||
Enabled = { Value = User.Id != api.LocalUser.Value.Id }
|
Enabled = { Value = User.Id != api.LocalUser.Value.Id }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ namespace osu.Game.Overlays.Dialog
|
|||||||
};
|
};
|
||||||
|
|
||||||
// It's important we start in a visible state so our state fires on hide, even before load.
|
// It's important we start in a visible state so our state fires on hide, even before load.
|
||||||
// This is used by the DialogOverlay to know when the dialog was dismissed.
|
// This is used by the dialog overlay to know when the dialog was dismissed.
|
||||||
Show();
|
Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ using osu.Game.Audio.Effects;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
public class DialogOverlay : OsuFocusedOverlayContainer
|
public class DialogOverlay : OsuFocusedOverlayContainer, IDialogOverlay
|
||||||
{
|
{
|
||||||
private readonly Container dialogContainer;
|
private readonly Container dialogContainer;
|
||||||
|
|
||||||
|
32
osu.Game/Overlays/IDialogOverlay.cs
Normal file
32
osu.Game/Overlays/IDialogOverlay.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Overlays.Dialog;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A global overlay that can show popup dialogs.
|
||||||
|
/// </summary>
|
||||||
|
[Cached(typeof(IDialogOverlay))]
|
||||||
|
public interface IDialogOverlay
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Push a new dialog for display.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This will immediate dismiss any already displayed dialog (cancelling the action).
|
||||||
|
/// If the dialog instance provided is already displayed, it will be a noop.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="dialog">The dialog to be presented.</param>
|
||||||
|
void Push(PopupDialog dialog);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The currently displayed dialog, if any.
|
||||||
|
/// </summary>
|
||||||
|
PopupDialog? CurrentDialog { get; }
|
||||||
|
}
|
||||||
|
}
|
32
osu.Game/Overlays/INotificationOverlay.cs
Normal file
32
osu.Game/Overlays/INotificationOverlay.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Overlays.Notifications;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An overlay which is capable of showing notifications to the user.
|
||||||
|
/// </summary>
|
||||||
|
[Cached]
|
||||||
|
public interface INotificationOverlay
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Post a new notification for display.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="notification">The notification to display.</param>
|
||||||
|
void Post(Notification notification);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hide the overlay, if it is currently visible.
|
||||||
|
/// </summary>
|
||||||
|
void Hide();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current number of unread notifications.
|
||||||
|
/// </summary>
|
||||||
|
IBindable<int> UnreadCount { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
AutoSizeAxes = Axes.X,
|
AutoSizeAxes = Axes.X,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
CornerRadius = ModPanel.CORNER_RADIUS,
|
CornerRadius = ModPanel.CORNER_RADIUS,
|
||||||
Shear = new Vector2(ModPanel.SHEAR_X, 0),
|
Shear = new Vector2(ShearedOverlayContainer.SHEAR, 0),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
underlayBackground = new Box
|
underlayBackground = new Box
|
||||||
@ -98,7 +98,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Margin = new MarginPadding { Horizontal = 18 },
|
Margin = new MarginPadding { Horizontal = 18 },
|
||||||
Shear = new Vector2(-ModPanel.SHEAR_X, 0),
|
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0),
|
||||||
Text = "Difficulty Multiplier",
|
Text = "Difficulty Multiplier",
|
||||||
Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold)
|
Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold)
|
||||||
}
|
}
|
||||||
@ -109,7 +109,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Shear = new Vector2(-ModPanel.SHEAR_X, 0),
|
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0),
|
||||||
Direction = FillDirection.Horizontal,
|
Direction = FillDirection.Horizontal,
|
||||||
Spacing = new Vector2(2, 0),
|
Spacing = new Vector2(2, 0),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
|
@ -81,7 +81,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
Width = 320;
|
Width = 320;
|
||||||
RelativeSizeAxes = Axes.Y;
|
RelativeSizeAxes = Axes.Y;
|
||||||
Shear = new Vector2(ModPanel.SHEAR_X, 0);
|
Shear = new Vector2(ShearedOverlayContainer.SHEAR, 0);
|
||||||
|
|
||||||
Container controlContainer;
|
Container controlContainer;
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
@ -115,7 +115,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Shear = new Vector2(-ModPanel.SHEAR_X, 0),
|
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0),
|
||||||
Padding = new MarginPadding
|
Padding = new MarginPadding
|
||||||
{
|
{
|
||||||
Horizontal = 17,
|
Horizontal = 17,
|
||||||
@ -195,7 +195,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
Scale = new Vector2(0.8f),
|
Scale = new Vector2(0.8f),
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
LabelText = "Enable All",
|
LabelText = "Enable All",
|
||||||
Shear = new Vector2(-ModPanel.SHEAR_X, 0)
|
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0)
|
||||||
});
|
});
|
||||||
panelFlow.Padding = new MarginPadding
|
panelFlow.Padding = new MarginPadding
|
||||||
{
|
{
|
||||||
@ -260,7 +260,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
cancellationTokenSource?.Cancel();
|
cancellationTokenSource?.Cancel();
|
||||||
|
|
||||||
var panels = newMods.Select(mod => CreateModPanel(mod).With(panel => panel.Shear = new Vector2(-ModPanel.SHEAR_X, 0)));
|
var panels = newMods.Select(mod => CreateModPanel(mod).With(panel => panel.Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0)));
|
||||||
|
|
||||||
Task? loadTask;
|
Task? loadTask;
|
||||||
|
|
||||||
|
@ -42,7 +42,6 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
protected const double TRANSITION_DURATION = 150;
|
protected const double TRANSITION_DURATION = 150;
|
||||||
|
|
||||||
public const float SHEAR_X = 0.2f;
|
|
||||||
public const float CORNER_RADIUS = 7;
|
public const float CORNER_RADIUS = 7;
|
||||||
|
|
||||||
protected const float HEIGHT = 42;
|
protected const float HEIGHT = 42;
|
||||||
@ -67,7 +66,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
Content.Masking = true;
|
Content.Masking = true;
|
||||||
Content.CornerRadius = CORNER_RADIUS;
|
Content.CornerRadius = CORNER_RADIUS;
|
||||||
Content.BorderThickness = 2;
|
Content.BorderThickness = 2;
|
||||||
Content.Shear = new Vector2(SHEAR_X, 0);
|
Content.Shear = new Vector2(ShearedOverlayContainer.SHEAR, 0);
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -83,7 +82,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Active = { BindTarget = Active },
|
Active = { BindTarget = Active },
|
||||||
Shear = new Vector2(-SHEAR_X, 0),
|
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0),
|
||||||
Scale = new Vector2(HEIGHT / ModSwitchSmall.DEFAULT_SIZE)
|
Scale = new Vector2(HEIGHT / ModSwitchSmall.DEFAULT_SIZE)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -116,10 +115,10 @@ namespace osu.Game.Overlays.Mods
|
|||||||
{
|
{
|
||||||
Text = mod.Name,
|
Text = mod.Name,
|
||||||
Font = OsuFont.TorusAlternate.With(size: 18, weight: FontWeight.SemiBold),
|
Font = OsuFont.TorusAlternate.With(size: 18, weight: FontWeight.SemiBold),
|
||||||
Shear = new Vector2(-SHEAR_X, 0),
|
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0),
|
||||||
Margin = new MarginPadding
|
Margin = new MarginPadding
|
||||||
{
|
{
|
||||||
Left = -18 * SHEAR_X
|
Left = -18 * ShearedOverlayContainer.SHEAR
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new OsuSpriteText
|
new OsuSpriteText
|
||||||
@ -128,7 +127,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
Font = OsuFont.Default.With(size: 12),
|
Font = OsuFont.Default.With(size: 12),
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Truncate = true,
|
Truncate = true,
|
||||||
Shear = new Vector2(-SHEAR_X, 0)
|
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Layout;
|
using osu.Framework.Layout;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
@ -23,16 +22,13 @@ using osuTK.Input;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays.Mods
|
namespace osu.Game.Overlays.Mods
|
||||||
{
|
{
|
||||||
public abstract class ModSelectScreen : OsuFocusedOverlayContainer
|
public abstract class ModSelectScreen : ShearedOverlayContainer
|
||||||
{
|
{
|
||||||
[Cached]
|
protected override OverlayColourScheme ColourScheme => OverlayColourScheme.Green;
|
||||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
public Bindable<IReadOnlyList<Mod>> SelectedMods { get; private set; } = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
public Bindable<IReadOnlyList<Mod>> SelectedMods { get; private set; } = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||||
|
|
||||||
protected override bool StartHidden => true;
|
|
||||||
|
|
||||||
private Func<Mod, bool> isValidMod = m => true;
|
private Func<Mod, bool> isValidMod = m => true;
|
||||||
|
|
||||||
public Func<Mod, bool> IsValidMod
|
public Func<Mod, bool> IsValidMod
|
||||||
@ -63,132 +59,21 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
private DifficultyMultiplierDisplay? multiplierDisplay;
|
private DifficultyMultiplierDisplay? multiplierDisplay;
|
||||||
private ModSettingsArea modSettingsArea = null!;
|
private ModSettingsArea modSettingsArea = null!;
|
||||||
private Container aboveColumnsContainer = null!;
|
|
||||||
private FillFlowContainer<ModColumn> columnFlow = null!;
|
private FillFlowContainer<ModColumn> columnFlow = null!;
|
||||||
private GridContainer grid = null!;
|
|
||||||
private Container mainContent = null!;
|
|
||||||
|
|
||||||
private PopupScreenTitle header = null!;
|
|
||||||
private Container footer = null!;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
Header.Title = "Mod Select";
|
||||||
RelativePositionAxes = Axes.Both;
|
Header.Description = "Mods provide different ways to enjoy gameplay. Some have an effect on the score you can achieve during ranked play. Others are just for fun.";
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
mainContent = new Container
|
new ClickToReturnContainer
|
||||||
{
|
{
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
HandleMouse = { BindTarget = customisationVisible },
|
||||||
{
|
OnClicked = () => customisationVisible.Value = false
|
||||||
grid = new GridContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
RowDimensions = new[]
|
|
||||||
{
|
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
|
||||||
new Dimension(),
|
|
||||||
new Dimension(GridSizeMode.Absolute, 75),
|
|
||||||
},
|
|
||||||
Content = new[]
|
|
||||||
{
|
|
||||||
new Drawable[]
|
|
||||||
{
|
|
||||||
header = new PopupScreenTitle
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
Title = "Mod Select",
|
|
||||||
Description = "Mods provide different ways to enjoy gameplay. Some have an effect on the score you can achieve during ranked play. Others are just for fun.",
|
|
||||||
Close = Hide
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new Drawable[]
|
|
||||||
{
|
|
||||||
aboveColumnsContainer = new Container
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
AutoSizeAxes = Axes.X,
|
|
||||||
RelativePositionAxes = Axes.X,
|
|
||||||
X = 0.3f,
|
|
||||||
Height = DifficultyMultiplierDisplay.HEIGHT,
|
|
||||||
Margin = new MarginPadding
|
|
||||||
{
|
|
||||||
Horizontal = 100,
|
|
||||||
Vertical = 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new Drawable[]
|
|
||||||
{
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
Depth = float.MaxValue,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
RelativePositionAxes = Axes.Both,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new OsuScrollContainer(Direction.Horizontal)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Masking = false,
|
|
||||||
ClampExtension = 100,
|
|
||||||
ScrollbarOverlapsContent = false,
|
|
||||||
Child = columnFlow = new ModColumnContainer
|
|
||||||
{
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
AutoSizeAxes = Axes.X,
|
|
||||||
Spacing = new Vector2(10, 0),
|
|
||||||
Margin = new MarginPadding { Right = 70 },
|
|
||||||
Children = new[]
|
|
||||||
{
|
|
||||||
CreateModColumn(ModType.DifficultyReduction, new[] { Key.Q, Key.W, Key.E, Key.R, Key.T, Key.Y, Key.U, Key.I, Key.O, Key.P }),
|
|
||||||
CreateModColumn(ModType.DifficultyIncrease, new[] { Key.A, Key.S, Key.D, Key.F, Key.G, Key.H, Key.J, Key.K, Key.L }),
|
|
||||||
CreateModColumn(ModType.Automation, new[] { Key.Z, Key.X, Key.C, Key.V, Key.B, Key.N, Key.M }),
|
|
||||||
CreateModColumn(ModType.Conversion),
|
|
||||||
CreateModColumn(ModType.Fun)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new[] { Empty() }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
footer = new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 50,
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Colour = colourProvider.Background5
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new ClickToReturnContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
HandleMouse = { BindTarget = customisationVisible },
|
|
||||||
OnClicked = () => customisationVisible.Value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
modSettingsArea = new ModSettingsArea
|
modSettingsArea = new ModSettingsArea
|
||||||
{
|
{
|
||||||
@ -196,30 +81,73 @@ namespace osu.Game.Overlays.Mods
|
|||||||
Origin = Anchor.BottomCentre,
|
Origin = Anchor.BottomCentre,
|
||||||
Height = 0
|
Height = 0
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if (AllowConfiguration)
|
MainAreaContent.AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
footer.Add(new ShearedToggleButton(200)
|
new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.BottomLeft,
|
Origin = Anchor.TopRight,
|
||||||
Margin = new MarginPadding { Vertical = 14, Left = 70 },
|
AutoSizeAxes = Axes.X,
|
||||||
Text = "Mod Customisation",
|
Height = DifficultyMultiplierDisplay.HEIGHT,
|
||||||
Active = { BindTarget = customisationVisible }
|
Margin = new MarginPadding
|
||||||
});
|
{
|
||||||
}
|
Horizontal = 100,
|
||||||
|
},
|
||||||
|
Child = multiplierDisplay = new DifficultyMultiplierDisplay
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Padding = new MarginPadding
|
||||||
|
{
|
||||||
|
Top = DifficultyMultiplierDisplay.HEIGHT + PADDING,
|
||||||
|
},
|
||||||
|
Depth = float.MaxValue,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
RelativePositionAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuScrollContainer(Direction.Horizontal)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = false,
|
||||||
|
ClampExtension = 100,
|
||||||
|
ScrollbarOverlapsContent = false,
|
||||||
|
Child = columnFlow = new ModColumnContainer
|
||||||
|
{
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Shear = new Vector2(SHEAR, 0),
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Spacing = new Vector2(10, 0),
|
||||||
|
Margin = new MarginPadding { Right = 70 },
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
CreateModColumn(ModType.DifficultyReduction, new[] { Key.Q, Key.W, Key.E, Key.R, Key.T, Key.Y, Key.U, Key.I, Key.O, Key.P }),
|
||||||
|
CreateModColumn(ModType.DifficultyIncrease, new[] { Key.A, Key.S, Key.D, Key.F, Key.G, Key.H, Key.J, Key.K, Key.L }),
|
||||||
|
CreateModColumn(ModType.Automation, new[] { Key.Z, Key.X, Key.C, Key.V, Key.B, Key.N, Key.M }),
|
||||||
|
CreateModColumn(ModType.Conversion),
|
||||||
|
CreateModColumn(ModType.Fun)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (ShowTotalMultiplier)
|
Footer.Add(new ShearedToggleButton(200)
|
||||||
{
|
{
|
||||||
aboveColumnsContainer.Add(multiplierDisplay = new DifficultyMultiplierDisplay
|
Anchor = Anchor.BottomLeft,
|
||||||
{
|
Origin = Anchor.BottomLeft,
|
||||||
Anchor = Anchor.CentreRight,
|
Margin = new MarginPadding { Vertical = PADDING, Left = 70 },
|
||||||
Origin = Anchor.CentreRight
|
Text = "Mod Customisation",
|
||||||
});
|
Active = { BindTarget = customisationVisible }
|
||||||
}
|
});
|
||||||
|
|
||||||
columnFlow.Shear = new Vector2(ModPanel.SHEAR_X, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -298,12 +226,12 @@ namespace osu.Game.Overlays.Mods
|
|||||||
{
|
{
|
||||||
const double transition_duration = 300;
|
const double transition_duration = 300;
|
||||||
|
|
||||||
grid.FadeColour(customisationVisible.Value ? Colour4.Gray : Colour4.White, transition_duration, Easing.InOutCubic);
|
MainAreaContent.FadeColour(customisationVisible.Value ? Colour4.Gray : Colour4.White, transition_duration, Easing.InOutCubic);
|
||||||
|
|
||||||
float modAreaHeight = customisationVisible.Value ? ModSettingsArea.HEIGHT : 0;
|
float modAreaHeight = customisationVisible.Value ? ModSettingsArea.HEIGHT : 0;
|
||||||
|
|
||||||
modSettingsArea.ResizeHeightTo(modAreaHeight, transition_duration, Easing.InOutCubic);
|
modSettingsArea.ResizeHeightTo(modAreaHeight, transition_duration, Easing.InOutCubic);
|
||||||
mainContent.TransformTo(nameof(Margin), new MarginPadding { Bottom = modAreaHeight }, transition_duration, Easing.InOutCubic);
|
TopLevelContent.MoveToY(-modAreaHeight, transition_duration, Easing.InOutCubic);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool selectionBindableSyncInProgress;
|
private bool selectionBindableSyncInProgress;
|
||||||
@ -338,10 +266,6 @@ namespace osu.Game.Overlays.Mods
|
|||||||
const double fade_in_duration = 400;
|
const double fade_in_duration = 400;
|
||||||
|
|
||||||
base.PopIn();
|
base.PopIn();
|
||||||
this.FadeIn(fade_in_duration, Easing.OutQuint);
|
|
||||||
|
|
||||||
header.MoveToY(0, fade_in_duration, Easing.OutQuint);
|
|
||||||
footer.MoveToY(0, fade_in_duration, Easing.OutQuint);
|
|
||||||
|
|
||||||
multiplierDisplay?
|
multiplierDisplay?
|
||||||
.Delay(fade_in_duration * 0.65f)
|
.Delay(fade_in_duration * 0.65f)
|
||||||
@ -362,15 +286,11 @@ namespace osu.Game.Overlays.Mods
|
|||||||
const double fade_out_duration = 500;
|
const double fade_out_duration = 500;
|
||||||
|
|
||||||
base.PopOut();
|
base.PopOut();
|
||||||
this.FadeOut(fade_out_duration, Easing.OutQuint);
|
|
||||||
|
|
||||||
multiplierDisplay?
|
multiplierDisplay?
|
||||||
.FadeOut(fade_out_duration / 2, Easing.OutQuint)
|
.FadeOut(fade_out_duration / 2, Easing.OutQuint)
|
||||||
.ScaleTo(0.75f, fade_out_duration, Easing.OutQuint);
|
.ScaleTo(0.75f, fade_out_duration, Easing.OutQuint);
|
||||||
|
|
||||||
header.MoveToY(-header.DrawHeight, fade_out_duration, Easing.OutQuint);
|
|
||||||
footer.MoveToY(footer.DrawHeight, fade_out_duration, Easing.OutQuint);
|
|
||||||
|
|
||||||
for (int i = 0; i < columnFlow.Count; i++)
|
for (int i = 0; i < columnFlow.Count; i++)
|
||||||
{
|
{
|
||||||
const float distance = 700;
|
const float distance = 700;
|
||||||
@ -406,7 +326,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
{
|
{
|
||||||
Padding = new MarginPadding
|
Padding = new MarginPadding
|
||||||
{
|
{
|
||||||
Left = DrawHeight * ModPanel.SHEAR_X,
|
Left = DrawHeight * SHEAR,
|
||||||
Bottom = 10
|
Bottom = 10
|
||||||
};
|
};
|
||||||
|
|
||||||
|
138
osu.Game/Overlays/Mods/ShearedOverlayContainer.cs
Normal file
138
osu.Game/Overlays/Mods/ShearedOverlayContainer.cs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
// 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.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Mods
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A sheared overlay which provides a header and footer and basic animations.
|
||||||
|
/// Exposes <see cref="TopLevelContent"/>, <see cref="MainAreaContent"/> and <see cref="Footer"/> as valid targets for content.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ShearedOverlayContainer : OsuFocusedOverlayContainer
|
||||||
|
{
|
||||||
|
protected const float PADDING = 14;
|
||||||
|
|
||||||
|
public const float SHEAR = 0.2f;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
protected readonly OverlayColourProvider ColourProvider;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The overlay's header.
|
||||||
|
/// </summary>
|
||||||
|
protected ShearedOverlayHeader Header { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The overlay's footer.
|
||||||
|
/// </summary>
|
||||||
|
protected Container Footer { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A container containing all content, including the header and footer.
|
||||||
|
/// May be used for overlay-wide animations.
|
||||||
|
/// </summary>
|
||||||
|
protected Container TopLevelContent { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A container for content that is to be displayed between the header and footer.
|
||||||
|
/// </summary>
|
||||||
|
protected Container MainAreaContent { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A container for content that is to be displayed inside the footer.
|
||||||
|
/// </summary>
|
||||||
|
protected Container FooterContent { get; private set; }
|
||||||
|
|
||||||
|
protected abstract OverlayColourScheme ColourScheme { get; }
|
||||||
|
|
||||||
|
protected override bool StartHidden => true;
|
||||||
|
|
||||||
|
protected override bool BlockNonPositionalInput => true;
|
||||||
|
|
||||||
|
protected ShearedOverlayContainer()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
ColourProvider = new OverlayColourProvider(ColourScheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
const float footer_height = 50;
|
||||||
|
|
||||||
|
Child = TopLevelContent = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
Header = new ShearedOverlayHeader
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Depth = float.MinValue,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Close = Hide
|
||||||
|
},
|
||||||
|
MainAreaContent = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding
|
||||||
|
{
|
||||||
|
Top = ShearedOverlayHeader.HEIGHT,
|
||||||
|
Bottom = footer_height + PADDING,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Footer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Depth = float.MinValue,
|
||||||
|
Height = footer_height,
|
||||||
|
Margin = new MarginPadding { Top = PADDING },
|
||||||
|
Anchor = Anchor.BottomCentre,
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = ColourProvider.Background5
|
||||||
|
},
|
||||||
|
FooterContent = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopIn()
|
||||||
|
{
|
||||||
|
const double fade_in_duration = 400;
|
||||||
|
|
||||||
|
base.PopIn();
|
||||||
|
this.FadeIn(fade_in_duration, Easing.OutQuint);
|
||||||
|
|
||||||
|
Header.MoveToY(0, fade_in_duration, Easing.OutQuint);
|
||||||
|
Footer.MoveToY(0, fade_in_duration, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopOut()
|
||||||
|
{
|
||||||
|
const double fade_out_duration = 500;
|
||||||
|
|
||||||
|
base.PopOut();
|
||||||
|
this.FadeOut(fade_out_duration, Easing.OutQuint);
|
||||||
|
|
||||||
|
Header.MoveToY(-Header.DrawHeight, fade_out_duration, Easing.OutQuint);
|
||||||
|
Footer.MoveToY(Footer.DrawHeight, fade_out_duration, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,7 @@ using osu.Game.Localisation;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
public class NotificationOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent
|
public class NotificationOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent, INotificationOverlay
|
||||||
{
|
{
|
||||||
public string IconTexture => "Icons/Hexacons/notification";
|
public string IconTexture => "Icons/Hexacons/notification";
|
||||||
public LocalisableString Title => NotificationsStrings.HeaderTitle;
|
public LocalisableString Title => NotificationsStrings.HeaderTitle;
|
||||||
@ -99,7 +99,9 @@ namespace osu.Game.Overlays
|
|||||||
OverlayActivationMode.BindValueChanged(_ => updateProcessingMode(), true);
|
OverlayActivationMode.BindValueChanged(_ => updateProcessingMode(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly BindableInt UnreadCount = new BindableInt();
|
public IBindable<int> UnreadCount => unreadCount;
|
||||||
|
|
||||||
|
private readonly BindableInt unreadCount = new BindableInt();
|
||||||
|
|
||||||
private int runningDepth;
|
private int runningDepth;
|
||||||
|
|
||||||
@ -111,10 +113,6 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private double? lastSamplePlayback;
|
private double? lastSamplePlayback;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Post a new notification for display.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="notification">The notification to display.</param>
|
|
||||||
public void Post(Notification notification) => postScheduler.Add(() =>
|
public void Post(Notification notification) => postScheduler.Add(() =>
|
||||||
{
|
{
|
||||||
++runningDepth;
|
++runningDepth;
|
||||||
@ -184,7 +182,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private void updateCounts()
|
private void updateCounts()
|
||||||
{
|
{
|
||||||
UnreadCount.Value = sections.Select(c => c.UnreadCount).Sum();
|
unreadCount.Value = sections.Select(c => c.UnreadCount).Sum();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markAllRead()
|
private void markAllRead()
|
||||||
|
@ -20,11 +20,12 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps
|
|||||||
private const float panel_padding = 10f;
|
private const float panel_padding = 10f;
|
||||||
private readonly BeatmapSetType type;
|
private readonly BeatmapSetType type;
|
||||||
|
|
||||||
|
protected override int InitialItemsCount => type == BeatmapSetType.Graveyard ? 2 : 6;
|
||||||
|
|
||||||
public PaginatedBeatmapContainer(BeatmapSetType type, Bindable<APIUser> user, LocalisableString headerText)
|
public PaginatedBeatmapContainer(BeatmapSetType type, Bindable<APIUser> user, LocalisableString headerText)
|
||||||
: base(user, headerText)
|
: base(user, headerText)
|
||||||
{
|
{
|
||||||
this.type = type;
|
this.type = type;
|
||||||
ItemsPerPage = 6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -57,8 +58,8 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override APIRequest<List<APIBeatmapSet>> CreateRequest() =>
|
protected override APIRequest<List<APIBeatmapSet>> CreateRequest(PaginationParameters pagination) =>
|
||||||
new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
|
new GetUserBeatmapsRequest(User.Value.Id, type, pagination);
|
||||||
|
|
||||||
protected override Drawable CreateDrawableItem(APIBeatmapSet model) => model.OnlineID > 0
|
protected override Drawable CreateDrawableItem(APIBeatmapSet model) => model.OnlineID > 0
|
||||||
? new BeatmapCardNormal(model)
|
? new BeatmapCardNormal(model)
|
||||||
|
@ -19,7 +19,6 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
|
|||||||
public PaginatedMostPlayedBeatmapContainer(Bindable<APIUser> user)
|
public PaginatedMostPlayedBeatmapContainer(Bindable<APIUser> user)
|
||||||
: base(user, UsersStrings.ShowExtraHistoricalMostPlayedTitle)
|
: base(user, UsersStrings.ShowExtraHistoricalMostPlayedTitle)
|
||||||
{
|
{
|
||||||
ItemsPerPage = 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -30,8 +29,8 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
|
|||||||
|
|
||||||
protected override int GetCount(APIUser user) => user.BeatmapPlayCountsCount;
|
protected override int GetCount(APIUser user) => user.BeatmapPlayCountsCount;
|
||||||
|
|
||||||
protected override APIRequest<List<APIUserMostPlayedBeatmap>> CreateRequest() =>
|
protected override APIRequest<List<APIUserMostPlayedBeatmap>> CreateRequest(PaginationParameters pagination) =>
|
||||||
new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
|
new GetUserMostPlayedBeatmapsRequest(User.Value.Id, pagination);
|
||||||
|
|
||||||
protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap mostPlayed) =>
|
protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap mostPlayed) =>
|
||||||
new DrawableMostPlayedBeatmap(mostPlayed);
|
new DrawableMostPlayedBeatmap(mostPlayed);
|
||||||
|
@ -17,11 +17,10 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu
|
|||||||
public PaginatedKudosuHistoryContainer(Bindable<APIUser> user)
|
public PaginatedKudosuHistoryContainer(Bindable<APIUser> user)
|
||||||
: base(user, missingText: UsersStrings.ShowExtraKudosuEntryEmpty)
|
: base(user, missingText: UsersStrings.ShowExtraKudosuEntryEmpty)
|
||||||
{
|
{
|
||||||
ItemsPerPage = 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override APIRequest<List<APIKudosuHistory>> CreateRequest()
|
protected override APIRequest<List<APIKudosuHistory>> CreateRequest(PaginationParameters pagination)
|
||||||
=> new GetUserKudosuHistoryRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
|
=> new GetUserKudosuHistoryRequest(User.Value.Id, pagination);
|
||||||
|
|
||||||
protected override Drawable CreateDrawableItem(APIKudosuHistory item) => new DrawableKudosuHistoryItem(item);
|
protected override Drawable CreateDrawableItem(APIKudosuHistory item) => new DrawableKudosuHistoryItem(item);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ using osu.Game.Graphics.Sprites;
|
|||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -21,11 +22,20 @@ namespace osu.Game.Overlays.Profile.Sections
|
|||||||
{
|
{
|
||||||
public abstract class PaginatedProfileSubsection<TModel> : ProfileSubsection
|
public abstract class PaginatedProfileSubsection<TModel> : ProfileSubsection
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The number of items displayed per page.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual int ItemsPerPage => 50;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of items displayed initially.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual int InitialItemsCount => 5;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IAPIProvider api { get; set; }
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
protected int VisiblePages;
|
protected PaginationParameters? CurrentPage { get; private set; }
|
||||||
protected int ItemsPerPage;
|
|
||||||
|
|
||||||
protected ReverseChildIDFillFlowContainer<Drawable> ItemsContainer { get; private set; }
|
protected ReverseChildIDFillFlowContainer<Drawable> ItemsContainer { get; private set; }
|
||||||
|
|
||||||
@ -87,7 +97,7 @@ namespace osu.Game.Overlays.Profile.Sections
|
|||||||
loadCancellation?.Cancel();
|
loadCancellation?.Cancel();
|
||||||
retrievalRequest?.Cancel();
|
retrievalRequest?.Cancel();
|
||||||
|
|
||||||
VisiblePages = 0;
|
CurrentPage = null;
|
||||||
ItemsContainer.Clear();
|
ItemsContainer.Clear();
|
||||||
|
|
||||||
if (e.NewValue != null)
|
if (e.NewValue != null)
|
||||||
@ -101,7 +111,9 @@ namespace osu.Game.Overlays.Profile.Sections
|
|||||||
{
|
{
|
||||||
loadCancellation = new CancellationTokenSource();
|
loadCancellation = new CancellationTokenSource();
|
||||||
|
|
||||||
retrievalRequest = CreateRequest();
|
CurrentPage = CurrentPage?.TakeNext(ItemsPerPage) ?? new PaginationParameters(InitialItemsCount);
|
||||||
|
|
||||||
|
retrievalRequest = CreateRequest(CurrentPage.Value);
|
||||||
retrievalRequest.Success += UpdateItems;
|
retrievalRequest.Success += UpdateItems;
|
||||||
|
|
||||||
api.Queue(retrievalRequest);
|
api.Queue(retrievalRequest);
|
||||||
@ -111,7 +123,7 @@ namespace osu.Game.Overlays.Profile.Sections
|
|||||||
{
|
{
|
||||||
OnItemsReceived(items);
|
OnItemsReceived(items);
|
||||||
|
|
||||||
if (!items.Any() && VisiblePages == 1)
|
if (!items.Any() && CurrentPage?.Offset == 0)
|
||||||
{
|
{
|
||||||
moreButton.Hide();
|
moreButton.Hide();
|
||||||
moreButton.IsLoading = false;
|
moreButton.IsLoading = false;
|
||||||
@ -125,7 +137,8 @@ namespace osu.Game.Overlays.Profile.Sections
|
|||||||
LoadComponentsAsync(items.Select(CreateDrawableItem).Where(d => d != null), drawables =>
|
LoadComponentsAsync(items.Select(CreateDrawableItem).Where(d => d != null), drawables =>
|
||||||
{
|
{
|
||||||
missing.Hide();
|
missing.Hide();
|
||||||
moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0);
|
|
||||||
|
moreButton.FadeTo(items.Count == CurrentPage?.Limit ? 1 : 0);
|
||||||
moreButton.IsLoading = false;
|
moreButton.IsLoading = false;
|
||||||
|
|
||||||
ItemsContainer.AddRange(drawables);
|
ItemsContainer.AddRange(drawables);
|
||||||
@ -138,7 +151,7 @@ namespace osu.Game.Overlays.Profile.Sections
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract APIRequest<List<TModel>> CreateRequest();
|
protected abstract APIRequest<List<TModel>> CreateRequest(PaginationParameters pagination);
|
||||||
|
|
||||||
protected abstract Drawable CreateDrawableItem(TModel model);
|
protected abstract Drawable CreateDrawableItem(TModel model);
|
||||||
|
|
||||||
|
@ -23,8 +23,6 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
|||||||
: base(user, headerText)
|
: base(user, headerText)
|
||||||
{
|
{
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
|
||||||
ItemsPerPage = 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -56,14 +54,14 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
|||||||
|
|
||||||
protected override void OnItemsReceived(List<APIScore> items)
|
protected override void OnItemsReceived(List<APIScore> items)
|
||||||
{
|
{
|
||||||
if (VisiblePages == 0)
|
if (CurrentPage == null || CurrentPage?.Offset == 0)
|
||||||
drawableItemIndex = 0;
|
drawableItemIndex = 0;
|
||||||
|
|
||||||
base.OnItemsReceived(items);
|
base.OnItemsReceived(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override APIRequest<List<APIScore>> CreateRequest() =>
|
protected override APIRequest<List<APIScore>> CreateRequest(PaginationParameters pagination) =>
|
||||||
new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
|
new GetUserScoresRequest(User.Value.Id, type, pagination);
|
||||||
|
|
||||||
private int drawableItemIndex;
|
private int drawableItemIndex;
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
|
|||||||
public PaginatedRecentActivityContainer(Bindable<APIUser> user)
|
public PaginatedRecentActivityContainer(Bindable<APIUser> user)
|
||||||
: base(user, missingText: EventsStrings.Empty)
|
: base(user, missingText: EventsStrings.Empty)
|
||||||
{
|
{
|
||||||
ItemsPerPage = 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -28,8 +27,8 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
|
|||||||
ItemsContainer.Spacing = new Vector2(0, 8);
|
ItemsContainer.Spacing = new Vector2(0, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override APIRequest<List<APIRecentActivity>> CreateRequest() =>
|
protected override APIRequest<List<APIRecentActivity>> CreateRequest(PaginationParameters pagination) =>
|
||||||
new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
|
new GetUserRecentActivitiesRequest(User.Value.Id, pagination);
|
||||||
|
|
||||||
protected override Drawable CreateDrawableItem(APIRecentActivity model) => new DrawableRecentActivity(model);
|
protected override Drawable CreateDrawableItem(APIRecentActivity model) => new DrawableRecentActivity(model);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
|
using osu.Game.Screens;
|
||||||
using osu.Game.Screens.Import;
|
using osu.Game.Screens.Import;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Settings.Sections.DebugSettings
|
namespace osu.Game.Overlays.Settings.Sections.DebugSettings
|
||||||
@ -16,7 +17,7 @@ namespace osu.Game.Overlays.Settings.Sections.DebugSettings
|
|||||||
protected override LocalisableString Header => DebugSettingsStrings.GeneralHeader;
|
protected override LocalisableString Header => DebugSettingsStrings.GeneralHeader;
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(FrameworkDebugConfigManager config, FrameworkConfigManager frameworkConfig, OsuGame game)
|
private void load(FrameworkDebugConfigManager config, FrameworkConfigManager frameworkConfig, IPerformFromScreenRunner performer)
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -34,7 +35,7 @@ namespace osu.Game.Overlays.Settings.Sections.DebugSettings
|
|||||||
Add(new SettingsButton
|
Add(new SettingsButton
|
||||||
{
|
{
|
||||||
Text = DebugSettingsStrings.ImportFiles,
|
Text = DebugSettingsStrings.ImportFiles,
|
||||||
Action = () => game?.PerformFromScreen(menu => menu.Push(new FileImportScreen()))
|
Action = () => performer?.PerformFromScreen(menu => menu.Push(new FileImportScreen()))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
private SettingsButton checkForUpdatesButton;
|
private SettingsButton checkForUpdatesButton;
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private NotificationOverlay notifications { get; set; }
|
private INotificationOverlay notifications { get; set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(Storage storage, OsuConfigManager config, OsuGame game)
|
private void load(Storage storage, OsuConfigManager config, OsuGame game)
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
private SettingsButton undeleteButton;
|
private SettingsButton undeleteButton;
|
||||||
|
|
||||||
[BackgroundDependencyLoader(permitNulls: true)]
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, [CanBeNull] CollectionManager collectionManager, [CanBeNull] LegacyImportManager legacyImportManager, DialogOverlay dialogOverlay)
|
private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, [CanBeNull] CollectionManager collectionManager, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay)
|
||||||
{
|
{
|
||||||
if (legacyImportManager?.SupportsImportFromStable == true)
|
if (legacyImportManager?.SupportsImportFromStable == true)
|
||||||
{
|
{
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
private OsuGame game { get; set; }
|
private OsuGame game { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private NotificationOverlay notifications { get; set; }
|
private INotificationOverlay notifications { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private Storage storage { get; set; }
|
private Storage storage { get; set; }
|
||||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
private OsuGameBase game { get; set; }
|
private OsuGameBase game { get; set; }
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private DialogOverlay dialogOverlay { get; set; }
|
private IDialogOverlay dialogOverlay { get; set; }
|
||||||
|
|
||||||
protected override DirectoryInfo InitialPath => new DirectoryInfo(storage.GetFullPath(string.Empty)).Parent;
|
protected override DirectoryInfo InitialPath => new DirectoryInfo(storage.GetFullPath(string.Empty)).Parent;
|
||||||
|
|
||||||
|
@ -6,13 +6,14 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Overlays.Dialog;
|
using osu.Game.Overlays.Dialog;
|
||||||
|
using osu.Game.Screens;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||||
{
|
{
|
||||||
public class StableDirectoryLocationDialog : PopupDialog
|
public class StableDirectoryLocationDialog : PopupDialog
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuGame game { get; set; }
|
private IPerformFromScreenRunner performer { get; set; }
|
||||||
|
|
||||||
public StableDirectoryLocationDialog(TaskCompletionSource<string> taskCompletionSource)
|
public StableDirectoryLocationDialog(TaskCompletionSource<string> taskCompletionSource)
|
||||||
{
|
{
|
||||||
@ -25,7 +26,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
new PopupDialogOkButton
|
new PopupDialogOkButton
|
||||||
{
|
{
|
||||||
Text = "Sure! I know where it is located!",
|
Text = "Sure! I know where it is located!",
|
||||||
Action = () => Schedule(() => game.PerformFromScreen(screen => screen.Push(new StableDirectorySelectScreen(taskCompletionSource))))
|
Action = () => Schedule(() => performer.PerformFromScreen(screen => screen.Push(new StableDirectorySelectScreen(taskCompletionSource))))
|
||||||
},
|
},
|
||||||
new PopupDialogCancelButton
|
new PopupDialogCancelButton
|
||||||
{
|
{
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
{
|
{
|
||||||
protected override Anchor TooltipAnchor => Anchor.TopRight;
|
protected override Anchor TooltipAnchor => Anchor.TopRight;
|
||||||
|
|
||||||
public BindableInt NotificationCount = new BindableInt();
|
public IBindable<int> NotificationCount = new BindableInt();
|
||||||
|
|
||||||
private readonly CountCircle countDisplay;
|
private readonly CountCircle countDisplay;
|
||||||
|
|
||||||
@ -36,10 +36,10 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader]
|
||||||
private void load(NotificationOverlay notificationOverlay)
|
private void load(INotificationOverlay notificationOverlay)
|
||||||
{
|
{
|
||||||
StateContainer = notificationOverlay;
|
StateContainer = notificationOverlay as NotificationOverlay;
|
||||||
|
|
||||||
if (notificationOverlay != null)
|
if (notificationOverlay != null)
|
||||||
NotificationCount.BindTo(notificationOverlay.UnreadCount);
|
NotificationCount.BindTo(notificationOverlay.UnreadCount);
|
||||||
|
@ -23,10 +23,10 @@ namespace osu.Game
|
|||||||
private readonly Func<IScreen> getCurrentScreen;
|
private readonly Func<IScreen> getCurrentScreen;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private NotificationOverlay notifications { get; set; }
|
private INotificationOverlay notifications { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private DialogOverlay dialogOverlay { get; set; }
|
private IDialogOverlay dialogOverlay { get; set; }
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private OsuGame game { get; set; }
|
private OsuGame game { get; set; }
|
||||||
|
@ -84,10 +84,10 @@ namespace osu.Game.Screens.Edit
|
|||||||
private Storage storage { get; set; }
|
private Storage storage { get; set; }
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private DialogOverlay dialogOverlay { get; set; }
|
private IDialogOverlay dialogOverlay { get; set; }
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private NotificationOverlay notifications { get; set; }
|
private INotificationOverlay notifications { get; set; }
|
||||||
|
|
||||||
public readonly Bindable<EditorScreenMode> Mode = new Bindable<EditorScreenMode>();
|
public readonly Bindable<EditorScreenMode> Mode = new Bindable<EditorScreenMode>();
|
||||||
|
|
||||||
|
@ -21,21 +21,24 @@ namespace osu.Game.Screens.Edit
|
|||||||
{
|
{
|
||||||
public event Action BeatmapSkinChanged;
|
public event Action BeatmapSkinChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The underlying beatmap skin.
|
||||||
|
/// </summary>
|
||||||
|
protected internal readonly Skin Skin;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The combo colours of this skin.
|
/// The combo colours of this skin.
|
||||||
/// If empty, the default combo colours will be used.
|
/// If empty, the default combo colours will be used.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly BindableList<Colour4> ComboColours;
|
public BindableList<Colour4> ComboColours { get; }
|
||||||
|
|
||||||
private readonly Skin skin;
|
|
||||||
|
|
||||||
public EditorBeatmapSkin(Skin skin)
|
public EditorBeatmapSkin(Skin skin)
|
||||||
{
|
{
|
||||||
this.skin = skin;
|
Skin = skin;
|
||||||
|
|
||||||
ComboColours = new BindableList<Colour4>();
|
ComboColours = new BindableList<Colour4>();
|
||||||
if (skin.Configuration.ComboColours != null)
|
if (Skin.Configuration.ComboColours != null)
|
||||||
ComboColours.AddRange(skin.Configuration.ComboColours.Select(c => (Colour4)c));
|
ComboColours.AddRange(Skin.Configuration.ComboColours.Select(c => (Colour4)c));
|
||||||
ComboColours.BindCollectionChanged((_, __) => updateColours());
|
ComboColours.BindCollectionChanged((_, __) => updateColours());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,16 +46,16 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
private void updateColours()
|
private void updateColours()
|
||||||
{
|
{
|
||||||
skin.Configuration.CustomComboColours = ComboColours.Select(c => (Color4)c).ToList();
|
Skin.Configuration.CustomComboColours = ComboColours.Select(c => (Color4)c).ToList();
|
||||||
invokeSkinChanged();
|
invokeSkinChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Delegated ISkin implementation
|
#region Delegated ISkin implementation
|
||||||
|
|
||||||
public Drawable GetDrawableComponent(ISkinComponent component) => skin.GetDrawableComponent(component);
|
public Drawable GetDrawableComponent(ISkinComponent component) => Skin.GetDrawableComponent(component);
|
||||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => skin.GetTexture(componentName, wrapModeS, wrapModeT);
|
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => Skin.GetTexture(componentName, wrapModeS, wrapModeT);
|
||||||
public ISample GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo);
|
public ISample GetSample(ISampleInfo sampleInfo) => Skin.GetSample(sampleInfo);
|
||||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => skin.GetConfig<TLookup, TValue>(lookup);
|
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => Skin.GetConfig<TLookup, TValue>(lookup);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
private readonly EditorBeatmapSkin? beatmapSkin;
|
private readonly EditorBeatmapSkin? beatmapSkin;
|
||||||
|
|
||||||
public EditorSkinProvidingContainer(EditorBeatmap editorBeatmap)
|
public EditorSkinProvidingContainer(EditorBeatmap editorBeatmap)
|
||||||
: base(editorBeatmap.PlayableBeatmap.BeatmapInfo.Ruleset.CreateInstance(), editorBeatmap.PlayableBeatmap, editorBeatmap.BeatmapSkin)
|
: base(editorBeatmap.PlayableBeatmap.BeatmapInfo.Ruleset.CreateInstance(), editorBeatmap.PlayableBeatmap, editorBeatmap.BeatmapSkin?.Skin)
|
||||||
{
|
{
|
||||||
beatmapSkin = editorBeatmap.BeatmapSkin;
|
beatmapSkin = editorBeatmap.BeatmapSkin;
|
||||||
}
|
}
|
||||||
|
26
osu.Game/Screens/IPerformFromScreenRunner.cs
Normal file
26
osu.Game/Screens/IPerformFromScreenRunner.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// 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.Screens;
|
||||||
|
using osu.Game.Screens.Menu;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Manages a global screen stack to allow nested components a guarantee of where work is executed.
|
||||||
|
/// </summary>
|
||||||
|
[Cached]
|
||||||
|
public interface IPerformFromScreenRunner
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Perform an action only after returning to a specific screen as indicated by <paramref name="validScreens"/>.
|
||||||
|
/// Eagerly tries to exit the current screen until it succeeds.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="action">The action to perform once we are in the correct state.</param>
|
||||||
|
/// <param name="validScreens">An optional collection of valid screen types. If any of these screens are already current we can perform the action immediately, else the first valid parent will be made current before performing the action. <see cref="MainMenu"/> is used if not specified.</param>
|
||||||
|
void PerformFromScreen(Action<IScreen> action, IEnumerable<Type> validScreens = null);
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,6 @@ using osu.Game.Input.Bindings;
|
|||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Notifications;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
@ -117,9 +116,6 @@ namespace osu.Game.Screens.Menu
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IAPIProvider api { get; set; }
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
|
||||||
private NotificationOverlay notifications { get; set; }
|
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private LoginOverlay loginOverlay { get; set; }
|
private LoginOverlay loginOverlay { get; set; }
|
||||||
|
|
||||||
@ -161,17 +157,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
{
|
{
|
||||||
if (api.State.Value != APIState.Online)
|
if (api.State.Value != APIState.Online)
|
||||||
{
|
{
|
||||||
notifications?.Post(new SimpleNotification
|
loginOverlay?.Show();
|
||||||
{
|
|
||||||
Text = "You gotta be online to multi 'yo!",
|
|
||||||
Icon = FontAwesome.Solid.Globe,
|
|
||||||
Activated = () =>
|
|
||||||
{
|
|
||||||
loginOverlay?.Show();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,17 +168,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
{
|
{
|
||||||
if (api.State.Value != APIState.Online)
|
if (api.State.Value != APIState.Online)
|
||||||
{
|
{
|
||||||
notifications?.Post(new SimpleNotification
|
loginOverlay?.Show();
|
||||||
{
|
|
||||||
Text = "You gotta be online to view playlists 'yo!",
|
|
||||||
Icon = FontAwesome.Solid.Globe,
|
|
||||||
Activated = () =>
|
|
||||||
{
|
|
||||||
loginOverlay?.Show();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private NotificationOverlay notifications { get; set; }
|
private INotificationOverlay notifications { get; set; }
|
||||||
|
|
||||||
private void ensureEventuallyArrivingAtMenu()
|
private void ensureEventuallyArrivingAtMenu()
|
||||||
{
|
{
|
||||||
|
@ -60,7 +60,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
private IAPIProvider api { get; set; }
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private DialogOverlay dialogOverlay { get; set; }
|
private IDialogOverlay dialogOverlay { get; set; }
|
||||||
|
|
||||||
private BackgroundScreenDefault background;
|
private BackgroundScreenDefault background;
|
||||||
|
|
||||||
@ -148,14 +148,14 @@ namespace osu.Game.Screens.Menu
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private OsuGame game { get; set; }
|
private IPerformFromScreenRunner performer { get; set; }
|
||||||
|
|
||||||
private void confirmAndExit()
|
private void confirmAndExit()
|
||||||
{
|
{
|
||||||
if (exitConfirmed) return;
|
if (exitConfirmed) return;
|
||||||
|
|
||||||
exitConfirmed = true;
|
exitConfirmed = true;
|
||||||
game?.PerformFromScreen(menu => menu.Exit());
|
performer?.PerformFromScreen(menu => menu.Exit());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void preloadSongSelect()
|
private void preloadSongSelect()
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
public class StorageErrorDialog : PopupDialog
|
public class StorageErrorDialog : PopupDialog
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private DialogOverlay dialogOverlay { get; set; }
|
private IDialogOverlay dialogOverlay { get; set; }
|
||||||
|
|
||||||
public StorageErrorDialog(OsuStorage storage, OsuStorageError error)
|
public StorageErrorDialog(OsuStorage storage, OsuStorageError error)
|
||||||
{
|
{
|
||||||
|
@ -238,7 +238,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private DialogOverlay dialogOverlay { get; set; }
|
private IDialogOverlay dialogOverlay { get; set; }
|
||||||
|
|
||||||
private bool exitConfirmed;
|
private bool exitConfirmed;
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay)
|
private void load(OsuConfigManager config, INotificationOverlay notificationOverlay)
|
||||||
{
|
{
|
||||||
if (drawableRuleset != null)
|
if (drawableRuleset != null)
|
||||||
{
|
{
|
||||||
|
@ -124,7 +124,7 @@ namespace osu.Game.Screens.Play
|
|||||||
private EpilepsyWarning? epilepsyWarning;
|
private EpilepsyWarning? epilepsyWarning;
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private NotificationOverlay? notificationOverlay { get; set; }
|
private INotificationOverlay? notificationOverlay { get; set; }
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private VolumeOverlay? volumeOverlay { get; set; }
|
private VolumeOverlay? volumeOverlay { get; set; }
|
||||||
@ -515,7 +515,7 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours, AudioManager audioManager, NotificationOverlay notificationOverlay, VolumeOverlay volumeOverlay)
|
private void load(OsuColour colours, AudioManager audioManager, INotificationOverlay notificationOverlay, VolumeOverlay volumeOverlay)
|
||||||
{
|
{
|
||||||
Icon = FontAwesome.Solid.VolumeMute;
|
Icon = FontAwesome.Solid.VolumeMute;
|
||||||
IconBackground.Colour = colours.RedDark;
|
IconBackground.Colour = colours.RedDark;
|
||||||
@ -567,7 +567,7 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours, NotificationOverlay notificationOverlay)
|
private void load(OsuColour colours, INotificationOverlay notificationOverlay)
|
||||||
{
|
{
|
||||||
Icon = FontAwesome.Solid.BatteryQuarter;
|
Icon = FontAwesome.Solid.BatteryQuarter;
|
||||||
IconBackground.Colour = colours.RedDark;
|
IconBackground.Colour = colours.RedDark;
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
private Action<int> viewDetails;
|
private Action<int> viewDetails;
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private DialogOverlay dialogOverlay { get; set; }
|
private IDialogOverlay dialogOverlay { get; set; }
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private CollectionManager collectionManager { get; set; }
|
private CollectionManager collectionManager { get; set; }
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Screens.Select
|
|||||||
private OsuScreen playerLoader;
|
private OsuScreen playerLoader;
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private NotificationOverlay notifications { get; set; }
|
private INotificationOverlay notifications { get; set; }
|
||||||
|
|
||||||
public override bool AllowExternalScreenChange => true;
|
public override bool AllowExternalScreenChange => true;
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ namespace osu.Game.Screens.Select
|
|||||||
protected Container LeftArea { get; private set; }
|
protected Container LeftArea { get; private set; }
|
||||||
|
|
||||||
private BeatmapInfoWedge beatmapInfoWedge;
|
private BeatmapInfoWedge beatmapInfoWedge;
|
||||||
private DialogOverlay dialogOverlay;
|
private IDialogOverlay dialogOverlay;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private BeatmapManager beatmaps { get; set; }
|
private BeatmapManager beatmaps { get; set; }
|
||||||
@ -114,7 +114,7 @@ namespace osu.Game.Screens.Select
|
|||||||
private MusicController music { get; set; }
|
private MusicController music { get; set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(AudioManager audio, DialogOverlay dialog, OsuColour colours, ManageCollectionsDialog manageCollectionsDialog, DifficultyRecommender recommender)
|
private void load(AudioManager audio, IDialogOverlay dialog, OsuColour colours, ManageCollectionsDialog manageCollectionsDialog, DifficultyRecommender recommender)
|
||||||
{
|
{
|
||||||
// initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter).
|
// initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter).
|
||||||
transferRulesetValue();
|
transferRulesetValue();
|
||||||
|
@ -15,6 +15,7 @@ using osu.Game.Graphics.UserInterface;
|
|||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Screens;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -28,7 +29,7 @@ namespace osu.Game.Skinning.Editor
|
|||||||
private const float padding = 10;
|
private const float padding = 10;
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private OsuGame game { get; set; }
|
private IPerformFromScreenRunner performer { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IBindable<RulesetInfo> ruleset { get; set; }
|
private IBindable<RulesetInfo> ruleset { get; set; }
|
||||||
@ -75,7 +76,7 @@ namespace osu.Game.Skinning.Editor
|
|||||||
Text = "Song Select",
|
Text = "Song Select",
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Action = () => game?.PerformFromScreen(screen =>
|
Action = () => performer?.PerformFromScreen(screen =>
|
||||||
{
|
{
|
||||||
if (screen is SongSelect)
|
if (screen is SongSelect)
|
||||||
return;
|
return;
|
||||||
@ -88,7 +89,7 @@ namespace osu.Game.Skinning.Editor
|
|||||||
Text = "Gameplay",
|
Text = "Gameplay",
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Action = () => game?.PerformFromScreen(screen =>
|
Action = () => performer?.PerformFromScreen(screen =>
|
||||||
{
|
{
|
||||||
if (screen is Player)
|
if (screen is Player)
|
||||||
return;
|
return;
|
||||||
|
@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
private DialogOverlay dialogOverlay { get; set; }
|
private IDialogOverlay dialogOverlay { get; set; }
|
||||||
|
|
||||||
public new void Undo() => base.Undo();
|
public new void Undo() => base.Undo();
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
protected override Container<Drawable> Content => content;
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
[Cached]
|
[Cached(typeof(IDialogOverlay))]
|
||||||
protected DialogOverlay DialogOverlay { get; private set; }
|
protected DialogOverlay DialogOverlay { get; private set; }
|
||||||
|
|
||||||
protected ScreenTestScene()
|
protected ScreenTestScene()
|
||||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Updater
|
|||||||
private OsuGameBase game { get; set; }
|
private OsuGameBase game { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
protected NotificationOverlay Notifications { get; private set; }
|
protected INotificationOverlay Notifications { get; private set; }
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
@ -94,7 +94,7 @@ namespace osu.Game.Updater
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours, ChangelogOverlay changelog, NotificationOverlay notificationOverlay)
|
private void load(OsuColour colours, ChangelogOverlay changelog, INotificationOverlay notificationOverlay)
|
||||||
{
|
{
|
||||||
Icon = FontAwesome.Solid.CheckSquare;
|
Icon = FontAwesome.Solid.CheckSquare;
|
||||||
IconBackground.Colour = colours.BlueDark;
|
IconBackground.Colour = colours.BlueDark;
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Realm" Version="10.10.0" />
|
<PackageReference Include="Realm" Version="10.10.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2022.415.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2022.419.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.417.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.417.0" />
|
||||||
<PackageReference Include="Sentry" Version="3.14.1" />
|
<PackageReference Include="Sentry" Version="3.14.1" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.30.1" />
|
<PackageReference Include="SharpCompress" Version="0.30.1" />
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
<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="2022.415.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.419.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.417.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.417.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net6.0) -->
|
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net6.0) -->
|
||||||
@ -84,7 +84,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.14" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.14" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.14" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.14" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2022.415.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2022.419.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.30.1" />
|
<PackageReference Include="SharpCompress" Version="0.30.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
|
Loading…
Reference in New Issue
Block a user