diff --git a/Dalamud/Interface/ImGuiNotification/IActiveNotification.cs b/Dalamud/Interface/ImGuiNotification/IActiveNotification.cs
index 3e8aef196..d1aa1d95b 100644
--- a/Dalamud/Interface/ImGuiNotification/IActiveNotification.cs
+++ b/Dalamud/Interface/ImGuiNotification/IActiveNotification.cs
@@ -1,28 +1,24 @@
using System.Threading;
+using System.Threading.Tasks;
+
+using Dalamud.Game.Text;
+using Dalamud.Interface.Internal;
+using Dalamud.Interface.Internal.Notifications;
namespace Dalamud.Interface.ImGuiNotification;
-///
-/// Represents an active notification.
-///
+/// Represents an active notification.
public interface IActiveNotification : INotification
{
- ///
- /// The counter for field.
- ///
+ /// The counter for field.
private static long idCounter;
- ///
- /// Invoked upon dismissing the notification.
- ///
- ///
- /// The event callback will not be called, if a user interacts with the notification after the plugin is unloaded.
- ///
+ /// Invoked upon dismissing the notification.
+ /// The event callback will not be called,
+ /// if a user interacts with the notification after the plugin is unloaded.
event NotificationDismissedDelegate Dismiss;
- ///
- /// Invoked upon clicking on the notification.
- ///
+ /// Invoked upon clicking on the notification.
///
/// This event is not applicable when is set to false.
/// Note that this function may be called even after has been invoked.
@@ -30,9 +26,7 @@ public interface IActiveNotification : INotification
///
event Action Click;
- ///
- /// Invoked when the mouse enters the notification window.
- ///
+ /// Invoked when the mouse enters the notification window.
///
/// This event is applicable regardless of .
/// Note that this function may be called even after has been invoked.
@@ -40,9 +34,7 @@ public interface IActiveNotification : INotification
///
event Action MouseEnter;
- ///
- /// Invoked when the mouse leaves the notification window.
- ///
+ /// Invoked when the mouse leaves the notification window.
///
/// This event is applicable regardless of .
/// Note that this function may be called even after has been invoked.
@@ -50,9 +42,7 @@ public interface IActiveNotification : INotification
///
event Action MouseLeave;
- ///
- /// Invoked upon drawing the action bar of the notification.
- ///
+ /// Invoked upon drawing the action bar of the notification.
///
/// This event is applicable regardless of .
/// Note that this function may be called even after has been invoked.
@@ -60,50 +50,60 @@ public interface IActiveNotification : INotification
///
event Action DrawActions;
- ///
- /// Gets the ID of this notification.
- ///
+ ///
+ new string Content { get; set; }
+
+ ///
+ new string? Title { get; set; }
+
+ ///
+ new NotificationType Type { get; set; }
+
+ ///
+ new Func>? IconCreator { get; set; }
+
+ ///
+ new DateTime Expiry { get; set; }
+
+ ///
+ new bool Interactible { get; set; }
+
+ ///
+ new TimeSpan HoverExtendDuration { get; set; }
+
+ ///
+ new float Progress { get; set; }
+
+ /// Gets the ID of this notification.
long Id { get; }
- ///
- /// Gets a value indicating whether the mouse cursor is on the notification window.
- ///
+ /// Gets a value indicating whether the mouse cursor is on the notification window.
bool IsMouseHovered { get; }
- ///
- /// Gets a value indicating whether the notification has been dismissed.
- /// This includes when the hide animation is being played.
- ///
+ /// Gets a value indicating whether the notification has been dismissed.
+ /// This includes when the hide animation is being played.
bool IsDismissed { get; }
- ///
- /// Clones this notification as a .
- ///
+ /// Clones this notification as a .
/// A new instance of .
Notification CloneNotification();
- ///
- /// Dismisses this notification.
- ///
+ /// Dismisses this notification.
void DismissNow();
- ///
- /// Updates the notification data.
- ///
+ /// Updates the notification data.
///
/// Call to update the icon using the new .
+ /// If is true, then this function is a no-op.
///
/// The new notification entry.
void Update(INotification newNotification);
- ///
- /// Loads the icon again using .
- ///
+ /// Loads the icon again using .
+ /// If is true, then this function is a no-op.
void UpdateIcon();
- ///
- /// Generates a new value to use for .
- ///
+ /// Generates a new value to use for .
/// The new value.
internal static long CreateNewId() => Interlocked.Increment(ref idCounter);
}
diff --git a/Dalamud/Interface/ImGuiNotification/INotification.cs b/Dalamud/Interface/ImGuiNotification/INotification.cs
index f5f66725c..cbd8ad633 100644
--- a/Dalamud/Interface/ImGuiNotification/INotification.cs
+++ b/Dalamud/Interface/ImGuiNotification/INotification.cs
@@ -6,31 +6,21 @@ using Dalamud.Interface.Internal.Notifications;
namespace Dalamud.Interface.ImGuiNotification;
-///
-/// Represents a notification.
-///
+/// Represents a notification.
public interface INotification
{
- ///
- /// Gets the content body of the notification.
- ///
+ /// Gets the content body of the notification.
string Content { get; }
- ///
- /// Gets the title of the notification.
- ///
+ /// Gets the title of the notification.
string? Title { get; }
- ///
- /// Gets the type of the notification.
- ///
+ /// Gets the type of the notification.
NotificationType Type { get; }
- ///
- /// Gets the icon creator function for the notification.
+ /// Gets the icon creator function for the notification.
/// Currently , , and types
- /// are accepted.
- ///
+ /// are accepted.
///
/// The icon created by the task returned will be owned by Dalamud,
/// i.e. it will be d automatically as needed.
@@ -41,35 +31,30 @@ public interface INotification
///
Func>? IconCreator { get; }
- ///
- /// Gets the expiry.
- ///
+ /// Gets the expiry.
+ /// Set to to make the notification not have an expiry time
+ /// (sticky, indeterminate, permanent, or persistent).
DateTime Expiry { get; }
- ///
- /// Gets a value indicating whether this notification may be interacted.
- ///
+ /// Gets a value indicating whether this notification may be interacted.
///
/// Set this value to true if you want to respond to user inputs from
/// .
/// Note that the close buttons for notifications are always provided and interactible.
+ /// If set to true, then clicking on the notification itself will be interpreted as user-initiated dismissal,
+ /// unless is set.
///
bool Interactible { get; }
-
- ///
- /// Gets a value indicating whether clicking on the notification window counts as dismissing the notification.
- ///
- ///
- /// This property has no effect if is false.
- ///
- bool ClickIsDismiss { get; }
- ///
- /// Gets the new duration for this notification if mouse cursor is on the notification window.
- /// If set to or less, then this feature is turned off.
- ///
+ /// Gets the new duration for this notification if mouse cursor is on the notification window.
///
+ /// If set to or less, then this feature is turned off.
/// This property is applicable regardless of .
///
TimeSpan HoverExtendDuration { get; }
+
+ /// Gets the progress for the progress bar of the notification.
+ /// The progress should either be in the range between 0 and 1 or be a negative value.
+ /// Specifying a negative value will show an indeterminate progress bar.
+ float Progress { get; }
}
diff --git a/Dalamud/Interface/ImGuiNotification/Notification.cs b/Dalamud/Interface/ImGuiNotification/Notification.cs
index fb2caa4f6..ccfb250c3 100644
--- a/Dalamud/Interface/ImGuiNotification/Notification.cs
+++ b/Dalamud/Interface/ImGuiNotification/Notification.cs
@@ -28,8 +28,8 @@ public sealed record Notification : INotification
public bool Interactible { get; set; }
///
- public bool ClickIsDismiss { get; set; } = true;
+ public TimeSpan HoverExtendDuration { get; set; } = NotificationConstants.DefaultHoverExtendDuration;
///
- public TimeSpan HoverExtendDuration { get; set; } = NotificationConstants.DefaultHoverExtendDuration;
+ public float Progress { get; set; } = 1f;
}
diff --git a/Dalamud/Interface/Internal/Notifications/ActiveNotification.cs b/Dalamud/Interface/Internal/Notifications/ActiveNotification.cs
index 5c343288e..c1fecdd3b 100644
--- a/Dalamud/Interface/Internal/Notifications/ActiveNotification.cs
+++ b/Dalamud/Interface/Internal/Notifications/ActiveNotification.cs
@@ -20,19 +20,25 @@ using Serilog;
namespace Dalamud.Interface.Internal.Notifications;
-///
-/// Represents an active notification.
-///
+/// Represents an active notification.
internal sealed class ActiveNotification : IActiveNotification, IDisposable
{
+ private readonly Notification underlyingNotification;
+
private readonly Easing showEasing;
private readonly Easing hideEasing;
+ private readonly Easing progressEasing;
- private Notification underlyingNotification;
+ /// The progress before for the progress bar animation with .
+ private float progressBefore;
- ///
- /// Initializes a new instance of the class.
- ///
+ /// Used for calculating correct dismissal progressbar animation (left edge).
+ private float prevProgressL;
+
+ /// Used for calculating correct dismissal progressbar animation (right edge).
+ private float prevProgressR;
+
+ /// Initializes a new instance of the class.
/// The underlying notification.
/// The initiator plugin. Use null if originated by Dalamud.
public ActiveNotification(Notification underlyingNotification, LocalPlugin? initiatorPlugin)
@@ -41,8 +47,10 @@ internal sealed class ActiveNotification : IActiveNotification, IDisposable
this.InitiatorPlugin = initiatorPlugin;
this.showEasing = new InCubic(NotificationConstants.ShowAnimationDuration);
this.hideEasing = new OutCubic(NotificationConstants.HideAnimationDuration);
+ this.progressEasing = new InOutCubic(NotificationConstants.ProgressAnimationDuration);
this.showEasing.Start();
+ this.progressEasing.Start();
this.UpdateIcon();
}
@@ -64,39 +72,111 @@ internal sealed class ActiveNotification : IActiveNotification, IDisposable
///
public long Id { get; } = IActiveNotification.CreateNewId();
- ///
- /// Gets the time of creating this notification.
- ///
+ /// Gets the time of creating this notification.
public DateTime CreatedAt { get; } = DateTime.Now;
- ///
- /// Gets the time of starting to count the timer for the expiration.
- ///
+ /// Gets the time of starting to count the timer for the expiration.
public DateTime ExpiryRelativeToTime { get; private set; } = DateTime.Now;
- ///
- public string Content => this.underlyingNotification.Content;
+ ///
+ public string Content
+ {
+ get => this.underlyingNotification.Content;
+ set
+ {
+ if (this.IsDismissed)
+ return;
+ this.underlyingNotification.Content = value;
+ }
+ }
- ///
- public string? Title => this.underlyingNotification.Title;
+ ///
+ public string? Title
+ {
+ get => this.underlyingNotification.Title;
+ set
+ {
+ if (this.IsDismissed)
+ return;
+ this.underlyingNotification.Title = value;
+ }
+ }
- ///
- public NotificationType Type => this.underlyingNotification.Type;
+ ///
+ public NotificationType Type
+ {
+ get => this.underlyingNotification.Type;
+ set
+ {
+ if (this.IsDismissed)
+ return;
+ this.underlyingNotification.Type = value;
+ }
+ }
- ///
- public Func>? IconCreator => this.underlyingNotification.IconCreator;
+ ///
+ public Func>? IconCreator
+ {
+ get => this.underlyingNotification.IconCreator;
+ set
+ {
+ if (this.IsDismissed)
+ return;
+ this.underlyingNotification.IconCreator = value;
+ }
+ }
- ///
- public DateTime Expiry => this.underlyingNotification.Expiry;
+ ///
+ public DateTime Expiry
+ {
+ get => this.underlyingNotification.Expiry;
+ set
+ {
+ if (this.underlyingNotification.Expiry == value || this.IsDismissed)
+ return;
+ this.underlyingNotification.Expiry = value;
+ this.ExpiryRelativeToTime = DateTime.Now;
+ }
+ }
- ///
- public bool Interactible => this.underlyingNotification.Interactible;
+ ///
+ public bool Interactible
+ {
+ get => this.underlyingNotification.Interactible;
+ set
+ {
+ if (this.IsDismissed)
+ return;
+ this.underlyingNotification.Interactible = value;
+ }
+ }
- ///
- public bool ClickIsDismiss => this.underlyingNotification.ClickIsDismiss;
+ ///
+ public TimeSpan HoverExtendDuration
+ {
+ get => this.underlyingNotification.HoverExtendDuration;
+ set
+ {
+ if (this.IsDismissed)
+ return;
+ this.underlyingNotification.HoverExtendDuration = value;
+ }
+ }
- ///
- public TimeSpan HoverExtendDuration => this.underlyingNotification.HoverExtendDuration;
+ ///
+ public float Progress
+ {
+ get => this.underlyingNotification.Progress;
+ set
+ {
+ if (this.IsDismissed)
+ return;
+
+ this.progressBefore = this.ProgressEased;
+ this.underlyingNotification.Progress = value;
+ this.progressEasing.Restart();
+ }
+ }
///
public bool IsMouseHovered { get; private set; }
@@ -104,19 +184,32 @@ internal sealed class ActiveNotification : IActiveNotification, IDisposable
///
public bool IsDismissed => this.hideEasing.IsRunning;
- ///
- /// Gets or sets the plugin that initiated this notification.
- ///
+ /// Gets a value indicating whether has been unloaded.
+ public bool IsInitiatorUnloaded { get; private set; }
+
+ /// Gets or sets the plugin that initiated this notification.
public LocalPlugin? InitiatorPlugin { get; set; }
- ///
- /// Gets or sets the icon of this notification.
- ///
+ /// Gets or sets the icon of this notification.
public Task