From 829fb2605b132c89d74f0c010111607a5d09b906 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Feb 2017 17:47:11 +0900 Subject: [PATCH 01/26] Fix visualtest regression. --- osu.Game/Screens/Menu/ButtonSystem.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index a76cdbe99b..6d720569df 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -119,11 +119,11 @@ namespace osu.Game.Screens.Menu buttonFlow.Add(buttonsTopLevel); } - [BackgroundDependencyLoader] - private void load(AudioManager audio, OsuGame game) + [BackgroundDependencyLoader(true)] + private void load(AudioManager audio, OsuGame game = null) { sampleOsuClick = audio.Sample.Get(@"Menu/menuhit"); - toolbar = game.Toolbar; + toolbar = game?.Toolbar; } protected override void LoadComplete() From e0b75175359cf076fccfc4b8d9c7cbf54b892201 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Feb 2017 19:24:53 +0900 Subject: [PATCH 02/26] Add desktop unit tests project. --- osu.Desktop.Tests/BenchmarkTest.cs | 33 +++++ osu.Desktop.Tests/app.config | 11 ++ osu.Desktop.Tests/osu.Desktop.Tests.csproj | 115 ++++++++++++++++++ osu.Desktop.Tests/packages.config | 8 ++ osu.Desktop.VisualTests/Benchmark.cs | 56 +++++++++ osu.Desktop.VisualTests/Program.cs | 7 +- osu.Desktop.VisualTests/VisualTestGame.cs | 1 - osu.Desktop.VisualTests/app.config | 16 +++ .../osu.Desktop.VisualTests.csproj | 4 +- osu.Desktop.VisualTests/packages.config | 23 ++-- osu.sln | 7 ++ 11 files changed, 265 insertions(+), 16 deletions(-) create mode 100644 osu.Desktop.Tests/BenchmarkTest.cs create mode 100644 osu.Desktop.Tests/app.config create mode 100644 osu.Desktop.Tests/osu.Desktop.Tests.csproj create mode 100644 osu.Desktop.Tests/packages.config create mode 100644 osu.Desktop.VisualTests/Benchmark.cs create mode 100644 osu.Desktop.VisualTests/app.config diff --git a/osu.Desktop.Tests/BenchmarkTest.cs b/osu.Desktop.Tests/BenchmarkTest.cs new file mode 100644 index 0000000000..c55b98aa57 --- /dev/null +++ b/osu.Desktop.Tests/BenchmarkTest.cs @@ -0,0 +1,33 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Desktop.VisualTests; +using osu.Framework.Desktop.Platform; +using osu.Game.Modes; +using osu.Game.Modes.Catch; +using osu.Game.Modes.Mania; +using osu.Game.Modes.Osu; +using osu.Game.Modes.Taiko; + +namespace osu.Desktop.Tests +{ + [TestFixture] + public class BenchmarkTest + { + [Test] + public void TestBenchmark() + { + using (var host = new HeadlessGameHost()) + { + Ruleset.Register(new OsuRuleset()); + Ruleset.Register(new TaikoRuleset()); + Ruleset.Register(new ManiaRuleset()); + Ruleset.Register(new CatchRuleset()); + + host.Add(new Benchmark()); + host.Run(); + } + } + } +} diff --git a/osu.Desktop.Tests/app.config b/osu.Desktop.Tests/app.config new file mode 100644 index 0000000000..44ccc4b77a --- /dev/null +++ b/osu.Desktop.Tests/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/osu.Desktop.Tests/osu.Desktop.Tests.csproj b/osu.Desktop.Tests/osu.Desktop.Tests.csproj new file mode 100644 index 0000000000..8a6581ccab --- /dev/null +++ b/osu.Desktop.Tests/osu.Desktop.Tests.csproj @@ -0,0 +1,115 @@ + + + + + Debug + AnyCPU + {230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D} + Library + Properties + osu.Desktop.Tests + osu.Desktop.Tests + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + ..\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll + True + + + False + $(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll + + + + $(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + + $(SolutionDir)\packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll + + + $(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net4\SQLite.Net.Platform.Win32.dll + + + $(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net40\SQLite.Net.Platform.Generic.dll + + + $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1339\lib\net45\OpenTK.dll + + + + + + + + {65DC628F-A640-4111-AB35-3A5652BC1E17} + osu.Framework.Desktop + + + {C76BF5B3-985E-4D39-95FE-97C9C879B83A} + osu.Framework + + + {d9a367c9-4c1a-489f-9b05-a0cea2b53b58} + osu.Game.Resources + + + {69051C69-12AE-4E7D-A3E6-460D2E282312} + osu.Desktop.VisualTests + + + {58F6C80C-1253-4A0E-A465-B8C85EBEADF3} + osu.Game.Modes.Catch + + + {48F4582B-7687-4621-9CBE-5C24197CB536} + osu.Game.Modes.Mania + + + {C92A607B-1FDD-4954-9F92-03FF547D9080} + osu.Game.Modes.Osu + + + {F167E17A-7DE6-4AF5-B920-A5112296C695} + osu.Game.Modes.Taiko + + + {0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D} + osu.Game + + + + + + + + + + + + \ No newline at end of file diff --git a/osu.Desktop.Tests/packages.config b/osu.Desktop.Tests/packages.config new file mode 100644 index 0000000000..05b53c019c --- /dev/null +++ b/osu.Desktop.Tests/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/osu.Desktop.VisualTests/Benchmark.cs b/osu.Desktop.VisualTests/Benchmark.cs new file mode 100644 index 0000000000..506788e93c --- /dev/null +++ b/osu.Desktop.VisualTests/Benchmark.cs @@ -0,0 +1,56 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using osu.Framework; +using osu.Framework.Allocation; +using osu.Framework.Desktop.Platform; +using osu.Framework.GameModes.Testing; +using osu.Game; +using osu.Game.Modes; +using osu.Game.Modes.Catch; +using osu.Game.Modes.Mania; +using osu.Game.Modes.Osu; +using osu.Game.Modes.Taiko; + +namespace osu.Desktop.VisualTests +{ + public class Benchmark : OsuGameBase + { + private double timePerTest = 200; + + [BackgroundDependencyLoader] + private void load(BaseGame game) + { + Host.MaximumDrawHz = int.MaxValue; + Host.MaximumUpdateHz = int.MaxValue; + Host.MaximumInactiveHz = int.MaxValue; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + TestBrowser f = new TestBrowser(); + Add(f); + + Console.WriteLine($@"{Time}: Running {f.TestCount} tests for {timePerTest}ms each..."); + + for (int i = 1; i < f.TestCount; i++) + { + int loadableCase = i; + Scheduler.AddDelayed(delegate + { + f.LoadTest(loadableCase); + Console.WriteLine($@"{Time}: Switching to test #{loadableCase}"); + }, loadableCase * timePerTest); + } + + Scheduler.AddDelayed(Host.Exit, f.TestCount * timePerTest); + } + } +} diff --git a/osu.Desktop.VisualTests/Program.cs b/osu.Desktop.VisualTests/Program.cs index df54297812..b89c6bcf4d 100644 --- a/osu.Desktop.VisualTests/Program.cs +++ b/osu.Desktop.VisualTests/Program.cs @@ -18,6 +18,8 @@ namespace osu.Desktop.VisualTests [STAThread] public static void Main(string[] args) { + bool benchmark = args.Length > 0 && args[0] == @"-benchmark"; + using (BasicGameHost host = Host.GetSuitableHost(@"osu")) { Ruleset.Register(new OsuRuleset()); @@ -25,7 +27,10 @@ namespace osu.Desktop.VisualTests Ruleset.Register(new ManiaRuleset()); Ruleset.Register(new CatchRuleset()); - host.Add(new VisualTestGame()); + if (benchmark) + host.Add(new Benchmark()); + else + host.Add(new VisualTestGame()); host.Run(); } } diff --git a/osu.Desktop.VisualTests/VisualTestGame.cs b/osu.Desktop.VisualTests/VisualTestGame.cs index 7489559c98..952de4ab26 100644 --- a/osu.Desktop.VisualTests/VisualTestGame.cs +++ b/osu.Desktop.VisualTests/VisualTestGame.cs @@ -10,7 +10,6 @@ using osu.Framework.Desktop.Platform; using System.Reflection; using System.IO; using System.Collections.Generic; -using SQLiteNetExtensions.Extensions; using osu.Framework.Allocation; namespace osu.Desktop.VisualTests diff --git a/osu.Desktop.VisualTests/app.config b/osu.Desktop.VisualTests/app.config new file mode 100644 index 0000000000..9bad888bf3 --- /dev/null +++ b/osu.Desktop.VisualTests/app.config @@ -0,0 +1,16 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj index 69df007013..c2215ec9ec 100644 --- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj +++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj @@ -100,13 +100,12 @@ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1339\lib\net45\OpenTK.dll - - osu.licenseheader + @@ -172,6 +171,7 @@ + diff --git a/osu.Desktop.VisualTests/packages.config b/osu.Desktop.VisualTests/packages.config index f39a585e49..75affafd35 100644 --- a/osu.Desktop.VisualTests/packages.config +++ b/osu.Desktop.VisualTests/packages.config @@ -1,13 +1,12 @@ - - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/osu.sln b/osu.sln index f3736c16c0..588cabf6b6 100644 --- a/osu.sln +++ b/osu.sln @@ -29,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Modes.Taiko", "osu EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Modes.Mania", "osu.Game.Modes.Mania\osu.Game.Modes.Mania.csproj", "{48F4582B-7687-4621-9CBE-5C24197CB536}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Desktop.Tests", "osu.Desktop.Tests\osu.Desktop.Tests.csproj", "{230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -79,6 +81,10 @@ Global {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|Any CPU.Build.0 = Debug|Any CPU {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|Any CPU.ActiveCfg = Release|Any CPU {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|Any CPU.Build.0 = Release|Any CPU + {230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -95,6 +101,7 @@ Global {58F6C80C-1253-4A0E-A465-B8C85EBEADF3} = {0D37A2AD-80A4-464F-A1DE-1560B70F1CE3} {F167E17A-7DE6-4AF5-B920-A5112296C695} = {0D37A2AD-80A4-464F-A1DE-1560B70F1CE3} {48F4582B-7687-4621-9CBE-5C24197CB536} = {0D37A2AD-80A4-464F-A1DE-1560B70F1CE3} + {230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D} = {0D37A2AD-80A4-464F-A1DE-1560B70F1CE3} EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution Policies = $0 From becb65f702c2c1ed33ec963983d2f9969083fdf6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Feb 2017 19:25:04 +0900 Subject: [PATCH 03/26] Fix ParallaxContainer breaking with no mouse state present. --- osu.Game/Graphics/Containers/ParallaxContainer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index c5e53e14a5..fe3601a5f2 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -45,7 +45,8 @@ namespace osu.Game.Graphics.Containers { base.Update(); - content.MoveTo((ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2) * ParallaxAmount, firstUpdate ? 0 : 1000, EasingTypes.OutQuint); + Vector2 offset = input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2; + content.MoveTo(offset * ParallaxAmount, firstUpdate ? 0 : 1000, EasingTypes.OutQuint); content.Scale = new Vector2(1 + ParallaxAmount); firstUpdate = false; From 4f7069520adacbc2b37ff57e5efab7be93479392 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Feb 2017 19:25:10 +0900 Subject: [PATCH 04/26] Framework bump. --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 21fd81a848..6cea2e68db 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 21fd81a84860cf6854026458ac82905b6248f41d +Subproject commit 6cea2e68db09a9bf92e56960e3f26ba42a52e1cd From d5b7a8ce9e3e1882befec91146d516edc028551b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2017 11:19:13 +0900 Subject: [PATCH 05/26] Add pink glow to cursor because I can't fucking see it against white. --- osu.Game/Graphics/Cursor/OsuCursorContainer.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Graphics/Cursor/OsuCursorContainer.cs b/osu.Game/Graphics/Cursor/OsuCursorContainer.cs index 8df0777989..691fb701f1 100644 --- a/osu.Game/Graphics/Cursor/OsuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/OsuCursorContainer.cs @@ -67,6 +67,11 @@ namespace osu.Game.Graphics.Cursor Masking = true, BorderThickness = Size.X / 6, BorderColour = Color4.White, + EdgeEffect = new EdgeEffect { + Type = EdgeEffectType.Shadow, + Colour = Color4.Pink.Opacity(0.5f), + Radius = 5, + }, Children = new Drawable[] { new Box From 8ec927899f3d04dfb0791b0d6c69ef490d5a21f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2017 16:26:43 +0900 Subject: [PATCH 06/26] Implement notifications. --- .../Tests/TestCaseNotificationManager.cs | 121 ++++++++ .../osu.Desktop.VisualTests.csproj | 1 + osu.Game/Graphics/Sprites/OsuSpriteText.cs | 2 +- osu.Game/Graphics/UserInterface/Nub.cs | 2 +- osu.Game/OsuGame.cs | 10 + osu.Game/Overlays/NotificationManager.cs | 111 +++++++ .../Notifications/IHasCompletionTarget.cs | 12 + .../Overlays/Notifications/Notification.cs | 285 ++++++++++++++++++ .../Notifications/NotificationSection.cs | 163 ++++++++++ .../ProgressCompletionNotification.cs | 16 + .../Notifications/ProgressNotification.cs | 198 ++++++++++++ .../Notifications/SimpleNotification.cs | 66 ++++ osu.Game/Overlays/OptionsOverlay.cs | 2 +- osu.Game/Overlays/Toolbar/Toolbar.cs | 6 +- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 11 +- .../Toolbar/ToolbarNotificationButton.cs | 28 ++ osu.Game/osu.Game.csproj | 8 + 17 files changed, 1033 insertions(+), 9 deletions(-) create mode 100644 osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs create mode 100644 osu.Game/Overlays/NotificationManager.cs create mode 100644 osu.Game/Overlays/Notifications/IHasCompletionTarget.cs create mode 100644 osu.Game/Overlays/Notifications/Notification.cs create mode 100644 osu.Game/Overlays/Notifications/NotificationSection.cs create mode 100644 osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs create mode 100644 osu.Game/Overlays/Notifications/ProgressNotification.cs create mode 100644 osu.Game/Overlays/Notifications/SimpleNotification.cs create mode 100644 osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs diff --git a/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs b/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs new file mode 100644 index 0000000000..cc9201c1fd --- /dev/null +++ b/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs @@ -0,0 +1,121 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Framework.GameModes.Testing; +using osu.Framework.MathUtils; +using osu.Framework.Timing; +using osu.Game.Overlays; +using System.Linq; +using osu.Game.Overlays.Notifications; +using osu.Game.Screens.Backgrounds; + +namespace osu.Desktop.VisualTests.Tests +{ + class TestCaseNotificationManager : TestCase + { + public override string Name => @"Notification Manager"; + public override string Description => @"I handle notifications"; + + NotificationManager manager; + + public override void Reset() + { + base.Reset(); + + progressingNotifications.Clear(); + + AddInternal(new BackgroundModeDefault() { Depth = 10 }); + + Content.Add(manager = new NotificationManager + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }); + + AddToggle(@"show", manager.ToggleVisibility); + + AddButton(@"simple #1", sendNotification1); + AddButton(@"simple #2", sendNotification2); + AddButton(@"progress #1", sendProgress1); + AddButton(@"progress #2", sendProgress2); + AddButton(@"barrage", () => sendBarrage()); + } + + private void sendBarrage(int remaining = 100) + { + switch (RNG.Next(0, 4)) + { + case 0: + sendNotification1(); + break; + case 1: + sendNotification2(); + break; + case 2: + sendProgress1(); + break; + case 3: + sendProgress2(); + break; + } + + if (remaining > 0) + { + Delay(80); + Schedule(() => sendBarrage(remaining - 1)); + } + } + + protected override void Update() + { + base.Update(); + + progressingNotifications.RemoveAll(n => n.State == ProgressNotificationState.Completed); + + while (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3) + { + var p = progressingNotifications.FirstOrDefault(n => n.IsLoaded && n.State == ProgressNotificationState.Queued); + if (p == null) + break; + + p.State = ProgressNotificationState.Active; + } + + foreach (var n in progressingNotifications.FindAll(n => n.State == ProgressNotificationState.Active)) + { + if (n.Progress < 1) + n.Progress += (float)(Time.Elapsed / 2000) * RNG.NextSingle(); + else + n.Complete(); + } + } + + private void sendProgress2() + { + var n = new ProgressNotification(@"Downloading Haitai..."); + manager.Post(n); + progressingNotifications.Add(n); + } + + List progressingNotifications = new List(); + + private void sendProgress1() + { + var n = new ProgressNotification(@"Uploading to BSS..."); + manager.Post(n); + progressingNotifications.Add(n); + } + + private void sendNotification2() + { + manager.Post(new SimpleNotification(@"You are amazing")); + } + + private void sendNotification1() + { + manager.Post(new SimpleNotification(@"Welcome to osu!. Enjoy your stay!")); + } + } +} diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj index 69df007013..6fa9ab604e 100644 --- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj +++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj @@ -176,6 +176,7 @@ + diff --git a/osu.Game/Graphics/Sprites/OsuSpriteText.cs b/osu.Game/Graphics/Sprites/OsuSpriteText.cs index 5bc76b74b4..f5749846be 100644 --- a/osu.Game/Graphics/Sprites/OsuSpriteText.cs +++ b/osu.Game/Graphics/Sprites/OsuSpriteText.cs @@ -9,7 +9,7 @@ using OpenTK.Graphics; namespace osu.Game.Graphics.Sprites { - class OsuSpriteText : SpriteText + public class OsuSpriteText : SpriteText { public const float FONT_SIZE = 16; diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index c8174ef546..61b59d6b51 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -13,7 +13,7 @@ using osu.Framework.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterface { - class Nub : CircularContainer, IStateful + public class Nub : CircularContainer, IStateful { public const float COLLAPSED_SIZE = 20; public const float EXPANDED_SIZE = 40; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 97c9dbb2e0..e8233366d9 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -35,6 +35,8 @@ namespace osu.Game private MusicController musicController; + private NotificationManager notificationManager; + private MainMenu mainMenu => modeStack?.ChildGameMode as MainMenu; private Intro intro => modeStack as Intro; @@ -117,8 +119,16 @@ namespace osu.Game Origin = Anchor.TopRight, }).Preload(this, overlayContent.Add); + (notificationManager = new NotificationManager + { + Depth = -2, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }).Preload(this, overlayContent.Add); + Dependencies.Cache(options); Dependencies.Cache(musicController); + Dependencies.Cache(notificationManager); (Toolbar = new Toolbar { diff --git a/osu.Game/Overlays/NotificationManager.cs b/osu.Game/Overlays/NotificationManager.cs new file mode 100644 index 0000000000..e4eb718639 --- /dev/null +++ b/osu.Game/Overlays/NotificationManager.cs @@ -0,0 +1,111 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transformations; +using osu.Game.Graphics; +using osu.Game.Overlays.Notifications; +using OpenTK.Graphics; + +namespace osu.Game.Overlays +{ + public class NotificationManager : FocusedOverlayContainer + { + private const float width = 320; + + public const float TRANSITION_LENGTH = 600; + + private ScrollContainer scrollContainer; + private FlowContainer sections; + + [BackgroundDependencyLoader(permitNulls: true)] + private void load(OsuColour colours) + { + Width = width; + RelativeSizeAxes = Axes.Y; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.6f, + }, + scrollContainer = new ScrollContainer() + { + Margin = new MarginPadding { Top = Toolbar.Toolbar.HEIGHT }, + Children = new[] + { + sections = new FlowContainer + { + Direction = FlowDirection.VerticalOnly, + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Children = new [] + { + new NotificationSection + { + Title = @"Notifications", + ClearText = @"Clear All", + AcceptTypes = new [] { typeof(SimpleNotification) }, + }, + new NotificationSection + { + Title = @"Running Tasks", + ClearText = @"Cancel All", + AcceptTypes = new [] { typeof(ProgressNotification) }, + }, + } + } + } + } + }; + } + + int runningDepth = 0; + + public void Post(Notification notification) + { + ++runningDepth; + notification.Depth = notification.DisplayOnTop ? runningDepth : -runningDepth; + + var hasCompletionTarget = notification as IHasCompletionTarget; + if (hasCompletionTarget != null) + hasCompletionTarget.CompletionTarget = Post; + + var ourType = notification.GetType(); + sections.Children.FirstOrDefault(s => s.AcceptTypes.Any(accept => ourType == accept || ourType.IsSubclassOf(accept)))?.Add(notification); + } + + protected override void PopIn() + { + base.PopIn(); + + scrollContainer.MoveToX(0, TRANSITION_LENGTH, EasingTypes.OutQuint); + MoveToX(0, TRANSITION_LENGTH, EasingTypes.OutQuint); + FadeTo(1, TRANSITION_LENGTH / 2); + } + + private void markAllRead() + { + sections.Children.ForEach(s => s.MarkAllRead()); + } + + protected override void PopOut() + { + base.PopOut(); + + markAllRead(); + + MoveToX(width, TRANSITION_LENGTH, EasingTypes.OutQuint); + FadeTo(0, TRANSITION_LENGTH / 2); + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Notifications/IHasCompletionTarget.cs b/osu.Game/Overlays/Notifications/IHasCompletionTarget.cs new file mode 100644 index 0000000000..7fba75c4fc --- /dev/null +++ b/osu.Game/Overlays/Notifications/IHasCompletionTarget.cs @@ -0,0 +1,12 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; + +namespace osu.Game.Overlays.Notifications +{ + public interface IHasCompletionTarget + { + Action CompletionTarget { get; set; } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs new file mode 100644 index 0000000000..9270e4e792 --- /dev/null +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -0,0 +1,285 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transformations; +using osu.Framework.Input; +using osu.Game.Graphics; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Overlays.Notifications +{ + public abstract class Notification : Container + { + /// + /// Use requested close. + /// + public Action Closed; + + /// + /// Run on user activating the notification. Return true to close. + /// + public Func Activated; + + /// + /// Should we show at the top of our section on display? + /// + public virtual bool DisplayOnTop => true; + + protected NotificationLight Light; + private CloseButton closeButton; + protected Container IconContent; + private Container content; + + protected override Container Content => content; + + protected Container NotificationContent; + + private bool read; + + public virtual bool Read + { + get { return read; } + set + { + read = value; + } + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + AddInternal(new Drawable[] + { + Light = new NotificationLight + { + Margin = new MarginPadding { Right = 5 }, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreRight, + }, + NotificationContent = new Container + { + CornerRadius = 8, + Masking = true, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + }, + new Container + { + RelativeSizeAxes = Axes.X, + Padding = new MarginPadding(5), + Height = 60, + Children = new Drawable[] + { + IconContent = new Container + { + Size = new Vector2(40), + Colour = Color4.DarkGray, + Masking = true, + CornerRadius = 5, + }, + content = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding + { + Top = 5, + Left = 45, + Right = 30 + }, + } + } + }, + closeButton = new CloseButton + { + Alpha = 0, + Action = Close, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Margin = new MarginPadding + { + Right = 5 + }, + } + } + } + }); + } + + protected override bool OnHover(InputState state) + { + closeButton.FadeIn(75); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + closeButton.FadeOut(75); + base.OnHoverLost(state); + } + + protected override bool OnClick(InputState state) + { + if (Activated?.Invoke() ?? true) + Close(); + + return true; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + FadeInFromZero(200); + NotificationContent.MoveToX(DrawSize.X); + NotificationContent.MoveToX(0, 500, EasingTypes.OutQuint); + } + + private bool wasClosed; + + public virtual void Close() + { + if (wasClosed) return; + wasClosed = true; + + Closed?.Invoke(); + FadeOut(100); + Expire(); + } + + class CloseButton : ClickableContainer + { + private Color4 hoverColour; + + public CloseButton() + { + Colour = OsuColour.Gray(0.2f); + AutoSizeAxes = Axes.Both; + + Children = new[] + { + new TextAwesome + { + Anchor = Anchor.Centre, + Icon = FontAwesome.fa_times_circle, + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + hoverColour = colours.Yellow; + } + + protected override bool OnHover(InputState state) + { + FadeColour(hoverColour, 200); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + FadeColour(OsuColour.Gray(0.2f), 200); + base.OnHoverLost(state); + } + } + + public class NotificationLight : Container + { + private bool pulsate; + private Container pulsateLayer; + + public bool Pulsate + { + get { return pulsate; } + set + { + pulsate = value; + + pulsateLayer.ClearTransformations(); + pulsateLayer.Alpha = 1; + + if (pulsate) + { + const float length = 1000; + pulsateLayer.Transforms.Add(new TransformAlpha + { + StartTime = Time.Current, + EndTime = Time.Current + length, + StartValue = 1, + EndValue = 0.4f, + Easing = EasingTypes.In + }); + pulsateLayer.Transforms.Add(new TransformAlpha + { + StartTime = Time.Current + length, + EndTime = Time.Current + length * 2, + StartValue = 0.4f, + EndValue = 1, + Easing = EasingTypes.Out + }); + + //todo: figure why we can't add arbitrary delays at the end of loop. + pulsateLayer.Loop(length * 2); + } + } + } + + public new SRGBColour Colour + { + set + { + base.Colour = value; + pulsateLayer.EdgeEffect = new EdgeEffect + { + Colour = ((Color4)value).Opacity(0.5f), //todo: avoid cast + Type = EdgeEffectType.Glow, + Radius = 12, + Roundness = 12, + }; + } + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Size = new Vector2(6, 15); + + Children = new[] + { + pulsateLayer = new CircularContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Masking = true, + RelativeSizeAxes = Axes.Both, + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + }, + } + } + }; + } + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs new file mode 100644 index 0000000000..526b568c12 --- /dev/null +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -0,0 +1,163 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Transformations; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using OpenTK; + +namespace osu.Game.Overlays.Notifications +{ + public class NotificationSection : FlowContainer + { + private OsuSpriteText titleText; + private OsuSpriteText countText; + + private ClearAllButton clearButton; + + private FlowContainer notifications; + + public void Add(Notification notification) + { + notifications.Add(notification); + } + + public IEnumerable AcceptTypes; + + private string clearText; + public string ClearText + { + get { return clearText; } + set + { + clearText = value; + if (clearButton != null) clearButton.Text = clearText; + } + } + + private string title; + + + public string Title + { + get { return title; } + set + { + title = value; + if (titleText != null) titleText.Text = title.ToUpper(); + } + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Direction = FlowDirection.VerticalOnly; + + Padding = new MarginPadding + { + Top = 10, + Bottom = 5, + Right = 20, + Left = 20, + }; + + AddInternal(new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + clearButton = new ClearAllButton + { + Text = clearText, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Action = clearAll + }, + new FlowContainer + { + Margin = new MarginPadding + { + Bottom = 5 + }, + Spacing = new Vector2(5, 0), + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + titleText = new OsuSpriteText + { + Text = title.ToUpper(), + Font = @"Exo2.0-Black", + }, + countText = new OsuSpriteText + { + Text = "3", + Colour = colours.Yellow, + Font = @"Exo2.0-Black", + }, + } + }, + }, + }, + notifications = new FlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + LayoutDuration = 150, + LayoutEasing = EasingTypes.OutQuart, + Spacing = new Vector2(3), + } + }); + } + + private void clearAll() + { + notifications.Children.ForEach(c => c.Close()); + } + + protected override void Update() + { + base.Update(); + + countText.Text = notifications.Children.Count(c => c.Alpha > 0.99f).ToString(); + } + + class ClearAllButton : ClickableContainer + { + private OsuSpriteText text; + + public ClearAllButton() + { + AutoSizeAxes = Axes.Both; + + Children = new[] + { + text = new OsuSpriteText() + }; + } + + public string Text + { + get { return text.Text; } + set { text.Text = value.ToUpper(); } + } + } + + public void MarkAllRead() + { + notifications.Children.ForEach(n => n.Read = true); + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs b/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs new file mode 100644 index 0000000000..1861e410d2 --- /dev/null +++ b/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs @@ -0,0 +1,16 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Overlays.Notifications +{ + public class ProgressCompletionNotification : SimpleNotification + { + private ProgressNotification progressNotification; + + public ProgressCompletionNotification(ProgressNotification progressNotification) + : base(@"Task has completed!") + { + this.progressNotification = progressNotification; + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs new file mode 100644 index 0000000000..a4cac41d33 --- /dev/null +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -0,0 +1,198 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Diagnostics; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transformations; +using osu.Game.Graphics; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Overlays.Notifications +{ + public class ProgressNotification : Notification, IHasCompletionTarget + { + private string text; + + private float progress; + public float Progress + { + get { return progress; } + set + { + Debug.Assert(state == ProgressNotificationState.Active); + progress = value; + progressBar.Progress = progress; + } + } + + public ProgressNotificationState State + { + get { return state; } + set + { + state = value; + switch (state) + { + case ProgressNotificationState.Queued: + Light.Colour = colourQueued; + Light.Pulsate = false; + progressBar.Active = false; + break; + case ProgressNotificationState.Active: + Light.Colour = colourActive; + Light.Pulsate = true; + progressBar.Active = true; + break; + case ProgressNotificationState.Cancelled: + Light.Colour = colourCancelled; + Light.Pulsate = false; + progressBar.Active = false; + break; + } + } + } + + private ProgressNotificationState state; + + public Action Completed; + + public override bool DisplayOnTop => false; + + private ProgressBar progressBar; + private Color4 colourQueued; + private Color4 colourActive; + private Color4 colourCancelled; + + public ProgressNotification(string text) + { + this.text = text; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + colourQueued = colours.YellowDark; + colourActive = colours.Blue; + colourCancelled = colours.Red; + + IconContent.Add(new Box + { + RelativeSizeAxes = Axes.Both, + }); + + Content.Add(new SpriteText + { + TextSize = 16, + Colour = OsuColour.Gray(128), + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Text = text + }); + + NotificationContent.Add(progressBar = new ProgressBar + { + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + }); + + State = ProgressNotificationState.Queued; + } + + public void Complete() + { + state = ProgressNotificationState.Completed; + + NotificationContent.MoveToY(-DrawSize.Y / 2, 200, EasingTypes.OutQuint); + FadeTo(0.01f, 200); //don't completely fade out or our scheduled task won't run. + + Delay(100); + Schedule(() => + { + CompletionTarget?.Invoke(new ProgressCompletionNotification(this)); + base.Close(); + }); + } + + public override void Close() + { + switch (State) + { + case ProgressNotificationState.Cancelled: + base.Close(); + break; + case ProgressNotificationState.Active: + case ProgressNotificationState.Queued: + State = ProgressNotificationState.Cancelled; + break; + } + } + + public Action CompletionTarget { get; set; } + + class ProgressBar : Container + { + private Box box; + + private Color4 colourActive; + private Color4 colourInactive; + + private float progress; + public float Progress + { + get { return progress; } + set + { + if (progress == value) return; + + progress = value; + box.ResizeTo(new Vector2(progress, 1), 100, EasingTypes.OutQuad); + } + } + + private bool active; + + public bool Active + { + get { return active; } + set + { + active = value; + FadeColour(active ? colourActive : colourInactive, 100); + } + } + + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + colourActive = colours.Blue; + Colour = colourInactive = OsuColour.Gray(0.5f); + + Height = 5; + + Children = new[] + { + box = new Box + { + RelativeSizeAxes = Axes.Both, + Width = 0, + } + }; + } + } + } + + public enum ProgressNotificationState + { + Queued, + Active, + Completed, + Cancelled + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs new file mode 100644 index 0000000000..7c6666082e --- /dev/null +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -0,0 +1,66 @@ +// Copyright (c) 2007-2017 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.Colour; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; + +namespace osu.Game.Overlays.Notifications +{ + public class SimpleNotification : Notification + { + private string text; + + public SimpleNotification(string text) + { + this.text = text; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + IconContent.Add(new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + ColourInfo = ColourInfo.GradientVertical(OsuColour.Gray(0.2f), OsuColour.Gray(0.5f)) + }, + new TextAwesome + { + Anchor = Anchor.Centre, + Icon = FontAwesome.fa_info_circle, + } + }); + + Content.Add(new SpriteText + { + TextSize = 16, + Colour = OsuColour.Gray(128), + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Text = text + }); + + Light.Colour = colours.Green; + } + + public override bool Read + { + get + { + return base.Read; + } + + set + { + if (base.Read = value) + Light.FadeOut(100); + else + Light.FadeIn(100); + } + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/OptionsOverlay.cs b/osu.Game/Overlays/OptionsOverlay.cs index 1fce450104..a93bbc10d3 100644 --- a/osu.Game/Overlays/OptionsOverlay.cs +++ b/osu.Game/Overlays/OptionsOverlay.cs @@ -90,7 +90,7 @@ namespace osu.Game.Overlays { Text = "settings", TextSize = 40, - Margin = new MarginPadding { Left = CONTENT_MARGINS, Top = 30 }, + Margin = new MarginPadding { Left = CONTENT_MARGINS, Top = Toolbar.Toolbar.TOOLTIP_HEIGHT }, }, new OsuSpriteText { diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 503a3e0bf5..dc8b8d1e9a 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -17,6 +17,7 @@ namespace osu.Game.Overlays.Toolbar public class Toolbar : OverlayContainer { public const float HEIGHT = 40; + public const float TOOLTIP_HEIGHT = 30; public Action OnHome; public Action OnPlayModeChange; @@ -73,10 +74,7 @@ namespace osu.Game.Overlays.Toolbar Icon = FontAwesome.fa_search }, userArea = new ToolbarUserArea(), - new ToolbarButton - { - Icon = FontAwesome.fa_bars - }, + new ToolbarNotificationButton(), } } }; diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index 160e4460d9..67b0039971 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -56,6 +56,8 @@ namespace osu.Game.Overlays.Toolbar } } + protected virtual Anchor TooltipAnchor => Anchor.TopLeft; + public Action Action; protected TextAwesome DrawableIcon; protected SpriteText DrawableText; @@ -107,19 +109,24 @@ namespace osu.Game.Overlays.Toolbar { Direction = FlowDirection.VerticalOnly, RelativeSizeAxes = Axes.Both, //stops us being considered in parent's autosize - Anchor = Anchor.BottomLeft, - Position = new Vector2(5, 5), + Anchor = (TooltipAnchor & Anchor.x0) > 0 ? Anchor.BottomLeft : Anchor.BottomRight, + Origin = TooltipAnchor, + Position = new Vector2((TooltipAnchor & Anchor.x0) > 0 ? 5 : -5, 5), Alpha = 0, Children = new[] { tooltip1 = new OsuSpriteText { + Anchor = TooltipAnchor, + Origin = TooltipAnchor, Shadow = true, TextSize = 22, Font = @"Exo2.0-Bold", }, tooltip2 = new OsuSpriteText { + Anchor = TooltipAnchor, + Origin = TooltipAnchor, Shadow = true, TextSize = 16 } diff --git a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs new file mode 100644 index 0000000000..973f9f2d8a --- /dev/null +++ b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs @@ -0,0 +1,28 @@ +// Copyright (c) 2007-2017 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.Game.Graphics; + +namespace osu.Game.Overlays.Toolbar +{ + class ToolbarNotificationButton : ToolbarOverlayToggleButton + { + protected override Anchor TooltipAnchor => Anchor.TopRight; + + public ToolbarNotificationButton() + { + Icon = FontAwesome.fa_bars; + TooltipMain = "Notifications"; + TooltipSub = "Waiting for 'ya"; + } + + [BackgroundDependencyLoader] + private void load(NotificationManager notificationManager) + { + StateContainer = notificationManager; + Action = notificationManager.ToggleVisibility; + } + } +} \ No newline at end of file diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 2ead6aad48..0477d85b43 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -100,6 +100,13 @@ + + + + + + + @@ -107,6 +114,7 @@ + From 456fc5e37578c41a8cf41164f88a02f90cf07dac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2017 16:43:11 +0900 Subject: [PATCH 07/26] Update framework. --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 21fd81a848..7df72f8d0c 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 21fd81a84860cf6854026458ac82905b6248f41d +Subproject commit 7df72f8d0cb887437a2816d3f413bf37ca2d6641 From dd8ec70bd5fdefa4e3a4ba4d3951a3461754d711 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2017 16:57:49 +0900 Subject: [PATCH 08/26] Remove excess newline. --- osu.Game/Overlays/Notifications/NotificationSection.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index 526b568c12..ec286302b8 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -45,7 +45,6 @@ namespace osu.Game.Overlays.Notifications private string title; - public string Title { get { return title; } From 398ac6f459b266a92d79f76e0ab3b38e96e140b5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Feb 2017 16:58:40 +0900 Subject: [PATCH 09/26] Add assert to ensure complete is only called once. --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index a4cac41d33..4cb1557c32 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -106,6 +106,8 @@ namespace osu.Game.Overlays.Notifications public void Complete() { + Debug.Assert(state != ProgressNotificationState.Completed); + state = ProgressNotificationState.Completed; NotificationContent.MoveToY(-DrawSize.Y / 2, 200, EasingTypes.OutQuint); From 2c4ecb990db1145ded74bb5a0e7115e943df9c8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sat, 11 Feb 2017 16:23:15 +0100 Subject: [PATCH 10/26] Remove line break in MusicController --- osu.Game/Overlays/MusicController.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 457dc1e7e1..3b13c7bf88 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -240,7 +240,6 @@ namespace osu.Game.Overlays if (current?.TrackLoaded ?? false) { - progress.UpdatePosition((float)(current.Track.CurrentTime / current.Track.Length)); playButton.Icon = current.Track.IsRunning ? FontAwesome.fa_pause_circle_o : FontAwesome.fa_play_circle_o; From 8394e2ff382666018da256b73f6bb699f5eac7c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sat, 11 Feb 2017 16:27:15 +0100 Subject: [PATCH 11/26] Update OptionDropDown value when items change Items of OptionDropDown could previously already be changes on-the-fly, but the selected value was not correctly updated (it kept the same index). This commit addresses this problem. --- osu.Game/Overlays/Options/OptionDropDown.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Overlays/Options/OptionDropDown.cs b/osu.Game/Overlays/Options/OptionDropDown.cs index ee355d4016..b9d676109e 100644 --- a/osu.Game/Overlays/Options/OptionDropDown.cs +++ b/osu.Game/Overlays/Options/OptionDropDown.cs @@ -71,7 +71,14 @@ namespace osu.Game.Overlays.Options { items = value; if(dropdown != null) + { dropdown.Items = value; + + // We need to refresh the dropdown because our items changed, + // thus its selected value may be outdated. + if (bindable != null) + dropdown.SelectedValue = bindable.Value; + } } } From d79c8b9695eddd906d1ecdc2f01af887b9dc6f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sat, 11 Feb 2017 16:29:33 +0100 Subject: [PATCH 12/26] Update AudioDevicesOptions when devices are found or lost This commit hooks up AudioDevicesOptions to the new events exposed by the AudioManager of osu-framework. The device list is now updated when new devices become available or are lost. --- .../Sections/Audio/AudioDevicesOptions.cs | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Options/Sections/Audio/AudioDevicesOptions.cs b/osu.Game/Overlays/Options/Sections/Audio/AudioDevicesOptions.cs index 370676ead6..2301080411 100644 --- a/osu.Game/Overlays/Options/Sections/Audio/AudioDevicesOptions.cs +++ b/osu.Game/Overlays/Options/Sections/Audio/AudioDevicesOptions.cs @@ -14,6 +14,7 @@ namespace osu.Game.Overlays.Options.Sections.Audio protected override string Header => "Devices"; private AudioManager audio; + private OptionDropDown dropdown; [BackgroundDependencyLoader] private void load(AudioManager audio) @@ -21,21 +22,40 @@ namespace osu.Game.Overlays.Options.Sections.Audio this.audio = audio; } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + audio.OnNewDevice -= onDeviceChanged; + audio.OnLostDevice -= onDeviceChanged; + } + + private void updateItems() + { + var deviceItems = new List>(); + deviceItems.Add(new KeyValuePair("Default", string.Empty)); + deviceItems.AddRange(audio.AudioDeviceNames.Select(d => new KeyValuePair(d, d))); + dropdown.Items = deviceItems; + } + + private void onDeviceChanged(string name) => updateItems(); + protected override void LoadComplete() { base.LoadComplete(); - var deviceItems = new List>(); - deviceItems.Add(new KeyValuePair("Default", string.Empty)); - deviceItems.AddRange(audio.GetDeviceNames().Select(d => new KeyValuePair(d, d))); Children = new Drawable[] { - new OptionDropDown() + dropdown = new OptionDropDown() { - Items = deviceItems, Bindable = audio.AudioDevice }, }; + + updateItems(); + + audio.OnNewDevice += onDeviceChanged; + audio.OnLostDevice += onDeviceChanged; } } } \ No newline at end of file From d3380631e8b1dab7e7378053193fc9a552716bc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sat, 11 Feb 2017 16:33:54 +0100 Subject: [PATCH 13/26] Handle preferred audio device correctly when it is unavailable This commit allows loading, storing, and displaying a preferred audio device from config even when it is unavailable. --- .../Overlays/Options/Sections/Audio/AudioDevicesOptions.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Overlays/Options/Sections/Audio/AudioDevicesOptions.cs b/osu.Game/Overlays/Options/Sections/Audio/AudioDevicesOptions.cs index 2301080411..06ddf584b2 100644 --- a/osu.Game/Overlays/Options/Sections/Audio/AudioDevicesOptions.cs +++ b/osu.Game/Overlays/Options/Sections/Audio/AudioDevicesOptions.cs @@ -35,6 +35,11 @@ namespace osu.Game.Overlays.Options.Sections.Audio var deviceItems = new List>(); deviceItems.Add(new KeyValuePair("Default", string.Empty)); deviceItems.AddRange(audio.AudioDeviceNames.Select(d => new KeyValuePair(d, d))); + + var preferredDeviceName = audio.AudioDevice.Value; + if (!deviceItems.Any(kv => kv.Value == preferredDeviceName)) + deviceItems.Add(new KeyValuePair(preferredDeviceName, preferredDeviceName)); + dropdown.Items = deviceItems; } From 85d3337257bb8bfbdcdde382200a99ad8e0d360d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sat, 11 Feb 2017 16:38:30 +0100 Subject: [PATCH 14/26] Bump framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 7df72f8d0c..68c82a6ad1 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 7df72f8d0cb887437a2816d3f413bf37ca2d6641 +Subproject commit 68c82a6ad16bc3bf237695152515694e19dc0b05 From 1c3eca8813789372571a1edce36c76d5a98f4fd4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 12 Feb 2017 03:18:15 +0900 Subject: [PATCH 15/26] Update framework. --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 68c82a6ad1..16cc4a53a0 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 68c82a6ad16bc3bf237695152515694e19dc0b05 +Subproject commit 16cc4a53a0447264b8f67f149da701c4f00a41ea From a14b7eb59831c1a043c4659c2fdffb169d1f10fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 12 Feb 2017 14:50:02 +0900 Subject: [PATCH 16/26] NotificationManager should become visible when receiving a notification (until we implement toasts). --- osu.Game/Overlays/NotificationManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/NotificationManager.cs b/osu.Game/Overlays/NotificationManager.cs index e4eb718639..ecfa3daa38 100644 --- a/osu.Game/Overlays/NotificationManager.cs +++ b/osu.Game/Overlays/NotificationManager.cs @@ -73,6 +73,8 @@ namespace osu.Game.Overlays public void Post(Notification notification) { + State = Visibility.Visible; + ++runningDepth; notification.Depth = notification.DisplayOnTop ? runningDepth : -runningDepth; From ac548dc9ec1c37f4cdb9fdc83c9217bfe3f82f59 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 12 Feb 2017 14:50:42 +0900 Subject: [PATCH 17/26] Rework notifications to be more flexible. --- .../Tests/TestCaseNotificationManager.cs | 10 +- .../ProgressCompletionNotification.cs | 4 +- .../Notifications/ProgressNotification.cs | 121 +++++++++++------- .../Notifications/SimpleNotification.cs | 33 ++++- 4 files changed, 113 insertions(+), 55 deletions(-) diff --git a/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs b/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs index cc9201c1fd..77b313f4ad 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs @@ -88,13 +88,13 @@ namespace osu.Desktop.VisualTests.Tests if (n.Progress < 1) n.Progress += (float)(Time.Elapsed / 2000) * RNG.NextSingle(); else - n.Complete(); + n.State = ProgressNotificationState.Completed; } } private void sendProgress2() { - var n = new ProgressNotification(@"Downloading Haitai..."); + var n = new ProgressNotification { Text = @"Downloading Haitai..." }; manager.Post(n); progressingNotifications.Add(n); } @@ -103,19 +103,19 @@ namespace osu.Desktop.VisualTests.Tests private void sendProgress1() { - var n = new ProgressNotification(@"Uploading to BSS..."); + var n = new ProgressNotification { Text = @"Uploading to BSS..." }; manager.Post(n); progressingNotifications.Add(n); } private void sendNotification2() { - manager.Post(new SimpleNotification(@"You are amazing")); + manager.Post(new SimpleNotification { Text = @"You are amazing" }); } private void sendNotification1() { - manager.Post(new SimpleNotification(@"Welcome to osu!. Enjoy your stay!")); + manager.Post(new SimpleNotification { Text = @"Welcome to osu!. Enjoy your stay!" }); } } } diff --git a/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs b/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs index 1861e410d2..a5ec9a3545 100644 --- a/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs @@ -1,6 +1,8 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Graphics; + namespace osu.Game.Overlays.Notifications { public class ProgressCompletionNotification : SimpleNotification @@ -8,9 +10,9 @@ namespace osu.Game.Overlays.Notifications private ProgressNotification progressNotification; public ProgressCompletionNotification(ProgressNotification progressNotification) - : base(@"Task has completed!") { this.progressNotification = progressNotification; + Icon = FontAwesome.fa_check; } } } \ No newline at end of file diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 4cb1557c32..b00204e166 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -17,6 +17,16 @@ namespace osu.Game.Overlays.Notifications public class ProgressNotification : Notification, IHasCompletionTarget { private string text; + public string Text + { + get { return text; } + set + { + text = value; + if (IsLoaded) + textDrawable.Text = text; + } + } private float progress; public float Progress @@ -24,42 +34,79 @@ namespace osu.Game.Overlays.Notifications get { return progress; } set { - Debug.Assert(state == ProgressNotificationState.Active); progress = value; - progressBar.Progress = progress; + if (IsLoaded) + progressBar.Progress = progress; } } - public ProgressNotificationState State + protected override void LoadComplete() + { + base.LoadComplete(); + + //we may have received changes before we were displayed. + State = state; + Progress = progress; + } + + public virtual ProgressNotificationState State { get { return state; } set { + bool stateChanged = state != value; state = value; - switch (state) + + if (IsLoaded) { - case ProgressNotificationState.Queued: - Light.Colour = colourQueued; - Light.Pulsate = false; - progressBar.Active = false; - break; - case ProgressNotificationState.Active: - Light.Colour = colourActive; - Light.Pulsate = true; - progressBar.Active = true; - break; - case ProgressNotificationState.Cancelled: - Light.Colour = colourCancelled; - Light.Pulsate = false; - progressBar.Active = false; - break; + switch (state) + { + case ProgressNotificationState.Queued: + Light.Colour = colourQueued; + Light.Pulsate = false; + progressBar.Active = false; + break; + case ProgressNotificationState.Active: + Light.Colour = colourActive; + Light.Pulsate = true; + progressBar.Active = true; + break; + case ProgressNotificationState.Cancelled: + Light.Colour = colourCancelled; + Light.Pulsate = false; + progressBar.Active = false; + break; + } + } + + if (stateChanged) + { + switch (state) + { + case ProgressNotificationState.Completed: + NotificationContent.MoveToY(-DrawSize.Y / 2, 200, EasingTypes.OutQuint); + FadeTo(0.01f, 200); //don't completely fade out or our scheduled task won't run. + + Delay(100); + Schedule(Completed); + break; + } } } } private ProgressNotificationState state; - public Action Completed; + protected virtual Notification CreateCompletionNotification() => new ProgressCompletionNotification(this) + { + Activated = CompletionClickAction, + Text = $"Task \"{Text}\" has completed!" + }; + + protected virtual void Completed() + { + CompletionTarget?.Invoke(CreateCompletionNotification()); + } public override bool DisplayOnTop => false; @@ -68,10 +115,7 @@ namespace osu.Game.Overlays.Notifications private Color4 colourActive; private Color4 colourCancelled; - public ProgressNotification(string text) - { - this.text = text; - } + private SpriteText textDrawable; [BackgroundDependencyLoader] private void load(OsuColour colours) @@ -85,7 +129,7 @@ namespace osu.Game.Overlays.Notifications RelativeSizeAxes = Axes.Both, }); - Content.Add(new SpriteText + Content.Add(textDrawable = new SpriteText { TextSize = 16, Colour = OsuColour.Gray(128), @@ -104,23 +148,6 @@ namespace osu.Game.Overlays.Notifications State = ProgressNotificationState.Queued; } - public void Complete() - { - Debug.Assert(state != ProgressNotificationState.Completed); - - state = ProgressNotificationState.Completed; - - NotificationContent.MoveToY(-DrawSize.Y / 2, 200, EasingTypes.OutQuint); - FadeTo(0.01f, 200); //don't completely fade out or our scheduled task won't run. - - Delay(100); - Schedule(() => - { - CompletionTarget?.Invoke(new ProgressCompletionNotification(this)); - base.Close(); - }); - } - public override void Close() { switch (State) @@ -135,8 +162,16 @@ namespace osu.Game.Overlays.Notifications } } + /// + /// The function to post completion notifications back to. + /// public Action CompletionTarget { get; set; } + /// + /// An action to complete when the completion notification is clicked. + /// + public Func CompletionClickAction; + class ProgressBar : Container { private Box box; @@ -175,7 +210,7 @@ namespace osu.Game.Overlays.Notifications { colourActive = colours.Blue; Colour = colourInactive = OsuColour.Gray(0.5f); - + Height = 5; Children = new[] diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs index 7c6666082e..52bd271252 100644 --- a/osu.Game/Overlays/Notifications/SimpleNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -12,12 +12,33 @@ namespace osu.Game.Overlays.Notifications public class SimpleNotification : Notification { private string text; - - public SimpleNotification(string text) + public string Text { - this.text = text; + get { return text; } + set + { + text = value; + if (IsLoaded) + textDrawable.Text = text; + } } + private FontAwesome icon = FontAwesome.fa_info_circle; + public FontAwesome Icon + { + get { return icon; } + set + { + icon = value; + if (IsLoaded) + iconDrawable.Icon = icon; + } + } + + + private SpriteText textDrawable; + private TextAwesome iconDrawable; + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -28,14 +49,14 @@ namespace osu.Game.Overlays.Notifications RelativeSizeAxes = Axes.Both, ColourInfo = ColourInfo.GradientVertical(OsuColour.Gray(0.2f), OsuColour.Gray(0.5f)) }, - new TextAwesome + iconDrawable = new TextAwesome { Anchor = Anchor.Centre, - Icon = FontAwesome.fa_info_circle, + Icon = icon , } }); - Content.Add(new SpriteText + Content.Add(textDrawable = new SpriteText { TextSize = 16, Colour = OsuColour.Gray(128), From 49ae976af665a695f3025379ff27efa3b6a22965 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 12 Feb 2017 14:52:10 +0900 Subject: [PATCH 18/26] Add squirrel dependencies. --- osu.Desktop/app.config | 11 ++++++++ osu.Desktop/osu.Desktop.csproj | 46 ++++++++++++++++++++++++++++++++++ osu.Desktop/packages.config | 7 ++++++ 3 files changed, 64 insertions(+) create mode 100644 osu.Desktop/app.config create mode 100644 osu.Desktop/packages.config diff --git a/osu.Desktop/app.config b/osu.Desktop/app.config new file mode 100644 index 0000000000..44ccc4b77a --- /dev/null +++ b/osu.Desktop/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 9df4148ac0..65bf80700f 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -80,8 +80,52 @@ osu!.res + + ..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.dll + True + + + ..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.MsDelta.dll + True + + + ..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.PatchApi.dll + True + + + ..\packages\squirrel.windows.1.5.2\lib\Net45\ICSharpCode.SharpZipLib.dll + True + + + ..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.dll + True + + + ..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Mdb.dll + True + + + ..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Pdb.dll + True + + + ..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Rocks.dll + True + + + ..\packages\squirrel.windows.1.5.2\lib\Net45\NuGet.Squirrel.dll + True + + + ..\packages\Splat.1.6.2\lib\Net45\Splat.dll + True + + + ..\packages\squirrel.windows.1.5.2\lib\Net45\Squirrel.dll + True + @@ -89,7 +133,9 @@ osu.licenseheader + + diff --git a/osu.Desktop/packages.config b/osu.Desktop/packages.config new file mode 100644 index 0000000000..8d1361bd0a --- /dev/null +++ b/osu.Desktop/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file From 870aa2750f83935939236c6c5acb44f48f1f6aa1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 12 Feb 2017 14:53:33 +0900 Subject: [PATCH 19/26] Don't attempt to import command line arguments as beatmaps. --- osu.Game/Database/BeatmapDatabase.cs | 106 ++++++++++++++------------- osu.Game/OsuGame.cs | 8 +- 2 files changed, 60 insertions(+), 54 deletions(-) diff --git a/osu.Game/Database/BeatmapDatabase.cs b/osu.Game/Database/BeatmapDatabase.cs index dff76479e8..d515c71ed4 100644 --- a/osu.Game/Database/BeatmapDatabase.cs +++ b/osu.Game/Database/BeatmapDatabase.cs @@ -83,64 +83,66 @@ namespace osu.Game.Database connection.DeleteAll(); } - public void Import(params string[] paths) + public void Import(IEnumerable paths) { foreach (string p in paths) + Import(p); + } + + public void Import(string path) + { + string hash = null; + + BeatmapMetadata metadata; + + using (var reader = ArchiveReader.GetReader(storage, path)) + metadata = reader.ReadMetadata(); + + if (metadata.OnlineBeatmapSetID.HasValue && + connection.Table().Count(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID) != 0) + return; // TODO: Update this beatmap instead + + if (File.Exists(path)) // Not always the case, i.e. for LegacyFilesystemReader { - var path = p; - string hash = null; - - BeatmapMetadata metadata; - - using (var reader = ArchiveReader.GetReader(storage, path)) - metadata = reader.ReadMetadata(); - - if (metadata.OnlineBeatmapSetID.HasValue && - connection.Table().Count(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID) != 0) - return; // TODO: Update this beatmap instead - - if (File.Exists(path)) // Not always the case, i.e. for LegacyFilesystemReader + using (var md5 = MD5.Create()) + using (var input = storage.GetStream(path)) { - using (var md5 = MD5.Create()) - using (var input = storage.GetStream(path)) - { - hash = BitConverter.ToString(md5.ComputeHash(input)).Replace("-", "").ToLowerInvariant(); - input.Seek(0, SeekOrigin.Begin); - path = Path.Combine(@"beatmaps", hash.Remove(1), hash.Remove(2), hash); - using (var output = storage.GetStream(path, FileAccess.Write)) - input.CopyTo(output); - } + hash = BitConverter.ToString(md5.ComputeHash(input)).Replace("-", "").ToLowerInvariant(); + input.Seek(0, SeekOrigin.Begin); + path = Path.Combine(@"beatmaps", hash.Remove(1), hash.Remove(2), hash); + using (var output = storage.GetStream(path, FileAccess.Write)) + input.CopyTo(output); } - var beatmapSet = new BeatmapSetInfo - { - OnlineBeatmapSetID = metadata.OnlineBeatmapSetID, - Beatmaps = new List(), - Path = path, - Hash = hash, - Metadata = metadata - }; - - using (var reader = ArchiveReader.GetReader(storage, path)) - { - string[] mapNames = reader.ReadBeatmaps(); - foreach (var name in mapNames) - { - using (var stream = new StreamReader(reader.GetStream(name))) - { - var decoder = BeatmapDecoder.GetDecoder(stream); - Beatmap beatmap = decoder.Decode(stream); - beatmap.BeatmapInfo.Path = name; - - // TODO: Diff beatmap metadata with set metadata and leave it here if necessary - beatmap.BeatmapInfo.Metadata = null; - - beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo); - } - } - } - - Import(new[] { beatmapSet }); } + var beatmapSet = new BeatmapSetInfo + { + OnlineBeatmapSetID = metadata.OnlineBeatmapSetID, + Beatmaps = new List(), + Path = path, + Hash = hash, + Metadata = metadata + }; + + using (var reader = ArchiveReader.GetReader(storage, path)) + { + string[] mapNames = reader.ReadBeatmaps(); + foreach (var name in mapNames) + { + using (var stream = new StreamReader(reader.GetStream(name))) + { + var decoder = BeatmapDecoder.GetDecoder(stream); + Beatmap beatmap = decoder.Decode(stream); + beatmap.BeatmapInfo.Path = name; + + // TODO: Diff beatmap metadata with set metadata and leave it here if necessary + beatmap.BeatmapInfo.Metadata = null; + + beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo); + } + } + } + + Import(new[] { beatmapSet }); } public void Import(IEnumerable beatmapSets) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e8233366d9..9188fab355 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -24,6 +24,7 @@ using osu.Game.Screens.Menu; using OpenTK; using System.Linq; using osu.Framework.Graphics.Primitives; +using System.Collections.Generic; namespace osu.Game { @@ -67,14 +68,17 @@ namespace osu.Game } if (args?.Length > 0) - ImportBeatmaps(args); + { + var paths = args.Where(a => !a.StartsWith(@"-")); + ImportBeatmaps(paths); + } Dependencies.Cache(this); PlayMode = LocalConfig.GetBindable(OsuConfig.PlayMode); } - public void ImportBeatmaps(params string[] paths) + public void ImportBeatmaps(IEnumerable paths) { Schedule(delegate { Dependencies.Get().Import(paths); }); } From 0cd149eda46cf180f70ee3fa938dd9f5036c0165 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 12 Feb 2017 14:54:07 +0900 Subject: [PATCH 20/26] Stop using embedded manifest, add AssemblyInfo. --- osu.Desktop/Properties/AssemblyInfo.cs | 26 ++++++++++++++++++++++++++ osu.Desktop/osu.Desktop.csproj | 15 +++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 osu.Desktop/Properties/AssemblyInfo.cs diff --git a/osu.Desktop/Properties/AssemblyInfo.cs b/osu.Desktop/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..d7391080a6 --- /dev/null +++ b/osu.Desktop/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("osu!lazer")] +[assembly: AssemblyDescription("click the circles. to the beat.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("ppy Pty Ltd")] +[assembly: AssemblyProduct("osu!lazer")] +[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("55e28cb2-7b6c-4595-8dcc-9871d8aad7e9")] + +[assembly: AssemblyVersion("0.0.3")] +[assembly: AssemblyFileVersion("0.0.3")] diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 65bf80700f..0eda38bbd7 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -77,7 +77,14 @@ false - osu!.res + + + + + lazer.ico + + + Properties\app.manifest @@ -201,10 +208,14 @@ + + + + + -