From 2bf0dcf398f2f62a00158a37801ca74ff18c2492 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 16:31:15 +0900 Subject: [PATCH] Adjust friend notification logic to fix a few flaws (#36348) Just a couple of things I noticed in passing: - When changing the configuration setting, things were not reset. Likewise, if the setting was off the queues would still be added to but never flushed. - When the setting is toggled, a stale next notification time was still present due to the `??=` and lack of resetting. This should no longer be the case. --- osu.Game/Online/FriendPresenceNotifier.cs | 65 ++++++++++++----------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/osu.Game/Online/FriendPresenceNotifier.cs b/osu.Game/Online/FriendPresenceNotifier.cs index 8329f3b46b..0297aea556 100644 --- a/osu.Game/Online/FriendPresenceNotifier.cs +++ b/osu.Game/Online/FriendPresenceNotifier.cs @@ -45,14 +45,24 @@ namespace osu.Game.Online private readonly HashSet onlineAlertQueue = new HashSet(); private readonly HashSet offlineAlertQueue = new HashSet(); - private double? lastOnlineAlertTime; - private double? lastOfflineAlertTime; + private double? nextOnlineAlertTime; + private double? nextOfflineAlertTime; + + private const double debounce_time_before_notification = 1000; protected override void LoadComplete() { base.LoadComplete(); config.BindWith(OsuSetting.NotifyOnFriendPresenceChange, notifyOnFriendPresenceChange); + notifyOnFriendPresenceChange.BindValueChanged(_ => + { + onlineAlertQueue.Clear(); + offlineAlertQueue.Clear(); + + nextOfflineAlertTime = null; + nextOnlineAlertTime = null; + }); friends.BindTo(api.LocalUserState.Friends); friends.BindCollectionChanged(onFriendsChanged, true); @@ -65,8 +75,11 @@ namespace osu.Game.Online { base.Update(); - alertOnlineUsers(); - alertOfflineUsers(); + if (notifyOnFriendPresenceChange.Value) + { + alertOnlineUsers(); + alertOfflineUsers(); + } } private void onFriendsChanged(object? sender, NotifyCollectionChangedEventArgs e) @@ -132,7 +145,7 @@ namespace osu.Game.Online if (!offlineAlertQueue.Remove(user)) { onlineAlertQueue.Add(user); - lastOnlineAlertTime ??= Time.Current; + nextOnlineAlertTime ??= Time.Current + debounce_time_before_notification; } } @@ -141,57 +154,45 @@ namespace osu.Game.Online if (!onlineAlertQueue.Remove(user)) { offlineAlertQueue.Add(user); - lastOfflineAlertTime ??= Time.Current; + nextOfflineAlertTime ??= Time.Current + debounce_time_before_notification; } } private void alertOnlineUsers() { - if (onlineAlertQueue.Count == 0) + if (nextOnlineAlertTime == null || Time.Current < nextOnlineAlertTime) return; - if (lastOnlineAlertTime == null || Time.Current - lastOnlineAlertTime < 1000) - return; - - if (!notifyOnFriendPresenceChange.Value) - { - lastOnlineAlertTime = null; - return; - } + // If a user quickly switches online-offline, we might reach here without actually having a notification + // to fire. Importantly, we should still reset the next alert time in such a scenario. if (onlineAlertQueue.Count == 1) notifications.Post(new SingleFriendOnlineNotification(onlineAlertQueue.Single())); - else + else if (onlineAlertQueue.Count > 1) notifications.Post(new MultipleFriendsOnlineNotification(onlineAlertQueue.ToArray())); onlineAlertQueue.Clear(); - lastOnlineAlertTime = null; + nextOnlineAlertTime = null; } private void alertOfflineUsers() { - if (offlineAlertQueue.Count == 0) + if (nextOfflineAlertTime == null || Time.Current < nextOfflineAlertTime) return; - if (lastOfflineAlertTime == null || Time.Current - lastOfflineAlertTime < 1000) - return; - - if (!notifyOnFriendPresenceChange.Value) - { - lastOfflineAlertTime = null; - return; - } + // If a user quickly switches offline-online, we might reach here without actually having a notification + // to fire. Importantly, we should still reset the next alert time in such a scenario. if (offlineAlertQueue.Count == 1) notifications.Post(new SingleFriendOfflineNotification(offlineAlertQueue.Single())); - else + else if (offlineAlertQueue.Count > 1) notifications.Post(new MultipleFriendsOfflineNotification(offlineAlertQueue.ToArray())); offlineAlertQueue.Clear(); - lastOfflineAlertTime = null; + nextOfflineAlertTime = null; } - public partial class SingleFriendOnlineNotification : UserAvatarNotification + private partial class SingleFriendOnlineNotification : UserAvatarNotification { public SingleFriendOnlineNotification(APIUser user) : base(user) @@ -216,7 +217,7 @@ namespace osu.Game.Online public override string PopInSampleName => "UI/notification-friend-online"; } - public partial class MultipleFriendsOnlineNotification : SimpleNotification + private partial class MultipleFriendsOnlineNotification : SimpleNotification { public MultipleFriendsOnlineNotification(ICollection users) { @@ -233,7 +234,7 @@ namespace osu.Game.Online public override string PopInSampleName => "UI/notification-friend-online"; } - public partial class SingleFriendOfflineNotification : UserAvatarNotification + private partial class SingleFriendOfflineNotification : UserAvatarNotification { public SingleFriendOfflineNotification(APIUser user) : base(user) @@ -253,7 +254,7 @@ namespace osu.Game.Online public override string PopInSampleName => "UI/notification-friend-offline"; } - public partial class MultipleFriendsOfflineNotification : SimpleNotification + private partial class MultipleFriendsOfflineNotification : SimpleNotification { public MultipleFriendsOfflineNotification(ICollection users) {