mirror of
https://github.com/ppy/osu.git
synced 2025-01-22 06:02:56 +08:00
Merge pull request #29188 from bdach/daily-challenge/better-messaging
Add notification on daily challenge conclusion & start of new one
This commit is contained in:
commit
e9ed9ff58b
@ -4,16 +4,34 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.Metadata;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osu.Game.Tests.Visual.Metadata;
|
||||
using osu.Game.Tests.Visual.OnlinePlay;
|
||||
|
||||
namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
{
|
||||
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]
|
||||
public void TestDailyChallenge()
|
||||
{
|
||||
@ -36,5 +54,33 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
AddStep("add room", () => API.Perform(new CreateRoomRequest(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
@ -10,6 +11,7 @@ using osu.Game.Localisation;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.Metadata;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osuTK.Input;
|
||||
using Color4 = osuTK.Graphics.Color4;
|
||||
@ -39,8 +41,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
[Test]
|
||||
public void TestDailyChallengeButton()
|
||||
{
|
||||
AddStep("beatmap of the day not active", () => metadataClient.DailyChallengeUpdated(null));
|
||||
|
||||
AddStep("set up API", () => dummyAPI.HandleRequest = 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)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
ButtonSystemState = ButtonSystemState.TopLevel,
|
||||
});
|
||||
NotificationOverlay notificationOverlay = null!;
|
||||
DependencyProvidingContainer buttonContainer = null!;
|
||||
|
||||
AddStep("beatmap of the day active", () => metadataClient.DailyChallengeUpdated(new DailyChallengeInfo
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
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}";
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Metadata;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Screens.OnlinePlay.DailyChallenge;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Input;
|
||||
@ -44,6 +45,9 @@ namespace osu.Game.Screens.Menu
|
||||
[Resolved]
|
||||
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)
|
||||
: base(ButtonSystemStrings.DailyChallenge, sampleName, OsuIcon.DailyChallenge, colour, clickAction, triggerKeys)
|
||||
{
|
||||
@ -100,7 +104,8 @@ namespace osu.Game.Screens.Menu
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
info.BindValueChanged(updateDisplay, true);
|
||||
info.BindValueChanged(_ => dailyChallengeChanged(postNotification: true));
|
||||
dailyChallengeChanged(postNotification: false);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
scheduledCountdownUpdate?.Cancel();
|
||||
scheduledCountdownUpdate = null;
|
||||
|
||||
if (info.NewValue == null)
|
||||
if (info.Value == null)
|
||||
{
|
||||
Room = null;
|
||||
cover.OnlineInfo = TooltipContent = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var roomRequest = new GetRoomRequest(info.NewValue.Value.RoomID);
|
||||
var roomRequest = new GetRoomRequest(info.Value.Value.RoomID);
|
||||
|
||||
roomRequest.Success += room =>
|
||||
{
|
||||
Room = room;
|
||||
cover.OnlineInfo = TooltipContent = room.Playlist.FirstOrDefault()?.Beatmap.BeatmapSet as APIBeatmapSet;
|
||||
|
||||
if (postNotification)
|
||||
notificationOverlay?.Post(new NewDailyChallengeNotification(room));
|
||||
|
||||
updateCountdown();
|
||||
Scheduler.AddDelayed(updateCountdown, 1000, true);
|
||||
};
|
||||
|
@ -30,6 +30,7 @@ using osu.Game.Online.Metadata;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
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 IBindable<APIState> apiState = new Bindable<APIState>();
|
||||
private readonly IBindable<DailyChallengeInfo?> dailyChallengeInfo = new Bindable<DailyChallengeInfo?>();
|
||||
|
||||
private OnlinePlayScreenWaveContainer waves = null!;
|
||||
private DailyChallengeLeaderboard leaderboard = null!;
|
||||
@ -98,6 +100,9 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
|
||||
[Resolved]
|
||||
private PreviewTrackManager previewTrackManager { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private INotificationOverlay? notificationOverlay { get; set; }
|
||||
|
||||
public override bool DisallowExternalBeatmapRulesetChanges => true;
|
||||
|
||||
public override bool? ApplyModTrackAdjustments => true;
|
||||
@ -336,6 +341,7 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
|
||||
}
|
||||
|
||||
metadataClient.MultiplayerRoomScoreSet += onRoomScoreSet;
|
||||
dailyChallengeInfo.BindTo(metadataClient.DailyChallengeInfo);
|
||||
|
||||
((IBindable<MultiplayerScore?>)breakdown.UserBestScore).BindTo(leaderboard.UserBestScore);
|
||||
}
|
||||
@ -388,6 +394,8 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
|
||||
|
||||
apiState.BindTo(API.State);
|
||||
apiState.BindValueChanged(onlineStateChanged, true);
|
||||
|
||||
dailyChallengeInfo.BindValueChanged(dailyChallengeChanged);
|
||||
}
|
||||
|
||||
private void trySetDailyChallengeBeatmap()
|
||||
@ -405,9 +413,17 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
|
||||
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()
|
||||
{
|
||||
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
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Metadata
|
||||
public override IBindableDictionary<int, UserPresence> UserStates => userStates;
|
||||
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?>();
|
||||
|
||||
[Resolved]
|
||||
@ -88,7 +88,14 @@ namespace osu.Game.Tests.Visual.Metadata
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user