added notification system for file downloads and pair requests
This commit is contained in:
212
LightlessSync/Services/LightlessNotificationService.cs
Normal file
212
LightlessSync/Services/LightlessNotificationService.cs
Normal file
@@ -0,0 +1,212 @@
|
||||
using Dalamud.Interface;
|
||||
using LightlessSync.LightlessConfiguration;
|
||||
using LightlessSync.LightlessConfiguration.Models;
|
||||
using LightlessSync.Services.Mediator;
|
||||
using LightlessSync.UI;
|
||||
using LightlessSync.UI.Models;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Numerics;
|
||||
namespace LightlessSync.Services;
|
||||
public class LightlessNotificationService : DisposableMediatorSubscriberBase, IHostedService
|
||||
{
|
||||
private readonly ILogger<LightlessNotificationService> _logger;
|
||||
private readonly LightlessConfigService _configService;
|
||||
private readonly DalamudUtilService _dalamudUtilService;
|
||||
private LightlessNotificationUI? _notificationUI;
|
||||
public LightlessNotificationService(
|
||||
ILogger<LightlessNotificationService> logger,
|
||||
LightlessConfigService configService,
|
||||
DalamudUtilService dalamudUtilService,
|
||||
LightlessMediator mediator) : base(logger, mediator)
|
||||
{
|
||||
_logger = logger;
|
||||
_configService = configService;
|
||||
_dalamudUtilService = dalamudUtilService;
|
||||
}
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
public void SetNotificationUI(LightlessNotificationUI notificationUI)
|
||||
{
|
||||
_notificationUI = notificationUI;
|
||||
}
|
||||
public void ShowNotification(string title, string message, NotificationType type = NotificationType.Info,
|
||||
TimeSpan? duration = null, List<LightlessNotificationAction>? actions = null)
|
||||
{
|
||||
var notification = new LightlessNotification
|
||||
{
|
||||
Title = title,
|
||||
Message = message,
|
||||
Type = type,
|
||||
Duration = duration ?? TimeSpan.FromSeconds(10),
|
||||
Actions = actions ?? new List<LightlessNotificationAction>()
|
||||
};
|
||||
Mediator.Publish(new LightlessNotificationMessage(notification));
|
||||
}
|
||||
public void ShowPairRequestNotification(string senderName, string senderId, Action onAccept, Action onDecline)
|
||||
{
|
||||
var notification = new LightlessNotification
|
||||
{
|
||||
Title = "Pair Request Received",
|
||||
Message = $"{senderName} wants to pair with you.",
|
||||
Type = NotificationType.Info,
|
||||
Duration = TimeSpan.FromSeconds(60),
|
||||
Actions = new List<LightlessNotificationAction>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Id = "accept",
|
||||
Label = "Accept",
|
||||
Icon = FontAwesomeIcon.Check,
|
||||
Color = UIColors.Get("LightlessGreen"),
|
||||
IsPrimary = true,
|
||||
OnClick = (n) =>
|
||||
{
|
||||
_logger.LogInformation("Pair request accepted");
|
||||
onAccept();
|
||||
n.IsDismissed = true;
|
||||
n.IsAnimatingOut = true;
|
||||
}
|
||||
},
|
||||
new()
|
||||
{
|
||||
Id = "decline",
|
||||
Label = "Decline",
|
||||
Icon = FontAwesomeIcon.Times,
|
||||
Color = UIColors.Get("DimRed"),
|
||||
IsDestructive = true,
|
||||
OnClick = (n) =>
|
||||
{
|
||||
_logger.LogInformation("Pair request declined");
|
||||
onDecline();
|
||||
n.IsDismissed = true;
|
||||
n.IsAnimatingOut = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
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
|
||||
{
|
||||
Id = "open_folder",
|
||||
Label = "Open Folder",
|
||||
Icon = FontAwesomeIcon.FolderOpen,
|
||||
Color = UIColors.Get("LightlessBlue"),
|
||||
OnClick = (n) =>
|
||||
{
|
||||
onOpenFolder();
|
||||
n.IsDismissed = true;
|
||||
n.IsAnimatingOut = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
var notification = new LightlessNotification
|
||||
{
|
||||
Title = "Download Complete",
|
||||
Message = fileCount > 1 ?
|
||||
$"Downloaded {fileCount} files successfully." :
|
||||
$"Downloaded {fileName} successfully.",
|
||||
Type = NotificationType.Info,
|
||||
Duration = TimeSpan.FromSeconds(8),
|
||||
Actions = actions
|
||||
};
|
||||
Mediator.Publish(new LightlessNotificationMessage(notification));
|
||||
}
|
||||
public void ShowErrorNotification(string title, string message, Exception? exception = null, Action? onRetry = null, Action? onViewLog = null)
|
||||
{
|
||||
var actions = new List<LightlessNotificationAction>();
|
||||
if (onRetry != null)
|
||||
{
|
||||
actions.Add(new LightlessNotificationAction
|
||||
{
|
||||
Id = "retry",
|
||||
Label = "Retry",
|
||||
Icon = FontAwesomeIcon.Redo,
|
||||
Color = UIColors.Get("LightlessBlue"),
|
||||
OnClick = (n) =>
|
||||
{
|
||||
onRetry();
|
||||
n.IsDismissed = true;
|
||||
n.IsAnimatingOut = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (onViewLog != null)
|
||||
{
|
||||
actions.Add(new LightlessNotificationAction
|
||||
{
|
||||
Id = "view_log",
|
||||
Label = "View Log",
|
||||
Icon = FontAwesomeIcon.FileAlt,
|
||||
Color = UIColors.Get("LightlessYellow"),
|
||||
OnClick = (n) => onViewLog()
|
||||
});
|
||||
}
|
||||
var notification = new LightlessNotification
|
||||
{
|
||||
Title = title,
|
||||
Message = exception != null ? $"{message}\n\nError: {exception.Message}" : message,
|
||||
Type = NotificationType.Error,
|
||||
Duration = TimeSpan.FromSeconds(15),
|
||||
Actions = actions
|
||||
};
|
||||
Mediator.Publish(new LightlessNotificationMessage(notification));
|
||||
}
|
||||
public void ShowPairDownloadNotification(List<(string playerName, float progress, string status)> downloadStatus)
|
||||
{
|
||||
var totalProgress = downloadStatus.Count > 0 ? downloadStatus.Average(x => x.progress) : 0f;
|
||||
var completedCount = downloadStatus.Count(x => x.progress >= 1.0f);
|
||||
var totalCount = downloadStatus.Count;
|
||||
|
||||
var message = $"Progress: {completedCount}/{totalCount} completed";
|
||||
if (downloadStatus.Any(x => x.progress < 1.0f))
|
||||
{
|
||||
var activeDownloads = downloadStatus.Where(x => x.progress < 1.0f).Take(3);
|
||||
message += "\n" + string.Join("\n", activeDownloads.Select(x =>
|
||||
{
|
||||
var statusText = x.status switch
|
||||
{
|
||||
"downloading" => $"{x.progress:P0}",
|
||||
"decompressing" => "decompressing",
|
||||
"queued" => "queued",
|
||||
"waiting" => "waiting for slot",
|
||||
_ => x.status
|
||||
};
|
||||
return $"• {x.playerName}: {statusText}";
|
||||
}));
|
||||
|
||||
if (downloadStatus.Count(x => x.progress < 1.0f) > 3)
|
||||
{
|
||||
message += $"\n• ... and {downloadStatus.Count(x => x.progress < 1.0f) - 3} more";
|
||||
}
|
||||
}
|
||||
var notification = new LightlessNotification
|
||||
{
|
||||
Id = "pair_download_progress",
|
||||
Title = "Downloading Pair Data",
|
||||
Message = message,
|
||||
Type = NotificationType.Info,
|
||||
Duration = TimeSpan.FromMinutes(5),
|
||||
ShowProgress = true,
|
||||
Progress = totalProgress
|
||||
};
|
||||
Mediator.Publish(new LightlessNotificationMessage(notification));
|
||||
}
|
||||
public void DismissPairDownloadNotification()
|
||||
{
|
||||
Mediator.Publish(new LightlessNotificationDismissMessage("pair_download_progress"));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using LightlessSync.API.Data;
|
||||
using LightlessSync.API.Dto;
|
||||
using LightlessSync.API.Dto.CharaData;
|
||||
@@ -53,6 +53,8 @@ public record NotificationMessage
|
||||
public record CreateCacheForObjectMessage(GameObjectHandler ObjectToCreateFor) : SameThreadMessage;
|
||||
public record ClearCacheForObjectMessage(GameObjectHandler ObjectToCreateFor) : SameThreadMessage;
|
||||
public record CharacterDataCreatedMessage(CharacterData CharacterData) : SameThreadMessage;
|
||||
public record LightlessNotificationMessage(LightlessSync.UI.Models.LightlessNotification Notification) : MessageBase;
|
||||
public record LightlessNotificationDismissMessage(string NotificationId) : MessageBase;
|
||||
public record CharacterDataAnalyzedMessage : MessageBase;
|
||||
public record PenumbraStartRedrawMessage(IntPtr Address) : MessageBase;
|
||||
public record PenumbraEndRedrawMessage(IntPtr Address) : MessageBase;
|
||||
|
||||
@@ -22,7 +22,8 @@ public sealed class UiService : DisposableMediatorSubscriberBase
|
||||
LightlessConfigService lightlessConfigService, WindowSystem windowSystem,
|
||||
IEnumerable<WindowMediatorSubscriberBase> windows,
|
||||
UiFactory uiFactory, FileDialogManager fileDialogManager,
|
||||
LightlessMediator lightlessMediator) : base(logger, lightlessMediator)
|
||||
LightlessMediator lightlessMediator,
|
||||
LightlessNotificationService lightlessNotificationService) : base(logger, lightlessMediator)
|
||||
{
|
||||
_logger = logger;
|
||||
_logger.LogTrace("Creating {type}", GetType().Name);
|
||||
@@ -40,6 +41,12 @@ public sealed class UiService : DisposableMediatorSubscriberBase
|
||||
foreach (var window in windows)
|
||||
{
|
||||
_windowSystem.AddWindow(window);
|
||||
|
||||
// Connect the notification service to the notification UI
|
||||
if (window is LightlessNotificationUI notificationUI)
|
||||
{
|
||||
lightlessNotificationService.SetNotificationUI(notificationUI);
|
||||
}
|
||||
}
|
||||
|
||||
Mediator.Subscribe<ProfileOpenStandaloneMessage>(this, (msg) =>
|
||||
|
||||
Reference in New Issue
Block a user