1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-12 18:23:04 +08:00

Merge remote-tracking branch 'upstream/master' into back-button-part-2

This commit is contained in:
Dean Herbert 2019-09-25 22:12:00 +09:00
commit 8c01677e0b
13 changed files with 289 additions and 132 deletions

View File

@ -1,11 +1,11 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
CFPropertyList (3.0.0) CFPropertyList (3.0.1)
addressable (2.6.0) addressable (2.7.0)
public_suffix (>= 2.0.2, < 4.0) public_suffix (>= 2.0.2, < 5.0)
atomos (0.1.3) atomos (0.1.3)
babosa (1.0.2) babosa (1.0.3)
claide (1.0.3) claide (1.0.3)
colored (1.2) colored (1.2)
colored2 (3.1.2) colored2 (3.1.2)
@ -26,8 +26,8 @@ GEM
http-cookie (~> 1.0.0) http-cookie (~> 1.0.0)
faraday_middleware (0.13.1) faraday_middleware (0.13.1)
faraday (>= 0.7.4, < 1.0) faraday (>= 0.7.4, < 1.0)
fastimage (2.1.5) fastimage (2.1.7)
fastlane (2.129.0) fastlane (2.131.0)
CFPropertyList (>= 2.3, < 4.0.0) CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0) addressable (>= 2.3, < 3.0.0)
babosa (>= 1.0.2, < 2.0.0) babosa (>= 1.0.2, < 2.0.0)
@ -77,9 +77,9 @@ GEM
representable (~> 3.0) representable (~> 3.0)
retriable (>= 2.0, < 4.0) retriable (>= 2.0, < 4.0)
signet (~> 0.9) signet (~> 0.9)
google-cloud-core (1.3.0) google-cloud-core (1.3.1)
google-cloud-env (~> 1.0) google-cloud-env (~> 1.0)
google-cloud-env (1.2.0) google-cloud-env (1.2.1)
faraday (~> 0.11) faraday (~> 0.11)
google-cloud-storage (1.16.0) google-cloud-storage (1.16.0)
digest-crc (~> 0.4) digest-crc (~> 0.4)
@ -100,9 +100,9 @@ GEM
json (2.2.0) json (2.2.0)
jwt (2.1.0) jwt (2.1.0)
memoist (0.16.0) memoist (0.16.0)
mime-types (3.2.2) mime-types (3.3)
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2019.0331) mime-types-data (3.2019.0904)
mini_magick (4.9.5) mini_magick (4.9.5)
mini_portile2 (2.4.0) mini_portile2 (2.4.0)
multi_json (1.13.1) multi_json (1.13.1)
@ -121,14 +121,14 @@ GEM
uber (< 0.2.0) uber (< 0.2.0)
retriable (3.1.2) retriable (3.1.2)
rouge (2.0.7) rouge (2.0.7)
rubyzip (1.2.3) rubyzip (1.2.4)
security (0.1.3) security (0.1.3)
signet (0.11.0) signet (0.11.0)
addressable (~> 2.3) addressable (~> 2.3)
faraday (~> 0.9) faraday (~> 0.9)
jwt (>= 1.5, < 3.0) jwt (>= 1.5, < 3.0)
multi_json (~> 1.10) multi_json (~> 1.10)
simctl (1.6.5) simctl (1.6.6)
CFPropertyList CFPropertyList
naturally naturally
slack-notifier (2.3.2) slack-notifier (2.3.2)

View File

@ -31,12 +31,10 @@ If you are not interested in developing the game, you can still consume our [bin
**Latest build:** **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. - **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. If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.

View File

@ -1,5 +1,83 @@
update_fastlane 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 platform :ios do
desc 'Deploy to testflight' desc 'Deploy to testflight'
lane :beta do |options| lane :beta do |options|

View File

@ -15,6 +15,30 @@ Install _fastlane_ using
or alternatively using `brew cask install fastlane` or alternatively using `brew cask install fastlane`
# Available Actions # 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
### ios beta ### ios beta
``` ```

View File

@ -4,11 +4,37 @@
using System; using System;
using Android.App; using Android.App;
using osu.Game; using osu.Game;
using osu.Game.Updater;
namespace osu.Android namespace osu.Android
{ {
public class OsuGameAndroid : OsuGame 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());
}
} }
} }

