mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 19:42:55 +08:00
Merge branch 'master' into fix-pause-in-osu-again
This commit is contained in:
commit
419d5a76ce
@ -21,7 +21,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"ppy.localisationanalyser.tools": {
|
"ppy.localisationanalyser.tools": {
|
||||||
"version": "2024.517.0",
|
"version": "2024.802.0",
|
||||||
"commands": [
|
"commands": [
|
||||||
"localisation"
|
"localisation"
|
||||||
]
|
]
|
||||||
|
@ -16,7 +16,6 @@ using osu.Framework.Graphics.Shaders.Types;
|
|||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Layout;
|
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -63,8 +62,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
// -1 signals that the part is unusable, and should not be drawn
|
// -1 signals that the part is unusable, and should not be drawn
|
||||||
parts[i].InvalidationID = -1;
|
parts[i].InvalidationID = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddLayout(partSizeCache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -95,12 +92,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly LayoutValue<Vector2> partSizeCache = new LayoutValue<Vector2>(Invalidation.DrawInfo | Invalidation.RequiredParentSizeToFit | Invalidation.Presence);
|
|
||||||
|
|
||||||
private Vector2 partSize => partSizeCache.IsValid
|
|
||||||
? partSizeCache.Value
|
|
||||||
: (partSizeCache.Value = new Vector2(Texture.DisplayWidth, Texture.DisplayHeight) * DrawInfo.Matrix.ExtractScale().Xy);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of time to fade the cursor trail pieces.
|
/// The amount of time to fade the cursor trail pieces.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -156,6 +147,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
|
|
||||||
protected void AddTrail(Vector2 position)
|
protected void AddTrail(Vector2 position)
|
||||||
{
|
{
|
||||||
|
position = ToLocalSpace(position);
|
||||||
|
|
||||||
if (InterpolateMovements)
|
if (InterpolateMovements)
|
||||||
{
|
{
|
||||||
if (!lastPosition.HasValue)
|
if (!lastPosition.HasValue)
|
||||||
@ -174,7 +167,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
float distance = diff.Length;
|
float distance = diff.Length;
|
||||||
Vector2 direction = diff / distance;
|
Vector2 direction = diff / distance;
|
||||||
|
|
||||||
float interval = partSize.X / 2.5f * IntervalMultiplier;
|
float interval = Texture.DisplayWidth / 2.5f * IntervalMultiplier;
|
||||||
float stopAt = distance - (AvoidDrawingNearCursor ? interval : 0);
|
float stopAt = distance - (AvoidDrawingNearCursor ? interval : 0);
|
||||||
|
|
||||||
for (float d = interval; d < stopAt; d += interval)
|
for (float d = interval; d < stopAt; d += interval)
|
||||||
@ -191,9 +184,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPart(Vector2 screenSpacePosition)
|
private void addPart(Vector2 localSpacePosition)
|
||||||
{
|
{
|
||||||
parts[currentIndex].Position = ToLocalSpace(screenSpacePosition);
|
parts[currentIndex].Position = localSpacePosition;
|
||||||
parts[currentIndex].Time = time + 1;
|
parts[currentIndex].Time = time + 1;
|
||||||
++parts[currentIndex].InvalidationID;
|
++parts[currentIndex].InvalidationID;
|
||||||
|
|
||||||
|
@ -259,6 +259,44 @@ namespace osu.Game.Tests.Database
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNoChangesAfterDelete()
|
||||||
|
{
|
||||||
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
|
{
|
||||||
|
var importer = new BeatmapImporter(storage, realm);
|
||||||
|
using var rulesets = new RealmRulesetStore(realm, storage);
|
||||||
|
|
||||||
|
using var __ = getBeatmapArchive(out string pathOriginal);
|
||||||
|
using var _ = getBeatmapArchive(out string pathOriginalSecond);
|
||||||
|
|
||||||
|
var importBeforeUpdate = await importer.Import(new ImportTask(pathOriginal));
|
||||||
|
|
||||||
|
importBeforeUpdate!.PerformWrite(s => s.DeletePending = true);
|
||||||
|
|
||||||
|
var dateBefore = importBeforeUpdate.Value.DateAdded;
|
||||||
|
|
||||||
|
Assert.That(importBeforeUpdate, Is.Not.Null);
|
||||||
|
Debug.Assert(importBeforeUpdate != null);
|
||||||
|
|
||||||
|
var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathOriginalSecond), importBeforeUpdate.Value);
|
||||||
|
|
||||||
|
realm.Run(r => r.Refresh());
|
||||||
|
|
||||||
|
Assert.That(importAfterUpdate, Is.Not.Null);
|
||||||
|
Debug.Assert(importAfterUpdate != null);
|
||||||
|
|
||||||
|
checkCount<BeatmapSetInfo>(realm, 1);
|
||||||
|
checkCount<BeatmapInfo>(realm, count_beatmaps);
|
||||||
|
checkCount<BeatmapMetadata>(realm, count_beatmaps);
|
||||||
|
|
||||||
|
Assert.That(importBeforeUpdate.Value.Beatmaps.First().OnlineID, Is.GreaterThan(-1));
|
||||||
|
Assert.That(importBeforeUpdate.Value.DateAdded, Is.EqualTo(dateBefore));
|
||||||
|
Assert.That(importAfterUpdate.Value.DateAdded, Is.EqualTo(dateBefore));
|
||||||
|
Assert.That(importBeforeUpdate.ID, Is.EqualTo(importAfterUpdate.ID));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNoChanges()
|
public void TestNoChanges()
|
||||||
{
|
{
|
||||||
@ -272,21 +310,25 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
var importBeforeUpdate = await importer.Import(new ImportTask(pathOriginal));
|
var importBeforeUpdate = await importer.Import(new ImportTask(pathOriginal));
|
||||||
|
|
||||||
|
var dateBefore = importBeforeUpdate!.Value.DateAdded;
|
||||||
|
|
||||||
Assert.That(importBeforeUpdate, Is.Not.Null);
|
Assert.That(importBeforeUpdate, Is.Not.Null);
|
||||||
Debug.Assert(importBeforeUpdate != null);
|
Debug.Assert(importBeforeUpdate != null);
|
||||||
|
|
||||||
var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathOriginalSecond), importBeforeUpdate.Value);
|
var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathOriginalSecond), importBeforeUpdate.Value);
|
||||||
|
|
||||||
|
realm.Run(r => r.Refresh());
|
||||||
|
|
||||||
Assert.That(importAfterUpdate, Is.Not.Null);
|
Assert.That(importAfterUpdate, Is.Not.Null);
|
||||||
Debug.Assert(importAfterUpdate != null);
|
Debug.Assert(importAfterUpdate != null);
|
||||||
|
|
||||||
realm.Run(r => r.Refresh());
|
|
||||||
|
|
||||||
checkCount<BeatmapSetInfo>(realm, 1);
|
checkCount<BeatmapSetInfo>(realm, 1);
|
||||||
checkCount<BeatmapInfo>(realm, count_beatmaps);
|
checkCount<BeatmapInfo>(realm, count_beatmaps);
|
||||||
checkCount<BeatmapMetadata>(realm, count_beatmaps);
|
checkCount<BeatmapMetadata>(realm, count_beatmaps);
|
||||||
|
|
||||||
Assert.That(importBeforeUpdate.Value.Beatmaps.First().OnlineID, Is.GreaterThan(-1));
|
Assert.That(importBeforeUpdate.Value.Beatmaps.First().OnlineID, Is.GreaterThan(-1));
|
||||||
|
Assert.That(importBeforeUpdate.Value.DateAdded, Is.EqualTo(dateBefore));
|
||||||
|
Assert.That(importAfterUpdate.Value.DateAdded, Is.EqualTo(dateBefore));
|
||||||
Assert.That(importBeforeUpdate.ID, Is.EqualTo(importAfterUpdate.ID));
|
Assert.That(importBeforeUpdate.ID, Is.EqualTo(importAfterUpdate.ID));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -4,16 +4,34 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.Metadata;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
|
using osu.Game.Tests.Visual.Metadata;
|
||||||
using osu.Game.Tests.Visual.OnlinePlay;
|
using osu.Game.Tests.Visual.OnlinePlay;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.DailyChallenge
|
namespace osu.Game.Tests.Visual.DailyChallenge
|
||||||
{
|
{
|
||||||
public partial class TestSceneDailyChallenge : OnlinePlayTestScene
|
public partial class TestSceneDailyChallenge : OnlinePlayTestScene
|
||||||
{
|
{
|
||||||
|
[Cached(typeof(MetadataClient))]
|
||||||
|
private TestMetadataClient metadataClient = new TestMetadataClient();
|
||||||
|
|
||||||
|
[Cached(typeof(INotificationOverlay))]
|
||||||
|
private NotificationOverlay notificationOverlay = new NotificationOverlay();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
base.Content.Add(notificationOverlay);
|
||||||
|
base.Content.Add(metadataClient);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestDailyChallenge()
|
public void TestDailyChallenge()
|
||||||
{
|
{
|
||||||
@ -36,5 +54,33 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
|||||||
AddStep("add room", () => API.Perform(new CreateRoomRequest(room)));
|
AddStep("add room", () => API.Perform(new CreateRoomRequest(room)));
|
||||||
AddStep("push screen", () => LoadScreen(new Screens.OnlinePlay.DailyChallenge.DailyChallenge(room)));
|
AddStep("push screen", () => LoadScreen(new Screens.OnlinePlay.DailyChallenge.DailyChallenge(room)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNotifications()
|
||||||
|
{
|
||||||
|
var room = new Room
|
||||||
|
{
|
||||||
|
RoomID = { Value = 1234 },
|
||||||
|
Name = { Value = "Daily Challenge: June 4, 2024" },
|
||||||
|
Playlist =
|
||||||
|
{
|
||||||
|
new PlaylistItem(TestResources.CreateTestBeatmapSetInfo().Beatmaps.First())
|
||||||
|
{
|
||||||
|
RequiredMods = [new APIMod(new OsuModTraceable())],
|
||||||
|
AllowedMods = [new APIMod(new OsuModDoubleTime())]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
EndDate = { Value = DateTimeOffset.Now.AddHours(12) },
|
||||||
|
Category = { Value = RoomCategory.DailyChallenge }
|
||||||
|
};
|
||||||
|
|
||||||
|
AddStep("add room", () => API.Perform(new CreateRoomRequest(room)));
|
||||||
|
AddStep("set daily challenge info", () => metadataClient.DailyChallengeInfo.Value = new DailyChallengeInfo { RoomID = 1234 });
|
||||||
|
|
||||||
|
Screens.OnlinePlay.DailyChallenge.DailyChallenge screen = null!;
|
||||||
|
AddStep("push screen", () => LoadScreen(screen = new Screens.OnlinePlay.DailyChallenge.DailyChallenge(room)));
|
||||||
|
AddUntilStep("wait for screen", () => screen.IsCurrentScreen());
|
||||||
|
AddStep("daily challenge ended", () => metadataClient.DailyChallengeInfo.Value = null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.Profile;
|
||||||
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Online
|
||||||
|
{
|
||||||
|
public partial class TestSceneUserProfileDailyChallenge : OsuManualInputManagerTestScene
|
||||||
|
{
|
||||||
|
[Cached]
|
||||||
|
public readonly Bindable<UserProfileData?> User = new Bindable<UserProfileData?>(new UserProfileData(new APIUser(), new OsuRuleset().RulesetInfo));
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink);
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
DailyChallengeStatsDisplay display = null!;
|
||||||
|
|
||||||
|
AddSliderStep("daily", 0, 999, 2, v => update(s => s.DailyStreakCurrent = v));
|
||||||
|
AddSliderStep("daily best", 0, 999, 2, v => update(s => s.DailyStreakBest = v));
|
||||||
|
AddSliderStep("weekly", 0, 250, 1, v => update(s => s.WeeklyStreakCurrent = v));
|
||||||
|
AddSliderStep("weekly best", 0, 250, 1, v => update(s => s.WeeklyStreakBest = v));
|
||||||
|
AddSliderStep("top 10%", 0, 999, 0, v => update(s => s.Top10PercentPlacements = v));
|
||||||
|
AddSliderStep("top 50%", 0, 999, 0, v => update(s => s.Top50PercentPlacements = v));
|
||||||
|
AddSliderStep("playcount", 0, 999, 0, v => update(s => s.PlayCount = v));
|
||||||
|
AddStep("create", () =>
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
Add(new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colourProvider.Background2,
|
||||||
|
});
|
||||||
|
Add(display = new DailyChallengeStatsDisplay
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Scale = new Vector2(1f),
|
||||||
|
User = { BindTarget = User },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
AddStep("hover", () => InputManager.MoveMouseTo(display));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update(Action<APIUserDailyChallengeStatistics> change)
|
||||||
|
{
|
||||||
|
change.Invoke(User.Value!.User.DailyChallengeStatistics);
|
||||||
|
User.Value = new UserProfileData(User.Value.User, User.Value.Ruleset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
@ -24,7 +25,17 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUp()
|
public void SetUp()
|
||||||
{
|
{
|
||||||
AddStep("create profile overlay", () => Child = profile = new UserProfileOverlay());
|
AddStep("create profile overlay", () =>
|
||||||
|
{
|
||||||
|
profile = new UserProfileOverlay();
|
||||||
|
|
||||||
|
Child = new DependencyProvidingContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
CachedDependencies = new (Type, object)[] { (typeof(UserProfileOverlay), profile) },
|
||||||
|
Child = profile,
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -131,6 +142,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
CountryCode = CountryCode.JP,
|
CountryCode = CountryCode.JP,
|
||||||
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg",
|
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg",
|
||||||
ProfileHue = hue,
|
ProfileHue = hue,
|
||||||
|
PlayMode = "osu",
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -174,6 +186,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
CountryCode = CountryCode.JP,
|
CountryCode = CountryCode.JP,
|
||||||
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg",
|
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg",
|
||||||
ProfileHue = hue,
|
ProfileHue = hue,
|
||||||
|
PlayMode = "osu",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
int hue2 = 0;
|
int hue2 = 0;
|
||||||
@ -189,6 +202,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
CountryCode = CountryCode.JP,
|
CountryCode = CountryCode.JP,
|
||||||
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg",
|
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg",
|
||||||
ProfileHue = hue2,
|
ProfileHue = hue2,
|
||||||
|
PlayMode = "osu",
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,6 +296,15 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
ImageUrlLowRes = "https://assets.ppy.sh/profile-badges/contributor.png",
|
ImageUrlLowRes = "https://assets.ppy.sh/profile-badges/contributor.png",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DailyChallengeStatistics = new APIUserDailyChallengeStatistics
|
||||||
|
{
|
||||||
|
DailyStreakCurrent = 231,
|
||||||
|
WeeklyStreakCurrent = 18,
|
||||||
|
DailyStreakBest = 370,
|
||||||
|
WeeklyStreakBest = 51,
|
||||||
|
Top10PercentPlacements = 345,
|
||||||
|
Top50PercentPlacements = 427,
|
||||||
|
},
|
||||||
Title = "osu!volunteer",
|
Title = "osu!volunteer",
|
||||||
Colour = "ff0000",
|
Colour = "ff0000",
|
||||||
Achievements = Array.Empty<APIUserAchievement>(),
|
Achievements = Array.Empty<APIUserAchievement>(),
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -10,6 +11,7 @@ using osu.Game.Localisation;
|
|||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.Metadata;
|
using osu.Game.Online.Metadata;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
using Color4 = osuTK.Graphics.Color4;
|
using Color4 = osuTK.Graphics.Color4;
|
||||||
@ -39,8 +41,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestDailyChallengeButton()
|
public void TestDailyChallengeButton()
|
||||||
{
|
{
|
||||||
AddStep("beatmap of the day not active", () => metadataClient.DailyChallengeUpdated(null));
|
|
||||||
|
|
||||||
AddStep("set up API", () => dummyAPI.HandleRequest = req =>
|
AddStep("set up API", () => dummyAPI.HandleRequest = req =>
|
||||||
{
|
{
|
||||||
switch (req)
|
switch (req)
|
||||||
@ -67,17 +67,45 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("add button", () => Child = new DailyChallengeButton(@"button-default-select", new Color4(102, 68, 204, 255), _ => { }, 0, Key.D)
|
NotificationOverlay notificationOverlay = null!;
|
||||||
{
|
DependencyProvidingContainer buttonContainer = null!;
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
ButtonSystemState = ButtonSystemState.TopLevel,
|
|
||||||
});
|
|
||||||
|
|
||||||
AddStep("beatmap of the day active", () => metadataClient.DailyChallengeUpdated(new DailyChallengeInfo
|
AddStep("beatmap of the day active", () => metadataClient.DailyChallengeUpdated(new DailyChallengeInfo
|
||||||
{
|
{
|
||||||
RoomID = 1234,
|
RoomID = 1234,
|
||||||
}));
|
}));
|
||||||
|
AddStep("add content", () =>
|
||||||
|
{
|
||||||
|
notificationOverlay = new NotificationOverlay();
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
notificationOverlay,
|
||||||
|
buttonContainer = new DependencyProvidingContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
CachedDependencies = [(typeof(INotificationOverlay), notificationOverlay)],
|
||||||
|
Child = new DailyChallengeButton(@"button-default-select", new Color4(102, 68, 204, 255), _ => { }, 0, Key.D)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
ButtonSystemState = ButtonSystemState.TopLevel,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
AddAssert("no notification posted", () => notificationOverlay.AllNotifications.Count(), () => Is.Zero);
|
||||||
|
|
||||||
|
AddStep("beatmap of the day not active", () => metadataClient.DailyChallengeUpdated(null));
|
||||||
|
AddAssert("no notification posted", () => notificationOverlay.AllNotifications.Count(), () => Is.Zero);
|
||||||
|
|
||||||
|
AddStep("hide button's parent", () => buttonContainer.Hide());
|
||||||
|
AddStep("beatmap of the day active", () => metadataClient.DailyChallengeUpdated(new DailyChallengeInfo
|
||||||
|
{
|
||||||
|
RoomID = 1234,
|
||||||
|
}));
|
||||||
|
AddAssert("notification posted", () => notificationOverlay.AllNotifications.Count(), () => Is.EqualTo(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,8 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public override async Task<Live<BeatmapSetInfo>?> ImportAsUpdate(ProgressNotification notification, ImportTask importTask, BeatmapSetInfo original)
|
public override async Task<Live<BeatmapSetInfo>?> ImportAsUpdate(ProgressNotification notification, ImportTask importTask, BeatmapSetInfo original)
|
||||||
{
|
{
|
||||||
|
var originalDateAdded = original.DateAdded;
|
||||||
|
|
||||||
Guid originalId = original.ID;
|
Guid originalId = original.ID;
|
||||||
|
|
||||||
var imported = await Import(notification, new[] { importTask }).ConfigureAwait(false);
|
var imported = await Import(notification, new[] { importTask }).ConfigureAwait(false);
|
||||||
@ -57,8 +59,11 @@ namespace osu.Game.Beatmaps
|
|||||||
// If there were no changes, ensure we don't accidentally nuke ourselves.
|
// If there were no changes, ensure we don't accidentally nuke ourselves.
|
||||||
if (first.ID == originalId)
|
if (first.ID == originalId)
|
||||||
{
|
{
|
||||||
first.PerformRead(s =>
|
first.PerformWrite(s =>
|
||||||
{
|
{
|
||||||
|
// Transfer local values which should be persisted across a beatmap update.
|
||||||
|
s.DateAdded = originalDateAdded;
|
||||||
|
|
||||||
// Re-run processing even in this case. We might have outdated metadata.
|
// Re-run processing even in this case. We might have outdated metadata.
|
||||||
ProcessBeatmap?.Invoke(s, MetadataLookupScope.OnlineFirst);
|
ProcessBeatmap?.Invoke(s, MetadataLookupScope.OnlineFirst);
|
||||||
});
|
});
|
||||||
@ -79,7 +84,7 @@ namespace osu.Game.Beatmaps
|
|||||||
original.DeletePending = true;
|
original.DeletePending = true;
|
||||||
|
|
||||||
// Transfer local values which should be persisted across a beatmap update.
|
// Transfer local values which should be persisted across a beatmap update.
|
||||||
updated.DateAdded = original.DateAdded;
|
updated.DateAdded = originalDateAdded;
|
||||||
|
|
||||||
transferCollectionReferences(realm, original, updated);
|
transferCollectionReferences(realm, original, updated);
|
||||||
|
|
||||||
@ -278,6 +283,9 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
protected override void UndeleteForReuse(BeatmapSetInfo existing)
|
protected override void UndeleteForReuse(BeatmapSetInfo existing)
|
||||||
{
|
{
|
||||||
|
if (!existing.DeletePending)
|
||||||
|
return;
|
||||||
|
|
||||||
base.UndeleteForReuse(existing);
|
base.UndeleteForReuse(existing);
|
||||||
existing.DateAdded = DateTimeOffset.UtcNow;
|
existing.DateAdded = DateTimeOffset.UtcNow;
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,9 @@ namespace osu.Game.Collections
|
|||||||
//
|
//
|
||||||
// if we want to support user sorting (but changes will need to be made to realm to persist).
|
// if we want to support user sorting (but changes will need to be made to realm to persist).
|
||||||
ShowDragHandle.Value = false;
|
ShowDragHandle.Value = false;
|
||||||
|
|
||||||
|
Masking = true;
|
||||||
|
CornerRadius = item_height / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Drawable CreateContent() => new ItemContent(Model);
|
protected override Drawable CreateContent() => new ItemContent(Model);
|
||||||
@ -50,7 +53,7 @@ namespace osu.Game.Collections
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The main content of the <see cref="DrawableCollectionListItem"/>.
|
/// The main content of the <see cref="DrawableCollectionListItem"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private partial class ItemContent : CircularContainer
|
private partial class ItemContent : CompositeDrawable
|
||||||
{
|
{
|
||||||
private readonly Live<BeatmapCollection> collection;
|
private readonly Live<BeatmapCollection> collection;
|
||||||
|
|
||||||
@ -65,13 +68,12 @@ namespace osu.Game.Collections
|
|||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Height = item_height;
|
Height = item_height;
|
||||||
Masking = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Children = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
collection.IsManaged
|
collection.IsManaged
|
||||||
? new DeleteButton(collection)
|
? new DeleteButton(collection)
|
||||||
@ -132,7 +134,7 @@ namespace osu.Game.Collections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class DeleteButton : CompositeDrawable
|
public partial class DeleteButton : OsuClickableContainer
|
||||||
{
|
{
|
||||||
public Func<Vector2, bool> IsTextBoxHovered = null!;
|
public Func<Vector2, bool> IsTextBoxHovered = null!;
|
||||||
|
|
||||||
@ -155,7 +157,7 @@ namespace osu.Game.Collections
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
InternalChild = fadeContainer = new Container
|
Child = fadeContainer = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Alpha = 0.1f,
|
Alpha = 0.1f,
|
||||||
@ -176,6 +178,14 @@ namespace osu.Game.Collections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
if (collection.PerformRead(c => c.BeatmapMD5Hashes.Count) == 0)
|
||||||
|
deleteCollection();
|
||||||
|
else
|
||||||
|
dialogOverlay?.Push(new DeleteCollectionDialog(collection, deleteCollection));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) && !IsTextBoxHovered(screenSpacePos);
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) && !IsTextBoxHovered(screenSpacePos);
|
||||||
@ -195,12 +205,7 @@ namespace osu.Game.Collections
|
|||||||
{
|
{
|
||||||
background.FlashColour(Color4.White, 150);
|
background.FlashColour(Color4.White, 150);
|
||||||
|
|
||||||
if (collection.PerformRead(c => c.BeatmapMD5Hashes.Count) == 0)
|
return base.OnClick(e);
|
||||||
deleteCollection();
|
|
||||||
else
|
|
||||||
dialogOverlay?.Push(new DeleteCollectionDialog(collection, deleteCollection));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteCollection() => collection.PerformWrite(c => c.Realm!.Remove(c));
|
private void deleteCollection() => collection.PerformWrite(c => c.Realm!.Remove(c));
|
||||||
|
@ -64,6 +64,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
{
|
{
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
|
new HoverClickSounds(),
|
||||||
new GridContainer
|
new GridContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
@ -92,7 +93,6 @@ namespace osu.Game.Graphics.Containers
|
|||||||
ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
|
ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
|
||||||
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }
|
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }
|
||||||
},
|
},
|
||||||
new HoverClickSounds()
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
29
osu.Game/Localisation/DailyChallengeStrings.cs
Normal file
29
osu.Game/Localisation/DailyChallengeStrings.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// 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.Localisation;
|
||||||
|
|
||||||
|
namespace osu.Game.Localisation
|
||||||
|
{
|
||||||
|
public static class DailyChallengeStrings
|
||||||
|
{
|
||||||
|
private const string prefix = @"osu.Game.Resources.Localisation.DailyChallenge";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Today's daily challenge has concluded – thanks for playing!
|
||||||
|
///
|
||||||
|
/// Tomorrow's challenge is now being prepared and will appear soon."
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ChallengeEndedNotification => new TranslatableString(getKey(@"todays_daily_challenge_has_concluded"),
|
||||||
|
@"Today's daily challenge has concluded – thanks for playing!
|
||||||
|
|
||||||
|
Tomorrow's challenge is now being prepared and will appear soon.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Today's daily challenge is now live! Click here to play."
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ChallengeLiveNotification => new TranslatableString(getKey(@"todays_daily_challenge_is_now"), @"Today's daily challenge is now live! Click here to play.");
|
||||||
|
|
||||||
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
|
}
|
||||||
|
}
|
@ -272,6 +272,9 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
[JsonProperty("groups")]
|
[JsonProperty("groups")]
|
||||||
public APIUserGroup[] Groups;
|
public APIUserGroup[] Groups;
|
||||||
|
|
||||||
|
[JsonProperty("daily_challenge_user_stats")]
|
||||||
|
public APIUserDailyChallengeStatistics DailyChallengeStatistics = new APIUserDailyChallengeStatistics();
|
||||||
|
|
||||||
public override string ToString() => Username;
|
public override string ToString() => Username;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace osu.Game.Online.API.Requests.Responses
|
||||||
|
{
|
||||||
|
public class APIUserDailyChallengeStatistics
|
||||||
|
{
|
||||||
|
[JsonProperty("user_id")]
|
||||||
|
public int UserID;
|
||||||
|
|
||||||
|
[JsonProperty("daily_streak_best")]
|
||||||
|
public int DailyStreakBest;
|
||||||
|
|
||||||
|
[JsonProperty("daily_streak_current")]
|
||||||
|
public int DailyStreakCurrent;
|
||||||
|
|
||||||
|
[JsonProperty("weekly_streak_best")]
|
||||||
|
public int WeeklyStreakBest;
|
||||||
|
|
||||||
|
[JsonProperty("weekly_streak_current")]
|
||||||
|
public int WeeklyStreakCurrent;
|
||||||
|
|
||||||
|
[JsonProperty("top_10p_placements")]
|
||||||
|
public int Top10PercentPlacements;
|
||||||
|
|
||||||
|
[JsonProperty("top_50p_placements")]
|
||||||
|
public int Top50PercentPlacements;
|
||||||
|
|
||||||
|
[JsonProperty("playcount")]
|
||||||
|
public int PlayCount;
|
||||||
|
|
||||||
|
[JsonProperty("last_update")]
|
||||||
|
public DateTimeOffset? LastUpdate;
|
||||||
|
|
||||||
|
[JsonProperty("last_weekly_streak")]
|
||||||
|
public DateTimeOffset? LastWeeklyStreak;
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
@ -11,14 +12,16 @@ using osu.Framework.Graphics.Sprites;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osuTK;
|
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Mods
|
namespace osu.Game.Overlays.Mods
|
||||||
{
|
{
|
||||||
public partial class ModCustomisationHeader : OsuHoverContainer
|
public partial class ModCustomisationHeader : OsuHoverContainer
|
||||||
{
|
{
|
||||||
private Box background = null!;
|
private Box background = null!;
|
||||||
|
private Box backgroundFlash = null!;
|
||||||
private SpriteIcon icon = null!;
|
private SpriteIcon icon = null!;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -46,6 +49,13 @@ namespace osu.Game.Overlays.Mods
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
|
backgroundFlash = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.White.Opacity(0.4f),
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
Alpha = 0,
|
||||||
|
},
|
||||||
new OsuSpriteText
|
new OsuSpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
@ -84,6 +94,12 @@ namespace osu.Game.Overlays.Mods
|
|||||||
TooltipText = e.NewValue
|
TooltipText = e.NewValue
|
||||||
? string.Empty
|
? string.Empty
|
||||||
: ModSelectOverlayStrings.CustomisationPanelDisabledReason;
|
: ModSelectOverlayStrings.CustomisationPanelDisabledReason;
|
||||||
|
|
||||||
|
if (e.NewValue)
|
||||||
|
{
|
||||||
|
backgroundFlash.FadeInFromZero(150, Easing.OutQuad).Then()
|
||||||
|
.FadeOutFromOne(350, Easing.OutQuad);
|
||||||
|
}
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
Expanded.BindValueChanged(v =>
|
Expanded.BindValueChanged(v =>
|
||||||
|
@ -138,6 +138,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
},
|
},
|
||||||
new GridContainer
|
new GridContainer
|
||||||
{
|
{
|
||||||
|
Padding = new MarginPadding { Top = 1, Bottom = 3 },
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
RowDimensions = new[]
|
RowDimensions = new[]
|
||||||
{
|
{
|
||||||
|
@ -668,6 +668,8 @@ namespace osu.Game.Overlays.Mods
|
|||||||
[Cached]
|
[Cached]
|
||||||
internal partial class ColumnScrollContainer : OsuScrollContainer<ColumnFlowContainer>
|
internal partial class ColumnScrollContainer : OsuScrollContainer<ColumnFlowContainer>
|
||||||
{
|
{
|
||||||
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||||
|
|
||||||
public ColumnScrollContainer()
|
public ColumnScrollContainer()
|
||||||
: base(Direction.Horizontal)
|
: base(Direction.Horizontal)
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,121 @@
|
|||||||
|
// 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.Bindables;
|
||||||
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public partial class DailyChallengeStatsDisplay : CompositeDrawable, IHasCustomTooltip<DailyChallengeTooltipData>
|
||||||
|
{
|
||||||
|
public readonly Bindable<UserProfileData?> User = new Bindable<UserProfileData?>();
|
||||||
|
|
||||||
|
public DailyChallengeTooltipData? TooltipContent { get; private set; }
|
||||||
|
|
||||||
|
private OsuSpriteText dailyPlayCount = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OsuColour colours { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OverlayColourProvider colourProvider { get; set; } = null!;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
CornerRadius = 5;
|
||||||
|
Masking = true;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colourProvider.Background4,
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Padding = new MarginPadding(5f),
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuTextFlowContainer(s => s.Font = OsuFont.GetFont(size: 12))
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
// can't use this because osu-web does weird stuff with \\n.
|
||||||
|
// Text = UsersStrings.ShowDailyChallengeTitle.,
|
||||||
|
Text = "Daily\nChallenge",
|
||||||
|
Margin = new MarginPadding { Horizontal = 5f, Bottom = 2f },
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
CornerRadius = 5f,
|
||||||
|
Masking = true,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colourProvider.Background6,
|
||||||
|
},
|
||||||
|
dailyPlayCount = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
UseFullGlyphHeight = false,
|
||||||
|
Colour = colourProvider.Content2,
|
||||||
|
Margin = new MarginPadding { Horizontal = 10f, Vertical = 5f },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
User.BindValueChanged(_ => updateDisplay(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDisplay()
|
||||||
|
{
|
||||||
|
if (User.Value == null || User.Value.Ruleset.OnlineID != 0)
|
||||||
|
{
|
||||||
|
Hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
APIUserDailyChallengeStatistics stats = User.Value.User.DailyChallengeStatistics;
|
||||||
|
|
||||||
|
dailyPlayCount.Text = UsersStrings.ShowDailyChallengeUnitDay(stats.PlayCount.ToLocalisableString("N0"));
|
||||||
|
dailyPlayCount.Colour = colours.ForRankingTier(tierForPlayCount(stats.PlayCount));
|
||||||
|
|
||||||
|
TooltipContent = new DailyChallengeTooltipData(colourProvider, stats);
|
||||||
|
|
||||||
|
Show();
|
||||||
|
|
||||||
|
static RankingTier tierForPlayCount(int playCount) => DailyChallengeStatsTooltip.TierForDaily(playCount / 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITooltip<DailyChallengeTooltipData> GetCustomTooltip() => new DailyChallengeStatsTooltip();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,241 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osuTK;
|
||||||
|
using Box = osu.Framework.Graphics.Shapes.Box;
|
||||||
|
using Color4 = osuTK.Graphics.Color4;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public partial class DailyChallengeStatsTooltip : VisibilityContainer, ITooltip<DailyChallengeTooltipData>
|
||||||
|
{
|
||||||
|
private StreakPiece currentDaily = null!;
|
||||||
|
private StreakPiece currentWeekly = null!;
|
||||||
|
private StatisticsPiece bestDaily = null!;
|
||||||
|
private StatisticsPiece bestWeekly = null!;
|
||||||
|
private StatisticsPiece topTen = null!;
|
||||||
|
private StatisticsPiece topFifty = null!;
|
||||||
|
|
||||||
|
private Box topBackground = null!;
|
||||||
|
private Box background = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OsuColour colours { get; set; } = null!;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
CornerRadius = 20f;
|
||||||
|
Masking = true;
|
||||||
|
|
||||||
|
EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Shadow,
|
||||||
|
Colour = Color4.Black.Opacity(0.25f),
|
||||||
|
Radius = 30f,
|
||||||
|
};
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
background = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
topBackground = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Padding = new MarginPadding(15f),
|
||||||
|
Spacing = new Vector2(30f),
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
currentDaily = new StreakPiece(UsersStrings.ShowDailyChallengeDailyStreakCurrent),
|
||||||
|
currentWeekly = new StreakPiece(UsersStrings.ShowDailyChallengeWeeklyStreakCurrent),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Padding = new MarginPadding(15f),
|
||||||
|
Spacing = new Vector2(10f),
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
bestDaily = new StatisticsPiece(UsersStrings.ShowDailyChallengeDailyStreakBest),
|
||||||
|
bestWeekly = new StatisticsPiece(UsersStrings.ShowDailyChallengeWeeklyStreakBest),
|
||||||
|
topTen = new StatisticsPiece(UsersStrings.ShowDailyChallengeTop10pPlacements),
|
||||||
|
topFifty = new StatisticsPiece(UsersStrings.ShowDailyChallengeTop50pPlacements),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetContent(DailyChallengeTooltipData content)
|
||||||
|
{
|
||||||
|
var statistics = content.Statistics;
|
||||||
|
var colourProvider = content.ColourProvider;
|
||||||
|
|
||||||
|
background.Colour = colourProvider.Background4;
|
||||||
|
topBackground.Colour = colourProvider.Background5;
|
||||||
|
|
||||||
|
currentDaily.Value = UsersStrings.ShowDailyChallengeUnitDay(content.Statistics.DailyStreakCurrent.ToLocalisableString(@"N0"));
|
||||||
|
currentDaily.ValueColour = colours.ForRankingTier(TierForDaily(statistics.DailyStreakCurrent));
|
||||||
|
|
||||||
|
currentWeekly.Value = UsersStrings.ShowDailyChallengeUnitWeek(statistics.WeeklyStreakCurrent.ToLocalisableString(@"N0"));
|
||||||
|
currentWeekly.ValueColour = colours.ForRankingTier(TierForWeekly(statistics.WeeklyStreakCurrent));
|
||||||
|
|
||||||
|
bestDaily.Value = UsersStrings.ShowDailyChallengeUnitDay(statistics.DailyStreakBest.ToLocalisableString(@"N0"));
|
||||||
|
bestDaily.ValueColour = colours.ForRankingTier(TierForDaily(statistics.DailyStreakBest));
|
||||||
|
|
||||||
|
bestWeekly.Value = UsersStrings.ShowDailyChallengeUnitWeek(statistics.WeeklyStreakBest.ToLocalisableString(@"N0"));
|
||||||
|
bestWeekly.ValueColour = colours.ForRankingTier(TierForWeekly(statistics.WeeklyStreakBest));
|
||||||
|
|
||||||
|
topTen.Value = statistics.Top10PercentPlacements.ToLocalisableString(@"N0");
|
||||||
|
topTen.ValueColour = colourProvider.Content2;
|
||||||
|
|
||||||
|
topFifty.Value = statistics.Top50PercentPlacements.ToLocalisableString(@"N0");
|
||||||
|
topFifty.ValueColour = colourProvider.Content2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reference: https://github.com/ppy/osu-web/blob/8206e0e91eeea80ccf92f0586561346dd40e085e/resources/js/profile-page/daily-challenge.tsx#L13-L43
|
||||||
|
public static RankingTier TierForDaily(int daily)
|
||||||
|
{
|
||||||
|
if (daily > 360)
|
||||||
|
return RankingTier.Lustrous;
|
||||||
|
|
||||||
|
if (daily > 240)
|
||||||
|
return RankingTier.Radiant;
|
||||||
|
|
||||||
|
if (daily > 120)
|
||||||
|
return RankingTier.Rhodium;
|
||||||
|
|
||||||
|
if (daily > 60)
|
||||||
|
return RankingTier.Platinum;
|
||||||
|
|
||||||
|
if (daily > 30)
|
||||||
|
return RankingTier.Gold;
|
||||||
|
|
||||||
|
if (daily > 10)
|
||||||
|
return RankingTier.Silver;
|
||||||
|
|
||||||
|
if (daily > 5)
|
||||||
|
return RankingTier.Bronze;
|
||||||
|
|
||||||
|
return RankingTier.Iron;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RankingTier TierForWeekly(int weekly) => TierForDaily((weekly - 1) * 7);
|
||||||
|
|
||||||
|
protected override void PopIn() => this.FadeIn(200, Easing.OutQuint);
|
||||||
|
|
||||||
|
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
|
||||||
|
|
||||||
|
public void Move(Vector2 pos) => Position = pos;
|
||||||
|
|
||||||
|
private partial class StreakPiece : FillFlowContainer
|
||||||
|
{
|
||||||
|
private readonly OsuSpriteText valueText;
|
||||||
|
|
||||||
|
public LocalisableString Value
|
||||||
|
{
|
||||||
|
set => valueText.Text = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColourInfo ValueColour
|
||||||
|
{
|
||||||
|
set => valueText.Colour = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreakPiece(LocalisableString title)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
Direction = FillDirection.Vertical;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12),
|
||||||
|
Text = title,
|
||||||
|
},
|
||||||
|
valueText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 40, weight: FontWeight.Light),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private partial class StatisticsPiece : CompositeDrawable
|
||||||
|
{
|
||||||
|
private readonly OsuSpriteText valueText;
|
||||||
|
|
||||||
|
public LocalisableString Value
|
||||||
|
{
|
||||||
|
set => valueText.Text = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColourInfo ValueColour
|
||||||
|
{
|
||||||
|
set => valueText.Colour = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatisticsPiece(LocalisableString title)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12),
|
||||||
|
Text = title,
|
||||||
|
},
|
||||||
|
valueText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
Font = OsuFont.GetFont(size: 12),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record DailyChallengeTooltipData(OverlayColourProvider ColourProvider, APIUserDailyChallengeStatistics Statistics);
|
||||||
|
}
|
@ -44,22 +44,41 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
|||||||
Spacing = new Vector2(0, 15),
|
Spacing = new Vector2(0, 15),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
new GridContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Direction = FillDirection.Horizontal,
|
ColumnDimensions = new[]
|
||||||
Spacing = new Vector2(20),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
{
|
||||||
detailGlobalRank = new ProfileValueDisplay(true)
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
|
new Dimension(GridSizeMode.Absolute, 20),
|
||||||
|
new Dimension(),
|
||||||
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
|
},
|
||||||
|
RowDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
|
},
|
||||||
|
Content = new[]
|
||||||
|
{
|
||||||
|
new[]
|
||||||
{
|
{
|
||||||
Title = UsersStrings.ShowRankGlobalSimple,
|
detailGlobalRank = new ProfileValueDisplay(true)
|
||||||
},
|
{
|
||||||
detailCountryRank = new ProfileValueDisplay(true)
|
Title = UsersStrings.ShowRankGlobalSimple,
|
||||||
{
|
},
|
||||||
Title = UsersStrings.ShowRankCountrySimple,
|
Empty(),
|
||||||
},
|
detailCountryRank = new ProfileValueDisplay(true)
|
||||||
|
{
|
||||||
|
Title = UsersStrings.ShowRankCountrySimple,
|
||||||
|
},
|
||||||
|
new DailyChallengeStatsDisplay
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
User = { BindTarget = User },
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Settings
|
namespace osu.Game.Overlays.Settings
|
||||||
@ -10,6 +14,8 @@ namespace osu.Game.Overlays.Settings
|
|||||||
public partial class SettingsEnumDropdown<T> : SettingsDropdown<T>
|
public partial class SettingsEnumDropdown<T> : SettingsDropdown<T>
|
||||||
where T : struct, Enum
|
where T : struct, Enum
|
||||||
{
|
{
|
||||||
|
public override IEnumerable<LocalisableString> FilterTerms => base.FilterTerms.Concat(Control.Items.Select(i => i.GetLocalisableDescription()));
|
||||||
|
|
||||||
protected override OsuDropdown<T> CreateDropdown() => new DropdownControl();
|
protected override OsuDropdown<T> CreateDropdown() => new DropdownControl();
|
||||||
|
|
||||||
protected new partial class DropdownControl : OsuEnumDropdown<T>
|
protected new partial class DropdownControl : OsuEnumDropdown<T>
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
@ -30,11 +28,26 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
|
|
||||||
private readonly Drawable userContent;
|
private readonly Drawable userContent;
|
||||||
|
|
||||||
[Resolved]
|
private bool alwaysShowControlPoints;
|
||||||
private EditorClock editorClock { get; set; }
|
|
||||||
|
public bool AlwaysShowControlPoints
|
||||||
|
{
|
||||||
|
get => alwaysShowControlPoints;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == alwaysShowControlPoints)
|
||||||
|
return;
|
||||||
|
|
||||||
|
alwaysShowControlPoints = value;
|
||||||
|
controlPointsVisible.TriggerChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private EditorBeatmap editorBeatmap { get; set; }
|
private EditorClock editorClock { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private EditorBeatmap editorBeatmap { get; set; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The timeline's scroll position in the last frame.
|
/// The timeline's scroll position in the last frame.
|
||||||
@ -61,6 +74,22 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private float defaultTimelineZoom;
|
private float defaultTimelineZoom;
|
||||||
|
|
||||||
|
private WaveformGraph waveform = null!;
|
||||||
|
|
||||||
|
private TimelineTickDisplay ticks = null!;
|
||||||
|
|
||||||
|
private TimelineControlPointDisplay controlPoints = null!;
|
||||||
|
|
||||||
|
private Container mainContent = null!;
|
||||||
|
|
||||||
|
private Bindable<float> waveformOpacity = null!;
|
||||||
|
private Bindable<bool> controlPointsVisible = null!;
|
||||||
|
private Bindable<bool> ticksVisible = null!;
|
||||||
|
|
||||||
|
private double trackLengthForZoom;
|
||||||
|
|
||||||
|
private readonly IBindable<Track> track = new Bindable<Track>();
|
||||||
|
|
||||||
public Timeline(Drawable userContent)
|
public Timeline(Drawable userContent)
|
||||||
{
|
{
|
||||||
this.userContent = userContent;
|
this.userContent = userContent;
|
||||||
@ -73,22 +102,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
ScrollbarVisible = false;
|
ScrollbarVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private WaveformGraph waveform;
|
|
||||||
|
|
||||||
private TimelineTickDisplay ticks;
|
|
||||||
|
|
||||||
private TimelineControlPointDisplay controlPoints;
|
|
||||||
|
|
||||||
private Container mainContent;
|
|
||||||
|
|
||||||
private Bindable<float> waveformOpacity;
|
|
||||||
private Bindable<bool> controlPointsVisible;
|
|
||||||
private Bindable<bool> ticksVisible;
|
|
||||||
|
|
||||||
private double trackLengthForZoom;
|
|
||||||
|
|
||||||
private readonly IBindable<Track> track = new Bindable<Track>();
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(IBindable<WorkingBeatmap> beatmap, OsuColour colours, OsuConfigManager config)
|
private void load(IBindable<WorkingBeatmap> beatmap, OsuColour colours, OsuConfigManager config)
|
||||||
{
|
{
|
||||||
@ -178,7 +191,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
|
|
||||||
controlPointsVisible.BindValueChanged(visible =>
|
controlPointsVisible.BindValueChanged(visible =>
|
||||||
{
|
{
|
||||||
if (visible.NewValue)
|
if (visible.NewValue || alwaysShowControlPoints)
|
||||||
{
|
{
|
||||||
this.ResizeHeightTo(timeline_expanded_height, 200, Easing.OutQuint);
|
this.ResizeHeightTo(timeline_expanded_height, 200, Easing.OutQuint);
|
||||||
mainContent.MoveToY(15, 200, Easing.OutQuint);
|
mainContent.MoveToY(15, 200, Easing.OutQuint);
|
||||||
@ -318,7 +331,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IBeatSnapProvider beatSnapProvider { get; set; }
|
private IBeatSnapProvider beatSnapProvider { get; set; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The total amount of time visible on the timeline.
|
/// The total amount of time visible on the timeline.
|
||||||
|
@ -69,19 +69,24 @@ namespace osu.Game.Screens.Edit.Compose
|
|||||||
if (ruleset == null || composer == null)
|
if (ruleset == null || composer == null)
|
||||||
return base.CreateTimelineContent();
|
return base.CreateTimelineContent();
|
||||||
|
|
||||||
|
TimelineBreakDisplay breakDisplay = new TimelineBreakDisplay
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Height = 0.75f,
|
||||||
|
};
|
||||||
|
|
||||||
return wrapSkinnableContent(new Container
|
return wrapSkinnableContent(new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
|
// We want to display this below hitobjects to better expose placement objects visually.
|
||||||
|
// It needs to be above the blueprint container to handle drags on breaks though.
|
||||||
|
breakDisplay.CreateProxy(),
|
||||||
new TimelineBlueprintContainer(composer),
|
new TimelineBlueprintContainer(composer),
|
||||||
new TimelineBreakDisplay
|
breakDisplay
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
Height = 0.75f,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Overlays;
|
|
||||||
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit
|
namespace osu.Game.Screens.Edit
|
||||||
@ -26,7 +25,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(OverlayColourProvider colourProvider)
|
private void load()
|
||||||
{
|
{
|
||||||
// Grid with only two rows.
|
// Grid with only two rows.
|
||||||
// First is the timeline area, which should be allowed to expand as required.
|
// First is the timeline area, which should be allowed to expand as required.
|
||||||
@ -107,10 +106,18 @@ namespace osu.Game.Screens.Edit
|
|||||||
MainContent.Add(content);
|
MainContent.Add(content);
|
||||||
content.FadeInFromZero(300, Easing.OutQuint);
|
content.FadeInFromZero(300, Easing.OutQuint);
|
||||||
|
|
||||||
LoadComponentAsync(TimelineArea = new TimelineArea(CreateTimelineContent()), timelineContent.Add);
|
LoadComponentAsync(TimelineArea = new TimelineArea(CreateTimelineContent()), timeline =>
|
||||||
|
{
|
||||||
|
ConfigureTimeline(timeline);
|
||||||
|
timelineContent.Add(timeline);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void ConfigureTimeline(TimelineArea timelineArea)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract Drawable CreateMainContent();
|
protected abstract Drawable CreateMainContent();
|
||||||
|
|
||||||
protected virtual Drawable CreateTimelineContent() => new Container();
|
protected virtual Drawable CreateTimelineContent() => new Container();
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Timing
|
namespace osu.Game.Screens.Edit.Timing
|
||||||
{
|
{
|
||||||
@ -53,5 +54,12 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
SelectedGroup.Value = EditorBeatmap.ControlPointInfo.GroupAt(nearestTimingPoint.Time);
|
SelectedGroup.Value = EditorBeatmap.ControlPointInfo.GroupAt(nearestTimingPoint.Time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void ConfigureTimeline(TimelineArea timelineArea)
|
||||||
|
{
|
||||||
|
base.ConfigureTimeline(timelineArea);
|
||||||
|
|
||||||
|
timelineArea.Timeline.AlwaysShowControlPoints = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ using osu.Game.Online.API.Requests.Responses;
|
|||||||
using osu.Game.Online.Metadata;
|
using osu.Game.Online.Metadata;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Screens.OnlinePlay.DailyChallenge;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
@ -44,6 +45,9 @@ namespace osu.Game.Screens.Menu
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IAPIProvider api { get; set; } = null!;
|
private IAPIProvider api { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private INotificationOverlay? notificationOverlay { get; set; }
|
||||||
|
|
||||||
public DailyChallengeButton(string sampleName, Color4 colour, Action<MainMenuButton>? clickAction = null, params Key[] triggerKeys)
|
public DailyChallengeButton(string sampleName, Color4 colour, Action<MainMenuButton>? clickAction = null, params Key[] triggerKeys)
|
||||||
: base(ButtonSystemStrings.DailyChallenge, sampleName, OsuIcon.DailyChallenge, colour, clickAction, triggerKeys)
|
: base(ButtonSystemStrings.DailyChallenge, sampleName, OsuIcon.DailyChallenge, colour, clickAction, triggerKeys)
|
||||||
{
|
{
|
||||||
@ -100,7 +104,8 @@ namespace osu.Game.Screens.Menu
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
info.BindValueChanged(updateDisplay, true);
|
info.BindValueChanged(_ => dailyChallengeChanged(postNotification: true));
|
||||||
|
dailyChallengeChanged(postNotification: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -126,27 +131,30 @@ namespace osu.Game.Screens.Menu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDisplay(ValueChangedEvent<DailyChallengeInfo?> info)
|
private void dailyChallengeChanged(bool postNotification)
|
||||||
{
|
{
|
||||||
UpdateState();
|
UpdateState();
|
||||||
|
|
||||||
scheduledCountdownUpdate?.Cancel();
|
scheduledCountdownUpdate?.Cancel();
|
||||||
scheduledCountdownUpdate = null;
|
scheduledCountdownUpdate = null;
|
||||||
|
|
||||||
if (info.NewValue == null)
|
if (info.Value == null)
|
||||||
{
|
{
|
||||||
Room = null;
|
Room = null;
|
||||||
cover.OnlineInfo = TooltipContent = null;
|
cover.OnlineInfo = TooltipContent = null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var roomRequest = new GetRoomRequest(info.NewValue.Value.RoomID);
|
var roomRequest = new GetRoomRequest(info.Value.Value.RoomID);
|
||||||
|
|
||||||
roomRequest.Success += room =>
|
roomRequest.Success += room =>
|
||||||
{
|
{
|
||||||
Room = room;
|
Room = room;
|
||||||
cover.OnlineInfo = TooltipContent = room.Playlist.FirstOrDefault()?.Beatmap.BeatmapSet as APIBeatmapSet;
|
cover.OnlineInfo = TooltipContent = room.Playlist.FirstOrDefault()?.Beatmap.BeatmapSet as APIBeatmapSet;
|
||||||
|
|
||||||
|
if (postNotification)
|
||||||
|
notificationOverlay?.Post(new NewDailyChallengeNotification(room));
|
||||||
|
|
||||||
updateCountdown();
|
updateCountdown();
|
||||||
Scheduler.AddDelayed(updateCountdown, 1000, true);
|
Scheduler.AddDelayed(updateCountdown, 1000, true);
|
||||||
};
|
};
|
||||||
|
@ -30,6 +30,7 @@ using osu.Game.Online.Metadata;
|
|||||||
using osu.Game.Online.Multiplayer;
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Screens.OnlinePlay.Components;
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
@ -54,6 +55,7 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
|
|||||||
private readonly Bindable<IReadOnlyList<Mod>> userMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
private readonly Bindable<IReadOnlyList<Mod>> userMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||||
|
|
||||||
private readonly IBindable<APIState> apiState = new Bindable<APIState>();
|
private readonly IBindable<APIState> apiState = new Bindable<APIState>();
|
||||||
|
private readonly IBindable<DailyChallengeInfo?> dailyChallengeInfo = new Bindable<DailyChallengeInfo?>();
|
||||||
|
|
||||||
private OnlinePlayScreenWaveContainer waves = null!;
|
private OnlinePlayScreenWaveContainer waves = null!;
|
||||||
private DailyChallengeLeaderboard leaderboard = null!;
|
private DailyChallengeLeaderboard leaderboard = null!;
|
||||||
@ -98,6 +100,9 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private PreviewTrackManager previewTrackManager { get; set; } = null!;
|
private PreviewTrackManager previewTrackManager { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private INotificationOverlay? notificationOverlay { get; set; }
|
||||||
|
|
||||||
public override bool DisallowExternalBeatmapRulesetChanges => true;
|
public override bool DisallowExternalBeatmapRulesetChanges => true;
|
||||||
|
|
||||||
public override bool? ApplyModTrackAdjustments => true;
|
public override bool? ApplyModTrackAdjustments => true;
|
||||||
@ -336,6 +341,7 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
|
|||||||
}
|
}
|
||||||
|
|
||||||
metadataClient.MultiplayerRoomScoreSet += onRoomScoreSet;
|
metadataClient.MultiplayerRoomScoreSet += onRoomScoreSet;
|
||||||
|
dailyChallengeInfo.BindTo(metadataClient.DailyChallengeInfo);
|
||||||
|
|
||||||
((IBindable<MultiplayerScore?>)breakdown.UserBestScore).BindTo(leaderboard.UserBestScore);
|
((IBindable<MultiplayerScore?>)breakdown.UserBestScore).BindTo(leaderboard.UserBestScore);
|
||||||
}
|
}
|
||||||
@ -388,6 +394,8 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
|
|||||||
|
|
||||||
apiState.BindTo(API.State);
|
apiState.BindTo(API.State);
|
||||||
apiState.BindValueChanged(onlineStateChanged, true);
|
apiState.BindValueChanged(onlineStateChanged, true);
|
||||||
|
|
||||||
|
dailyChallengeInfo.BindValueChanged(dailyChallengeChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void trySetDailyChallengeBeatmap()
|
private void trySetDailyChallengeBeatmap()
|
||||||
@ -405,9 +413,17 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
|
|||||||
Schedule(forcefullyExit);
|
Schedule(forcefullyExit);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private void dailyChallengeChanged(ValueChangedEvent<DailyChallengeInfo?> change)
|
||||||
|
{
|
||||||
|
if (change.OldValue?.RoomID == room.RoomID.Value && change.NewValue == null)
|
||||||
|
{
|
||||||
|
notificationOverlay?.Post(new SimpleNotification { Text = DailyChallengeStrings.ChallengeEndedNotification });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void forcefullyExit()
|
private void forcefullyExit()
|
||||||
{
|
{
|
||||||
Logger.Log($"{this} forcefully exiting due to loss of API connection");
|
Logger.Log(@$"{this} forcefully exiting due to loss of API connection");
|
||||||
|
|
||||||
// This is temporary since we don't currently have a way to force screens to be exited
|
// This is temporary since we don't currently have a way to force screens to be exited
|
||||||
// See also: `OnlinePlayScreen.forcefullyExit()`
|
// See also: `OnlinePlayScreen.forcefullyExit()`
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Screens;
|
||||||
|
using osu.Game.Beatmaps.Drawables.Cards;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Online.Rooms;
|
||||||
|
using osu.Game.Overlays.Notifications;
|
||||||
|
using osu.Game.Screens.Menu;
|
||||||
|
using osu.Game.Localisation;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.OnlinePlay.DailyChallenge
|
||||||
|
{
|
||||||
|
public partial class NewDailyChallengeNotification : SimpleNotification
|
||||||
|
{
|
||||||
|
private readonly Room room;
|
||||||
|
|
||||||
|
private BeatmapCardNano card = null!;
|
||||||
|
|
||||||
|
public NewDailyChallengeNotification(Room room)
|
||||||
|
{
|
||||||
|
this.room = room;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuGame? game)
|
||||||
|
{
|
||||||
|
Text = DailyChallengeStrings.ChallengeLiveNotification;
|
||||||
|
Content.Add(card = new BeatmapCardNano((APIBeatmapSet)room.Playlist.Single().Beatmap.BeatmapSet!));
|
||||||
|
Activated = () =>
|
||||||
|
{
|
||||||
|
game?.PerformFromScreen(s => s.Push(new DailyChallenge(room)), [typeof(MainMenu)]);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
card.Width = Content.DrawWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -40,6 +40,7 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
case "star":
|
case "star":
|
||||||
case "stars":
|
case "stars":
|
||||||
|
case "sr":
|
||||||
return TryUpdateCriteriaRange(ref criteria.StarDifficulty, op, value, 0.01d / 2);
|
return TryUpdateCriteriaRange(ref criteria.StarDifficulty, op, value, 0.01d / 2);
|
||||||
|
|
||||||
case "ar":
|
case "ar":
|
||||||
|
@ -15,7 +15,6 @@ using osu.Framework.Graphics.Cursor;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Layout;
|
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Extensions;
|
using osu.Game.Extensions;
|
||||||
@ -38,6 +37,7 @@ using osu.Game.Users.Drawables;
|
|||||||
using osu.Game.Utils;
|
using osu.Game.Utils;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
using CommonStrings = osu.Game.Localisation.CommonStrings;
|
||||||
|
|
||||||
namespace osu.Game.Screens.SelectV2.Leaderboards
|
namespace osu.Game.Screens.SelectV2.Leaderboards
|
||||||
{
|
{
|
||||||
@ -61,7 +61,6 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
|
|||||||
private const float statistics_regular_min_width = 175;
|
private const float statistics_regular_min_width = 175;
|
||||||
private const float statistics_compact_min_width = 100;
|
private const float statistics_compact_min_width = 100;
|
||||||
private const float rank_label_width = 65;
|
private const float rank_label_width = 65;
|
||||||
private const float rank_label_visibility_width_cutoff = rank_label_width + height + username_min_width + statistics_regular_min_width + expanded_right_content_width;
|
|
||||||
|
|
||||||
private readonly ScoreInfo score;
|
private readonly ScoreInfo score;
|
||||||
private readonly bool sheared;
|
private readonly bool sheared;
|
||||||
@ -560,33 +559,34 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
|
|||||||
background.FadeColour(IsHovered ? backgroundColour.Lighten(0.2f) : backgroundColour, transition_duration, Easing.OutQuint);
|
background.FadeColour(IsHovered ? backgroundColour.Lighten(0.2f) : backgroundColour, transition_duration, Easing.OutQuint);
|
||||||
totalScoreBackground.FadeColour(IsHovered ? lightenedGradient : totalScoreBackgroundGradient, transition_duration, Easing.OutQuint);
|
totalScoreBackground.FadeColour(IsHovered ? lightenedGradient : totalScoreBackgroundGradient, transition_duration, Easing.OutQuint);
|
||||||
|
|
||||||
if (DrawWidth < rank_label_visibility_width_cutoff && IsHovered)
|
if (IsHovered && currentMode != DisplayMode.Full)
|
||||||
rankLabelOverlay.FadeIn(transition_duration, Easing.OutQuint);
|
rankLabelOverlay.FadeIn(transition_duration, Easing.OutQuint);
|
||||||
else
|
else
|
||||||
rankLabelOverlay.FadeOut(transition_duration, Easing.OutQuint);
|
rankLabelOverlay.FadeOut(transition_duration, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnInvalidate(Invalidation invalidation, InvalidationSource source)
|
private DisplayMode? currentMode;
|
||||||
{
|
|
||||||
Scheduler.AddOnce(() =>
|
|
||||||
{
|
|
||||||
// when width decreases
|
|
||||||
// - hide rank and show rank overlay on avatar when hovered, then
|
|
||||||
// - compact statistics, then
|
|
||||||
// - hide statistics
|
|
||||||
|
|
||||||
if (DrawWidth >= rank_label_visibility_width_cutoff)
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
DisplayMode mode = getCurrentDisplayMode();
|
||||||
|
|
||||||
|
if (currentMode != mode)
|
||||||
|
{
|
||||||
|
if (mode >= DisplayMode.Full)
|
||||||
rankLabel.FadeIn(transition_duration, Easing.OutQuint).MoveToX(0, transition_duration, Easing.OutQuint);
|
rankLabel.FadeIn(transition_duration, Easing.OutQuint).MoveToX(0, transition_duration, Easing.OutQuint);
|
||||||
else
|
else
|
||||||
rankLabel.FadeOut(transition_duration, Easing.OutQuint).MoveToX(-rankLabel.DrawWidth, transition_duration, Easing.OutQuint);
|
rankLabel.FadeOut(transition_duration, Easing.OutQuint).MoveToX(-rankLabel.DrawWidth, transition_duration, Easing.OutQuint);
|
||||||
|
|
||||||
if (DrawWidth >= height + username_min_width + statistics_regular_min_width + expanded_right_content_width)
|
if (mode >= DisplayMode.Regular)
|
||||||
{
|
{
|
||||||
statisticsContainer.FadeIn(transition_duration, Easing.OutQuint).MoveToX(0, transition_duration, Easing.OutQuint);
|
statisticsContainer.FadeIn(transition_duration, Easing.OutQuint).MoveToX(0, transition_duration, Easing.OutQuint);
|
||||||
statisticsContainer.Direction = FillDirection.Horizontal;
|
statisticsContainer.Direction = FillDirection.Horizontal;
|
||||||
statisticsContainer.ScaleTo(1, transition_duration, Easing.OutQuint);
|
statisticsContainer.ScaleTo(1, transition_duration, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
else if (DrawWidth >= height + username_min_width + statistics_compact_min_width + expanded_right_content_width)
|
else if (mode >= DisplayMode.Compact)
|
||||||
{
|
{
|
||||||
statisticsContainer.FadeIn(transition_duration, Easing.OutQuint).MoveToX(0, transition_duration, Easing.OutQuint);
|
statisticsContainer.FadeIn(transition_duration, Easing.OutQuint).MoveToX(0, transition_duration, Easing.OutQuint);
|
||||||
statisticsContainer.Direction = FillDirection.Vertical;
|
statisticsContainer.Direction = FillDirection.Vertical;
|
||||||
@ -594,13 +594,35 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
statisticsContainer.FadeOut(transition_duration, Easing.OutQuint).MoveToX(statisticsContainer.DrawWidth, transition_duration, Easing.OutQuint);
|
statisticsContainer.FadeOut(transition_duration, Easing.OutQuint).MoveToX(statisticsContainer.DrawWidth, transition_duration, Easing.OutQuint);
|
||||||
});
|
|
||||||
|
|
||||||
return base.OnInvalidate(invalidation, source);
|
currentMode = mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DisplayMode getCurrentDisplayMode()
|
||||||
|
{
|
||||||
|
if (DrawWidth >= height + username_min_width + statistics_regular_min_width + expanded_right_content_width + rank_label_width)
|
||||||
|
return DisplayMode.Full;
|
||||||
|
|
||||||
|
if (DrawWidth >= height + username_min_width + statistics_regular_min_width + expanded_right_content_width)
|
||||||
|
return DisplayMode.Regular;
|
||||||
|
|
||||||
|
if (DrawWidth >= height + username_min_width + statistics_compact_min_width + expanded_right_content_width)
|
||||||
|
return DisplayMode.Compact;
|
||||||
|
|
||||||
|
return DisplayMode.Minimal;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Subclasses
|
#region Subclasses
|
||||||
|
|
||||||
|
private enum DisplayMode
|
||||||
|
{
|
||||||
|
Minimal,
|
||||||
|
Compact,
|
||||||
|
Regular,
|
||||||
|
Full
|
||||||
|
}
|
||||||
|
|
||||||
private partial class DateLabel : DrawableDate
|
private partial class DateLabel : DrawableDate
|
||||||
{
|
{
|
||||||
public DateLabel(DateTimeOffset date)
|
public DateLabel(DateTimeOffset date)
|
||||||
@ -749,8 +771,8 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
|
|||||||
|
|
||||||
if (score.Files.Count <= 0) return items.ToArray();
|
if (score.Files.Count <= 0) return items.ToArray();
|
||||||
|
|
||||||
items.Add(new OsuMenuItem(Localisation.CommonStrings.Export, MenuItemType.Standard, () => scoreManager.Export(score)));
|
items.Add(new OsuMenuItem(CommonStrings.Export, MenuItemType.Standard, () => scoreManager.Export(score)));
|
||||||
items.Add(new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(score))));
|
items.Add(new OsuMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(score))));
|
||||||
|
|
||||||
return items.ToArray();
|
return items.ToArray();
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Metadata
|
|||||||
public override IBindableDictionary<int, UserPresence> UserStates => userStates;
|
public override IBindableDictionary<int, UserPresence> UserStates => userStates;
|
||||||
private readonly BindableDictionary<int, UserPresence> userStates = new BindableDictionary<int, UserPresence>();
|
private readonly BindableDictionary<int, UserPresence> userStates = new BindableDictionary<int, UserPresence>();
|
||||||
|
|
||||||
public override IBindable<DailyChallengeInfo?> DailyChallengeInfo => dailyChallengeInfo;
|
public override Bindable<DailyChallengeInfo?> DailyChallengeInfo => dailyChallengeInfo;
|
||||||
private readonly Bindable<DailyChallengeInfo?> dailyChallengeInfo = new Bindable<DailyChallengeInfo?>();
|
private readonly Bindable<DailyChallengeInfo?> dailyChallengeInfo = new Bindable<DailyChallengeInfo?>();
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -88,7 +88,14 @@ namespace osu.Game.Tests.Visual.Metadata
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override Task<MultiplayerPlaylistItemStats[]> BeginWatchingMultiplayerRoom(long id)
|
public override Task<MultiplayerPlaylistItemStats[]> BeginWatchingMultiplayerRoom(long id)
|
||||||
=> Task.FromResult(new MultiplayerPlaylistItemStats[MultiplayerPlaylistItemStats.TOTAL_SCORE_DISTRIBUTION_BINS]);
|
{
|
||||||
|
var stats = new MultiplayerPlaylistItemStats[MultiplayerPlaylistItemStats.TOTAL_SCORE_DISTRIBUTION_BINS];
|
||||||
|
|
||||||
|
for (int i = 0; i < stats.Length; i++)
|
||||||
|
stats[i] = new MultiplayerPlaylistItemStats { PlaylistItemID = i };
|
||||||
|
|
||||||
|
return Task.FromResult(stats);
|
||||||
|
}
|
||||||
|
|
||||||
public override Task EndWatchingMultiplayerRoom(long id) => Task.CompletedTask;
|
public override Task EndWatchingMultiplayerRoom(long id) => Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
@ -30,13 +30,13 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.Toolkit.HighPerformance" Version="7.1.2" />
|
<PackageReference Include="Microsoft.Toolkit.HighPerformance" Version="7.1.2" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="ppy.LocalisationAnalyser" Version="2024.517.0">
|
<PackageReference Include="ppy.LocalisationAnalyser" Version="2024.802.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Realm" Version="11.5.0" />
|
<PackageReference Include="Realm" Version="11.5.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2024.802.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2024.802.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2024.713.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2024.802.0" />
|
||||||
<PackageReference Include="Sentry" Version="4.3.0" />
|
<PackageReference Include="Sentry" Version="4.3.0" />
|
||||||
<!-- Held back due to 0.34.0 failing AOT compilation on ZstdSharp.dll dependency. -->
|
<!-- Held back due to 0.34.0 failing AOT compilation on ZstdSharp.dll dependency. -->
|
||||||
<PackageReference Include="SharpCompress" Version="0.36.0" />
|
<PackageReference Include="SharpCompress" Version="0.36.0" />
|
||||||
|
Loading…
Reference in New Issue
Block a user