mirror of
https://github.com/ppy/osu.git
synced 2026-05-13 20:33:35 +08:00
Debounce user offline notifications (#37028)
This commit is contained in:
committed by
GitHub
Unverified
parent
bd30f70045
commit
ed6ec8b417
@@ -25,6 +25,7 @@ namespace osu.Game.Tests.Visual.Components
|
||||
private NotificationOverlay notificationOverlay = null!;
|
||||
private ChatOverlay chatOverlay = null!;
|
||||
private TestMetadataClient metadataClient = null!;
|
||||
private FriendPresenceNotifier notifier = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
@@ -45,7 +46,11 @@ namespace osu.Game.Tests.Visual.Components
|
||||
notificationOverlay,
|
||||
chatOverlay,
|
||||
metadataClient,
|
||||
new FriendPresenceNotifier()
|
||||
notifier = new FriendPresenceNotifier
|
||||
{
|
||||
// Speeds up tests that don't rely on this debounce a little bit.
|
||||
OfflineDebounceTime = 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -127,5 +132,27 @@ namespace osu.Game.Tests.Visual.Components
|
||||
|
||||
AddUntilStep("wait for notification", () => notificationOverlay.AllNotifications.Count(), () => Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOfflineDebounce()
|
||||
{
|
||||
AddStep("set debounce time", () =>
|
||||
{
|
||||
notifier.NotificationDebounceTime = 0;
|
||||
notifier.OfflineDebounceTime = 5000;
|
||||
});
|
||||
|
||||
AddStep("bring friend online", () => metadataClient.FriendPresenceUpdated(1, new UserPresence { Status = UserStatus.Online }));
|
||||
AddUntilStep("online notification posted", () => notificationOverlay.AllNotifications.Count(), () => Is.EqualTo(1));
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
AddStep("bring friend online", () => metadataClient.FriendPresenceUpdated(1, new UserPresence { Status = UserStatus.Online }));
|
||||
AddStep("bring friend offline", () => metadataClient.FriendPresenceUpdated(1, null));
|
||||
}
|
||||
|
||||
AddUntilStep("online notification posted", () => notificationOverlay.AllNotifications.Count(), () => Is.EqualTo(1));
|
||||
AddUntilStep("offline notification posted", () => notificationOverlay.AllNotifications.Count(), () => Is.EqualTo(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,16 @@ namespace osu.Game.Online
|
||||
{
|
||||
public partial class FriendPresenceNotifier : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Minimum time between subsequent online/offline notifications.
|
||||
/// </summary>
|
||||
public double NotificationDebounceTime { get; set; } = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum time after a user has gone offline, before they're added to the offline alert queue.
|
||||
/// </summary>
|
||||
public double OfflineDebounceTime { get; set; } = 15000;
|
||||
|
||||
[Resolved]
|
||||
private INotificationOverlay notifications { get; set; } = null!;
|
||||
|
||||
@@ -42,13 +52,31 @@ namespace osu.Game.Online
|
||||
private readonly IBindableList<APIRelation> friends = new BindableList<APIRelation>();
|
||||
private readonly IBindableDictionary<int, UserPresence> friendPresences = new BindableDictionary<int, UserPresence>();
|
||||
|
||||
/// <summary>
|
||||
/// List of users that will be notified as having come online with the next notification.
|
||||
/// </summary>
|
||||
private readonly HashSet<APIUser> onlineAlertQueue = new HashSet<APIUser>();
|
||||
|
||||
/// <summary>
|
||||
/// List of users that will be notified as having gone offline with the next notification.
|
||||
/// </summary>
|
||||
private readonly HashSet<APIUser> offlineAlertQueue = new HashSet<APIUser>();
|
||||
|
||||
private double? nextOnlineAlertTime;
|
||||
private double? nextOfflineAlertTime;
|
||||
/// <summary>
|
||||
/// List of users that have gone offline, but we're waiting for them to potentially come online again before queueing them for notification.
|
||||
/// For example, if a user is quickly toggling between the "Online" and "Appear Offline" states.
|
||||
/// </summary>
|
||||
private readonly HashSet<APIUser> pendingOfflineUsers = new HashSet<APIUser>();
|
||||
|
||||
private const double debounce_time_before_notification = 1000;
|
||||
/// <summary>
|
||||
/// The post time for the next online notification.
|
||||
/// </summary>
|
||||
private double? nextOnlineAlertTime;
|
||||
|
||||
/// <summary>
|
||||
/// The post time for the next offline notification.
|
||||
/// </summary>
|
||||
private double? nextOfflineAlertTime;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
@@ -133,28 +161,55 @@ namespace osu.Game.Online
|
||||
APIRelation? friend = friends.FirstOrDefault(f => f.TargetID == friendId);
|
||||
|
||||
if (friend?.TargetUser is APIUser user)
|
||||
markUserOffline(user);
|
||||
markUserOfflineDebounced(user);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Immediately registers a user for the next online notification alert.
|
||||
/// </summary>
|
||||
private void markUserOnline(APIUser user)
|
||||
{
|
||||
if (pendingOfflineUsers.Remove(user))
|
||||
return;
|
||||
|
||||
if (!offlineAlertQueue.Remove(user))
|
||||
{
|
||||
onlineAlertQueue.Add(user);
|
||||
nextOnlineAlertTime ??= Time.Current + debounce_time_before_notification;
|
||||
nextOnlineAlertTime ??= Time.Current + NotificationDebounceTime;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Waits <see cref="OfflineDebounceTime"/> before adding a user to the next offline notification alert.
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
private void markUserOfflineDebounced(APIUser user)
|
||||
{
|
||||
pendingOfflineUsers.Add(user);
|
||||
|
||||
Scheduler.AddDelayed(() =>
|
||||
{
|
||||
// Check if the friend has come back online.
|
||||
if (!pendingOfflineUsers.Remove(user))
|
||||
return;
|
||||
|
||||
markUserOffline(user);
|
||||
}, OfflineDebounceTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Immediately registers a user for the next offline notification alert.
|
||||
/// </summary>
|
||||
private void markUserOffline(APIUser user)
|
||||
{
|
||||
if (!onlineAlertQueue.Remove(user))
|
||||
{
|
||||
offlineAlertQueue.Add(user);
|
||||
nextOfflineAlertTime ??= Time.Current + debounce_time_before_notification;
|
||||
nextOfflineAlertTime ??= Time.Current + NotificationDebounceTime;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user