mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 08:52:55 +08:00
Merge branch 'master' into MyBranch
This commit is contained in:
commit
648e9fa21f
@ -2,6 +2,7 @@
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.osu.Desktop/.idea/.idea.osu.Desktop.iml" filepath="$PROJECT_DIR$/.idea/.idea.osu.Desktop/.idea/.idea.osu.Desktop.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.osu.Desktop/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.osu.Desktop/riderModule.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
|
@ -93,7 +93,7 @@ JetBrains ReSharper InspectCode is also used for wider rule sets. You can run it
|
||||
|
||||
We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention of having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time to ensure no effort is wasted.
|
||||
|
||||
If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues) (especially those with the ["good first issue"](https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) label).
|
||||
If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues) (especially those with the ["good first issue"](https://github.com/ppy/osu/issues?q=is%3Aopen+label%3Agood-first-issue+sort%3Aupdated-desc) label).
|
||||
|
||||
Before starting, please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have set up. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**.
|
||||
|
||||
|
@ -1,12 +1,15 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osuTK.Graphics;
|
||||
@ -14,14 +17,14 @@ using osuTK.Graphics;
|
||||
namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneLoaderAnimation : ScreenTestScene
|
||||
public class TestSceneLoader : ScreenTestScene
|
||||
{
|
||||
private TestLoader loader;
|
||||
|
||||
[Cached]
|
||||
private OsuLogo logo;
|
||||
|
||||
public TestSceneLoaderAnimation()
|
||||
public TestSceneLoader()
|
||||
{
|
||||
Child = logo = new OsuLogo
|
||||
{
|
||||
@ -42,33 +45,33 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
|
||||
LoadScreen(loader);
|
||||
});
|
||||
|
||||
AddAssert("spinner did not display", () => loader.LoadingSpinner?.Alpha == 0);
|
||||
|
||||
AddUntilStep("loaded", () => loader.ScreenLoaded);
|
||||
AddUntilStep("not current", () => !loader.IsCurrentScreen());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDelayedLoad()
|
||||
{
|
||||
AddStep("begin loading", () => LoadScreen(loader = new TestLoader()));
|
||||
AddUntilStep("wait for logo visible", () => loader.Logo?.Alpha > 0);
|
||||
AddUntilStep("wait for spinner visible", () => loader.LoadingSpinner?.Alpha > 0);
|
||||
AddStep("finish loading", () => loader.AllowLoad.Set());
|
||||
AddUntilStep("loaded", () => loader.Logo != null && loader.ScreenLoaded);
|
||||
AddUntilStep("logo gone", () => loader.Logo?.Alpha == 0);
|
||||
AddUntilStep("spinner gone", () => loader.LoadingSpinner?.Alpha == 0);
|
||||
AddUntilStep("loaded", () => loader.ScreenLoaded);
|
||||
AddUntilStep("not current", () => !loader.IsCurrentScreen());
|
||||
}
|
||||
|
||||
private class TestLoader : Loader
|
||||
{
|
||||
public readonly ManualResetEventSlim AllowLoad = new ManualResetEventSlim();
|
||||
|
||||
public OsuLogo Logo;
|
||||
public LoadingSpinner LoadingSpinner => this.ChildrenOfType<LoadingSpinner>().FirstOrDefault();
|
||||
private TestScreen screen;
|
||||
|
||||
public bool ScreenLoaded => screen.IsCurrentScreen();
|
||||
|
||||
protected override void LogoArriving(OsuLogo logo, bool resuming)
|
||||
{
|
||||
Logo = logo;
|
||||
base.LogoArriving(logo, resuming);
|
||||
}
|
||||
|
||||
protected override OsuScreen CreateLoadableScreen() => screen = new TestScreen();
|
||||
protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler(AllowLoad);
|
||||
|
@ -54,7 +54,8 @@ namespace osu.Game.Tests.Visual.Online
|
||||
.Select(index => new Channel(new User())
|
||||
{
|
||||
Name = $"Channel no. {index}",
|
||||
Topic = index == 3 ? null : $"We talk about the number {index} here"
|
||||
Topic = index == 3 ? null : $"We talk about the number {index} here",
|
||||
Type = index % 2 == 0 ? ChannelType.PM : ChannelType.Temporary
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
@ -100,28 +101,11 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddAssert("Channel selector was closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCloseChannelWhileSelectorClosed()
|
||||
{
|
||||
AddStep("Join channel 1", () => channelManager.JoinChannel(channel1));
|
||||
AddStep("Join channel 2", () => channelManager.JoinChannel(channel2));
|
||||
|
||||
AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.TabMap[channel2]));
|
||||
AddStep("Close channel 2", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child));
|
||||
|
||||
AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||
AddAssert("Current channel is channel 1", () => currentChannel == channel1);
|
||||
|
||||
AddStep("Close channel 1", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child));
|
||||
|
||||
AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSearchInSelector()
|
||||
{
|
||||
AddStep("search for 'no. 2'", () => chatOverlay.ChildrenOfType<SearchTextBox>().First().Text = "no. 2");
|
||||
AddUntilStep("only channel 2 visible", () =>
|
||||
AddStep("Search for 'no. 2'", () => chatOverlay.ChildrenOfType<SearchTextBox>().First().Text = "no. 2");
|
||||
AddUntilStep("Only channel 2 visible", () =>
|
||||
{
|
||||
var listItems = chatOverlay.ChildrenOfType<ChannelListItem>().Where(c => c.IsPresent);
|
||||
return listItems.Count() == 1 && listItems.Single().Channel == channel2;
|
||||
@ -131,28 +115,28 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[Test]
|
||||
public void TestChannelShortcutKeys()
|
||||
{
|
||||
AddStep("join 10 channels", () => channels.ForEach(channel => channelManager.JoinChannel(channel)));
|
||||
AddStep("close channel selector", () =>
|
||||
AddStep("Join channels", () => channels.ForEach(channel => channelManager.JoinChannel(channel)));
|
||||
AddStep("Close channel selector", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.Escape);
|
||||
InputManager.ReleaseKey(Key.Escape);
|
||||
});
|
||||
AddUntilStep("wait for close", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||
AddUntilStep("Wait for close", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||
|
||||
for (int zeroBasedIndex = 0; zeroBasedIndex < 10; ++zeroBasedIndex)
|
||||
{
|
||||
var oneBasedIndex = zeroBasedIndex + 1;
|
||||
var targetNumberKey = oneBasedIndex % 10;
|
||||
var targetChannel = channels[zeroBasedIndex];
|
||||
AddStep($"press Alt+{targetNumberKey}", () => pressChannelHotkey(targetNumberKey));
|
||||
AddAssert($"channel #{oneBasedIndex} is selected", () => currentChannel == targetChannel);
|
||||
AddStep($"Press Alt+{targetNumberKey}", () => pressChannelHotkey(targetNumberKey));
|
||||
AddAssert($"Channel #{oneBasedIndex} is selected", () => currentChannel == targetChannel);
|
||||
}
|
||||
}
|
||||
|
||||
private Channel expectedChannel;
|
||||
|
||||
[Test]
|
||||
public void TestCloseChannelWhileActive()
|
||||
public void TestCloseChannelBehaviour()
|
||||
{
|
||||
AddUntilStep("Join until dropdown has channels", () =>
|
||||
{
|
||||
@ -160,8 +144,11 @@ namespace osu.Game.Tests.Visual.Online
|
||||
return true;
|
||||
|
||||
// Using temporary channels because they don't hide their names when not active
|
||||
Channel toAdd = new Channel { Name = $"test channel {joinedChannels.Count()}", Type = ChannelType.Temporary };
|
||||
channelManager.JoinChannel(toAdd);
|
||||
channelManager.JoinChannel(new Channel
|
||||
{
|
||||
Name = $"Channel no. {joinedChannels.Count() + 11}",
|
||||
Type = ChannelType.Temporary
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
@ -176,6 +163,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
chatOverlay.ChannelTabControl.RemoveChannel(currentChannel);
|
||||
});
|
||||
AddAssert("Next channel selected", () => currentChannel == expectedChannel);
|
||||
AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||
|
||||
// Depending on the window size, one more channel might need to be closed for the selectorTab to appear
|
||||
AddUntilStep("Close channels until selector visible", () =>
|
||||
@ -194,7 +182,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
expectedChannel = previousChannel;
|
||||
chatOverlay.ChannelTabControl.RemoveChannel(currentChannel);
|
||||
});
|
||||
AddAssert("Channel changed to previous", () => currentChannel == expectedChannel);
|
||||
AddAssert("Previous channel selected", () => currentChannel == expectedChannel);
|
||||
|
||||
// Standard channel closing
|
||||
AddStep("Switch to previous channel", () => chatOverlay.ChannelTabControl.SwitchTab(-1));
|
||||
@ -203,7 +191,38 @@ namespace osu.Game.Tests.Visual.Online
|
||||
expectedChannel = nextChannel;
|
||||
chatOverlay.ChannelTabControl.RemoveChannel(currentChannel);
|
||||
});
|
||||
AddAssert("Channel changed to next", () => currentChannel == expectedChannel);
|
||||
AddAssert("Next channel selected", () => currentChannel == expectedChannel);
|
||||
|
||||
// Selector reappearing after all channels closed
|
||||
AddUntilStep("Close all channels", () =>
|
||||
{
|
||||
if (!joinedChannels.Any())
|
||||
return true;
|
||||
|
||||
chatOverlay.ChannelTabControl.RemoveChannel(joinedChannels.Last());
|
||||
return false;
|
||||
});
|
||||
AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChannelCloseButton()
|
||||
{
|
||||
AddStep("Join 2 channels", () =>
|
||||
{
|
||||
channelManager.JoinChannel(channel1);
|
||||
channelManager.JoinChannel(channel2);
|
||||
});
|
||||
|
||||
// PM channel close button only appears when active
|
||||
AddStep("Select PM channel", () => clickDrawable(chatOverlay.TabMap[channel2]));
|
||||
AddStep("Click PM close button", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child));
|
||||
AddAssert("PM channel closed", () => !channelManager.JoinedChannels.Contains(channel2));
|
||||
|
||||
// Non-PM chat channel close button only appears when hovered
|
||||
AddStep("Hover normal channel tab", () => InputManager.MoveMouseTo(chatOverlay.TabMap[channel1]));
|
||||
AddStep("Click normal close button", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child));
|
||||
AddAssert("All channels closed", () => !channelManager.JoinedChannels.Any());
|
||||
}
|
||||
|
||||
private void pressChannelHotkey(int number)
|
||||
|
@ -3,10 +3,18 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
@ -23,6 +31,9 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
public class TestSceneExpandedPanelMiddleContent : OsuTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private RulesetStore rulesetStore { get; set; }
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(ExpandedPanelMiddleContent),
|
||||
@ -35,23 +46,36 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
typeof(TotalScoreCounter)
|
||||
};
|
||||
|
||||
public TestSceneExpandedPanelMiddleContent()
|
||||
[Test]
|
||||
public void TestMapWithKnownMapper()
|
||||
{
|
||||
Child = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(500, 700),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#444"),
|
||||
},
|
||||
new ExpandedPanelMiddleContent(createTestScore())
|
||||
}
|
||||
};
|
||||
var author = new User { Username = "mapper_name" };
|
||||
|
||||
AddStep("show example score", () => showPanel(createTestBeatmap(author), createTestScore()));
|
||||
|
||||
AddAssert("mapper name present", () => this.ChildrenOfType<OsuSpriteText>().Any(spriteText => spriteText.Text == "mapper_name"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMapWithUnknownMapper()
|
||||
{
|
||||
AddStep("show example score", () => showPanel(createTestBeatmap(null), createTestScore()));
|
||||
|
||||
AddAssert("mapped by text not present", () =>
|
||||
this.ChildrenOfType<OsuSpriteText>().All(spriteText => !containsAny(spriteText.Text, "mapped", "by")));
|
||||
}
|
||||
|
||||
private void showPanel(WorkingBeatmap workingBeatmap, ScoreInfo score)
|
||||
{
|
||||
Child = new ExpandedPanelMiddleContentContainer(workingBeatmap, score);
|
||||
}
|
||||
|
||||
private WorkingBeatmap createTestBeatmap(User author)
|
||||
{
|
||||
var beatmap = new TestBeatmap(rulesetStore.GetRuleset(0));
|
||||
beatmap.Metadata.Author = author;
|
||||
|
||||
return new TestWorkingBeatmap(beatmap);
|
||||
}
|
||||
|
||||
private ScoreInfo createTestScore() => new ScoreInfo
|
||||
@ -76,5 +100,31 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
{ HitResult.Great, 300 },
|
||||
}
|
||||
};
|
||||
|
||||
private bool containsAny(string text, params string[] stringsToMatch) => stringsToMatch.Any(text.Contains);
|
||||
|
||||
private class ExpandedPanelMiddleContentContainer : Container
|
||||
{
|
||||
[Cached]
|
||||
private Bindable<WorkingBeatmap> workingBeatmap { get; set; }
|
||||
|
||||
public ExpandedPanelMiddleContentContainer(WorkingBeatmap beatmap, ScoreInfo score)
|
||||
{
|
||||
workingBeatmap = new Bindable<WorkingBeatmap>(beatmap);
|
||||
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
Size = new Vector2(500, 700);
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#444"),
|
||||
},
|
||||
new ExpandedPanelMiddleContent(score)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -47,23 +48,49 @@ namespace osu.Game.Graphics
|
||||
{
|
||||
case ScoreRank.XH:
|
||||
case ScoreRank.X:
|
||||
return Color4Extensions.FromHex(@"ce1c9d");
|
||||
return Color4Extensions.FromHex(@"de31ae");
|
||||
|
||||
case ScoreRank.SH:
|
||||
case ScoreRank.S:
|
||||
return Color4Extensions.FromHex(@"00a8b5");
|
||||
return Color4Extensions.FromHex(@"02b5c3");
|
||||
|
||||
case ScoreRank.A:
|
||||
return Color4Extensions.FromHex(@"7cce14");
|
||||
return Color4Extensions.FromHex(@"88da20");
|
||||
|
||||
case ScoreRank.B:
|
||||
return Color4Extensions.FromHex(@"e3b130");
|
||||
|
||||
case ScoreRank.C:
|
||||
return Color4Extensions.FromHex(@"f18252");
|
||||
return Color4Extensions.FromHex(@"ff8e5d");
|
||||
|
||||
default:
|
||||
return Color4Extensions.FromHex(@"e95353");
|
||||
return Color4Extensions.FromHex(@"ff5a5a");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the colour for a <see cref="HitResult"/>.
|
||||
/// </summary>
|
||||
public Color4 ForHitResult(HitResult judgement)
|
||||
{
|
||||
switch (judgement)
|
||||
{
|
||||
case HitResult.Perfect:
|
||||
case HitResult.Great:
|
||||
return Blue;
|
||||
|
||||
case HitResult.Ok:
|
||||
case HitResult.Good:
|
||||
return Green;
|
||||
|
||||
case HitResult.Meh:
|
||||
return Yellow;
|
||||
|
||||
case HitResult.Miss:
|
||||
return Red;
|
||||
|
||||
default:
|
||||
return Color4.White;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
protected Container MainContents;
|
||||
|
||||
protected const float TRANSITION_DURATION = 500;
|
||||
public const float TRANSITION_DURATION = 500;
|
||||
|
||||
private const float spin_duration = 900;
|
||||
|
||||
@ -27,7 +27,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
/// Constuct a new loading spinner.
|
||||
/// </summary>
|
||||
/// <param name="withBox">Whether the spinner should have a surrounding black box for visibility.</param>
|
||||
public LoadingSpinner(bool withBox = false)
|
||||
/// <param name="inverted">Whether colours should be inverted (black spinner instead of white).</param>
|
||||
public LoadingSpinner(bool withBox = false, bool inverted = false)
|
||||
{
|
||||
Size = new Vector2(60);
|
||||
|
||||
@ -45,7 +46,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
Colour = inverted ? Color4.White : Color4.Black,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = withBox ? 0.7f : 0
|
||||
},
|
||||
@ -53,6 +54,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Colour = inverted ? Color4.Black : Color4.White,
|
||||
Scale = new Vector2(withBox ? 0.6f : 1),
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Icon = FontAwesome.Solid.CircleNotch
|
||||
|
@ -12,7 +12,6 @@ using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Judgements
|
||||
{
|
||||
@ -68,7 +67,7 @@ namespace osu.Game.Rulesets.Judgements
|
||||
{
|
||||
Text = Result.Type.GetDescription().ToUpperInvariant(),
|
||||
Font = OsuFont.Numeric.With(size: 20),
|
||||
Colour = judgementColour(Result.Type),
|
||||
Colour = colours.ForHitResult(Result.Type),
|
||||
Scale = new Vector2(0.85f, 1),
|
||||
}, confineMode: ConfineMode.NoScaling)
|
||||
};
|
||||
@ -110,28 +109,5 @@ namespace osu.Game.Rulesets.Judgements
|
||||
|
||||
Expire(true);
|
||||
}
|
||||
|
||||
private Color4 judgementColour(HitResult judgement)
|
||||
{
|
||||
switch (judgement)
|
||||
{
|
||||
case HitResult.Perfect:
|
||||
case HitResult.Great:
|
||||
return colours.Blue;
|
||||
|
||||
case HitResult.Ok:
|
||||
case HitResult.Good:
|
||||
return colours.Green;
|
||||
|
||||
case HitResult.Meh:
|
||||
return colours.Yellow;
|
||||
|
||||
case HitResult.Miss:
|
||||
return colours.Red;
|
||||
|
||||
default:
|
||||
return Color4.White;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,12 +5,14 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shaders;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osuTK;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using IntroSequence = osu.Game.Configuration.IntroSequence;
|
||||
|
||||
namespace osu.Game.Screens
|
||||
@ -24,31 +26,12 @@ namespace osu.Game.Screens
|
||||
ValidForResume = false;
|
||||
}
|
||||
|
||||
protected override void LogoArriving(OsuLogo logo, bool resuming)
|
||||
{
|
||||
base.LogoArriving(logo, resuming);
|
||||
|
||||
logo.BeatMatching = false;
|
||||
logo.Triangles = false;
|
||||
logo.RelativePositionAxes = Axes.None;
|
||||
logo.Origin = Anchor.BottomRight;
|
||||
logo.Anchor = Anchor.BottomRight;
|
||||
logo.Position = new Vector2(-40);
|
||||
logo.Scale = new Vector2(0.2f);
|
||||
|
||||
logo.Delay(500).FadeInFromZero(1000, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void LogoSuspending(OsuLogo logo)
|
||||
{
|
||||
base.LogoSuspending(logo);
|
||||
logo.FadeOut(logo.Alpha * 400);
|
||||
}
|
||||
|
||||
private OsuScreen loadableScreen;
|
||||
private ShaderPrecompiler precompiler;
|
||||
|
||||
private IntroSequence introSequence;
|
||||
private LoadingSpinner spinner;
|
||||
private ScheduledDelegate spinnerShow;
|
||||
|
||||
protected virtual OsuScreen CreateLoadableScreen()
|
||||
{
|
||||
@ -82,6 +65,17 @@ namespace osu.Game.Screens
|
||||
LoadComponentAsync(precompiler = CreateShaderPrecompiler(), AddInternal);
|
||||
LoadComponentAsync(loadableScreen = CreateLoadableScreen());
|
||||
|
||||
LoadComponentAsync(spinner = new LoadingSpinner(true, true)
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
Margin = new MarginPadding(40),
|
||||
}, _ =>
|
||||
{
|
||||
AddInternal(spinner);
|
||||
spinnerShow = Scheduler.AddDelayed(spinner.Show, 200);
|
||||
});
|
||||
|
||||
checkIfLoaded();
|
||||
}
|
||||
|
||||
@ -93,7 +87,15 @@ namespace osu.Game.Screens
|
||||
return;
|
||||
}
|
||||
|
||||
this.Push(loadableScreen);
|
||||
spinnerShow?.Cancel();
|
||||
|
||||
if (spinner.State.Value == Visibility.Visible)
|
||||
{
|
||||
spinner.Hide();
|
||||
Scheduler.AddDelayed(() => this.Push(loadableScreen), LoadingSpinner.TRANSITION_DURATION);
|
||||
}
|
||||
else
|
||||
this.Push(loadableScreen);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|
@ -119,42 +119,42 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
|
||||
new SmoothCircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#BE0089"),
|
||||
Colour = OsuColour.ForRank(ScoreRank.X),
|
||||
InnerRadius = RANK_CIRCLE_RADIUS,
|
||||
Current = { Value = 1 }
|
||||
},
|
||||
new SmoothCircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#0096A2"),
|
||||
Colour = OsuColour.ForRank(ScoreRank.S),
|
||||
InnerRadius = RANK_CIRCLE_RADIUS,
|
||||
Current = { Value = 1 - virtual_ss_percentage }
|
||||
},
|
||||
new SmoothCircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#72C904"),
|
||||
Colour = OsuColour.ForRank(ScoreRank.A),
|
||||
InnerRadius = RANK_CIRCLE_RADIUS,
|
||||
Current = { Value = 0.95f }
|
||||
},
|
||||
new SmoothCircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#D99D03"),
|
||||
Colour = OsuColour.ForRank(ScoreRank.B),
|
||||
InnerRadius = RANK_CIRCLE_RADIUS,
|
||||
Current = { Value = 0.9f }
|
||||
},
|
||||
new SmoothCircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#EA7948"),
|
||||
Colour = OsuColour.ForRank(ScoreRank.C),
|
||||
InnerRadius = RANK_CIRCLE_RADIUS,
|
||||
Current = { Value = 0.8f }
|
||||
},
|
||||
new SmoothCircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#FF5858"),
|
||||
Colour = OsuColour.ForRank(ScoreRank.D),
|
||||
InnerRadius = RANK_CIRCLE_RADIUS,
|
||||
Current = { Value = 0.7f }
|
||||
},
|
||||
|
@ -5,7 +5,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Localisation;
|
||||
@ -14,6 +13,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osu.Game.Screens.Ranking.Expanded.Accuracy;
|
||||
@ -51,17 +51,18 @@ namespace osu.Game.Screens.Ranking.Expanded
|
||||
{
|
||||
var beatmap = working.Value.BeatmapInfo;
|
||||
var metadata = beatmap.Metadata;
|
||||
var creator = metadata.Author?.Username;
|
||||
|
||||
var topStatistics = new List<StatisticDisplay>
|
||||
{
|
||||
new AccuracyStatistic(score.Accuracy),
|
||||
new ComboStatistic(score.MaxCombo, true),
|
||||
new ComboStatistic(score.MaxCombo, !score.Statistics.TryGetValue(HitResult.Miss, out var missCount) || missCount == 0),
|
||||
new CounterStatistic("pp", (int)(score.PP ?? 0)),
|
||||
};
|
||||
|
||||
var bottomStatistics = new List<StatisticDisplay>();
|
||||
foreach (var stat in score.SortedStatistics)
|
||||
bottomStatistics.Add(new CounterStatistic(stat.Key.GetDescription(), stat.Value));
|
||||
bottomStatistics.Add(new HitResultStatistic(stat.Key, stat.Value));
|
||||
|
||||
statisticDisplays.AddRange(topStatistics);
|
||||
statisticDisplays.AddRange(bottomStatistics);
|
||||
@ -86,14 +87,14 @@ namespace osu.Game.Screens.Ranking.Expanded
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Text = new LocalisedString((metadata.Title, metadata.TitleUnicode)),
|
||||
Text = new LocalisedString((metadata.TitleUnicode, metadata.Title)),
|
||||
Font = OsuFont.Torus.With(size: 20, weight: FontWeight.SemiBold),
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Text = new LocalisedString((metadata.Artist, metadata.ArtistUnicode)),
|
||||
Text = new LocalisedString((metadata.ArtistUnicode, metadata.Artist)),
|
||||
Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold)
|
||||
},
|
||||
new Container
|
||||
@ -158,12 +159,17 @@ namespace osu.Game.Screens.Ranking.Expanded
|
||||
},
|
||||
new OsuTextFlowContainer(s => s.Font = OsuFont.Torus.With(size: 12))
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
}.With(t =>
|
||||
{
|
||||
t.AddText("mapped by ");
|
||||
t.AddText(score.UserString, s => s.Font = s.Font.With(weight: FontWeight.SemiBold));
|
||||
if (!string.IsNullOrEmpty(creator))
|
||||
{
|
||||
t.AddText("mapped by ");
|
||||
t.AddText(creator, s => s.Font = s.Font.With(weight: FontWeight.SemiBold));
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
@ -198,6 +204,13 @@ namespace osu.Game.Screens.Ranking.Expanded
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold),
|
||||
Text = $"Played on {score.Date.ToLocalTime():g}"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -0,0 +1,27 @@
|
||||
// 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.Extensions;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Screens.Ranking.Expanded.Statistics
|
||||
{
|
||||
public class HitResultStatistic : CounterStatistic
|
||||
{
|
||||
private readonly HitResult result;
|
||||
|
||||
public HitResultStatistic(HitResult result, int count)
|
||||
: base(result.GetDescription(), count)
|
||||
{
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
HeaderText.Colour = colours.ForHitResult(result);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
@ -16,8 +17,9 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics
|
||||
/// </summary>
|
||||
public abstract class StatisticDisplay : CompositeDrawable
|
||||
{
|
||||
private readonly string header;
|
||||
protected SpriteText HeaderText { get; private set; }
|
||||
|
||||
private readonly string header;
|
||||
private Drawable content;
|
||||
|
||||
/// <summary>
|
||||
@ -53,7 +55,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#222")
|
||||
},
|
||||
new OsuSpriteText
|
||||
HeaderText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
@ -135,7 +136,7 @@ namespace osu.Game.Screens.Ranking
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
content.Height = DrawHeight;
|
||||
content.Height = Math.Max(768, DrawHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user