diff --git a/osu-framework b/osu-framework
index 71900dc350..6372fb22c1 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 71900dc350bcebbb60d912d4023a1d2a6bbbc3c1
+Subproject commit 6372fb22c1c85f600921a139849b8dedf71026d5
diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs
index d49e9c7c26..4dbe65b3ce 100644
--- a/osu.Game.Rulesets.Catch/CatchRuleset.cs
+++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs
@@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Catch
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap);
- public override int LegacyID => 2;
+ public override int? LegacyID => 2;
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new CatchReplayFrame();
diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
index 3ad498e6ea..16b6888f2b 100644
--- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs
+++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
@@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Mania
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap);
- public override int LegacyID => 3;
+ public override int? LegacyID => 3;
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame();
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
index baa9eac1a3..058e3606f4 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
@@ -50,10 +50,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void UpdatePreemptState()
{
- this.Animate(
- d => d.FadeIn(ANIM_DURATION),
- d => d.ScaleTo(0.5f).ScaleTo(1f, ANIM_DURATION * 4, Easing.OutElasticHalf)
- );
+ this.FadeOut().FadeIn(ANIM_DURATION);
+ this.ScaleTo(0.5f).ScaleTo(1f, ANIM_DURATION * 4, Easing.OutElasticHalf);
}
protected override void UpdateCurrentState(ArmedState state)
@@ -64,12 +62,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
this.Delay(HitObject.TimePreempt).FadeOut();
break;
case ArmedState.Miss:
- this.FadeOut(ANIM_DURATION)
- .FadeColour(Color4.Red, ANIM_DURATION / 2);
+ this.FadeOut(ANIM_DURATION);
+ this.FadeColour(Color4.Red, ANIM_DURATION / 2);
break;
case ArmedState.Hit:
- this.FadeOut(ANIM_DURATION, Easing.OutQuint)
- .ScaleTo(Scale * 1.5f, ANIM_DURATION, Easing.Out);
+ this.FadeOut(ANIM_DURATION, Easing.OutQuint);
+ this.ScaleTo(Scale * 1.5f, ANIM_DURATION, Easing.Out);
break;
}
}
diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs
index 3f0aea5cb2..d407835a96 100644
--- a/osu.Game.Rulesets.Osu/OsuRuleset.cs
+++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs
@@ -145,7 +145,7 @@ namespace osu.Game.Rulesets.Osu
public override SettingsSubsection CreateSettings() => new OsuSettings();
- public override int LegacyID => 0;
+ public override int? LegacyID => 0;
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new OsuReplayFrame();
diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs
index e5fe288f20..9d6b5b5ce4 100644
--- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs
+++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs
@@ -101,16 +101,16 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
// The duration of the taiko hit object
double taikoDuration = distance / taikoVelocity;
- // For some reason, old osu! always uses speedAdjustment to determine the taiko velocity, but
- // only uses it to determine osu! velocity if beatmap version < 8. Let's account for that here.
- if (beatmap.BeatmapInfo.BeatmapVersion >= 8)
- speedAdjustedBeatLength *= speedAdjustment;
-
// The velocity of the osu! hit object - calculated as the velocity of a slider
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength;
// The duration of the osu! hit object
double osuDuration = distance / osuVelocity;
+ // osu-stable always uses the speed-adjusted beatlength to determine the velocities, but
+ // only uses it for tick rate if beatmap version < 8
+ if (beatmap.BeatmapInfo.BeatmapVersion >= 8)
+ speedAdjustedBeatLength *= speedAdjustment;
+
// If the drum roll is to be split into hit circles, assume the ticks are 1/8 spaced within the duration of one beat
double tickSpacing = Math.Min(speedAdjustedBeatLength / beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate, taikoDuration / spans);
diff --git a/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/slider-generating-drumroll-expected-conversion.json b/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/slider-generating-drumroll-expected-conversion.json
new file mode 100644
index 0000000000..fc7d466c1b
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/slider-generating-drumroll-expected-conversion.json
@@ -0,0 +1,87 @@
+{
+ "Mappings": [{
+ "StartTime": 6590,
+ "Objects": [{
+ "StartTime": 6590,
+ "EndTime": 8320,
+ "IsRim": false,
+ "IsCentre": false,
+ "IsDrumRoll": true,
+ "IsSwell": false,
+ "IsStrong": false
+ }]
+ },
+ {
+ "StartTime": 8436,
+ "Objects": [{
+ "StartTime": 8436,
+ "EndTime": 10166,
+ "IsRim": false,
+ "IsCentre": false,
+ "IsDrumRoll": true,
+ "IsSwell": false,
+ "IsStrong": false
+ }]
+ },
+ {
+ "StartTime": 10282,
+ "Objects": [{
+ "StartTime": 10282,
+ "EndTime": 12012,
+ "IsRim": false,
+ "IsCentre": false,
+ "IsDrumRoll": true,
+ "IsSwell": false,
+ "IsStrong": false
+ }]
+ },
+ {
+ "StartTime": 12128,
+ "Objects": [{
+ "StartTime": 12128,
+ "EndTime": 13858,
+ "IsRim": false,
+ "IsCentre": false,
+ "IsDrumRoll": true,
+ "IsSwell": false,
+ "IsStrong": false
+ }]
+ },
+ {
+ "StartTime": 41666,
+ "Objects": [{
+ "StartTime": 41666,
+ "EndTime": 42589,
+ "IsRim": false,
+ "IsCentre": false,
+ "IsDrumRoll": true,
+ "IsSwell": false,
+ "IsStrong": false
+ }]
+ },
+ {
+ "StartTime": 62666,
+ "Objects": [{
+ "StartTime": 62666,
+ "EndTime": 63127,
+ "IsRim": false,
+ "IsCentre": false,
+ "IsDrumRoll": true,
+ "IsSwell": false,
+ "IsStrong": false
+ }]
+ },
+ {
+ "StartTime": 208743,
+ "Objects": [{
+ "StartTime": 208743,
+ "EndTime": 209204,
+ "IsRim": false,
+ "IsCentre": false,
+ "IsDrumRoll": true,
+ "IsSwell": false,
+ "IsStrong": false
+ }]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/slider-generating-drumroll.osu b/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/slider-generating-drumroll.osu
new file mode 100644
index 0000000000..4c493b47d4
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/slider-generating-drumroll.osu
@@ -0,0 +1,25 @@
+osu file format v14
+
+[Difficulty]
+HPDrainRate:6
+CircleSize:4.2
+OverallDifficulty:9
+ApproachRate:9.8
+SliderMultiplier:1.87
+SliderTickRate:1
+
+[TimingPoints]
+6590,461.538461538462,4,2,2,15,1,0
+6590,-200,4,2,2,15,0,0
+49051,230.769230769231,4,2,1,15,1,0
+62666,-200,4,2,1,60,0,0
+197666,-100,4,2,1,85,0,1
+
+[HitObjects]
+88,104,6590,6,0,B|176:156|256:108|256:108|336:60|423:112,1,350.625,6|0,0:0|0:0,0:0:0:0:
+396,213,8436,2,0,P|277:247|376:172,1,350.625,6|0,0:0|0:0,0:0:0:0:
+472,220,10282,2,0,P|456:288|220:300,1,350.625,6|0,0:0|0:0,0:0:0:0:
+277,200,12128,2,0,P|398:225|276:244,1,350.625,6|0,0:0|0:0,0:0:0:0:
+268,229,41666,2,0,L|473:210,1,187,2|2,0:0|0:0,0:0:0:0:
+133,342,62666,2,0,B|132:316|132:316|128:316|128:316|130:295|130:295|126:296|126:296|129:275|129:275|125:275|125:275|127:254|127:254|123:255|123:255|125:234|125:234|121:234|121:234|123:213|123:213|119:214|119:214|121:193|121:193|118:193|118:193|118:172,1,187,8|8,0:0|0:0,0:0:0:0:
+481,338,208743,6,0,P|492:262|383:195,2,187,2|8|2,0:0|0:0|0:0,0:0:0:0:
diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
index 713506e831..0a9719f27b 100644
--- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
+++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
@@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Taiko
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new TaikoDifficultyCalculator(beatmap);
- public override int LegacyID => 1;
+ public override int? LegacyID => 1;
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new TaikoReplayFrame();
diff --git a/osu.Game.Rulesets.Taiko/Tests/TaikoBeatmapConversionTest.cs b/osu.Game.Rulesets.Taiko/Tests/TaikoBeatmapConversionTest.cs
index 64f728a018..385e041ace 100644
--- a/osu.Game.Rulesets.Taiko/Tests/TaikoBeatmapConversionTest.cs
+++ b/osu.Game.Rulesets.Taiko/Tests/TaikoBeatmapConversionTest.cs
@@ -22,6 +22,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
[NonParallelizable]
[TestCase("basic", false), Ignore("See: https://github.com/ppy/osu/issues/2152")]
+ [TestCase("slider-generating-drumroll", false)]
public void Test(string name, bool isForCurrentRuleset)
{
this.isForCurrentRuleset = isForCurrentRuleset;
diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
index 07d27455b8..8f0aa88e62 100644
--- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
+++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
@@ -149,6 +149,8 @@
+
+
diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
index 2e774e0924..ab10da2cd1 100644
--- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
@@ -102,7 +102,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.AreEqual(4, difficulty.CircleSize);
Assert.AreEqual(8, difficulty.OverallDifficulty);
Assert.AreEqual(9, difficulty.ApproachRate);
- Assert.AreEqual(1.8f, difficulty.SliderMultiplier);
+ Assert.AreEqual(1.8, difficulty.SliderMultiplier);
Assert.AreEqual(2, difficulty.SliderTickRate);
}
}
diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
index 8168de091e..89d96c774e 100644
--- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
@@ -85,7 +85,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.AreEqual(4, difficulty.CircleSize);
Assert.AreEqual(8, difficulty.OverallDifficulty);
Assert.AreEqual(9, difficulty.ApproachRate);
- Assert.AreEqual(1.8f, difficulty.SliderMultiplier);
+ Assert.AreEqual(1.8, difficulty.SliderMultiplier);
Assert.AreEqual(2, difficulty.SliderTickRate);
}
diff --git a/osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs b/osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs
new file mode 100644
index 0000000000..1f7a7e7165
--- /dev/null
+++ b/osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs
@@ -0,0 +1,161 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using osu.Game.Online.API.Requests;
+using osu.Game.Overlays.Profile.Sections;
+using osu.Game.Overlays.Profile.Sections.Recent;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace osu.Game.Tests.Visual
+{
+ [TestFixture]
+ public class TestCaseUserProfileRecentSection : OsuTestCase
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(RecentSection),
+ typeof(DrawableRecentActivity),
+ typeof(PaginatedRecentActivityContainer),
+ typeof(MedalIcon)
+ };
+
+ public TestCaseUserProfileRecentSection()
+ {
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = OsuColour.Gray(0.2f)
+ },
+ new ScrollContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ ChildrenEnumerable = createDummyActivities().Select(a => new DrawableRecentActivity(a))
+ },
+ }
+ };
+ }
+
+ private IEnumerable createDummyActivities()
+ {
+ var dummyBeatmap = new RecentActivity.RecentActivityBeatmap
+ {
+ Title = @"Dummy beatmap",
+ Url = "/b/1337",
+ };
+
+ var dummyUser = new RecentActivity.RecentActivityUser
+ {
+ Username = "DummyReborn",
+ Url = "/u/666",
+ PreviousUsername = "Dummy",
+ };
+
+ return new[]
+ {
+ new RecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.Achievement,
+ Achievement = new RecentActivity.RecentActivityAchievement
+ {
+ Name = @"Feelin' It",
+ Slug = @"all-secret-feelinit",
+ },
+ },
+ new RecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.BeatmapPlaycount,
+ Count = 1337,
+ Beatmap = dummyBeatmap,
+ },
+ new RecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.BeatmapsetApprove,
+ Approval = BeatmapApproval.Qualified,
+ Beatmapset = dummyBeatmap,
+ },
+ new RecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.BeatmapsetDelete,
+ Beatmapset = dummyBeatmap,
+ },
+ new RecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.BeatmapsetRevive,
+ Beatmapset = dummyBeatmap,
+ },
+ new RecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.BeatmapsetRevive,
+ Beatmapset = dummyBeatmap,
+ },
+ new RecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.BeatmapsetUpdate,
+ Beatmapset = dummyBeatmap,
+ },
+ new RecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.BeatmapsetUpload,
+ Beatmapset = dummyBeatmap,
+ },
+ new RecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.Rank,
+ Rank = 1,
+ Mode = "osu!",
+ Beatmap = dummyBeatmap,
+ },
+ new RecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.RankLost,
+ Mode = "osu!",
+ Beatmap = dummyBeatmap,
+ },
+ new RecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.UsernameChange,
+ },
+ new RecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.UserSupportAgain,
+ },
+ new RecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.UserSupportFirst,
+ },
+ new RecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.UserSupportGift,
+ },
+ };
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/TestCaseVolumePieces.cs b/osu.Game.Tests/Visual/TestCaseVolumePieces.cs
new file mode 100644
index 0000000000..cfbf7fdb4d
--- /dev/null
+++ b/osu.Game.Tests/Visual/TestCaseVolumePieces.cs
@@ -0,0 +1,30 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Graphics;
+using osu.Game.Overlays.Volume;
+using OpenTK.Graphics;
+
+namespace osu.Game.Tests.Visual
+{
+ public class TestCaseVolumePieces : OsuTestCase
+ {
+ public override IReadOnlyList RequiredTypes => new[] { typeof(VolumeMeter), typeof(MuteButton) };
+
+ protected override void LoadComplete()
+ {
+ VolumeMeter meter;
+ MuteButton mute;
+ Add(meter = new VolumeMeter("MASTER", 125, Color4.Blue));
+ Add(mute = new MuteButton
+ {
+ Margin = new MarginPadding { Top = 200 }
+ });
+
+ AddSliderStep("master volume", 0, 10, 0, i => meter.Bindable.Value = i * 0.1);
+ AddToggleStep("mute", b => mute.Current.Value = b);
+ }
+ }
+}
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index 14810abf84..1cfa7bc111 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -173,7 +173,9 @@
+
+
diff --git a/osu.Game/Beatmaps/BeatmapDifficulty.cs b/osu.Game/Beatmaps/BeatmapDifficulty.cs
index 16e6692887..38b84b4b03 100644
--- a/osu.Game/Beatmaps/BeatmapDifficulty.cs
+++ b/osu.Game/Beatmaps/BeatmapDifficulty.cs
@@ -29,8 +29,8 @@ namespace osu.Game.Beatmaps
set => approachRate = value;
}
- public float SliderMultiplier { get; set; } = 1;
- public float SliderTickRate { get; set; } = 1;
+ public double SliderMultiplier { get; set; } = 1;
+ public double SliderTickRate { get; set; } = 1;
///
/// Maps a difficulty value [0, 10] to a two-piece linear range of values.
diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
index 1d54bc4b0c..7d4f8b5bf5 100644
--- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
@@ -249,10 +249,10 @@ namespace osu.Game.Beatmaps.Formats
difficulty.ApproachRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
break;
case @"SliderMultiplier":
- difficulty.SliderMultiplier = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
+ difficulty.SliderMultiplier = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
break;
case @"SliderTickRate":
- difficulty.SliderTickRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
+ difficulty.SliderTickRate = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
break;
}
}
diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
index 9f1b44af44..1d231ada23 100644
--- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs
+++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
@@ -90,6 +90,10 @@ namespace osu.Game.Graphics.Containers
case LinkAction.External:
Process.Start(url);
break;
+ case LinkAction.OpenUserProfile:
+ if (long.TryParse(linkArgument, out long userId))
+ game?.ShowUser(userId);
+ break;
default:
throw new NotImplementedException($"This {nameof(LinkAction)} ({linkType.ToString()}) is missing an associated action.");
}
diff --git a/osu.Game/Graphics/Containers/ReverseChildIDFillFlowContainer.cs b/osu.Game/Graphics/Containers/ReverseChildIDFillFlowContainer.cs
index 9f028490ef..5803c8a5db 100644
--- a/osu.Game/Graphics/Containers/ReverseChildIDFillFlowContainer.cs
+++ b/osu.Game/Graphics/Containers/ReverseChildIDFillFlowContainer.cs
@@ -1,8 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using System.Collections.Generic;
-using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -11,7 +9,5 @@ namespace osu.Game.Graphics.Containers
public class ReverseChildIDFillFlowContainer : FillFlowContainer where T : Drawable
{
protected override int Compare(Drawable x, Drawable y) => CompareReverseChildID(x, y);
-
- protected override IEnumerable FlowingChildren => base.FlowingChildren.Reverse();
}
}
diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs
index 43a3f06236..6d9bf231c3 100644
--- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs
@@ -18,8 +18,6 @@ namespace osu.Game.Graphics.UserInterface
public Action Exit;
- public override bool HandleLeftRightArrows => false;
-
private bool focus;
public bool HoldFocus
{
diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs
index 7ad9bc73a8..20385a7dae 100644
--- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs
@@ -9,6 +9,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions;
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.Framework.Graphics.UserInterface;
@@ -56,6 +57,14 @@ namespace osu.Game.Graphics.UserInterface
}
}
+ protected override TabFillFlowContainer CreateTabFlow() => new OsuTabFillFlowContainer
+ {
+ Direction = FillDirection.Full,
+ RelativeSizeAxes = Axes.Both,
+ Depth = -1,
+ Masking = true
+ };
+
public class OsuTabItem : TabItem, IHasAccentColour
{
protected readonly SpriteText Text;
@@ -239,5 +248,10 @@ namespace osu.Game.Graphics.UserInterface
}
}
}
+
+ private class OsuTabFillFlowContainer : TabFillFlowContainer
+ {
+ protected override int Compare(Drawable x, Drawable y) => CompareReverseChildID(x, y);
+ }
}
}
diff --git a/osu.Game/Graphics/UserInterface/SearchTextBox.cs b/osu.Game/Graphics/UserInterface/SearchTextBox.cs
index 9398eb55f3..28d33bbacd 100644
--- a/osu.Game/Graphics/UserInterface/SearchTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/SearchTextBox.cs
@@ -12,6 +12,8 @@ namespace osu.Game.Graphics.UserInterface
{
protected virtual bool AllowCommit => false;
+ public override bool HandleLeftRightArrows => false;
+
public SearchTextBox()
{
Height = 35;
diff --git a/osu.Game/Graphics/UserInterface/Volume/VolumeMeter.cs b/osu.Game/Graphics/UserInterface/Volume/VolumeMeter.cs
deleted file mode 100644
index ef3702fdf3..0000000000
--- a/osu.Game/Graphics/UserInterface/Volume/VolumeMeter.cs
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Framework.Configuration;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Game.Graphics.Sprites;
-using OpenTK;
-using OpenTK.Graphics;
-using osu.Framework.Graphics.Shapes;
-using osu.Framework.Input.Bindings;
-using osu.Game.Input.Bindings;
-
-namespace osu.Game.Graphics.UserInterface.Volume
-{
- public class VolumeMeter : Container, IKeyBindingHandler
- {
- private readonly Box meterFill;
- public BindableDouble Bindable { get; } = new BindableDouble();
-
- public VolumeMeter(string meterName)
- {
- Size = new Vector2(40, 180);
- Children = new Drawable[]
- {
- new Box
- {
- Colour = Color4.Black,
- RelativeSizeAxes = Axes.Both
- },
- new Container
- {
- RelativeSizeAxes = Axes.Both,
- Size = new Vector2(0.5f, 0.9f),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Children = new Drawable[]
- {
- new Box
- {
- Colour = Color4.DarkGray,
- RelativeSizeAxes = Axes.Both
- },
- meterFill = new Box
- {
- Colour = Color4.White,
- Scale = new Vector2(1, 0),
- RelativeSizeAxes = Axes.Both,
- Origin = Anchor.BottomCentre,
- Anchor = Anchor.BottomCentre
- }
- }
- },
- new OsuSpriteText
- {
- Text = meterName,
- Anchor = Anchor.BottomCentre,
- Origin = Anchor.TopCentre
- }
- };
-
- Bindable.ValueChanged += delegate { updateFill(); };
- }
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
- updateFill();
- }
-
- public double Volume
- {
- get => Bindable.Value;
- private set => Bindable.Value = value;
- }
-
- public void Increase()
- {
- Volume += 0.05f;
- }
-
- public void Decrease()
- {
- Volume -= 0.05f;
- }
-
- private void updateFill() => meterFill.ScaleTo(new Vector2(1, (float)Volume), 300, Easing.OutQuint);
-
- public bool OnPressed(GlobalAction action)
- {
- if (!IsHovered) return false;
-
- switch (action)
- {
- case GlobalAction.DecreaseVolume:
- Decrease();
- return true;
- case GlobalAction.IncreaseVolume:
- Increase();
- return true;
- }
-
- return false;
- }
-
- public bool OnReleased(GlobalAction action) => false;
- }
-}
diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs
index 90f3999ddd..1325179e0d 100644
--- a/osu.Game/Online/API/APIAccess.cs
+++ b/osu.Game/Online/API/APIAccess.cs
@@ -199,7 +199,7 @@ namespace osu.Game.Online.API
}
catch (WebException we)
{
- HttpStatusCode statusCode = (we.Response as HttpWebResponse)?.StatusCode ?? HttpStatusCode.RequestTimeout;
+ HttpStatusCode statusCode = (we.Response as HttpWebResponse)?.StatusCode ?? (we.Status == WebExceptionStatus.UnknownError ? HttpStatusCode.NotAcceptable : HttpStatusCode.RequestTimeout);
switch (statusCode)
{
diff --git a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs
new file mode 100644
index 0000000000..d1685b01f3
--- /dev/null
+++ b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs
@@ -0,0 +1,130 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using Newtonsoft.Json;
+using osu.Game.Rulesets.Scoring;
+using Humanizer;
+using System;
+using System.Collections.Generic;
+
+namespace osu.Game.Online.API.Requests
+{
+ public class GetUserRecentActivitiesRequest : APIRequest>
+ {
+ private readonly long userId;
+ private readonly int offset;
+
+ public GetUserRecentActivitiesRequest(long userId, int offset = 0)
+ {
+ this.userId = userId;
+ this.offset = offset;
+ }
+
+ protected override string Target => $"users/{userId}/recent_activity?offset={offset}";
+ }
+
+ public class RecentActivity
+ {
+ [JsonProperty("id")]
+ public int ID;
+
+ [JsonProperty("createdAt")]
+ public DateTimeOffset CreatedAt;
+
+ [JsonProperty]
+ private string type
+ {
+ set => Type = (RecentActivityType)Enum.Parse(typeof(RecentActivityType), value.Pascalize());
+ }
+
+ public RecentActivityType Type;
+
+ [JsonProperty]
+ private string scoreRank
+ {
+ set => ScoreRank = (ScoreRank)Enum.Parse(typeof(ScoreRank), value);
+ }
+
+ public ScoreRank ScoreRank;
+
+ [JsonProperty("rank")]
+ public int Rank;
+
+ [JsonProperty("approval")]
+ public BeatmapApproval Approval;
+
+ [JsonProperty("count")]
+ public int Count;
+
+ [JsonProperty("mode")]
+ public string Mode;
+
+ [JsonProperty("beatmap")]
+ public RecentActivityBeatmap Beatmap;
+
+ [JsonProperty("beatmapset")]
+ public RecentActivityBeatmap Beatmapset;
+
+ [JsonProperty("user")]
+ public RecentActivityUser User;
+
+ [JsonProperty("achievement")]
+ public RecentActivityAchievement Achievement;
+
+ public class RecentActivityBeatmap
+ {
+ [JsonProperty("title")]
+ public string Title;
+
+ [JsonProperty("url")]
+ public string Url;
+ }
+
+ public class RecentActivityUser
+ {
+ [JsonProperty("username")]
+ public string Username;
+
+ [JsonProperty("url")]
+ public string Url;
+
+ [JsonProperty("previousUsername")]
+ public string PreviousUsername;
+ }
+
+ public class RecentActivityAchievement
+ {
+ [JsonProperty("slug")]
+ public string Slug;
+
+ [JsonProperty("name")]
+ public string Name;
+ }
+
+ }
+
+ public enum RecentActivityType
+ {
+ Achievement,
+ BeatmapPlaycount,
+ BeatmapsetApprove,
+ BeatmapsetDelete,
+ BeatmapsetRevive,
+ BeatmapsetUpdate,
+ BeatmapsetUpload,
+ Medal,
+ Rank,
+ RankLost,
+ UserSupportAgain,
+ UserSupportFirst,
+ UserSupportGift,
+ UsernameChange,
+ }
+
+ public enum BeatmapApproval
+ {
+ Ranked,
+ Approved,
+ Qualified,
+ }
+}
diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs
index 906f42d50e..9966f78435 100644
--- a/osu.Game/Online/Chat/MessageFormatter.cs
+++ b/osu.Game/Online/Chat/MessageFormatter.cs
@@ -118,6 +118,8 @@ namespace osu.Game.Online.Chat
case "beatmapsets":
case "d":
return new LinkDetails(LinkAction.OpenBeatmapSet, args[3]);
+ case "u":
+ return new LinkDetails(LinkAction.OpenUserProfile, args[3]);
}
}
@@ -146,6 +148,9 @@ namespace osu.Game.Online.Chat
case "spectate":
linkType = LinkAction.Spectate;
break;
+ case "u":
+ linkType = LinkAction.OpenUserProfile;
+ break;
default:
linkType = LinkAction.External;
break;
@@ -205,6 +210,15 @@ namespace osu.Game.Online.Chat
return inputMessage;
}
+ public static MessageFormatterResult FormatText(string text)
+ {
+ var result = format(text);
+
+ result.Links.Sort();
+
+ return result;
+ }
+
public class MessageFormatterResult
{
public List Links = new List();
@@ -239,6 +253,7 @@ namespace osu.Game.Online.Chat
OpenEditorTimestamp,
JoinMultiplayerMatch,
Spectate,
+ OpenUserProfile,
}
public class Link : IComparable
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index aeb23dccd7..e656c7256e 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -10,7 +10,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Overlays;
using osu.Framework.Logging;
-using osu.Game.Graphics.UserInterface.Volume;
using osu.Framework.Allocation;
using osu.Game.Overlays.Toolbar;
using osu.Game.Screens;
@@ -33,6 +32,7 @@ using osu.Game.Input.Bindings;
using osu.Game.Rulesets.Mods;
using osu.Game.Skinning;
using OpenTK.Graphics;
+using osu.Game.Overlays.Volume;
namespace osu.Game
{
@@ -75,7 +75,7 @@ namespace osu.Game
private OsuScreen screenStack;
- private VolumeControl volume;
+ private VolumeOverlay volume;
private OnScreenDisplay onscreenDisplay;
private Bindable configRuleset;
@@ -155,6 +155,12 @@ namespace osu.Game
/// The set to display.
public void ShowBeatmapSet(int setId) => beatmapSetOverlay.ShowBeatmapSet(setId);
+ ///
+ /// Show a user's profile as an overlay.
+ ///
+ /// The user to display.
+ public void ShowUser(long userId) => userProfile.ShowUser(userId);
+
protected void LoadScore(Score s)
{
scoreLoad?.Cancel();
@@ -232,7 +238,7 @@ namespace osu.Game
},
}, overlayContent.Add);
- loadComponentSingleFile(volume = new VolumeControl(), Add);
+ loadComponentSingleFile(volume = new VolumeOverlay(), overlayContent.Add);
loadComponentSingleFile(onscreenDisplay = new OnScreenDisplay(), Add);
//overlay elements
diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs
index f028590bb4..1d3dab249d 100644
--- a/osu.Game/Overlays/Chat/ChatTabControl.cs
+++ b/osu.Game/Overlays/Chat/ChatTabControl.cs
@@ -53,9 +53,9 @@ namespace osu.Game.Overlays.Chat
protected override void AddTabItem(TabItem item, bool addToDropdown = true)
{
- if (selectorTab.Depth < float.MaxValue)
+ if (item != selectorTab && TabContainer.GetLayoutPosition(selectorTab) < float.MaxValue)
// performTabSort might've made selectorTab's position wonky, fix it
- TabContainer.ChangeChildDepth(selectorTab, float.MaxValue);
+ TabContainer.SetLayoutPosition(selectorTab, float.MaxValue);
base.AddTabItem(item, addToDropdown);
diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs
index 31b7d0f9aa..03ce7fd88f 100644
--- a/osu.Game/Overlays/Music/PlaylistList.cs
+++ b/osu.Game/Overlays/Music/PlaylistList.cs
@@ -101,11 +101,10 @@ namespace osu.Game.Overlays.Music
public void AddBeatmapSet(BeatmapSetInfo beatmapSet)
{
- items.Add(new PlaylistItem(beatmapSet)
- {
- OnSelect = set => OnSelect?.Invoke(set),
- Depth = items.Count
- });
+ var newItem = new PlaylistItem(beatmapSet) { OnSelect = set => OnSelect?.Invoke(set) };
+
+ items.Add(newItem);
+ items.SetLayoutPosition(newItem, items.Count);
}
public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet)
@@ -197,7 +196,7 @@ namespace osu.Game.Overlays.Music
{
var itemsPos = items.ToLocalSpace(nativeDragPosition);
- int srcIndex = (int)draggedItem.Depth;
+ int srcIndex = (int)items.GetLayoutPosition(draggedItem);
// Find the last item with position < mouse position. Note we can't directly use
// the item positions as they are being transformed
@@ -219,15 +218,15 @@ namespace osu.Game.Overlays.Music
if (srcIndex < dstIndex)
{
for (int i = srcIndex + 1; i <= dstIndex; i++)
- items.ChangeChildDepth(items[i], i - 1);
+ items.SetLayoutPosition(items[i], i - 1);
}
else
{
for (int i = dstIndex; i < srcIndex; i++)
- items.ChangeChildDepth(items[i], i + 1);
+ items.SetLayoutPosition(items[i], i + 1);
}
- items.ChangeChildDepth(draggedItem, dstIndex);
+ items.SetLayoutPosition(draggedItem, dstIndex);
}
private class ItemSearchContainer : FillFlowContainer, IHasFilterableChildren
@@ -243,9 +242,6 @@ namespace osu.Game.Overlays.Music
}
}
- // Compare with reversed ChildID and Depth
- protected override int Compare(Drawable x, Drawable y) => base.Compare(y, x);
-
public IEnumerable FilterableChildren => Children;
public ItemSearchContainer()
diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs
index 2f46bb4a71..48ad507d88 100644
--- a/osu.Game/Overlays/NotificationOverlay.cs
+++ b/osu.Game/Overlays/NotificationOverlay.cs
@@ -129,7 +129,6 @@ namespace osu.Game.Overlays
public void Post(Notification notification) => postScheduler.Add(() =>
{
++runningDepth;
- notification.Depth = notification.DisplayOnTop ? runningDepth : -runningDepth;
notification.Closed += notificationClosed;
@@ -138,7 +137,9 @@ namespace osu.Game.Overlays
hasCompletionTarget.CompletionTarget = Post;
var ourType = notification.GetType();
- sections.Children.FirstOrDefault(s => s.AcceptTypes.Any(accept => accept.IsAssignableFrom(ourType)))?.Add(notification);
+
+ var section = sections.Children.FirstOrDefault(s => s.AcceptTypes.Any(accept => accept.IsAssignableFrom(ourType)));
+ section?.Add(notification, notification.DisplayOnTop ? -runningDepth : runningDepth);
updateCounts();
});
diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs
index 13a69fbe3a..533f5326e3 100644
--- a/osu.Game/Overlays/Notifications/NotificationSection.cs
+++ b/osu.Game/Overlays/Notifications/NotificationSection.cs
@@ -25,10 +25,13 @@ namespace osu.Game.Overlays.Notifications
private FlowContainer notifications;
public int DisplayedCount => notifications.Count(n => !n.WasClosed);
-
public int UnreadCount => notifications.Count(n => !n.WasClosed && !n.Read);
- public void Add(Notification notification) => notifications.Add(notification);
+ public void Add(Notification notification, float position)
+ {
+ notifications.Add(notification);
+ notifications.SetLayoutPosition(notification, position);
+ }
public IEnumerable AcceptTypes;
diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
index 51b202844a..bb1a409f2e 100644
--- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
+++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
@@ -40,16 +40,18 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
[BackgroundDependencyLoader(true)]
private void load(OsuColour colour)
{
- RightFlowContainer.Add(new OsuSpriteText
+ var text = new OsuSpriteText
{
Text = $"accuracy: {Score.Accuracy:P2}",
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Colour = colour.GrayA,
TextSize = 11,
- Font = "Exo2.0-RegularItalic",
- Depth = -1,
- });
+ Font = "Exo2.0-RegularItalic"
+ };
+
+ RightFlowContainer.Add(text);
+ RightFlowContainer.SetLayoutPosition(text, 1);
LeftFlowContainer.Add(new BeatmapMetadataContainer(Score.Beatmap));
LeftFlowContainer.Add(new OsuSpriteText
diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs
new file mode 100644
index 0000000000..2dde8a3d54
--- /dev/null
+++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs
@@ -0,0 +1,165 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Online.API;
+using osu.Game.Online.API.Requests;
+using osu.Game.Online.Chat;
+using osu.Game.Screens.Select.Leaderboards;
+
+namespace osu.Game.Overlays.Profile.Sections.Recent
+{
+ public class DrawableRecentActivity : DrawableProfileRow
+ {
+ private APIAccess api;
+
+ private readonly RecentActivity activity;
+
+ private LinkFlowContainer content;
+
+ public DrawableRecentActivity(RecentActivity activity)
+ {
+ this.activity = activity;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(APIAccess api)
+ {
+ this.api = api;
+
+ LeftFlowContainer.Padding = new MarginPadding { Left = 10, Right = 160 };
+
+ LeftFlowContainer.Add(content = new LinkFlowContainer
+ {
+ AutoSizeAxes = Axes.Y,
+ RelativeSizeAxes = Axes.X,
+ });
+
+ RightFlowContainer.Add(new OsuSpriteText
+ {
+ Text = activity.CreatedAt.LocalDateTime.ToShortDateString(),
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ Font = "Exo2.0-RegularItalic",
+ TextSize = 12,
+ Colour = OsuColour.Gray(0xAA),
+ });
+
+ var formatted = createMessage();
+
+ content.AddLinks(formatted.Text, formatted.Links);
+ }
+
+ protected override Drawable CreateLeftVisual()
+ {
+ switch (activity.Type)
+ {
+ case RecentActivityType.Rank:
+ return new DrawableRank(activity.ScoreRank)
+ {
+ RelativeSizeAxes = Axes.Y,
+ Width = 60,
+ FillMode = FillMode.Fit,
+ };
+
+ case RecentActivityType.Achievement:
+ return new MedalIcon(activity.Achievement.Slug)
+ {
+ RelativeSizeAxes = Axes.Y,
+ Width = 60,
+ FillMode = FillMode.Fit,
+ };
+
+ default:
+ return new Container
+ {
+ RelativeSizeAxes = Axes.Y,
+ Width = 60,
+ FillMode = FillMode.Fit,
+ };
+ }
+ }
+
+ private string toAbsoluteUrl(string url) => $"{api.Endpoint}{url}";
+
+ private MessageFormatter.MessageFormatterResult createMessage()
+ {
+ string userLinkTemplate() => $"[{toAbsoluteUrl(activity.User?.Url)} {activity.User?.Username}]";
+ string beatmapLinkTemplate() => $"[{toAbsoluteUrl(activity.Beatmap?.Url)} {activity.Beatmap?.Title}]";
+ string beatmapsetLinkTemplate() => $"[{toAbsoluteUrl(activity.Beatmapset?.Url)} {activity.Beatmapset?.Title}]";
+
+ string message;
+
+ switch (activity.Type)
+ {
+ case RecentActivityType.Achievement:
+ message = $"{userLinkTemplate()} unlocked the {activity.Achievement.Name} medal!";
+ break;
+
+ case RecentActivityType.BeatmapPlaycount:
+ message = $"{beatmapLinkTemplate()} has been played {activity.Count} times!";
+ break;
+
+ case RecentActivityType.BeatmapsetApprove:
+ message = $"{beatmapsetLinkTemplate()} has been {activity.Approval.ToString().ToLowerInvariant()}!";
+ break;
+
+ case RecentActivityType.BeatmapsetDelete:
+ message = $"{beatmapsetLinkTemplate()} has been deleted.";
+ break;
+
+ case RecentActivityType.BeatmapsetRevive:
+ message = $"{beatmapsetLinkTemplate()} has been revived from eternal slumber by {userLinkTemplate()}.";
+ break;
+
+ case RecentActivityType.BeatmapsetUpdate:
+ message = $"{userLinkTemplate()} has updated the beatmap {beatmapsetLinkTemplate()}!";
+ break;
+
+ case RecentActivityType.BeatmapsetUpload:
+ message = $"{userLinkTemplate()} has submitted a new beatmap {beatmapsetLinkTemplate()}!";
+ break;
+
+ case RecentActivityType.Medal:
+ // apparently this shouldn't exist look at achievement instead (https://github.com/ppy/osu-web/blob/master/resources/assets/coffee/react/profile-page/recent-activity.coffee#L111)
+ message = string.Empty;
+ break;
+
+ case RecentActivityType.Rank:
+ message = $"{userLinkTemplate()} achieved rank #{activity.Rank} on {beatmapLinkTemplate()} ({activity.Mode}!)";
+ break;
+
+ case RecentActivityType.RankLost:
+ message = $"{userLinkTemplate()} has lost first place on {beatmapLinkTemplate()} ({activity.Mode}!)";
+ break;
+
+ case RecentActivityType.UserSupportAgain:
+ message = $"{userLinkTemplate()} has once again chosen to support osu! - thanks for your generosity!";
+ break;
+
+ case RecentActivityType.UserSupportFirst:
+ message = $"{userLinkTemplate()} has become an osu! supporter - thanks for your generosity!";
+ break;
+
+ case RecentActivityType.UserSupportGift:
+ message = $"{userLinkTemplate()} has received the gift of osu! supporter!";
+ break;
+
+ case RecentActivityType.UsernameChange:
+ message = $"{activity.User?.PreviousUsername} has changed their username to {userLinkTemplate()}!";
+ break;
+
+ default:
+ message = string.Empty;
+ break;
+ }
+
+ return MessageFormatter.FormatText(message);
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs
new file mode 100644
index 0000000000..6ffbe7193f
--- /dev/null
+++ b/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs
@@ -0,0 +1,38 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Textures;
+
+namespace osu.Game.Overlays.Profile.Sections.Recent
+{
+ public class MedalIcon : Container
+ {
+ private readonly string slug;
+ private readonly Sprite sprite;
+
+ private string url => $@"https://s.ppy.sh/images/medals-client/{slug}@2x.png";
+
+ public MedalIcon(string slug)
+ {
+ this.slug = slug;
+
+ Child = sprite = new Sprite
+ {
+ Height = 40,
+ Width = 40,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(TextureStore textures)
+ {
+ sprite.Texture = textures.Get(url);
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs
new file mode 100644
index 0000000000..d479627cde
--- /dev/null
+++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs
@@ -0,0 +1,48 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Configuration;
+using osu.Framework.Graphics;
+using osu.Game.Online.API.Requests;
+using osu.Game.Users;
+using System.Linq;
+
+namespace osu.Game.Overlays.Profile.Sections.Recent
+{
+ public class PaginatedRecentActivityContainer : PaginatedContainer
+ {
+ public PaginatedRecentActivityContainer(Bindable user, string header, string missing)
+ : base(user, header, missing)
+ {
+ ItemsPerPage = 5;
+ }
+
+ protected override void ShowMore()
+ {
+ base.ShowMore();
+
+ var req = new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++ * ItemsPerPage);
+
+ req.Success += activities =>
+ {
+ ShowMoreButton.FadeTo(activities.Count == ItemsPerPage ? 1 : 0);
+ ShowMoreLoading.Hide();
+
+ if (!activities.Any() && VisiblePages == 1)
+ {
+ MissingText.Show();
+ return;
+ }
+
+ MissingText.Hide();
+
+ foreach (RecentActivity activity in activities)
+ {
+ ItemsContainer.Add(new DrawableRecentActivity(activity));
+ }
+ };
+
+ Api.Queue(req);
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Profile/Sections/RecentSection.cs b/osu.Game/Overlays/Profile/Sections/RecentSection.cs
index 78b139efe8..84a941aa1a 100644
--- a/osu.Game/Overlays/Profile/Sections/RecentSection.cs
+++ b/osu.Game/Overlays/Profile/Sections/RecentSection.cs
@@ -1,12 +1,22 @@
// Copyright (c) 2007-2018 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using osu.Game.Overlays.Profile.Sections.Recent;
+
namespace osu.Game.Overlays.Profile.Sections
{
public class RecentSection : ProfileSection
{
public override string Title => "Recent";
- public override string Identifier => "recent_activities";
+ public override string Identifier => "recent_activity";
+
+ public RecentSection()
+ {
+ Children = new[]
+ {
+ new PaginatedRecentActivityContainer(User, null, @"This user hasn't done anything notable recently!"),
+ };
+ }
}
}
diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs
index 5afc415d83..cc290fe1bb 100644
--- a/osu.Game/Overlays/Settings/SettingsItem.cs
+++ b/osu.Game/Overlays/Settings/SettingsItem.cs
@@ -45,7 +45,8 @@ namespace osu.Game.Overlays.Settings
if (text == null)
{
// construct lazily for cases where the label is not needed (may be provided by the Control).
- Add(text = new OsuSpriteText { Depth = 1 });
+ Add(text = new OsuSpriteText());
+ FlowContent.SetLayoutPosition(text, -1);
}
text.Text = value;
diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs
index 59f940a19d..f3fd7aeac5 100644
--- a/osu.Game/Overlays/UserProfileOverlay.cs
+++ b/osu.Game/Overlays/UserProfileOverlay.cs
@@ -73,6 +73,14 @@ namespace osu.Game.Overlays
FadeEdgeEffectTo(0, DISAPPEAR_DURATION, Easing.Out);
}
+ public void ShowUser(long userId)
+ {
+ if (userId == Header.User.Id)
+ return;
+
+ ShowUser(new User { Id = userId });
+ }
+
public void ShowUser(User user, bool fetchOnline = true)
{
userReq?.Cancel();
@@ -82,7 +90,7 @@ namespace osu.Game.Overlays
sections = new ProfileSection[]
{
//new AboutSection(),
- //new RecentSection(),
+ new RecentSection(),
new RanksSection(),
//new MedalsSection(),
new HistoricalSection(),
diff --git a/osu.Game/Overlays/Volume/MuteButton.cs b/osu.Game/Overlays/Volume/MuteButton.cs
new file mode 100644
index 0000000000..adfc9c610f
--- /dev/null
+++ b/osu.Game/Overlays/Volume/MuteButton.cs
@@ -0,0 +1,83 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Allocation;
+using osu.Framework.Configuration;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Colour;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Input;
+using osu.Game.Graphics;
+using OpenTK;
+using OpenTK.Graphics;
+
+namespace osu.Game.Overlays.Volume
+{
+ public class MuteButton : Container, IHasCurrentValue
+ {
+ public Bindable Current { get; } = new Bindable();
+
+ private Color4 hoveredColour, unhoveredColour;
+ private const float width = 100;
+ public const float HEIGHT = 35;
+
+ public MuteButton()
+ {
+ Masking = true;
+ BorderThickness = 3;
+ CornerRadius = HEIGHT / 2;
+ Size = new Vector2(width, HEIGHT);
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ hoveredColour = colours.YellowDark;
+ BorderColour = unhoveredColour = colours.Gray1.Opacity(0.9f);
+
+ SpriteIcon icon;
+ AddRange(new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = colours.Gray1,
+ Alpha = 0.9f,
+ },
+ icon = new SpriteIcon
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Size = new Vector2(20),
+ }
+ });
+
+ Current.ValueChanged += newValue =>
+ {
+ icon.Icon = newValue ? FontAwesome.fa_volume_off : FontAwesome.fa_volume_up;
+ icon.Margin = new MarginPadding { Left = newValue ? width / 2 - 15 : width / 2 - 10 }; //Magic numbers to line up both icons because they're different widths
+ };
+ Current.TriggerChange();
+ }
+
+ protected override bool OnHover(InputState state)
+ {
+ this.TransformTo("BorderColour", hoveredColour, 500, Easing.OutQuint);
+ return true;
+ }
+
+ protected override void OnHoverLost(InputState state)
+ {
+ this.TransformTo("BorderColour", unhoveredColour, 500, Easing.OutQuint);
+ }
+
+ protected override bool OnClick(InputState state)
+ {
+ Current.Value = !Current.Value;
+ return true;
+ }
+ }
+}
diff --git a/osu.Game/Graphics/UserInterface/Volume/VolumeControlReceptor.cs b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs
similarity index 90%
rename from osu.Game/Graphics/UserInterface/Volume/VolumeControlReceptor.cs
rename to osu.Game/Overlays/Volume/VolumeControlReceptor.cs
index 2328533665..a5be7dc445 100644
--- a/osu.Game/Graphics/UserInterface/Volume/VolumeControlReceptor.cs
+++ b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs
@@ -7,7 +7,7 @@ using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings;
-namespace osu.Game.Graphics.UserInterface.Volume
+namespace osu.Game.Overlays.Volume
{
public class VolumeControlReceptor : Container, IKeyBindingHandler, IHandleGlobalInput
{
diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs
new file mode 100644
index 0000000000..64b9e513c4
--- /dev/null
+++ b/osu.Game/Overlays/Volume/VolumeMeter.cs
@@ -0,0 +1,186 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Globalization;
+using osu.Framework.Allocation;
+using osu.Framework.Configuration;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Effects;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Input.Bindings;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Input.Bindings;
+using OpenTK;
+using OpenTK.Graphics;
+
+namespace osu.Game.Overlays.Volume
+{
+ public class VolumeMeter : Container, IKeyBindingHandler
+ {
+ private CircularProgress volumeCircle;
+ public BindableDouble Bindable { get; } = new BindableDouble { MinValue = 0, MaxValue = 1 };
+ private readonly float circleSize;
+ private readonly Color4 meterColour;
+ private readonly string name;
+
+ private OsuSpriteText text;
+ private BufferedContainer maxGlow;
+
+ public VolumeMeter(string name, float circleSize, Color4 meterColour)
+ {
+ this.circleSize = circleSize;
+ this.meterColour = meterColour;
+ this.name = name;
+
+ AutoSizeAxes = Axes.Both;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ Add(new Container
+ {
+ Size = new Vector2(120, 20),
+ CornerRadius = 10,
+ Masking = true,
+ Margin = new MarginPadding { Left = circleSize + 10 },
+ Origin = Anchor.CentreLeft,
+ Anchor = Anchor.CentreLeft,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = colours.Gray1,
+ Alpha = 0.9f,
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Font = "Exo2.0-Bold",
+ Text = name
+ }
+ }
+ });
+
+ CircularProgress bgProgress;
+
+ Add(new CircularContainer
+ {
+ Masking = true,
+ Size = new Vector2(circleSize),
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = colours.Gray1,
+ Alpha = 0.9f,
+ },
+ bgProgress = new CircularProgress
+ {
+ RelativeSizeAxes = Axes.Both,
+ InnerRadius = 0.05f,
+ Rotation = 180,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Colour = colours.Gray2,
+ Size = new Vector2(0.8f)
+ },
+ (volumeCircle = new CircularProgress
+ {
+ RelativeSizeAxes = Axes.Both,
+ InnerRadius = 0.05f,
+ Rotation = 180,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(0.8f)
+ }).WithEffect(new GlowEffect
+ {
+ Colour = meterColour,
+ Strength = 2
+ }),
+ maxGlow = (text = new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Font = "Venera",
+ TextSize = 0.16f * circleSize
+ }).WithEffect(new GlowEffect
+ {
+ Colour = Color4.Transparent,
+ PadExtent = true,
+ })
+ }
+ });
+
+ Bindable.ValueChanged += newVolume => { this.TransformTo("DisplayVolume", newVolume, 400, Easing.OutQuint); };
+ bgProgress.Current.Value = 0.75f;
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ Bindable.TriggerChange();
+ }
+
+ private double displayVolume;
+
+ protected double DisplayVolume
+ {
+ get => displayVolume;
+ set
+ {
+ displayVolume = value;
+
+ if (displayVolume > 0.99f)
+ {
+ text.Text = "MAX";
+ maxGlow.EffectColour = meterColour.Opacity(2f);
+ }
+ else
+ {
+ maxGlow.EffectColour = Color4.Transparent;
+ text.Text = Math.Round(displayVolume * 100).ToString(CultureInfo.CurrentCulture);
+ }
+
+ volumeCircle.Current.Value = displayVolume * 0.75f;
+ }
+ }
+
+ public double Volume
+ {
+ get => Bindable;
+ private set => Bindable.Value = value;
+ }
+
+ public void Increase() => Volume += 0.05f;
+
+ public void Decrease() => Volume -= 0.05f;
+
+ public bool OnPressed(GlobalAction action)
+ {
+ if (!IsHovered) return false;
+
+ switch (action)
+ {
+ case GlobalAction.DecreaseVolume:
+ Decrease();
+ return true;
+ case GlobalAction.IncreaseVolume:
+ Increase();
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool OnReleased(GlobalAction action) => false;
+ }
+}
diff --git a/osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs b/osu.Game/Overlays/VolumeOverlay.cs
similarity index 57%
rename from osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs
rename to osu.Game/Overlays/VolumeOverlay.cs
index ccf70af6ed..17a4b139b0 100644
--- a/osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs
+++ b/osu.Game/Overlays/VolumeOverlay.cs
@@ -1,57 +1,84 @@
// Copyright (c) 2007-2018 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Threading;
-using OpenTK;
-using osu.Framework.Audio;
using osu.Framework.Allocation;
+using osu.Framework.Audio;
using osu.Framework.Configuration;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Colour;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Threading;
+using osu.Game.Graphics;
using osu.Game.Input.Bindings;
+using osu.Game.Overlays.Volume;
+using OpenTK;
+using OpenTK.Graphics;
-namespace osu.Game.Graphics.UserInterface.Volume
+namespace osu.Game.Overlays
{
- public class VolumeControl : OverlayContainer
+ public class VolumeOverlay : OverlayContainer
{
- private readonly VolumeMeter volumeMeterMaster;
- private readonly IconButton muteIcon;
+ private const float offset = 10;
+
+ private VolumeMeter volumeMeterMaster;
+ private VolumeMeter volumeMeterEffect;
+ private VolumeMeter volumeMeterMusic;
+ private MuteButton muteButton;
protected override bool BlockPassThroughMouse => false;
- public VolumeControl()
- {
- AutoSizeAxes = Axes.Both;
- Anchor = Anchor.BottomRight;
- Origin = Anchor.BottomRight;
+ private readonly BindableDouble muteAdjustment = new BindableDouble();
- Children = new Drawable[]
+ [BackgroundDependencyLoader]
+ private void load(AudioManager audio, OsuColour colours)
+ {
+ AutoSizeAxes = Axes.X;
+ RelativeSizeAxes = Axes.Y;
+
+ AddRange(new Drawable[]
{
+ new Box
+ {
+ RelativeSizeAxes = Axes.Y,
+ Width = 300,
+ Colour = ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.75f), Color4.Black.Opacity(0))
+ },
new FillFlowContainer
{
+ Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Both,
- Anchor = Anchor.BottomRight,
- Origin = Anchor.BottomRight,
- Margin = new MarginPadding { Left = 10, Right = 10, Top = 30, Bottom = 30 },
- Spacing = new Vector2(15, 0),
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Spacing = new Vector2(0, offset),
+ Margin = new MarginPadding { Left = offset },
Children = new Drawable[]
{
- new Container
+ volumeMeterEffect = new VolumeMeter("EFFECTS", 125, colours.BlueDarker)
{
- Size = new Vector2(IconButton.BUTTON_SIZE),
- Child = muteIcon = new IconButton
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Icon = FontAwesome.fa_volume_up,
- Action = () => Adjust(GlobalAction.ToggleMute),
- }
+ Margin = new MarginPadding { Top = 100 + MuteButton.HEIGHT } //to counter the mute button and re-center the volume meters
},
- volumeMeterMaster = new VolumeMeter("Master"),
- volumeMeterEffect = new VolumeMeter("Effects"),
- volumeMeterMusic = new VolumeMeter("Music")
+ volumeMeterMaster = new VolumeMeter("MASTER", 150, colours.PinkDarker),
+ volumeMeterMusic = new VolumeMeter("MUSIC", 125, colours.BlueDarker),
+ muteButton = new MuteButton
+ {
+ Margin = new MarginPadding { Top = 100 }
+ }
}
- }
+ },
+ });
+
+ volumeMeterMaster.Bindable.BindTo(audio.Volume);
+ volumeMeterEffect.Bindable.BindTo(audio.VolumeSample);
+ volumeMeterMusic.Bindable.BindTo(audio.VolumeTrack);
+
+ muteButton.Current.ValueChanged += mute =>
+ {
+ if (mute)
+ audio.AddAdjustment(AdjustableProperty.Volume, muteAdjustment);
+ else
+ audio.RemoveAdjustment(AdjustableProperty.Volume, muteAdjustment);
};
}
@@ -62,7 +89,13 @@ namespace osu.Game.Graphics.UserInterface.Volume
volumeMeterMaster.Bindable.ValueChanged += _ => settingChanged();
volumeMeterEffect.Bindable.ValueChanged += _ => settingChanged();
volumeMeterMusic.Bindable.ValueChanged += _ => settingChanged();
- muted.ValueChanged += _ => settingChanged();
+ muteButton.Current.ValueChanged += _ => settingChanged();
+ }
+
+ private void settingChanged()
+ {
+ Show();
+ schedulePopOut();
}
public bool Adjust(GlobalAction action)
@@ -83,50 +116,15 @@ namespace osu.Game.Graphics.UserInterface.Volume
return true;
case GlobalAction.ToggleMute:
Show();
- muted.Toggle();
+ muteButton.Current.Value = !muteButton.Current;
return true;
}
return false;
}
- private void settingChanged()
- {
- Show();
- schedulePopOut();
- }
-
- private readonly BindableDouble muteAdjustment = new BindableDouble();
-
- private readonly BindableBool muted = new BindableBool();
-
- [BackgroundDependencyLoader]
- private void load(AudioManager audio)
- {
- volumeMeterMaster.Bindable.BindTo(audio.Volume);
- volumeMeterEffect.Bindable.BindTo(audio.VolumeSample);
- volumeMeterMusic.Bindable.BindTo(audio.VolumeTrack);
-
- muted.ValueChanged += mute =>
- {
- if (mute)
- {
- audio.AddAdjustment(AdjustableProperty.Volume, muteAdjustment);
- muteIcon.Icon = FontAwesome.fa_volume_off;
- }
- else
- {
- audio.RemoveAdjustment(AdjustableProperty.Volume, muteAdjustment);
- muteIcon.Icon = FontAwesome.fa_volume_up;
- }
- };
- }
-
private ScheduledDelegate popOutDelegate;
- private readonly VolumeMeter volumeMeterEffect;
- private readonly VolumeMeter volumeMeterMusic;
-
protected override void PopIn()
{
ClearTransforms();
diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs
index f9b64995f9..cba849a491 100644
--- a/osu.Game/Rulesets/Ruleset.cs
+++ b/osu.Game/Rulesets/Ruleset.cs
@@ -64,7 +64,7 @@ namespace osu.Game.Rulesets
///
/// Do not override this unless you are a legacy mode.
///
- public virtual int LegacyID => -1;
+ public virtual int? LegacyID => null;
///
/// A unique short name to reference this ruleset in online requests.
diff --git a/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs b/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs
index 29ae35fca4..ae1e995373 100644
--- a/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs
+++ b/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs
@@ -4,8 +4,6 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using OpenTK;
-using System.Collections.Generic;
-using System.Linq;
namespace osu.Game.Screens.Menu
{
@@ -22,8 +20,6 @@ namespace osu.Game.Screens.Menu
protected override int Compare(Drawable x, Drawable y) => CompareReverseChildID(x, y);
- protected override IEnumerable FlowingChildren => base.FlowingChildren.Reverse();
-
public override Anchor Origin => Anchor.Custom;
public override Vector2 OriginPosition
diff --git a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs
index 1a7b80ec9a..6c4d929c71 100644
--- a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs
+++ b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs
@@ -15,7 +15,6 @@ namespace osu.Game.Screens.Play.PlayerSettings
private readonly PlayerSliderBar dimSliderBar;
private readonly PlayerSliderBar blurSliderBar;
private readonly PlayerCheckbox showStoryboardToggle;
- private readonly PlayerCheckbox mouseWheelDisabledToggle;
public VisualSettings()
{
@@ -35,8 +34,7 @@ namespace osu.Game.Screens.Play.PlayerSettings
{
Text = "Toggles:"
},
- showStoryboardToggle = new PlayerCheckbox { LabelText = "Storyboards" },
- mouseWheelDisabledToggle = new PlayerCheckbox { LabelText = "Disable mouse wheel" }
+ showStoryboardToggle = new PlayerCheckbox { LabelText = "Storyboards" }
};
}
@@ -46,7 +44,6 @@ namespace osu.Game.Screens.Play.PlayerSettings
dimSliderBar.Bindable = config.GetBindable(OsuSetting.DimLevel);
blurSliderBar.Bindable = config.GetBindable(OsuSetting.BlurLevel);
showStoryboardToggle.Bindable = config.GetBindable(OsuSetting.ShowStoryboard);
- mouseWheelDisabledToggle.Bindable = config.GetBindable(OsuSetting.MouseDisableWheel);
}
}
}
diff --git a/osu.Game/Screens/Select/Footer.cs b/osu.Game/Screens/Select/Footer.cs
index 21e6108489..be83d7b500 100644
--- a/osu.Game/Screens/Select/Footer.cs
+++ b/osu.Game/Screens/Select/Footer.cs
@@ -41,19 +41,25 @@ namespace osu.Game.Screens.Select
/// Higher depth to be put on the left, and lower to be put on the right.
/// Notice this is different to !
///
- public void AddButton(string text, Color4 colour, Action action, Key? hotkey = null, float depth = 0) => buttons.Add(new FooterButton
+ public void AddButton(string text, Color4 colour, Action action, Key? hotkey = null, float depth = 0)
{
- Text = text,
- Height = play_song_select_button_height,
- Width = play_song_select_button_width,
- Depth = depth,
- SelectedColour = colour,
- DeselectedColour = colour.Opacity(0.5f),
- Hotkey = hotkey,
- Hovered = updateModeLight,
- HoverLost = updateModeLight,
- Action = action,
- });
+ var button = new FooterButton
+ {
+ Text = text,
+ Height = play_song_select_button_height,
+ Width = play_song_select_button_width,
+ Depth = depth,
+ SelectedColour = colour,
+ DeselectedColour = colour.Opacity(0.5f),
+ Hotkey = hotkey,
+ Hovered = updateModeLight,
+ HoverLost = updateModeLight,
+ Action = action,
+ };
+
+ buttons.Add(button);
+ buttons.SetLayoutPosition(button, -depth);
+ }
private readonly List overlays = new List();
diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs
index 2e8b2f9014..dee1ec4511 100644
--- a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs
+++ b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs
@@ -95,7 +95,7 @@ namespace osu.Game.Screens.Select.Options
///
public void AddButton(string firstLine, string secondLine, FontAwesome icon, Color4 colour, Action action, Key? hotkey = null, float depth = 0)
{
- buttonsContainer.Add(new BeatmapOptionsButton
+ var button = new BeatmapOptionsButton
{
FirstLineText = firstLine,
SecondLineText = secondLine,
@@ -108,7 +108,10 @@ namespace osu.Game.Screens.Select.Options
action?.Invoke();
},
HotKey = hotkey
- });
+ };
+
+ buttonsContainer.Add(button);
+ buttonsContainer.SetLayoutPosition(button, depth);
}
}
}
diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs
index a9b13e87bf..219d805bc1 100644
--- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs
+++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs
@@ -109,10 +109,13 @@ namespace osu.Game.Tests.Beatmaps
private Beatmap getBeatmap(string name)
{
- var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var resStream = openResource($"{resource_namespace}.{name}.osu"))
using (var stream = new StreamReader(resStream))
+ {
+ var decoder = Decoder.GetDecoder(stream);
+ ((LegacyBeatmapDecoder)decoder).ApplyOffsets = false;
return decoder.DecodeBeatmap(stream);
+ }
}
private Stream openResource(string name)
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 406e251899..fdcf1152d0 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -294,12 +294,16 @@
+
20180125143340_Settings.cs
+
+
+
@@ -351,6 +355,10 @@
+
+
+
+
@@ -474,9 +482,6 @@
-
-
-