Add notification on daily challenge conclusion & start of new one

Because I wish to stop seeing "DAILY CHALLENGE WHERE" every day
on #general.

The notifications are constrained to the daily challenge screen only to
not spam users who may not care.
This commit is contained in:
Bartłomiej Dach 2024-07-29 14:20:47 +02:00
parent a6b442814d
commit b46f3c97da
No known key found for this signature in database
4 changed files with 151 additions and 1 deletions

View File

@ -4,16 +4,32 @@
using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
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);
}
[Test]
public void TestDailyChallenge()
{
@ -36,5 +52,62 @@ 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(CreateAPIBeatmapSet().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 });
AddStep("push screen", () => LoadScreen(new Screens.OnlinePlay.DailyChallenge.DailyChallenge(room)));
AddStep("daily challenge ended", () => metadataClient.DailyChallengeInfo.Value = null);
AddStep("install custom handler", () =>
{
((DummyAPIAccess)API).HandleRequest = req =>
{
switch (req)
{
case GetRoomRequest r:
{
r.TriggerSuccess(new Room
{
RoomID = { Value = 1235, },
Name = { Value = "Daily Challenge: June 5, 2024" },
Playlist =
{
new PlaylistItem(CreateAPIBeatmapSet().Beatmaps.First())
{
RequiredMods = [new APIMod(new OsuModTraceable())],
AllowedMods = [new APIMod(new OsuModDoubleTime())]
}
},
EndDate = { Value = DateTimeOffset.Now.AddHours(12) },
Category = { Value = RoomCategory.DailyChallenge }
});
return true;
}
default:
return false;
}
};
});
AddStep("next daily challenge started", () => metadataClient.DailyChallengeInfo.Value = new DailyChallengeInfo { RoomID = 1235 });
}
}
}

View File

@ -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!;
@ -65,6 +67,8 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
private DailyChallengeTotalsDisplay totals = null!;
private DailyChallengeEventFeed feed = null!;
private SimpleNotification? waitForNextChallengeNotification;
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Plum);
@ -98,6 +102,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 +343,7 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
}
metadataClient.MultiplayerRoomScoreSet += onRoomScoreSet;
dailyChallengeInfo.BindTo(metadataClient.DailyChallengeInfo);
((IBindable<MultiplayerScore?>)breakdown.UserBestScore).BindTo(leaderboard.UserBestScore);
}
@ -388,6 +396,8 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
apiState.BindTo(API.State);
apiState.BindValueChanged(onlineStateChanged, true);
dailyChallengeInfo.BindValueChanged(dailyChallengeChanged);
}
private void trySetDailyChallengeBeatmap()
@ -405,6 +415,29 @@ 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(waitForNextChallengeNotification = new SimpleNotification
{
Text = "Today's daily challenge has concluded. Thanks for playing! The next one should appear in a few minutes."
});
}
if (change.NewValue != null && change.NewValue.Value.RoomID != room.RoomID.Value)
{
var roomRequest = new GetRoomRequest(change.NewValue.Value.RoomID);
roomRequest.Success += room =>
{
waitForNextChallengeNotification?.Close(false);
notificationOverlay?.Post(new NewDailyChallengeNotification(room));
};
API.Queue(roomRequest);
}
}
private void forcefullyExit()
{
Logger.Log($"{this} forcefully exiting due to loss of API connection");

View File

@ -0,0 +1,44 @@
// 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;
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 = "Today's daily challenge is here! Click here to play.";
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;
}
}
}

View File

@ -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]