Skip to content

Commit

Permalink
autoupdate: wait longer for periodic check if user dismissed updates
Browse files Browse the repository at this point in the history
  • Loading branch information
goaaats committed Jun 19, 2024
1 parent 7939223 commit d244f7e
Showing 1 changed file with 60 additions and 35 deletions.
95 changes: 60 additions & 35 deletions Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -40,7 +41,13 @@ internal class AutoUpdateManager : IServiceType
/// <summary>
/// Time we should wait between scheduled update checks.
/// </summary>
private static readonly TimeSpan TimeBetweenUpdateChecks = TimeSpan.FromHours(1.5);
private static readonly TimeSpan TimeBetweenUpdateChecks = TimeSpan.FromHours(2);

/// <summary>
/// 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.
/// </summary>
private static readonly TimeSpan TimeBetweenUpdateChecksIfDismissed = TimeSpan.FromHours(12);

/// <summary>
/// Time we should wait after unblocking to nag the user.
Expand All @@ -63,12 +70,13 @@ internal class AutoUpdateManager : IServiceType
private readonly IConsoleVariable<bool> 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;

Expand Down Expand Up @@ -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;
});
}
Expand Down Expand Up @@ -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<DalamudInterface>.Get().OpenPluginInstallerTo(PluginInstallerOpenKind.UpdateablePlugins);
Service<DalamudInterface>.Get().OpenPluginInstallerTo(kind);
notification.DismissNow();
}
}
Expand Down Expand Up @@ -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;
Expand All @@ -198,23 +204,27 @@ 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;
}

// 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 =>
Expand All @@ -228,8 +238,6 @@ private void OnUpdate(IFramework framework)
this.GetAvailablePluginUpdates(
DecideUpdateListingRestriction(behavior)));
});

this.lastUpdateCheckTime = DateTime.Now;
}
}

Expand All @@ -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<AvailablePluginUpdate> updatablePlugins)
private void KickOffAutoUpdates(ICollection<AvailablePluginUpdate> updatablePlugins, IActiveNotification? notification = null)
{
this.autoUpdateTask =
Task.Run(() => this.RunAutoUpdates(updatablePlugins))
Task.Run(() => this.RunAutoUpdates(updatablePlugins, notification))
.ContinueWith(t =>
{
if (t.IsFaulted)
Expand All @@ -268,25 +290,23 @@ private void KickOffAutoUpdates(ICollection<AvailablePluginUpdate> updatablePlug
});
}

private async Task RunAutoUpdates(ICollection<AvailablePluginUpdate> updatablePlugins)
private async Task RunAutoUpdates(ICollection<AvailablePluginUpdate> 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<PluginManager.PluginUpdateProgress>();
progress.ProgressChanged += (_, updateProgress) =>
Expand All @@ -304,7 +324,7 @@ private async Task RunAutoUpdates(ICollection<AvailablePluginUpdate> updatablePl
notification.DrawActions += _ =>
{
ImGuiHelpers.ScaledDummy(2);
DrawOpenInstallerNotificationButton(true, notification);
DrawOpenInstallerNotificationButton(true, PluginInstallerOpenKind.InstalledPlugins, notification);
};

// Update the notification to show the final state
Expand Down Expand Up @@ -340,6 +360,8 @@ private void NotifyUpdatesAreAvailable(ICollection<AvailablePluginUpdate> updata
{
if (updatablePlugins.Count == 0)
return;

this.notificationHasStartedUpdate = false;

var notification = this.GetBaseNotification(new Notification
{
Expand All @@ -352,19 +374,22 @@ private void NotifyUpdatesAreAvailable(ICollection<AvailablePluginUpdate> 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<AvailablePluginUpdate> GetAvailablePluginUpdates(UpdateListingRestriction restriction)
Expand Down

0 comments on commit d244f7e

Please sign in to comment.