diff --git a/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs b/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs
index cbcbe637e..07f023006 100644
--- a/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs
+++ b/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs
@@ -11,6 +11,7 @@
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Interface;
using Dalamud.Interface.ImGuiNotification;
+using Dalamud.Interface.ImGuiNotification.EventArgs;
using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal;
using Dalamud.Interface.Internal.DesignSystem;
@@ -40,7 +41,13 @@ internal class AutoUpdateManager : IServiceType
///
/// Time we should wait between scheduled update checks.
///
- private static readonly TimeSpan TimeBetweenUpdateChecks = TimeSpan.FromHours(1.5);
+ private static readonly TimeSpan TimeBetweenUpdateChecks = TimeSpan.FromHours(2);
+
+ ///
+ /// Time we should wait between scheduled update checks if the user has dismissed the notification,
+ /// instead of updating. We don't want to spam the user with notifications.
+ ///
+ private static readonly TimeSpan TimeBetweenUpdateChecksIfDismissed = TimeSpan.FromHours(12);
///
/// Time we should wait after unblocking to nag the user.
@@ -63,12 +70,13 @@ internal class AutoUpdateManager : IServiceType
private readonly IConsoleVariable isDryRun;
private DateTime? loginTime;
- private DateTime? lastUpdateCheckTime;
+ private DateTime? nextUpdateCheckTime;
private DateTime? unblockedSince;
private bool hasStartedInitialUpdateThisSession;
private IActiveNotification? updateNotification;
+ private bool notificationHasStartedUpdate; // Used to track if the user has started an update from the notification.
private Task? autoUpdateTask;
@@ -96,7 +104,7 @@ public AutoUpdateManager(ConsoleManager console)
});
console.AddCommand("dalamud.autoupdate.force_check", "Force a check for updates", () =>
{
- this.lastUpdateCheckTime = DateTime.Now - TimeBetweenUpdateChecks;
+ this.nextUpdateCheckTime = DateTime.Now + TimeSpan.FromSeconds(5);
return true;
});
}
@@ -129,13 +137,13 @@ private static UpdateListingRestriction DecideUpdateListingRestriction(AutoUpdat
};
}
- private static void DrawOpenInstallerNotificationButton(bool primary, IActiveNotification notification)
+ private static void DrawOpenInstallerNotificationButton(bool primary, PluginInstallerOpenKind kind, IActiveNotification notification)
{
if (primary ?
DalamudComponents.PrimaryButton(Locs.NotificationButtonOpenPluginInstaller) :
DalamudComponents.SecondaryButton(Locs.NotificationButtonOpenPluginInstaller))
{
- Service.Get().OpenPluginInstallerTo(PluginInstallerOpenKind.UpdateablePlugins);
+ Service.Get().OpenPluginInstallerTo(kind);
notification.DismissNow();
}
}
@@ -182,11 +190,9 @@ private void OnUpdate(IFramework framework)
// the only time we actually install updates automatically.
if (!this.hasStartedInitialUpdateThisSession && DateTime.Now > this.loginTime.Value.Add(UpdateTimeAfterLogin))
{
- this.lastUpdateCheckTime = DateTime.Now;
this.hasStartedInitialUpdateThisSession = true;
var currentlyUpdatablePlugins = this.GetAvailablePluginUpdates(DecideUpdateListingRestriction(behavior));
-
if (currentlyUpdatablePlugins.Count == 0)
{
this.IsAutoUpdateComplete = true;
@@ -198,12 +204,13 @@ private void OnUpdate(IFramework framework)
if (behavior == AutoUpdateBehavior.OnlyNotify)
{
// List all plugins in the notification
- Log.Verbose("Ran initial update, notifying for {Num} plugins", currentlyUpdatablePlugins.Count);
+ Log.Verbose("Running initial auto-update, notifying for {Num} plugins", currentlyUpdatablePlugins.Count);
this.NotifyUpdatesAreAvailable(currentlyUpdatablePlugins);
return;
}
- Log.Verbose("Ran initial update, updating {Num} plugins", currentlyUpdatablePlugins.Count);
+ Log.Verbose("Running initial auto-update, updating {Num} plugins", currentlyUpdatablePlugins.Count);
+ this.notificationHasStartedUpdate = true;
this.KickOffAutoUpdates(currentlyUpdatablePlugins);
return;
}
@@ -211,10 +218,13 @@ private void OnUpdate(IFramework framework)
// 2. Continuously check for updates while the game is running. We run these every once in a while and
// will only show a notification here that lets people start the update or open the installer.
if (this.config.CheckPeriodicallyForUpdates &&
- this.lastUpdateCheckTime != null &&
- DateTime.Now - this.lastUpdateCheckTime > TimeBetweenUpdateChecks &&
+ this.nextUpdateCheckTime != null &&
+ DateTime.Now > this.nextUpdateCheckTime &&
this.updateNotification == null)
{
+ this.nextUpdateCheckTime = null;
+
+ Log.Verbose("Starting periodic update check");
this.pluginManager.ReloadPluginMastersAsync()
.ContinueWith(
t =>
@@ -228,8 +238,6 @@ private void OnUpdate(IFramework framework)
this.GetAvailablePluginUpdates(
DecideUpdateListingRestriction(behavior)));
});
-
- this.lastUpdateCheckTime = DateTime.Now;
}
}
@@ -238,20 +246,34 @@ private IActiveNotification GetBaseNotification(Notification notification)
if (this.updateNotification != null)
throw new InvalidOperationException("Already showing a notification");
+ if (this.notificationHasStartedUpdate)
+ throw new InvalidOperationException("Lost track of notification state");
+
this.updateNotification = this.notificationManager.AddNotification(notification);
this.updateNotification.Dismiss += _ =>
{
this.updateNotification = null;
- this.lastUpdateCheckTime = DateTime.Now;
+
+ // If the user just clicked off the notification, we don't want to bother them again for quite a while.
+ if (this.notificationHasStartedUpdate)
+ {
+ this.nextUpdateCheckTime = DateTime.Now + TimeBetweenUpdateChecks;
+ Log.Verbose("User started update, next check at {Time}", this.nextUpdateCheckTime);
+ }
+ else
+ {
+ this.nextUpdateCheckTime = DateTime.Now + TimeBetweenUpdateChecksIfDismissed;
+ Log.Verbose("User dismissed update notification, next check at {Time}", this.nextUpdateCheckTime);
+ }
};
return this.updateNotification!;
}
- private void KickOffAutoUpdates(ICollection updatablePlugins)
+ private void KickOffAutoUpdates(ICollection updatablePlugins, IActiveNotification? notification = null)
{
this.autoUpdateTask =
- Task.Run(() => this.RunAutoUpdates(updatablePlugins))
+ Task.Run(() => this.RunAutoUpdates(updatablePlugins, notification))
.ContinueWith(t =>
{
if (t.IsFaulted)
@@ -268,25 +290,23 @@ private void KickOffAutoUpdates(ICollection updatablePlug
});
}
- private async Task RunAutoUpdates(ICollection updatablePlugins)
+ private async Task RunAutoUpdates(ICollection updatablePlugins, IActiveNotification? notification = null)
{
Log.Information("Found {UpdatablePluginsCount} plugins to update", updatablePlugins.Count);
if (updatablePlugins.Count == 0)
return;
- var notification = this.GetBaseNotification(new Notification
- {
- Title = Locs.NotificationTitleUpdatingPlugins,
- Content = Locs.NotificationContentPreparingToUpdate(updatablePlugins.Count),
- Type = NotificationType.Info,
- InitialDuration = TimeSpan.MaxValue,
- ShowIndeterminateIfNoExpiry = false,
- UserDismissable = false,
- Progress = 0,
- Icon = INotificationIcon.From(FontAwesomeIcon.Download),
- Minimized = false,
- });
+ notification ??= this.GetBaseNotification(new Notification());
+ notification.Title = Locs.NotificationTitleUpdatingPlugins;
+ notification.Content = Locs.NotificationContentPreparingToUpdate(updatablePlugins.Count);
+ notification.Type = NotificationType.Info;
+ notification.InitialDuration = TimeSpan.MaxValue;
+ notification.ShowIndeterminateIfNoExpiry = false;
+ notification.UserDismissable = false;
+ notification.Progress = 0;
+ notification.Icon = INotificationIcon.From(FontAwesomeIcon.Download);
+ notification.Minimized = false;
var progress = new Progress();
progress.ProgressChanged += (_, updateProgress) =>
@@ -304,7 +324,7 @@ private async Task RunAutoUpdates(ICollection updatablePl
notification.DrawActions += _ =>
{
ImGuiHelpers.ScaledDummy(2);
- DrawOpenInstallerNotificationButton(true, notification);
+ DrawOpenInstallerNotificationButton(true, PluginInstallerOpenKind.InstalledPlugins, notification);
};
// Update the notification to show the final state
@@ -340,6 +360,8 @@ private void NotifyUpdatesAreAvailable(ICollection updata
{
if (updatablePlugins.Count == 0)
return;
+
+ this.notificationHasStartedUpdate = false;
var notification = this.GetBaseNotification(new Notification
{
@@ -352,19 +374,22 @@ private void NotifyUpdatesAreAvailable(ICollection updata
Icon = INotificationIcon.From(FontAwesomeIcon.Download),
});
- notification.DrawActions += _ =>
+ void DrawNotificationContent(INotificationDrawArgs args)
{
ImGuiHelpers.ScaledDummy(2);
if (DalamudComponents.PrimaryButton(Locs.NotificationButtonUpdate))
{
- this.KickOffAutoUpdates(updatablePlugins);
- notification.DismissNow();
+ notification.DrawActions -= DrawNotificationContent;
+ this.KickOffAutoUpdates(updatablePlugins, notification);
+ this.notificationHasStartedUpdate = true;
}
ImGui.SameLine();
- DrawOpenInstallerNotificationButton(false, notification);
- };
+ DrawOpenInstallerNotificationButton(false, PluginInstallerOpenKind.UpdateablePlugins, notification);
+ }
+
+ notification.DrawActions += DrawNotificationContent;
}
private List GetAvailablePluginUpdates(UpdateListingRestriction restriction)