more to notification system with new settings tab
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Plugin.Services;
|
||||
using LightlessSync.LightlessConfiguration;
|
||||
using LightlessSync.LightlessConfiguration.Models;
|
||||
@@ -8,6 +10,7 @@ using LightlessSync.UI.Models;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using NotificationType = LightlessSync.LightlessConfiguration.Models.NotificationType;
|
||||
|
||||
namespace LightlessSync.Services;
|
||||
public class LightlessNotificationService : DisposableMediatorSubscriberBase, IHostedService
|
||||
@@ -15,19 +18,26 @@ public class LightlessNotificationService : DisposableMediatorSubscriberBase, IH
|
||||
private readonly ILogger<LightlessNotificationService> _logger;
|
||||
private readonly LightlessConfigService _configService;
|
||||
private readonly DalamudUtilService _dalamudUtilService;
|
||||
private readonly INotificationManager _notificationManager;
|
||||
private readonly IChatGui _chatGui;
|
||||
private LightlessNotificationUI? _notificationUI;
|
||||
public LightlessNotificationService(
|
||||
ILogger<LightlessNotificationService> logger,
|
||||
LightlessConfigService configService,
|
||||
DalamudUtilService dalamudUtilService,
|
||||
INotificationManager notificationManager,
|
||||
IChatGui chatGui,
|
||||
LightlessMediator mediator) : base(logger, mediator)
|
||||
{
|
||||
_logger = logger;
|
||||
_configService = configService;
|
||||
_dalamudUtilService = dalamudUtilService;
|
||||
_notificationManager = notificationManager;
|
||||
_chatGui = chatGui;
|
||||
}
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
Mediator.Subscribe<NotificationMessage>(this, HandleNotificationMessage);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
@@ -46,12 +56,31 @@ public class LightlessNotificationService : DisposableMediatorSubscriberBase, IH
|
||||
Title = title,
|
||||
Message = message,
|
||||
Type = type,
|
||||
Duration = duration ?? TimeSpan.FromSeconds(10),
|
||||
Duration = duration ?? TimeSpan.FromSeconds(_configService.Current.DefaultNotificationDurationSeconds),
|
||||
Actions = actions ?? new List<LightlessNotificationAction>(),
|
||||
SoundEffectId = soundEffectId ?? NotificationSounds.GetDefaultSound(type)
|
||||
SoundEffectId = GetSoundEffectId(type, soundEffectId),
|
||||
ShowProgress = _configService.Current.ShowNotificationProgress,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
if (notification.SoundEffectId.HasValue)
|
||||
if (_configService.Current.AutoDismissOnAction && notification.Actions.Any())
|
||||
{
|
||||
foreach (var action in notification.Actions)
|
||||
{
|
||||
var originalOnClick = action.OnClick;
|
||||
action.OnClick = (n) =>
|
||||
{
|
||||
originalOnClick(n);
|
||||
if (_configService.Current.AutoDismissOnAction)
|
||||
{
|
||||
n.IsDismissed = true;
|
||||
n.IsAnimatingOut = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (notification.SoundEffectId.HasValue && _configService.Current.EnableNotificationSounds)
|
||||
{
|
||||
PlayNotificationSound(notification.SoundEffectId.Value);
|
||||
}
|
||||
@@ -101,18 +130,18 @@ public class LightlessNotificationService : DisposableMediatorSubscriberBase, IH
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
if (notification.SoundEffectId.HasValue)
|
||||
{
|
||||
PlayNotificationSound(notification.SoundEffectId.Value);
|
||||
}
|
||||
|
||||
|
||||
Mediator.Publish(new LightlessNotificationMessage(notification));
|
||||
}
|
||||
public void ShowDownloadCompleteNotification(string fileName, int fileCount, Action? onOpenFolder = null)
|
||||
{
|
||||
var actions = new List<LightlessNotificationAction>();
|
||||
|
||||
|
||||
if (onOpenFolder != null)
|
||||
{
|
||||
actions.Add(new LightlessNotificationAction
|
||||
@@ -132,20 +161,20 @@ public class LightlessNotificationService : DisposableMediatorSubscriberBase, IH
|
||||
var notification = new LightlessNotification
|
||||
{
|
||||
Title = "Download Complete",
|
||||
Message = fileCount > 1 ?
|
||||
$"Downloaded {fileCount} files successfully." :
|
||||
Message = fileCount > 1 ?
|
||||
$"Downloaded {fileCount} files successfully." :
|
||||
$"Downloaded {fileName} successfully.",
|
||||
Type = NotificationType.Info,
|
||||
Duration = TimeSpan.FromSeconds(8),
|
||||
Actions = actions,
|
||||
SoundEffectId = NotificationSounds.DownloadComplete
|
||||
};
|
||||
|
||||
|
||||
if (notification.SoundEffectId.HasValue)
|
||||
{
|
||||
PlayNotificationSound(notification.SoundEffectId.Value);
|
||||
}
|
||||
|
||||
|
||||
Mediator.Publish(new LightlessNotificationMessage(notification));
|
||||
}
|
||||
public void ShowErrorNotification(string title, string message, Exception? exception = null, Action? onRetry = null, Action? onViewLog = null)
|
||||
@@ -187,40 +216,40 @@ public class LightlessNotificationService : DisposableMediatorSubscriberBase, IH
|
||||
Actions = actions,
|
||||
SoundEffectId = NotificationSounds.Error
|
||||
};
|
||||
|
||||
|
||||
if (notification.SoundEffectId.HasValue)
|
||||
{
|
||||
PlayNotificationSound(notification.SoundEffectId.Value);
|
||||
}
|
||||
|
||||
|
||||
Mediator.Publish(new LightlessNotificationMessage(notification));
|
||||
}
|
||||
public void ShowPairDownloadNotification(List<(string playerName, float progress, string status)> downloadStatus, int queueWaiting = 0)
|
||||
{
|
||||
var userDownloads = downloadStatus.Where(x => x.playerName != "Pair Queue").ToList();
|
||||
|
||||
|
||||
var totalProgress = userDownloads.Count > 0 ? userDownloads.Average(x => x.progress) : 0f;
|
||||
var completedCount = userDownloads.Count(x => x.progress >= 1.0f);
|
||||
var totalCount = userDownloads.Count;
|
||||
|
||||
|
||||
var message = "";
|
||||
|
||||
|
||||
if (queueWaiting > 0)
|
||||
{
|
||||
message = $"Queue: {queueWaiting} waiting";
|
||||
}
|
||||
|
||||
|
||||
if (totalCount > 0)
|
||||
{
|
||||
var progressMessage = $"Progress: {completedCount}/{totalCount} completed";
|
||||
message = string.IsNullOrEmpty(message) ? progressMessage : $"{message}\n{progressMessage}";
|
||||
}
|
||||
|
||||
|
||||
if (userDownloads.Any(x => x.progress < 1.0f))
|
||||
{
|
||||
var maxNamesToShow = _configService.Current.MaxConcurrentPairApplications;
|
||||
var activeDownloads = userDownloads.Where(x => x.progress < 1.0f).Take(maxNamesToShow);
|
||||
var downloadLines = string.Join("\n", activeDownloads.Select(x =>
|
||||
var downloadLines = string.Join("\n", activeDownloads.Select(x =>
|
||||
{
|
||||
var statusText = x.status switch
|
||||
{
|
||||
@@ -232,12 +261,12 @@ public class LightlessNotificationService : DisposableMediatorSubscriberBase, IH
|
||||
};
|
||||
return $"• {x.playerName}: {statusText}";
|
||||
}));
|
||||
|
||||
|
||||
message += string.IsNullOrEmpty(message) ? downloadLines : $"\n{downloadLines}";
|
||||
}
|
||||
|
||||
|
||||
var allDownloadsCompleted = userDownloads.All(x => x.progress >= 1.0f) && userDownloads.Any();
|
||||
|
||||
|
||||
var notification = new LightlessNotification
|
||||
{
|
||||
Id = "pair_download_progress",
|
||||
@@ -251,15 +280,37 @@ public class LightlessNotificationService : DisposableMediatorSubscriberBase, IH
|
||||
Mediator.Publish(new LightlessNotificationMessage(notification));
|
||||
if (allDownloadsCompleted)
|
||||
{
|
||||
DismissPairDownloadNotification();
|
||||
DismissPairDownloadNotification();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void DismissPairDownloadNotification()
|
||||
{
|
||||
Mediator.Publish(new LightlessNotificationDismissMessage("pair_download_progress"));
|
||||
}
|
||||
|
||||
|
||||
private uint? GetSoundEffectId(NotificationType type, uint? overrideSoundId)
|
||||
{
|
||||
if (!_configService.Current.EnableNotificationSounds)
|
||||
return null;
|
||||
|
||||
if (overrideSoundId.HasValue)
|
||||
return overrideSoundId;
|
||||
|
||||
if (_configService.Current.UseCustomSounds)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
NotificationType.Info => _configService.Current.CustomInfoSoundId,
|
||||
NotificationType.Warning => _configService.Current.CustomWarningSoundId,
|
||||
NotificationType.Error => _configService.Current.CustomErrorSoundId,
|
||||
_ => NotificationSounds.GetDefaultSound(type)
|
||||
};
|
||||
}
|
||||
|
||||
return NotificationSounds.GetDefaultSound(type);
|
||||
}
|
||||
|
||||
private void PlayNotificationSound(uint soundEffectId)
|
||||
{
|
||||
try
|
||||
@@ -279,4 +330,172 @@ public class LightlessNotificationService : DisposableMediatorSubscriberBase, IH
|
||||
_logger.LogWarning(ex, "Failed to play notification sound effect {SoundId}", soundEffectId);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleNotificationMessage(NotificationMessage msg)
|
||||
{
|
||||
_logger.LogInformation("{msg}", msg.ToString());
|
||||
|
||||
if (!_dalamudUtilService.IsLoggedIn) return;
|
||||
|
||||
// Get both old and new notification locations
|
||||
var oldLocation = msg.Type switch
|
||||
{
|
||||
NotificationType.Info => _configService.Current.InfoNotification,
|
||||
NotificationType.Warning => _configService.Current.WarningNotification,
|
||||
NotificationType.Error => _configService.Current.ErrorNotification,
|
||||
_ => NotificationLocation.Nowhere
|
||||
};
|
||||
|
||||
var newLocation = msg.Type switch
|
||||
{
|
||||
NotificationType.Info => _configService.Current.LightlessInfoNotification,
|
||||
NotificationType.Warning => _configService.Current.LightlessWarningNotification,
|
||||
NotificationType.Error => _configService.Current.LightlessErrorNotification,
|
||||
_ => NotificationLocation.LightlessUI
|
||||
};
|
||||
|
||||
// Show notifications based on system selection with backwards compatibility
|
||||
if (!_configService.Current.UseLightlessNotifications)
|
||||
{
|
||||
// Only use old system when new system is disabled
|
||||
ShowNotificationLocationBased(msg, oldLocation);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use new enhanced system as primary
|
||||
ShowNotificationLocationBased(msg, newLocation);
|
||||
|
||||
// Also use old system as fallback for backwards compatibility
|
||||
// Only if it's different from the new location and not "Nowhere"
|
||||
if (oldLocation != NotificationLocation.Nowhere &&
|
||||
oldLocation != newLocation &&
|
||||
!IsLightlessLocation(oldLocation))
|
||||
{
|
||||
ShowNotificationLocationBased(msg, oldLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowNotificationLocationBased(NotificationMessage msg, NotificationLocation location)
|
||||
{
|
||||
switch (location)
|
||||
{
|
||||
case NotificationLocation.Toast:
|
||||
ShowToast(msg);
|
||||
break;
|
||||
|
||||
case NotificationLocation.Chat:
|
||||
ShowChat(msg);
|
||||
break;
|
||||
|
||||
case NotificationLocation.Both:
|
||||
ShowToast(msg);
|
||||
ShowChat(msg);
|
||||
break;
|
||||
|
||||
case NotificationLocation.LightlessUI:
|
||||
ShowLightlessNotification(msg);
|
||||
break;
|
||||
|
||||
case NotificationLocation.ChatAndLightlessUI:
|
||||
ShowChat(msg);
|
||||
ShowLightlessNotification(msg);
|
||||
break;
|
||||
|
||||
case NotificationLocation.Nowhere:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowLightlessNotification(NotificationMessage msg)
|
||||
{
|
||||
var duration = msg.TimeShownOnScreen ?? TimeSpan.FromSeconds(_configService.Current.DefaultNotificationDurationSeconds);
|
||||
uint? soundId = null;
|
||||
|
||||
if (_configService.Current.EnableNotificationSounds)
|
||||
{
|
||||
if (_configService.Current.UseCustomSounds)
|
||||
{
|
||||
soundId = msg.Type switch
|
||||
{
|
||||
NotificationType.Info => _configService.Current.CustomInfoSoundId,
|
||||
NotificationType.Warning => _configService.Current.CustomWarningSoundId,
|
||||
NotificationType.Error => _configService.Current.CustomErrorSoundId,
|
||||
_ => NotificationSounds.GetDefaultSound(msg.Type)
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
soundId = NotificationSounds.GetDefaultSound(msg.Type);
|
||||
}
|
||||
}
|
||||
|
||||
ShowNotification(msg.Title ?? "Lightless Sync", msg.Message ?? string.Empty, msg.Type, duration, null, soundId);
|
||||
}
|
||||
|
||||
private void ShowToast(NotificationMessage msg)
|
||||
{
|
||||
Dalamud.Interface.ImGuiNotification.NotificationType dalamudType = msg.Type switch
|
||||
{
|
||||
NotificationType.Error => Dalamud.Interface.ImGuiNotification.NotificationType.Error,
|
||||
NotificationType.Warning => Dalamud.Interface.ImGuiNotification.NotificationType.Warning,
|
||||
NotificationType.Info => Dalamud.Interface.ImGuiNotification.NotificationType.Info,
|
||||
_ => Dalamud.Interface.ImGuiNotification.NotificationType.Info
|
||||
};
|
||||
|
||||
_notificationManager.AddNotification(new Notification()
|
||||
{
|
||||
Content = msg.Message ?? string.Empty,
|
||||
Title = msg.Title,
|
||||
Type = dalamudType,
|
||||
Minimized = false,
|
||||
InitialDuration = msg.TimeShownOnScreen ?? TimeSpan.FromSeconds(3)
|
||||
});
|
||||
}
|
||||
|
||||
private void ShowChat(NotificationMessage msg)
|
||||
{
|
||||
switch (msg.Type)
|
||||
{
|
||||
case NotificationType.Info:
|
||||
PrintInfoChat(msg.Message);
|
||||
break;
|
||||
|
||||
case NotificationType.Warning:
|
||||
PrintWarnChat(msg.Message);
|
||||
break;
|
||||
|
||||
case NotificationType.Error:
|
||||
PrintErrorChat(msg.Message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintErrorChat(string? message)
|
||||
{
|
||||
SeStringBuilder se = new SeStringBuilder().AddText("[Lightless Sync] Error: " + message);
|
||||
_chatGui.PrintError(se.BuiltString);
|
||||
}
|
||||
|
||||
private void PrintInfoChat(string? message)
|
||||
{
|
||||
SeStringBuilder se = new SeStringBuilder().AddText("[Lightless Sync] Info: ").AddItalics(message ?? string.Empty);
|
||||
_chatGui.Print(se.BuiltString);
|
||||
}
|
||||
|
||||
private void PrintWarnChat(string? message)
|
||||
{
|
||||
SeStringBuilder se = new SeStringBuilder().AddText("[Lightless Sync] ").AddUiForeground("Warning: " + (message ?? string.Empty), 31).AddUiForegroundOff();
|
||||
_chatGui.Print(se.BuiltString);
|
||||
}
|
||||
|
||||
private bool IsLightlessLocation(NotificationLocation location)
|
||||
{
|
||||
return location switch
|
||||
{
|
||||
NotificationLocation.LightlessUI => true,
|
||||
NotificationLocation.ChatAndLightlessUI => true,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user