notifcation refactor for better readability
This commit is contained in:
@@ -17,12 +17,15 @@ namespace LightlessSync.UI;
|
||||
|
||||
public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
{
|
||||
private const float NotificationMinHeight = 60f;
|
||||
private const float NotificationMaxHeight = 250f;
|
||||
private const float WindowPaddingOffset = 6f;
|
||||
private const float SlideAnimationDistance = 100f;
|
||||
private const float OutAnimationSpeedMultiplier = 0.7f;
|
||||
|
||||
private readonly List<LightlessNotification> _notifications = new();
|
||||
private readonly object _notificationLock = new();
|
||||
private readonly LightlessConfigService _configService;
|
||||
|
||||
private const float NotificationMinHeight = 60f;
|
||||
private const float NotificationMaxHeight = 250f;
|
||||
|
||||
public LightlessNotificationUI(ILogger<LightlessNotificationUI> logger, LightlessMediator mediator, PerformanceCollectorService performanceCollector, LightlessConfigService configService)
|
||||
: base(logger, mediator, "Lightless Notifications##LightlessNotifications", performanceCollector)
|
||||
@@ -49,15 +52,11 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
Mediator.Subscribe<LightlessNotificationMessage>(this, HandleNotificationMessage);
|
||||
Mediator.Subscribe<LightlessNotificationDismissMessage>(this, HandleNotificationDismissMessage);
|
||||
}
|
||||
private void HandleNotificationMessage(LightlessNotificationMessage message)
|
||||
{
|
||||
private void HandleNotificationMessage(LightlessNotificationMessage message) =>
|
||||
AddNotification(message.Notification);
|
||||
}
|
||||
|
||||
private void HandleNotificationDismissMessage(LightlessNotificationDismissMessage message)
|
||||
{
|
||||
private void HandleNotificationDismissMessage(LightlessNotificationDismissMessage message) =>
|
||||
RemoveNotification(message.NotificationId);
|
||||
}
|
||||
|
||||
public void AddNotification(LightlessNotification notification)
|
||||
{
|
||||
@@ -66,12 +65,7 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
var existingNotification = _notifications.FirstOrDefault(n => n.Id == notification.Id);
|
||||
if (existingNotification != null)
|
||||
{
|
||||
// Update existing notification without restarting animation
|
||||
existingNotification.Message = notification.Message;
|
||||
existingNotification.Progress = notification.Progress;
|
||||
existingNotification.ShowProgress = notification.ShowProgress;
|
||||
existingNotification.Title = notification.Title;
|
||||
_logger.LogDebug("Updated existing notification: {Title}", notification.Title);
|
||||
UpdateExistingNotification(existingNotification, notification);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -79,12 +73,18 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
_logger.LogDebug("Added new notification: {Title}", notification.Title);
|
||||
}
|
||||
|
||||
if (!IsOpen)
|
||||
{
|
||||
IsOpen = true;
|
||||
}
|
||||
if (!IsOpen) IsOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateExistingNotification(LightlessNotification existing, LightlessNotification updated)
|
||||
{
|
||||
existing.Message = updated.Message;
|
||||
existing.Progress = updated.Progress;
|
||||
existing.ShowProgress = updated.ShowProgress;
|
||||
existing.Title = updated.Title;
|
||||
_logger.LogDebug("Updated existing notification: {Title}", updated.Title);
|
||||
}
|
||||
|
||||
public void RemoveNotification(string id)
|
||||
{
|
||||
@@ -93,11 +93,16 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
var notification = _notifications.FirstOrDefault(n => n.Id == id);
|
||||
if (notification != null)
|
||||
{
|
||||
notification.IsAnimatingOut = true;
|
||||
notification.IsAnimatingIn = false;
|
||||
StartOutAnimation(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void StartOutAnimation(LightlessNotification notification)
|
||||
{
|
||||
notification.IsAnimatingOut = true;
|
||||
notification.IsAnimatingIn = false;
|
||||
}
|
||||
|
||||
protected override void DrawInternal()
|
||||
{
|
||||
@@ -115,35 +120,45 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
}
|
||||
|
||||
var viewport = ImGui.GetMainViewport();
|
||||
|
||||
// Always position at top (choco doesnt know how to handle top positions how fitting)
|
||||
var baseX = viewport.WorkPos.X + viewport.WorkSize.X - _configService.Current.NotificationWidth - _configService.Current.NotificationOffsetX - 6f ;
|
||||
var baseY = viewport.WorkPos.Y;
|
||||
|
||||
// Apply Y offset
|
||||
var finalY = baseY + _configService.Current.NotificationOffsetY;
|
||||
|
||||
// Update position
|
||||
Position = new Vector2(baseX, finalY);
|
||||
|
||||
for (int i = 0; i < _notifications.Count; i++)
|
||||
{
|
||||
DrawNotification(_notifications[i], i);
|
||||
|
||||
if (i < _notifications.Count - 1)
|
||||
{
|
||||
ImGui.Dummy(new Vector2(0, _configService.Current.NotificationSpacing));
|
||||
}
|
||||
}
|
||||
Position = CalculateWindowPosition(viewport);
|
||||
DrawAllNotifications();
|
||||
}
|
||||
|
||||
ImGui.PopStyleVar();
|
||||
}
|
||||
|
||||
private Vector2 CalculateWindowPosition(ImGuiViewportPtr viewport)
|
||||
{
|
||||
var x = viewport.WorkPos.X + viewport.WorkSize.X -
|
||||
_configService.Current.NotificationWidth -
|
||||
_configService.Current.NotificationOffsetX -
|
||||
WindowPaddingOffset;
|
||||
var y = viewport.WorkPos.Y + _configService.Current.NotificationOffsetY;
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
|
||||
private void DrawAllNotifications()
|
||||
{
|
||||
for (int i = 0; i < _notifications.Count; i++)
|
||||
{
|
||||
DrawNotification(_notifications[i], i);
|
||||
|
||||
if (i < _notifications.Count - 1)
|
||||
{
|
||||
ImGui.Dummy(new Vector2(0, _configService.Current.NotificationSpacing));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateNotifications()
|
||||
{
|
||||
var deltaTime = ImGui.GetIO().DeltaTime;
|
||||
|
||||
EnforceMaxNotificationLimit();
|
||||
UpdateAnimationsAndRemoveExpired(deltaTime);
|
||||
}
|
||||
|
||||
private void EnforceMaxNotificationLimit()
|
||||
{
|
||||
var maxNotifications = _configService.Current.MaxSimultaneousNotifications;
|
||||
while (_notifications.Count(n => !n.IsAnimatingOut) > maxNotifications)
|
||||
{
|
||||
@@ -151,60 +166,70 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
.Where(n => !n.IsAnimatingOut)
|
||||
.OrderBy(n => n.CreatedAt)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (oldestNotification != null)
|
||||
{
|
||||
oldestNotification.IsAnimatingOut = true;
|
||||
oldestNotification.IsAnimatingIn = false;
|
||||
StartOutAnimation(oldestNotification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAnimationsAndRemoveExpired(float deltaTime)
|
||||
{
|
||||
for (int i = _notifications.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var notification = _notifications[i];
|
||||
UpdateNotificationAnimation(notification, deltaTime);
|
||||
|
||||
if (notification.IsAnimatingIn && notification.AnimationProgress < 1f)
|
||||
{
|
||||
notification.AnimationProgress = Math.Min(1f, notification.AnimationProgress + deltaTime * _configService.Current.NotificationAnimationSpeed);
|
||||
}
|
||||
else if (notification.IsAnimatingOut && notification.AnimationProgress > 0f)
|
||||
{
|
||||
notification.AnimationProgress = Math.Max(0f, notification.AnimationProgress - deltaTime * (_configService.Current.NotificationAnimationSpeed * 0.7f));
|
||||
}
|
||||
else if (!notification.IsAnimatingOut && !notification.IsDismissed)
|
||||
{
|
||||
notification.IsAnimatingIn = false;
|
||||
|
||||
if (notification.IsExpired && !notification.IsAnimatingOut)
|
||||
{
|
||||
notification.IsAnimatingOut = true;
|
||||
notification.IsAnimatingIn = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (notification.IsAnimatingOut && notification.AnimationProgress <= 0.01f)
|
||||
if (ShouldRemoveNotification(notification))
|
||||
{
|
||||
_notifications.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateNotificationAnimation(LightlessNotification notification, float deltaTime)
|
||||
{
|
||||
if (notification.IsAnimatingIn && notification.AnimationProgress < 1f)
|
||||
{
|
||||
notification.AnimationProgress = Math.Min(1f,
|
||||
notification.AnimationProgress + deltaTime * _configService.Current.NotificationAnimationSpeed);
|
||||
}
|
||||
else if (notification.IsAnimatingOut && notification.AnimationProgress > 0f)
|
||||
{
|
||||
notification.AnimationProgress = Math.Max(0f,
|
||||
notification.AnimationProgress - deltaTime * _configService.Current.NotificationAnimationSpeed * OutAnimationSpeedMultiplier);
|
||||
}
|
||||
else if (!notification.IsAnimatingOut && !notification.IsDismissed)
|
||||
{
|
||||
notification.IsAnimatingIn = false;
|
||||
|
||||
if (notification.IsExpired)
|
||||
{
|
||||
StartOutAnimation(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldRemoveNotification(LightlessNotification notification) =>
|
||||
notification.IsAnimatingOut && notification.AnimationProgress <= 0.01f;
|
||||
|
||||
private void DrawNotification(LightlessNotification notification, int index)
|
||||
{
|
||||
var alpha = notification.AnimationProgress;
|
||||
|
||||
if (alpha <= 0f)
|
||||
return;
|
||||
|
||||
var slideOffset = (1f - alpha) * 100f; // Fixed slide distance
|
||||
if (alpha <= 0f) return;
|
||||
|
||||
var slideOffset = (1f - alpha) * SlideAnimationDistance;
|
||||
var originalCursorPos = ImGui.GetCursorPos();
|
||||
ImGui.SetCursorPosX(originalCursorPos.X + slideOffset);
|
||||
|
||||
var notificationHeight = CalculateNotificationHeight(notification);
|
||||
var notificationWidth = _configService.Current.NotificationWidth - slideOffset;
|
||||
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
|
||||
|
||||
using var child = ImRaii.Child($"notification_{notification.Id}",
|
||||
new Vector2(_configService.Current.NotificationWidth - slideOffset, notificationHeight),
|
||||
new Vector2(notificationWidth, notificationHeight),
|
||||
false, ImGuiWindowFlags.NoScrollbar);
|
||||
|
||||
if (child.Success)
|
||||
@@ -221,50 +246,69 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
var windowPos = ImGui.GetWindowPos();
|
||||
var windowSize = ImGui.GetWindowSize();
|
||||
|
||||
var bgColor = CalculateBackgroundColor(alpha, ImGui.IsWindowHovered());
|
||||
var accentColor = GetNotificationAccentColor(notification.Type);
|
||||
accentColor.W *= alpha;
|
||||
|
||||
DrawShadow(drawList, windowPos, windowSize, alpha);
|
||||
HandleClickToDismiss(notification);
|
||||
DrawBackground(drawList, windowPos, windowSize, bgColor);
|
||||
DrawAccentBar(drawList, windowPos, windowSize, accentColor);
|
||||
DrawDurationProgressBar(notification, alpha, windowPos, windowSize, drawList);
|
||||
DrawNotificationText(notification, alpha);
|
||||
}
|
||||
|
||||
private Vector4 CalculateBackgroundColor(float alpha, bool isHovered)
|
||||
{
|
||||
var baseOpacity = _configService.Current.NotificationOpacity;
|
||||
var finalOpacity = baseOpacity * alpha;
|
||||
var bgColor = new Vector4(30f/255f, 30f/255f, 30f/255f, finalOpacity);
|
||||
var accentColor = GetNotificationAccentColor(notification.Type);
|
||||
var progressBarColor = UIColors.Get("LightlessBlue");
|
||||
|
||||
accentColor.W *= alpha;
|
||||
if (isHovered)
|
||||
{
|
||||
bgColor *= 1.1f;
|
||||
bgColor.W = Math.Min(bgColor.W, 0.98f);
|
||||
}
|
||||
|
||||
// Draw shadow with fixed intensity
|
||||
return bgColor;
|
||||
}
|
||||
|
||||
private void DrawShadow(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, float alpha)
|
||||
{
|
||||
var shadowOffset = new Vector2(1f, 1f);
|
||||
var shadowAlpha = 0.4f * alpha;
|
||||
var shadowColor = new Vector4(0f, 0f, 0f, shadowAlpha);
|
||||
var shadowColor = new Vector4(0f, 0f, 0f, 0.4f * alpha);
|
||||
drawList.AddRectFilled(
|
||||
windowPos + shadowOffset,
|
||||
windowPos + windowSize + shadowOffset,
|
||||
ImGui.ColorConvertFloat4ToU32(shadowColor),
|
||||
3f
|
||||
);
|
||||
|
||||
var isHovered = ImGui.IsWindowHovered();
|
||||
|
||||
if (isHovered)
|
||||
}
|
||||
|
||||
private void HandleClickToDismiss(LightlessNotification notification)
|
||||
{
|
||||
if (ImGui.IsWindowHovered() &&
|
||||
_configService.Current.DismissNotificationOnClick &&
|
||||
!notification.Actions.Any() &&
|
||||
ImGui.IsMouseClicked(ImGuiMouseButton.Left))
|
||||
{
|
||||
bgColor = bgColor * 1.1f;
|
||||
bgColor.W = Math.Min(bgColor.W, 0.98f);
|
||||
|
||||
// Handle click-to-dismiss for notifications without actions
|
||||
if (_configService.Current.DismissNotificationOnClick &&
|
||||
!notification.Actions.Any() &&
|
||||
ImGui.IsMouseClicked(ImGuiMouseButton.Left))
|
||||
{
|
||||
notification.IsDismissed = true;
|
||||
notification.IsAnimatingOut = true;
|
||||
}
|
||||
notification.IsDismissed = true;
|
||||
StartOutAnimation(notification);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void DrawBackground(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, Vector4 bgColor)
|
||||
{
|
||||
drawList.AddRectFilled(
|
||||
windowPos,
|
||||
windowPos + windowSize,
|
||||
ImGui.ColorConvertFloat4ToU32(bgColor),
|
||||
3f
|
||||
);
|
||||
|
||||
// Draw accent bar on left side of the notif (only if width > 0)
|
||||
}
|
||||
|
||||
private void DrawAccentBar(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, Vector4 accentColor)
|
||||
{
|
||||
var accentWidth = _configService.Current.NotificationAccentBarWidth;
|
||||
if (accentWidth > 0f)
|
||||
{
|
||||
@@ -275,30 +319,37 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
3f
|
||||
);
|
||||
}
|
||||
|
||||
DrawDurationProgressBar(notification, alpha, windowPos, windowSize, progressBarColor, drawList);
|
||||
|
||||
DrawNotificationText(notification, alpha);
|
||||
}
|
||||
|
||||
private void DrawDurationProgressBar(LightlessNotification notification, float alpha, Vector2 windowPos, Vector2 windowSize, Vector4 progressBarColor, ImDrawListPtr drawList)
|
||||
private void DrawDurationProgressBar(LightlessNotification notification, float alpha, Vector2 windowPos, Vector2 windowSize, ImDrawListPtr drawList)
|
||||
{
|
||||
// For download notifications, use download progress instead of duration
|
||||
float progress;
|
||||
if (notification.Type == NotificationType.Download && notification.ShowProgress)
|
||||
{
|
||||
progress = Math.Clamp(notification.Progress, 0f, 1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
var elapsed = DateTime.UtcNow - notification.CreatedAt;
|
||||
progress = Math.Min(1.0f, (float)(elapsed.TotalSeconds / notification.Duration.TotalSeconds));
|
||||
}
|
||||
|
||||
var progress = CalculateProgress(notification);
|
||||
var progressBarColor = UIColors.Get("LightlessBlue");
|
||||
var progressHeight = 2f;
|
||||
var progressY = windowPos.Y + windowSize.Y - progressHeight;
|
||||
var progressWidth = windowSize.X * progress;
|
||||
|
||||
DrawProgressBackground(drawList, windowPos, windowSize, progressY, progressHeight, progressBarColor, alpha);
|
||||
|
||||
if (progress > 0)
|
||||
{
|
||||
DrawProgressForeground(drawList, windowPos, progressY, progressHeight, progressWidth, progressBarColor, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
private float CalculateProgress(LightlessNotification notification)
|
||||
{
|
||||
if (notification.Type == NotificationType.Download && notification.ShowProgress)
|
||||
{
|
||||
return Math.Clamp(notification.Progress, 0f, 1f);
|
||||
}
|
||||
|
||||
var elapsed = DateTime.UtcNow - notification.CreatedAt;
|
||||
return Math.Min(1.0f, (float)(elapsed.TotalSeconds / notification.Duration.TotalSeconds));
|
||||
}
|
||||
|
||||
private void DrawProgressBackground(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, float progressY, float progressHeight, Vector4 progressBarColor, float alpha)
|
||||
{
|
||||
var bgProgressColor = new Vector4(progressBarColor.X * 0.3f, progressBarColor.Y * 0.3f, progressBarColor.Z * 0.3f, 0.5f * alpha);
|
||||
drawList.AddRectFilled(
|
||||
new Vector2(windowPos.X, progressY),
|
||||
@@ -306,71 +357,70 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
ImGui.ColorConvertFloat4ToU32(bgProgressColor),
|
||||
0f
|
||||
);
|
||||
|
||||
if (progress > 0)
|
||||
{
|
||||
var progressColor = progressBarColor;
|
||||
progressColor.W *= alpha;
|
||||
drawList.AddRectFilled(
|
||||
new Vector2(windowPos.X, progressY),
|
||||
new Vector2(windowPos.X + progressWidth, progressY + progressHeight),
|
||||
ImGui.ColorConvertFloat4ToU32(progressColor),
|
||||
0f
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawProgressForeground(ImDrawListPtr drawList, Vector2 windowPos, float progressY, float progressHeight, float progressWidth, Vector4 progressBarColor, float alpha)
|
||||
{
|
||||
var progressColor = progressBarColor;
|
||||
progressColor.W *= alpha;
|
||||
drawList.AddRectFilled(
|
||||
new Vector2(windowPos.X, progressY),
|
||||
new Vector2(windowPos.X + progressWidth, progressY + progressHeight),
|
||||
ImGui.ColorConvertFloat4ToU32(progressColor),
|
||||
0f
|
||||
);
|
||||
}
|
||||
|
||||
private void DrawNotificationText(LightlessNotification notification, float alpha)
|
||||
{
|
||||
var padding = new Vector2(10f, 6f);
|
||||
|
||||
var contentPos = new Vector2(padding.X, padding.Y);
|
||||
var windowSize = ImGui.GetWindowSize();
|
||||
var contentSize = new Vector2(windowSize.X - padding.X, windowSize.Y - padding.Y * 2);
|
||||
|
||||
ImGui.SetCursorPos(contentPos);
|
||||
|
||||
float titleHeight = 0f;
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, new Vector4(1f, 1f, 1f, alpha)))
|
||||
{
|
||||
// Set text wrap position to prevent title overflow
|
||||
ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + contentSize.X);
|
||||
|
||||
var titleStartY = ImGui.GetCursorPosY();
|
||||
|
||||
if (_configService.Current.ShowNotificationTimestamp)
|
||||
{
|
||||
var timestamp = notification.CreatedAt.ToLocalTime().ToString("HH:mm:ss");
|
||||
ImGui.TextWrapped($"[{timestamp}] {notification.Title}");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TextWrapped(notification.Title);
|
||||
}
|
||||
|
||||
titleHeight = ImGui.GetCursorPosY() - titleStartY;
|
||||
ImGui.PopTextWrapPos();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(notification.Message))
|
||||
{
|
||||
ImGui.SetCursorPos(contentPos + new Vector2(0f, titleHeight + 4f));
|
||||
ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + contentSize.X);
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, new Vector4(0.9f, 0.9f, 0.9f, alpha)))
|
||||
{
|
||||
ImGui.TextWrapped(notification.Message);
|
||||
}
|
||||
ImGui.PopTextWrapPos();
|
||||
}
|
||||
var titleHeight = DrawTitle(notification, contentSize.X, alpha);
|
||||
DrawMessage(notification, contentPos, contentSize.X, titleHeight, alpha);
|
||||
|
||||
if (notification.Actions.Count > 0)
|
||||
{
|
||||
var spacingHeight = ImGui.GetStyle().ItemSpacing.Y;
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + spacingHeight);
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetStyle().ItemSpacing.Y);
|
||||
ImGui.SetCursorPosX(contentPos.X);
|
||||
DrawNotificationActions(notification, contentSize.X, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
private float DrawTitle(LightlessNotification notification, float contentWidth, float alpha)
|
||||
{
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, new Vector4(1f, 1f, 1f, alpha)))
|
||||
{
|
||||
ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + contentWidth);
|
||||
var titleStartY = ImGui.GetCursorPosY();
|
||||
|
||||
var titleText = _configService.Current.ShowNotificationTimestamp
|
||||
? $"[{notification.CreatedAt.ToLocalTime():HH:mm:ss}] {notification.Title}"
|
||||
: notification.Title;
|
||||
|
||||
ImGui.TextWrapped(titleText);
|
||||
var titleHeight = ImGui.GetCursorPosY() - titleStartY;
|
||||
ImGui.PopTextWrapPos();
|
||||
return titleHeight;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawMessage(LightlessNotification notification, Vector2 contentPos, float contentWidth, float titleHeight, float alpha)
|
||||
{
|
||||
if (string.IsNullOrEmpty(notification.Message)) return;
|
||||
|
||||
ImGui.SetCursorPos(contentPos + new Vector2(0f, titleHeight + 4f));
|
||||
ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + contentWidth);
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, new Vector4(0.9f, 0.9f, 0.9f, alpha)))
|
||||
{
|
||||
ImGui.TextWrapped(notification.Message);
|
||||
}
|
||||
ImGui.PopTextWrapPos();
|
||||
}
|
||||
|
||||
private void DrawNotificationActions(LightlessNotification notification, float availableWidth, float alpha)
|
||||
{
|
||||
@@ -495,44 +545,43 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
|
||||
private float CalculateNotificationHeight(LightlessNotification notification)
|
||||
{
|
||||
var contentWidth = _configService.Current.NotificationWidth - 35f; // Account for padding and accent bar
|
||||
var height = 12f; // Base height for padding (top + bottom)
|
||||
var contentWidth = _configService.Current.NotificationWidth - 35f;
|
||||
var height = 12f;
|
||||
|
||||
var titleText = notification.Title;
|
||||
if (_configService.Current.ShowNotificationTimestamp)
|
||||
{
|
||||
var timestamp = notification.CreatedAt.ToLocalTime().ToString("HH:mm:ss");
|
||||
titleText = $"[{timestamp}] {titleText}";
|
||||
}
|
||||
height += CalculateTitleHeight(notification, contentWidth);
|
||||
height += CalculateMessageHeight(notification, contentWidth);
|
||||
|
||||
var titleSize = ImGui.CalcTextSize(titleText, true, contentWidth);
|
||||
height += titleSize.Y; // Title height
|
||||
|
||||
// Calculate message height
|
||||
if (!string.IsNullOrEmpty(notification.Message))
|
||||
{
|
||||
height += 4f; // Spacing between title and message
|
||||
var messageSize = ImGui.CalcTextSize(notification.Message, true, contentWidth); // This is cringe
|
||||
height += messageSize.Y; // Message height
|
||||
}
|
||||
|
||||
// Add height for progress bar
|
||||
if (notification.ShowProgress)
|
||||
{
|
||||
height += 12f;
|
||||
}
|
||||
|
||||
// Add height for action buttons
|
||||
if (notification.Actions.Count > 0)
|
||||
{
|
||||
height += ImGui.GetStyle().ItemSpacing.Y; // Spacing before buttons
|
||||
height += ImGui.GetFrameHeight(); // Button height
|
||||
height += 12f; // Bottom padding for buttons
|
||||
height += ImGui.GetStyle().ItemSpacing.Y;
|
||||
height += ImGui.GetFrameHeight();
|
||||
height += 12f;
|
||||
}
|
||||
|
||||
// Allow notifications to grow taller but cap at maximum height
|
||||
return Math.Clamp(height, NotificationMinHeight, NotificationMaxHeight);
|
||||
}
|
||||
|
||||
private float CalculateTitleHeight(LightlessNotification notification, float contentWidth)
|
||||
{
|
||||
var titleText = _configService.Current.ShowNotificationTimestamp
|
||||
? $"[{notification.CreatedAt.ToLocalTime():HH:mm:ss}] {notification.Title}"
|
||||
: notification.Title;
|
||||
|
||||
return ImGui.CalcTextSize(titleText, true, contentWidth).Y;
|
||||
}
|
||||
|
||||
private float CalculateMessageHeight(LightlessNotification notification, float contentWidth)
|
||||
{
|
||||
if (string.IsNullOrEmpty(notification.Message)) return 0f;
|
||||
|
||||
var messageHeight = ImGui.CalcTextSize(notification.Message, true, contentWidth).Y;
|
||||
return 4f + messageHeight;
|
||||
}
|
||||
|
||||
private Vector4 GetNotificationAccentColor(NotificationType type)
|
||||
{
|
||||
|
||||
@@ -15,12 +15,9 @@ public class LightlessNotification
|
||||
public List<LightlessNotificationAction> Actions { get; set; } = new();
|
||||
public bool ShowProgress { get; set; } = false;
|
||||
public float Progress { get; set; } = 0f;
|
||||
public bool IsMinimized { get; set; } = false;
|
||||
public float AnimationProgress { get; set; } = 0f;
|
||||
public bool IsAnimatingIn { get; set; } = true;
|
||||
public bool IsAnimatingOut { get; set; } = false;
|
||||
|
||||
// Sound properties
|
||||
public uint? SoundEffectId { get; set; } = null;
|
||||
}
|
||||
public class LightlessNotificationAction
|
||||
|
||||
Reference in New Issue
Block a user