View File

@ -17,6 +17,7 @@ using osu.Framework.Logging;
using osu.Framework.Platform.Windows; using osu.Framework.Platform.Windows;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using osu.Game.Updater;
namespace osu.Desktop namespace osu.Desktop
{ {

View File

@ -8,11 +8,8 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Game; using osu.Game;
using osu.Game.Configuration;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
@ -20,17 +17,9 @@ namespace osu.Desktop.Overlays
{ {
public class VersionManager : OverlayContainer public class VersionManager : OverlayContainer
{ {
private OsuConfigManager config;
private OsuGameBase game;
private NotificationOverlay notificationOverlay;
[BackgroundDependencyLoader] [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; AutoSizeAxes = Axes.Both;
Anchor = Anchor.BottomCentre; Anchor = Anchor.BottomCentre;
Origin = 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<string>(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() protected override void PopIn()
{ {
this.FadeIn(1400, Easing.OutQuint); this.FadeIn(1400, Easing.OutQuint);

View File

@ -20,7 +20,7 @@ using LogLevel = Splat.LogLevel;
namespace osu.Desktop.Updater namespace osu.Desktop.Updater
{ {
public class SquirrelUpdateManager : Component public class SquirrelUpdateManager : osu.Game.Updater.UpdateManager
{ {
private UpdateManager updateManager; private UpdateManager updateManager;
private NotificationOverlay notificationOverlay; private NotificationOverlay notificationOverlay;

View File

@ -40,9 +40,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
for (int i = 0; i < max_sprites; i++) 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 // -1 signals that the part is unusable, and should not be drawn
// This is to prevent garbage data from being sent to the vertex shader, resulting in visual issues on some platforms parts[i].InvalidationID = -1;
parts[i].InvalidationID = 1;
} }
} }
@ -112,6 +111,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
for (int i = 0; i < parts.Length; ++i) for (int i = 0; i < parts.Length; ++i)
{ {
parts[i].Time -= time; parts[i].Time -= time;
if (parts[i].InvalidationID != -1)
++parts[i].InvalidationID; ++parts[i].InvalidationID;
} }
@ -205,8 +206,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
public TrailDrawNode(CursorTrail source) public TrailDrawNode(CursorTrail source)
: base(source) : base(source)
{ {
for (int i = 0; i < max_sprites; i++)
parts[i].InvalidationID = 0;
} }
public override void ApplyState() public override void ApplyState()
@ -218,11 +217,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
size = Source.partSize; size = Source.partSize;
time = Source.time; time = Source.time;
for (int i = 0; i < Source.parts.Length; ++i) Source.parts.CopyTo(parts, 0);
{
if (Source.parts[i].InvalidationID > parts[i].InvalidationID)
parts[i] = Source.parts[i];
}
} }
public override void Draw(Action<TexturedVertex2D> vertexAction) public override void Draw(Action<TexturedVertex2D> vertexAction)
@ -234,6 +229,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
for (int i = 0; i < parts.Length; ++i) for (int i = 0; i < parts.Length; ++i)
{ {
if (parts[i].InvalidationID == -1)
continue;
vertexBatch.DrawTime = parts[i].Time; vertexBatch.DrawTime = parts[i].Time;
Vector2 pos = parts[i].Position; Vector2 pos = parts[i].Position;

View File

@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.SongSelect
private readonly Stack<BeatmapSetInfo> selectedSets = new Stack<BeatmapSetInfo>(); private readonly Stack<BeatmapSetInfo> selectedSets = new Stack<BeatmapSetInfo>();
private readonly HashSet<int> eagerSelectedIDs = new HashSet<int>(); private readonly HashSet<int> eagerSelectedIDs = new HashSet<int>();
private BeatmapInfo currentSelection; private BeatmapInfo currentSelection => carousel.SelectedBeatmap;
private const int set_count = 5; private const int set_count = 5;
@ -56,37 +56,26 @@ namespace osu.Game.Tests.Visual.SongSelect
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}); });
}
List<BeatmapSetInfo> beatmapSets = new List<BeatmapSetInfo>(); private void loadBeatmaps(List<BeatmapSetInfo> beatmapSets = null)
{
if (beatmapSets == null)
{
beatmapSets = new List<BeatmapSetInfo>();
for (int i = 1; i <= set_count; i++) for (int i = 1; i <= set_count; i++)
beatmapSets.Add(createTestBeatmapSet(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<BeatmapSetInfo> beatmapSets)
{
bool changed = false; bool changed = false;
AddStep($"Load {beatmapSets.Count} Beatmaps", () => AddStep($"Load {beatmapSets.Count} Beatmaps", () =>
{ {
carousel.Filter(new FilterCriteria());
carousel.BeatmapSetsChanged = () => changed = true; carousel.BeatmapSetsChanged = () => changed = true;
carousel.BeatmapSets = beatmapSets; carousel.BeatmapSets = beatmapSets;
}); });
AddUntilStep("Wait for load", () => changed); AddUntilStep("Wait for load", () => changed);
} }
@ -173,8 +162,11 @@ namespace osu.Game.Tests.Visual.SongSelect
/// <summary> /// <summary>
/// Test keyboard traversal /// Test keyboard traversal
/// </summary> /// </summary>
private void testTraversal() [Test]
public void TestTraversal()
{ {
loadBeatmaps();
advanceSelection(direction: 1, diff: false); advanceSelection(direction: 1, diff: false);
checkSelected(1, 1); checkSelected(1, 1);
@ -199,8 +191,11 @@ namespace osu.Game.Tests.Visual.SongSelect
/// <summary> /// <summary>
/// Test filtering /// Test filtering
/// </summary> /// </summary>
private void testFiltering() [Test]
public void TestFiltering()
{ {
loadBeatmaps();
// basic filtering // basic filtering
setSelected(1, 1); setSelected(1, 1);
@ -262,8 +257,11 @@ namespace osu.Game.Tests.Visual.SongSelect
/// <summary> /// <summary>
/// Test random non-repeating algorithm /// Test random non-repeating algorithm
/// </summary> /// </summary>
private void testRandom() [Test]
public void TestRandom()
{ {
loadBeatmaps();
setSelected(1, 1); setSelected(1, 1);
nextRandom(); nextRandom();
@ -299,8 +297,11 @@ namespace osu.Game.Tests.Visual.SongSelect
/// <summary> /// <summary>
/// Test adding and removing beatmap sets /// Test adding and removing beatmap sets
/// </summary> /// </summary>
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 + 1)));
AddStep("Add new set", () => carousel.UpdateBeatmapSet(createTestBeatmapSet(set_count + 2))); AddStep("Add new set", () => carousel.UpdateBeatmapSet(createTestBeatmapSet(set_count + 2)));
@ -322,16 +323,22 @@ namespace osu.Game.Tests.Visual.SongSelect
/// <summary> /// <summary>
/// Test sorting /// Test sorting
/// </summary> /// </summary>
private void testSorting() [Test]
public void TestSorting()
{ {
loadBeatmaps();
AddStep("Sort by author", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Author }, false)); AddStep("Sort by author", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Author }, false));
AddAssert("Check zzzzz is at bottom", () => carousel.BeatmapSets.Last().Metadata.AuthorString == "zzzzz"); AddAssert("Check zzzzz is at bottom", () => carousel.BeatmapSets.Last().Metadata.AuthorString == "zzzzz");
AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false)); 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}!")); 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); setSelected(2, 1);
AddAssert("Selection is non-null", () => currentSelection != null); AddAssert("Selection is non-null", () => currentSelection != null);
@ -353,8 +360,11 @@ namespace osu.Game.Tests.Visual.SongSelect
checkNoSelection(); checkNoSelection();
} }
private void testEmptyTraversal() [Test]
public void TestEmptyTraversal()
{ {
loadBeatmaps(new List<BeatmapSetInfo>());
advanceSelection(direction: 1, diff: false); advanceSelection(direction: 1, diff: false);
checkNoSelection(); checkNoSelection();
@ -368,11 +378,14 @@ namespace osu.Game.Tests.Visual.SongSelect
checkNoSelection(); checkNoSelection();
} }
private void testHiding() [Test]
public void TestHiding()
{ {
var hidingSet = createTestBeatmapSet(1); BeatmapSetInfo hidingSet = createTestBeatmapSet(1);
hidingSet.Beatmaps[1].Hidden = true; hidingSet.Beatmaps[1].Hidden = true;
AddStep("Add set with diff 2 hidden", () => carousel.UpdateBeatmapSet(hidingSet));
loadBeatmaps(new List<BeatmapSetInfo> { hidingSet });
setSelected(1, 1); setSelected(1, 1);
checkVisibleItemCount(true, 2); 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); var testMixed = createTestBeatmapSet(set_count + 1);
AddStep("add mixed ruleset beatmapset", () => AddStep("add mixed ruleset beatmapset", () =>
@ -437,14 +451,16 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("remove single ruleset set", () => carousel.RemoveBeatmapSet(testSingle)); AddStep("remove single ruleset set", () => carousel.RemoveBeatmapSet(testSingle));
} }
private void testCarouselRootIsRandom() [Test]
public void TestCarouselRootIsRandom()
{ {
List<BeatmapSetInfo> beatmapSets = new List<BeatmapSetInfo>(); List<BeatmapSetInfo> manySets = new List<BeatmapSetInfo>();
for (int i = 1; i <= 50; i++) for (int i = 1; i <= 50; i++)
beatmapSets.Add(createTestBeatmapSet(i)); manySets.Add(createTestBeatmapSet(i));
loadBeatmaps(manySets);
loadBeatmaps(beatmapSets);
advanceSelection(direction: 1, diff: false); advanceSelection(direction: 1, diff: false);
checkNonmatchingFilter(); checkNonmatchingFilter();
checkNonmatchingFilter(); checkNonmatchingFilter();

View File

@ -82,6 +82,9 @@ namespace osu.Game.Screens.Select
var _ = newRoot.Drawables; var _ = newRoot.Drawables;
root = newRoot; root = newRoot;
if (selectedBeatmapSet != null && !beatmapSets.Contains(selectedBeatmapSet.BeatmapSet))
selectedBeatmapSet = null;
scrollableContent.Clear(false); scrollableContent.Clear(false);
itemsCache.Invalidate(); itemsCache.Invalidate();
scrollPositionCache.Invalidate(); scrollPositionCache.Invalidate();

View File

@ -6,31 +6,25 @@ using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
using osu.Framework; using osu.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.IO.Network; using osu.Framework.IO.Network;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Game;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Notifications;
namespace osu.Desktop.Updater namespace osu.Game.Updater
{ {
/// <summary> /// <summary>
/// An update manager that shows notifications if a newer release is detected. /// An update manager that shows notifications if a newer release is detected.
/// Installation is left up to the user. /// Installation is left up to the user.
/// </summary> /// </summary>
internal class SimpleUpdateManager : CompositeDrawable public class SimpleUpdateManager : UpdateManager
{ {
private NotificationOverlay notificationOverlay;
private string version; private string version;
private GameHost host; private GameHost host;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(NotificationOverlay notification, OsuGameBase game, GameHost host) private void load(OsuGameBase game, GameHost host)
{ {
notificationOverlay = notification;
this.host = host; this.host = host;
version = game.Version; version = game.Version;
@ -50,7 +44,7 @@ namespace osu.Desktop.Updater
if (latest.TagName != version) 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" 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", + "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: case RuntimeInfo.Platform.MacOsx:
bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".app.zip")); bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".app.zip"));
break; 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; return bestAsset?.BrowserDownloadUrl ?? release.HtmlUrl;

View File

@ -0,0 +1,67 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics.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<string>(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;
};
}
}
}
}