diff --git a/Gemfile.lock b/Gemfile.lock
index f7c19064b4..7df9c46482 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,11 +1,11 @@
GEM
remote: https://rubygems.org/
specs:
- CFPropertyList (3.0.0)
- addressable (2.6.0)
- public_suffix (>= 2.0.2, < 4.0)
+ CFPropertyList (3.0.1)
+ addressable (2.7.0)
+ public_suffix (>= 2.0.2, < 5.0)
atomos (0.1.3)
- babosa (1.0.2)
+ babosa (1.0.3)
claide (1.0.3)
colored (1.2)
colored2 (3.1.2)
@@ -26,8 +26,8 @@ GEM
http-cookie (~> 1.0.0)
faraday_middleware (0.13.1)
faraday (>= 0.7.4, < 1.0)
- fastimage (2.1.5)
- fastlane (2.129.0)
+ fastimage (2.1.7)
+ fastlane (2.131.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0)
babosa (>= 1.0.2, < 2.0.0)
@@ -77,9 +77,9 @@ GEM
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
signet (~> 0.9)
- google-cloud-core (1.3.0)
+ google-cloud-core (1.3.1)
google-cloud-env (~> 1.0)
- google-cloud-env (1.2.0)
+ google-cloud-env (1.2.1)
faraday (~> 0.11)
google-cloud-storage (1.16.0)
digest-crc (~> 0.4)
@@ -100,9 +100,9 @@ GEM
json (2.2.0)
jwt (2.1.0)
memoist (0.16.0)
- mime-types (3.2.2)
+ mime-types (3.3)
mime-types-data (~> 3.2015)
- mime-types-data (3.2019.0331)
+ mime-types-data (3.2019.0904)
mini_magick (4.9.5)
mini_portile2 (2.4.0)
multi_json (1.13.1)
@@ -121,14 +121,14 @@ GEM
uber (< 0.2.0)
retriable (3.1.2)
rouge (2.0.7)
- rubyzip (1.2.3)
+ rubyzip (1.2.4)
security (0.1.3)
signet (0.11.0)
addressable (~> 2.3)
faraday (~> 0.9)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
- simctl (1.6.5)
+ simctl (1.6.6)
CFPropertyList
naturally
slack-notifier (2.3.2)
diff --git a/README.md b/README.md
index 56491a4be4..aefeb2e96e 100644
--- a/README.md
+++ b/README.md
@@ -31,12 +31,10 @@ If you are not interested in developing the game, you can still consume our [bin
**Latest build:**
-| [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) |
-| ------------- | ------------- |
+| [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [iOS(iOS 10+)](https://testflight.apple.com/join/2tLcjWlF) | [Android (5+)](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
+| ------------- | ------------- | ------------- | ------------- |
- **Linux** users are recommended to self-compile until we have official deployment in place.
-- **iOS** users can join the [TestFlight beta program](https://testflight.apple.com/join/2tLcjWlF) (note that due to high demand this is regularly full).
-- **Android** users can self-compile, and expect a public beta soon.
If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
index 0b60e28b0f..7adf42a1eb 100644
--- a/fastlane/Fastfile
+++ b/fastlane/Fastfile
@@ -1,5 +1,83 @@
update_fastlane
+platform :android do
+desc 'Deploy to play store'
+ lane :beta do |options|
+
+ update_version(
+ version: options[:version],
+ build: options[:build],
+ )
+
+ build(options)
+
+ supply(
+ apk: './osu.Android/bin/Release/sh.ppy.osulazer-Signed.apk',
+ package_name: 'sh.ppy.osulazer',
+ track: 'alpha', # upload to alpha, we can promote it later
+ json_key: options[:json_key],
+ )
+ end
+
+ desc 'Deploy to github release'
+ lane :build_github do |options|
+
+ update_version(
+ version: options[:version],
+ build: options[:build],
+ )
+
+ build(options)
+
+ client = HTTPClient.new
+ changelog = client.get_content 'https://gist.githubusercontent.com/peppy/aaa2ec1a323554b619671cac6dbbb776/raw'
+ changelog.gsub!('$BUILD_ID', options[:build])
+
+ set_github_release(
+ repository_name: "ppy/osu",
+ api_token: ENV["GITHUB_TOKEN"],
+ name: options[:build],
+ tag_name: options[:build],
+ is_draft: true,
+ description: changelog,
+ commitish: "master",
+ upload_assets: ["osu.Android/bin/Release/sh.ppy.osulazer.apk"]
+ )
+
+ end
+
+ desc 'Compile the project'
+ lane :build do |options|
+ nuget_restore(
+ project_path: 'osu.Android.sln'
+ )
+
+ souyuz(
+ build_configuration: 'Release',
+ solution_path: 'osu.Android.sln',
+ platform: "android",
+ output_path: "osu.Android/bin/Release/",
+ keystore_path: options[:keystore_path],
+ keystore_alias: options[:keystore_alias],
+ keystore_password: ENV["KEYSTORE_PASSWORD"]
+ )
+ end
+
+ lane :update_version do |options|
+
+ split = options[:build].split('.')
+ split[1] = split[1].to_s.rjust(4, '0')
+ android_build = split.join('')
+
+ app_version(
+ solution_path: 'osu.Android.sln',
+ version: options[:version],
+ build: android_build,
+ )
+ end
+
+end
+
platform :ios do
desc 'Deploy to testflight'
lane :beta do |options|
diff --git a/fastlane/README.md b/fastlane/README.md
index fbccf1c8c0..a400ed9516 100644
--- a/fastlane/README.md
+++ b/fastlane/README.md
@@ -15,6 +15,30 @@ Install _fastlane_ using
or alternatively using `brew cask install fastlane`
# Available Actions
+## Android
+### android beta
+```
+fastlane android beta
+```
+Deploy to play store
+### android build_github
+```
+fastlane android build_github
+```
+Deploy to github release
+### android build
+```
+fastlane android build
+```
+Compile the project
+### android update_version
+```
+fastlane android update_version
+```
+
+
+----
+
## iOS
### ios beta
```
diff --git a/osu.Android.props b/osu.Android.props
index c57fc342ba..46fd5424df 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -62,6 +62,6 @@
-
+
diff --git a/osu.Android/OsuGameAndroid.cs b/osu.Android/OsuGameAndroid.cs
index d9bdd9c0c2..a91c010809 100644
--- a/osu.Android/OsuGameAndroid.cs
+++ b/osu.Android/OsuGameAndroid.cs
@@ -4,11 +4,37 @@
using System;
using Android.App;
using osu.Game;
+using osu.Game.Updater;
namespace osu.Android
{
public class OsuGameAndroid : OsuGame
{
- public override Version AssemblyVersion => new Version(Application.Context.ApplicationContext.PackageManager.GetPackageInfo(Application.Context.ApplicationContext.PackageName, 0).VersionName);
+ public override Version AssemblyVersion
+ {
+ get
+ {
+ var packageInfo = Application.Context.ApplicationContext.PackageManager.GetPackageInfo(Application.Context.ApplicationContext.PackageName, 0);
+
+ try
+ {
+ string versionName = packageInfo.VersionCode.ToString();
+ // undo play store version garbling
+ return new Version(int.Parse(versionName.Substring(0, 4)), int.Parse(versionName.Substring(4, 4)), int.Parse(versionName.Substring(8, 1)));
+ }
+ catch
+ {
+ }
+
+ return new Version(packageInfo.VersionName);
+ }
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ Add(new SimpleUpdateManager());
+ }
}
-}
+}
\ No newline at end of file
diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs
index 761f52f961..7725ee6451 100644
--- a/osu.Desktop/OsuGameDesktop.cs
+++ b/osu.Desktop/OsuGameDesktop.cs
@@ -17,6 +17,7 @@ using osu.Framework.Logging;
using osu.Framework.Platform.Windows;
using osu.Framework.Screens;
using osu.Game.Screens.Menu;
+using osu.Game.Updater;
namespace osu.Desktop
{
diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs
index 51e801c185..6eed46867a 100644
--- a/osu.Desktop/Overlays/VersionManager.cs
+++ b/osu.Desktop/Overlays/VersionManager.cs
@@ -8,11 +8,8 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game;
-using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
-using osu.Game.Overlays;
-using osu.Game.Overlays.Notifications;
using osuTK;
using osuTK.Graphics;
@@ -20,17 +17,9 @@ namespace osu.Desktop.Overlays
{
public class VersionManager : OverlayContainer
{
- private OsuConfigManager config;
- private OsuGameBase game;
- private NotificationOverlay notificationOverlay;
-
[BackgroundDependencyLoader]
- private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game, OsuConfigManager config)
+ private void load(OsuColour colours, TextureStore textures, OsuGameBase game)
{
- notificationOverlay = notification;
- this.config = config;
- this.game = game;
-
AutoSizeAxes = Axes.Both;
Anchor = Anchor.BottomCentre;
Origin = Anchor.BottomCentre;
@@ -85,48 +74,6 @@ namespace osu.Desktop.Overlays
};
}
- protected override void LoadComplete()
- {
- base.LoadComplete();
-
- var version = game.Version;
- var lastVersion = config.Get(OsuSetting.Version);
-
- if (game.IsDeployedBuild && version != lastVersion)
- {
- config.Set(OsuSetting.Version, version);
-
- // only show a notification if we've previously saved a version to the config file (ie. not the first run).
- if (!string.IsNullOrEmpty(lastVersion))
- notificationOverlay.Post(new UpdateCompleteNotification(version));
- }
- }
-
- private class UpdateCompleteNotification : SimpleNotification
- {
- private readonly string version;
-
- public UpdateCompleteNotification(string version)
- {
- this.version = version;
- Text = $"You are now running osu!lazer {version}.\nClick to see what's new!";
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours, ChangelogOverlay changelog, NotificationOverlay notificationOverlay)
- {
- Icon = FontAwesome.Solid.CheckSquare;
- IconBackgound.Colour = colours.BlueDark;
-
- Activated = delegate
- {
- notificationOverlay.Hide();
- changelog.ShowBuild(OsuGameBase.CLIENT_STREAM_NAME, version);
- return true;
- };
- }
- }
-
protected override void PopIn()
{
this.FadeIn(1400, Easing.OutQuint);
diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs
index fa41c061b5..60b47a8b3a 100644
--- a/osu.Desktop/Updater/SquirrelUpdateManager.cs
+++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs
@@ -20,7 +20,7 @@ using LogLevel = Splat.LogLevel;
namespace osu.Desktop.Updater
{
- public class SquirrelUpdateManager : Component
+ public class SquirrelUpdateManager : osu.Game.Updater.UpdateManager
{
private UpdateManager updateManager;
private NotificationOverlay notificationOverlay;
diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs
index e7fd601abe..d5fd2808b8 100644
--- a/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs
@@ -15,7 +15,6 @@ using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Tests.Visual;
using osuTK;
@@ -67,6 +66,8 @@ namespace osu.Game.Rulesets.Mania.Tests
AddAssert("check note anchors", () => notesInStageAreAnchored(stages[0], Anchor.TopCentre));
AddAssert("check note anchors", () => notesInStageAreAnchored(stages[1], Anchor.BottomCentre));
+ AddAssert("check bar anchors", () => barsInStageAreAnchored(stages[0], Anchor.TopCentre));
+ AddAssert("check bar anchors", () => barsInStageAreAnchored(stages[1], Anchor.BottomCentre));
AddStep("flip direction", () =>
{
@@ -76,10 +77,14 @@ namespace osu.Game.Rulesets.Mania.Tests
AddAssert("check note anchors", () => notesInStageAreAnchored(stages[0], Anchor.BottomCentre));
AddAssert("check note anchors", () => notesInStageAreAnchored(stages[1], Anchor.TopCentre));
+ AddAssert("check bar anchors", () => barsInStageAreAnchored(stages[0], Anchor.BottomCentre));
+ AddAssert("check bar anchors", () => barsInStageAreAnchored(stages[1], Anchor.TopCentre));
}
private bool notesInStageAreAnchored(ManiaStage stage, Anchor anchor) => stage.Columns.SelectMany(c => c.AllHitObjects).All(o => o.Anchor == anchor);
+ private bool barsInStageAreAnchored(ManiaStage stage, Anchor anchor) => stage.AllHitObjects.Where(obj => obj is DrawableBarLine).All(o => o.Anchor == anchor);
+
private void createNote()
{
foreach (var stage in stages)
diff --git a/osu.Game.Rulesets.Mania/Objects/BarLine.cs b/osu.Game.Rulesets.Mania/Objects/BarLine.cs
new file mode 100644
index 0000000000..0981b028b2
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Objects/BarLine.cs
@@ -0,0 +1,12 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Rulesets.Objects;
+
+namespace osu.Game.Rulesets.Mania.Objects
+{
+ public class BarLine : ManiaHitObject, IBarLine
+ {
+ public bool Major { get; set; }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
index be21610525..56bc797c7f 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
@@ -4,7 +4,6 @@
using osuTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
-using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osuTK.Graphics;
@@ -14,7 +13,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// Visualises a . Although this derives DrawableManiaHitObject,
/// this does not handle input/sound like a normal hit object.
///
- public class DrawableBarLine : DrawableHitObject
+ public class DrawableBarLine : DrawableManiaHitObject
{
///
/// Height of major bar line triangles.
diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs
index 29863fba2e..d371c1f7a8 100644
--- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs
+++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs
@@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Mania.UI
public DrawableManiaRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods)
: base(ruleset, beatmap, mods)
{
- BarLines = new BarLineGenerator(Beatmap).BarLines;
+ BarLines = new BarLineGenerator(Beatmap).BarLines;
}
[BackgroundDependencyLoader]
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
index 12faa499ad..5ab07416a6 100644
--- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
+++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
@@ -8,7 +8,6 @@ using System.Collections.Generic;
using System.Linq;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
-using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI.Scrolling;
using osuTK;
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs
index 98a4b7d0b6..a28de7ea58 100644
--- a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs
+++ b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs
@@ -12,7 +12,6 @@ using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
-using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling;
diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
index b32dfd483f..80291c002e 100644
--- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
+++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
@@ -40,9 +40,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
for (int i = 0; i < max_sprites; i++)
{
- // InvalidationID 1 forces an update of each part of the cursor trail the first time ApplyState is run on the draw node
- // This is to prevent garbage data from being sent to the vertex shader, resulting in visual issues on some platforms
- parts[i].InvalidationID = 1;
+ // -1 signals that the part is unusable, and should not be drawn
+ parts[i].InvalidationID = -1;
}
}
@@ -112,7 +111,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
for (int i = 0; i < parts.Length; ++i)
{
parts[i].Time -= time;
- ++parts[i].InvalidationID;
+
+ if (parts[i].InvalidationID != -1)
+ ++parts[i].InvalidationID;
}
time = 0;
@@ -205,8 +206,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
public TrailDrawNode(CursorTrail source)
: base(source)
{
- for (int i = 0; i < max_sprites; i++)
- parts[i].InvalidationID = 0;
}
public override void ApplyState()
@@ -218,11 +217,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
size = Source.partSize;
time = Source.time;
- for (int i = 0; i < Source.parts.Length; ++i)
- {
- if (Source.parts[i].InvalidationID > parts[i].InvalidationID)
- parts[i] = Source.parts[i];
- }
+ Source.parts.CopyTo(parts, 0);
}
public override void Draw(Action vertexAction)
@@ -234,6 +229,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
for (int i = 0; i < parts.Length; ++i)
{
+ if (parts[i].InvalidationID == -1)
+ continue;
+
vertexBatch.DrawTime = parts[i].Time;
Vector2 pos = parts[i].Position;
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs
index 3aa461e779..cbbf5b0c09 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs
@@ -53,6 +53,11 @@ namespace osu.Game.Rulesets.Taiko.Tests
AddStep("Strong Rim", () => addRimHit(true));
AddStep("Add bar line", () => addBarLine(false));
AddStep("Add major bar line", () => addBarLine(true));
+ AddStep("Add centre w/ bar line", () =>
+ {
+ addCentreHit(false);
+ addBarLine(true);
+ });
AddStep("Height test 1", () => changePlayfieldSize(1));
AddStep("Height test 2", () => changePlayfieldSize(2));
AddStep("Height test 3", () => changePlayfieldSize(3));
diff --git a/osu.Game.Rulesets.Taiko/Objects/BarLine.cs b/osu.Game.Rulesets.Taiko/Objects/BarLine.cs
new file mode 100644
index 0000000000..2afbbc737c
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko/Objects/BarLine.cs
@@ -0,0 +1,12 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Rulesets.Objects;
+
+namespace osu.Game.Rulesets.Taiko.Objects
+{
+ public class BarLine : TaikoHitObject, IBarLine
+ {
+ public bool Major { get; set; }
+ }
+}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLineMajor.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLineMajor.cs
index f5b75a781b..4d3a1a3f8a 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLineMajor.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLineMajor.cs
@@ -5,7 +5,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osuTK;
using osu.Framework.Graphics.Shapes;
-using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs
index 5caa9e4626..fc109bf6a6 100644
--- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs
+++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs
@@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.UI
[BackgroundDependencyLoader]
private void load()
{
- new BarLineGenerator(Beatmap).BarLines.ForEach(bar => Playfield.Add(bar.Major ? new DrawableBarLineMajor(bar) : new DrawableBarLine(bar)));
+ new BarLineGenerator(Beatmap).BarLines.ForEach(bar => Playfield.Add(bar.Major ? new DrawableBarLineMajor(bar) : new DrawableBarLine(bar)));
}
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(this);
diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs
index bbcc4140a9..578030748b 100644
--- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs
+++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs
@@ -9,6 +9,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
+using osu.Framework.Testing;
using osu.Game.Audio;
using osu.Game.Skinning;
using osu.Game.Tests.Visual;
@@ -17,6 +18,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Skins
{
[TestFixture]
+ [HeadlessTest]
public class TestSceneSkinConfigurationLookup : OsuTestScene
{
private LegacySkin source1;
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
index 71399106f4..f12a613bf1 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
@@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.SongSelect
private readonly Stack selectedSets = new Stack();
private readonly HashSet eagerSelectedIDs = new HashSet();
- private BeatmapInfo currentSelection;
+ private BeatmapInfo currentSelection => carousel.SelectedBeatmap;
private const int set_count = 5;
@@ -56,37 +56,26 @@ namespace osu.Game.Tests.Visual.SongSelect
{
RelativeSizeAxes = Axes.Both,
});
-
- List beatmapSets = new List();
-
- for (int i = 1; i <= set_count; i++)
- beatmapSets.Add(createTestBeatmapSet(i));
-
- carousel.SelectionChanged = s => currentSelection = s;
-
- loadBeatmaps(beatmapSets);
-
- testTraversal();
- testFiltering();
- testRandom();
- testAddRemove();
- testSorting();
-
- testRemoveAll();
- testEmptyTraversal();
- testHiding();
- testSelectingFilteredRuleset();
- testCarouselRootIsRandom();
}
- private void loadBeatmaps(List beatmapSets)
+ private void loadBeatmaps(List beatmapSets = null)
{
+ if (beatmapSets == null)
+ {
+ beatmapSets = new List();
+
+ for (int i = 1; i <= set_count; i++)
+ beatmapSets.Add(createTestBeatmapSet(i));
+ }
+
bool changed = false;
AddStep($"Load {beatmapSets.Count} Beatmaps", () =>
{
+ carousel.Filter(new FilterCriteria());
carousel.BeatmapSetsChanged = () => changed = true;
carousel.BeatmapSets = beatmapSets;
});
+
AddUntilStep("Wait for load", () => changed);
}
@@ -173,8 +162,11 @@ namespace osu.Game.Tests.Visual.SongSelect
///
/// Test keyboard traversal
///
- private void testTraversal()
+ [Test]
+ public void TestTraversal()
{
+ loadBeatmaps();
+
advanceSelection(direction: 1, diff: false);
checkSelected(1, 1);
@@ -199,8 +191,11 @@ namespace osu.Game.Tests.Visual.SongSelect
///
/// Test filtering
///
- private void testFiltering()
+ [Test]
+ public void TestFiltering()
{
+ loadBeatmaps();
+
// basic filtering
setSelected(1, 1);
@@ -262,8 +257,11 @@ namespace osu.Game.Tests.Visual.SongSelect
///
/// Test random non-repeating algorithm
///
- private void testRandom()
+ [Test]
+ public void TestRandom()
{
+ loadBeatmaps();
+
setSelected(1, 1);
nextRandom();
@@ -299,8 +297,11 @@ namespace osu.Game.Tests.Visual.SongSelect
///
/// Test adding and removing beatmap sets
///
- private void testAddRemove()
+ [Test]
+ public void TestAddRemove()
{
+ loadBeatmaps();
+
AddStep("Add new set", () => carousel.UpdateBeatmapSet(createTestBeatmapSet(set_count + 1)));
AddStep("Add new set", () => carousel.UpdateBeatmapSet(createTestBeatmapSet(set_count + 2)));
@@ -322,16 +323,22 @@ namespace osu.Game.Tests.Visual.SongSelect
///
/// Test sorting
///
- private void testSorting()
+ [Test]
+ public void TestSorting()
{
+ loadBeatmaps();
+
AddStep("Sort by author", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Author }, false));
AddAssert("Check zzzzz is at bottom", () => carousel.BeatmapSets.Last().Metadata.AuthorString == "zzzzz");
AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false));
AddAssert($"Check #{set_count} is at bottom", () => carousel.BeatmapSets.Last().Metadata.Title.EndsWith($"#{set_count}!"));
}
- private void testRemoveAll()
+ [Test]
+ public void TestRemoveAll()
{
+ loadBeatmaps();
+
setSelected(2, 1);
AddAssert("Selection is non-null", () => currentSelection != null);
@@ -353,8 +360,11 @@ namespace osu.Game.Tests.Visual.SongSelect
checkNoSelection();
}
- private void testEmptyTraversal()
+ [Test]
+ public void TestEmptyTraversal()
{
+ loadBeatmaps(new List());
+
advanceSelection(direction: 1, diff: false);
checkNoSelection();
@@ -368,11 +378,14 @@ namespace osu.Game.Tests.Visual.SongSelect
checkNoSelection();
}
- private void testHiding()
+ [Test]
+ public void TestHiding()
{
- var hidingSet = createTestBeatmapSet(1);
+ BeatmapSetInfo hidingSet = createTestBeatmapSet(1);
hidingSet.Beatmaps[1].Hidden = true;
- AddStep("Add set with diff 2 hidden", () => carousel.UpdateBeatmapSet(hidingSet));
+
+ loadBeatmaps(new List { hidingSet });
+
setSelected(1, 1);
checkVisibleItemCount(true, 2);
@@ -402,7 +415,8 @@ namespace osu.Game.Tests.Visual.SongSelect
}
}
- private void testSelectingFilteredRuleset()
+ [Test]
+ public void TestSelectingFilteredRuleset()
{
var testMixed = createTestBeatmapSet(set_count + 1);
AddStep("add mixed ruleset beatmapset", () =>
@@ -437,14 +451,16 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("remove single ruleset set", () => carousel.RemoveBeatmapSet(testSingle));
}
- private void testCarouselRootIsRandom()
+ [Test]
+ public void TestCarouselRootIsRandom()
{
- List beatmapSets = new List();
+ List manySets = new List();
for (int i = 1; i <= 50; i++)
- beatmapSets.Add(createTestBeatmapSet(i));
+ manySets.Add(createTestBeatmapSet(i));
+
+ loadBeatmaps(manySets);
- loadBeatmaps(beatmapSets);
advanceSelection(direction: 1, diff: false);
checkNonmatchingFilter();
checkNonmatchingFilter();
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs
index a762d561c2..700adad9cb 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs
@@ -6,7 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Sprites;
-using osu.Game.Screens.Edit.Setup.Components.LabelledComponents;
+using osu.Game.Graphics.UserInterfaceV2;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs
index 395905a30d..53a2bfabbc 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs
@@ -7,7 +7,8 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Game.Screens.Edit.Setup.Components.LabelledComponents;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Graphics.UserInterfaceV2;
namespace osu.Game.Tests.Visual.UserInterface
{
@@ -19,6 +20,36 @@ namespace osu.Game.Tests.Visual.UserInterface
typeof(LabelledTextBox),
};
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestTextBox(bool hasDescription) => createTextBox(hasDescription);
+
+ private void createTextBox(bool hasDescription = false)
+ {
+ AddStep("create component", () =>
+ {
+ LabelledComponent component;
+
+ Child = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Width = 500,
+ AutoSizeAxes = Axes.Y,
+ Child = component = new LabelledTextBox
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Label = "Testing text",
+ PlaceholderText = "This is definitely working as intended",
+ }
+ };
+
+ component.Label = "a sample component";
+ component.Description = hasDescription ? "this text describes the component" : string.Empty;
+ });
+ }
+
[BackgroundDependencyLoader]
private void load()
{
@@ -32,7 +63,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- LabelText = "Testing text",
+ Label = "Testing text",
PlaceholderText = "This is definitely working as intended",
}
};
diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs
index 7a44e7a0e1..091a837745 100644
--- a/osu.Game.Tournament/Screens/SetupScreen.cs
+++ b/osu.Game.Tournament/Screens/SetupScreen.cs
@@ -7,9 +7,9 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
+using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Online.API;
using osu.Game.Overlays;
-using osu.Game.Screens.Edit.Setup.Components.LabelledComponents;
using osu.Game.Tournament.IPC;
using osuTK;
using osuTK.Graphics;
diff --git a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledComponent.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs
similarity index 98%
rename from osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledComponent.cs
rename to osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs
index 770065cb0e..2e659825b7 100644
--- a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledComponent.cs
+++ b/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs
@@ -5,11 +5,10 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
-using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osuTK;
-namespace osu.Game.Screens.Edit.Setup.Components.LabelledComponents
+namespace osu.Game.Graphics.UserInterfaceV2
{
public abstract class LabelledComponent : CompositeDrawable
where T : Drawable
diff --git a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledSwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs
similarity index 100%
rename from osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledSwitchButton.cs
rename to osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs
diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledTextBox.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledTextBox.cs
new file mode 100644
index 0000000000..50d2a14482
--- /dev/null
+++ b/osu.Game/Graphics/UserInterfaceV2/LabelledTextBox.cs
@@ -0,0 +1,49 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.UserInterface;
+using osu.Game.Graphics.UserInterface;
+
+namespace osu.Game.Graphics.UserInterfaceV2
+{
+ public class LabelledTextBox : LabelledComponent
+ {
+ public event TextBox.OnCommitHandler OnCommit;
+
+ public LabelledTextBox()
+ : base(false)
+ {
+ }
+
+ public bool ReadOnly
+ {
+ set => Component.ReadOnly = value;
+ }
+
+ public string PlaceholderText
+ {
+ set => Component.PlaceholderText = value;
+ }
+
+ public string Text
+ {
+ set => Component.Text = value;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ Component.BorderColour = colours.Blue;
+ }
+
+ protected override OsuTextBox CreateComponent() => new OsuTextBox
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.X,
+ CornerRadius = CORNER_RADIUS,
+ }.With(t => t.OnCommit += (sender, newText) => OnCommit?.Invoke(sender, newText));
+ }
+}
diff --git a/osu.Game/Rulesets/Objects/BarLine.cs b/osu.Game/Rulesets/Objects/BarLine.cs
deleted file mode 100644
index a5c716e127..0000000000
--- a/osu.Game/Rulesets/Objects/BarLine.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-namespace osu.Game.Rulesets.Objects
-{
- ///
- /// A hit object representing the end of a bar.
- ///
- public class BarLine : HitObject
- {
- ///
- /// Whether this barline is a prominent beat (based on time signature of beatmap).
- ///
- public bool Major;
- }
-}
diff --git a/osu.Game/Rulesets/Objects/BarLineGenerator.cs b/osu.Game/Rulesets/Objects/BarLineGenerator.cs
index ce571d7b17..4f9395435e 100644
--- a/osu.Game/Rulesets/Objects/BarLineGenerator.cs
+++ b/osu.Game/Rulesets/Objects/BarLineGenerator.cs
@@ -10,12 +10,13 @@ using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Objects
{
- public class BarLineGenerator
+ public class BarLineGenerator
+ where TBarLine : class, IBarLine, new()
{
///
/// The generated bar lines.
///
- public readonly List BarLines = new List();
+ public readonly List BarLines = new List();
///
/// Constructs and generates bar lines for provided beatmap.
@@ -46,7 +47,7 @@ namespace osu.Game.Rulesets.Objects
for (double t = currentTimingPoint.Time; Precision.DefinitelyBigger(endTime, t); t += barLength, currentBeat++)
{
- BarLines.Add(new BarLine
+ BarLines.Add(new TBarLine
{
StartTime = t,
Major = currentBeat % (int)currentTimingPoint.TimeSignature == 0
diff --git a/osu.Game/Rulesets/Objects/IBarLine.cs b/osu.Game/Rulesets/Objects/IBarLine.cs
new file mode 100644
index 0000000000..14df80e3b9
--- /dev/null
+++ b/osu.Game/Rulesets/Objects/IBarLine.cs
@@ -0,0 +1,22 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+namespace osu.Game.Rulesets.Objects
+{
+ ///
+ /// Interface for bar line hitobjects.
+ /// Used to decouple bar line generation from ruleset-specific rendering/drawing hierarchies.
+ ///
+ public interface IBarLine
+ {
+ ///
+ /// The time position of the bar.
+ ///
+ double StartTime { set; }
+
+ ///
+ /// Whether this bar line is a prominent beat (based on time signature of beatmap).
+ ///
+ bool Major { set; }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs b/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs
deleted file mode 100644
index 1c53fc7088..0000000000
--- a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Framework.Allocation;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Shapes;
-using osu.Framework.Graphics.UserInterface;
-using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
-using osu.Game.Graphics.UserInterface;
-using osuTK.Graphics;
-
-namespace osu.Game.Screens.Edit.Setup.Components.LabelledComponents
-{
- public class LabelledTextBox : CompositeDrawable
- {
- private const float label_container_width = 150;
- private const float corner_radius = 15;
- private const float default_height = 40;
- private const float default_label_left_padding = 15;
- private const float default_label_top_padding = 12;
- private const float default_label_text_size = 16;
-
- public event TextBox.OnCommitHandler OnCommit;
-
- public bool ReadOnly
- {
- get => textBox.ReadOnly;
- set => textBox.ReadOnly = value;
- }
-
- public string LabelText
- {
- get => label.Text;
- set => label.Text = value;
- }
-
- public float LabelTextSize
- {
- get => label.Font.Size;
- set => label.Font = label.Font.With(size: value);
- }
-
- public string PlaceholderText
- {
- get => textBox.PlaceholderText;
- set => textBox.PlaceholderText = value;
- }
-
- public string Text
- {
- get => textBox.Text;
- set => textBox.Text = value;
- }
-
- public Color4 LabelTextColour
- {
- get => label.Colour;
- set => label.Colour = value;
- }
-
- private readonly OsuTextBox textBox;
- private readonly OsuSpriteText label;
-
- public LabelledTextBox()
- {
- RelativeSizeAxes = Axes.X;
- Height = default_height;
- CornerRadius = corner_radius;
- Masking = true;
-
- InternalChild = new Container
- {
- RelativeSizeAxes = Axes.Both,
- CornerRadius = corner_radius,
- Masking = true,
- Children = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex("1c2125"),
- },
- new GridContainer
- {
- RelativeSizeAxes = Axes.X,
- Height = default_height,
- Content = new[]
- {
- new Drawable[]
- {
- label = new OsuSpriteText
- {
- Anchor = Anchor.TopLeft,
- Origin = Anchor.TopLeft,
- Padding = new MarginPadding { Left = default_label_left_padding, Top = default_label_top_padding },
- Colour = Color4.White,
- Font = OsuFont.GetFont(size: default_label_text_size, weight: FontWeight.Bold),
- },
- textBox = new OsuTextBox
- {
- Anchor = Anchor.TopLeft,
- Origin = Anchor.TopLeft,
- RelativeSizeAxes = Axes.Both,
- Height = 1,
- CornerRadius = corner_radius,
- },
- },
- },
- ColumnDimensions = new[]
- {
- new Dimension(GridSizeMode.Absolute, label_container_width),
- new Dimension()
- }
- }
- }
- };
-
- textBox.OnCommit += OnCommit;
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- textBox.BorderColour = colours.Blue;
- }
- }
-}
diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs
index 23c581c6f9..c3436ffd45 100644
--- a/osu.Game/Screens/Select/BeatmapCarousel.cs
+++ b/osu.Game/Screens/Select/BeatmapCarousel.cs
@@ -82,6 +82,9 @@ namespace osu.Game.Screens.Select
var _ = newRoot.Drawables;
root = newRoot;
+ if (selectedBeatmapSet != null && !beatmapSets.Contains(selectedBeatmapSet.BeatmapSet))
+ selectedBeatmapSet = null;
+
scrollableContent.Clear(false);
itemsCache.Invalidate();
scrollPositionCache.Invalidate();
diff --git a/osu.Desktop/Updater/SimpleUpdateManager.cs b/osu.Game/Updater/SimpleUpdateManager.cs
similarity index 87%
rename from osu.Desktop/Updater/SimpleUpdateManager.cs
rename to osu.Game/Updater/SimpleUpdateManager.cs
index 5184791de1..4789ac94d2 100644
--- a/osu.Desktop/Updater/SimpleUpdateManager.cs
+++ b/osu.Game/Updater/SimpleUpdateManager.cs
@@ -6,31 +6,25 @@ using System.Threading.Tasks;
using Newtonsoft.Json;
using osu.Framework;
using osu.Framework.Allocation;
-using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.IO.Network;
using osu.Framework.Platform;
-using osu.Game;
-using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
-namespace osu.Desktop.Updater
+namespace osu.Game.Updater
{
///
/// An update manager that shows notifications if a newer release is detected.
/// Installation is left up to the user.
///
- internal class SimpleUpdateManager : CompositeDrawable
+ public class SimpleUpdateManager : UpdateManager
{
- private NotificationOverlay notificationOverlay;
private string version;
private GameHost host;
[BackgroundDependencyLoader]
- private void load(NotificationOverlay notification, OsuGameBase game, GameHost host)
+ private void load(OsuGameBase game, GameHost host)
{
- notificationOverlay = notification;
-
this.host = host;
version = game.Version;
@@ -50,7 +44,7 @@ namespace osu.Desktop.Updater
if (latest.TagName != version)
{
- notificationOverlay.Post(new SimpleNotification
+ Notifications.Post(new SimpleNotification
{
Text = $"A newer release of osu! has been found ({version} → {latest.TagName}).\n\n"
+ "Click here to download the new version, which can be installed over the top of your existing installation",
@@ -82,6 +76,11 @@ namespace osu.Desktop.Updater
case RuntimeInfo.Platform.MacOsx:
bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".app.zip"));
break;
+
+ case RuntimeInfo.Platform.Android:
+ // on our testing device this causes the download to magically disappear.
+ //bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".apk"));
+ break;
}
return bestAsset?.BrowserDownloadUrl ?? release.HtmlUrl;
diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs
new file mode 100644
index 0000000000..e256cdbe45
--- /dev/null
+++ b/osu.Game/Updater/UpdateManager.cs
@@ -0,0 +1,67 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Configuration;
+using osu.Game.Graphics;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Notifications;
+
+namespace osu.Game.Updater
+{
+ public abstract class UpdateManager : CompositeDrawable
+ {
+ [Resolved]
+ private OsuConfigManager config { get; set; }
+
+ [Resolved]
+ private OsuGameBase game { get; set; }
+
+ [Resolved]
+ protected NotificationOverlay Notifications { get; private set; }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ var version = game.Version;
+ var lastVersion = config.Get(OsuSetting.Version);
+
+ if (game.IsDeployedBuild && version != lastVersion)
+ {
+ config.Set(OsuSetting.Version, version);
+
+ // only show a notification if we've previously saved a version to the config file (ie. not the first run).
+ if (!string.IsNullOrEmpty(lastVersion))
+ Notifications.Post(new UpdateCompleteNotification(version));
+ }
+ }
+
+ private class UpdateCompleteNotification : SimpleNotification
+ {
+ private readonly string version;
+
+ public UpdateCompleteNotification(string version)
+ {
+ this.version = version;
+ Text = $"You are now running osu!lazer {version}.\nClick to see what's new!";
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours, ChangelogOverlay changelog, NotificationOverlay notificationOverlay)
+ {
+ Icon = FontAwesome.Solid.CheckSquare;
+ IconBackgound.Colour = colours.BlueDark;
+
+ Activated = delegate
+ {
+ notificationOverlay.Hide();
+ changelog.ShowBuild(OsuGameBase.CLIENT_STREAM_NAME, version);
+ return true;
+ };
+ }
+ }
+ }
+}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index a699217503..83632f3d41 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -26,7 +26,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 7803ea1e49..30f1da362d 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -118,8 +118,8 @@
-
-
+
+