added notification system for file downloads and pair requests
This commit is contained in:
@@ -56,6 +56,7 @@ public class LightlessConfig : ILightlessConfiguration
|
|||||||
public bool ShowOnlineNotificationsOnlyForNamedPairs { get; set; } = false;
|
public bool ShowOnlineNotificationsOnlyForNamedPairs { get; set; } = false;
|
||||||
public bool ShowTransferBars { get; set; } = true;
|
public bool ShowTransferBars { get; set; } = true;
|
||||||
public bool ShowTransferWindow { get; set; } = false;
|
public bool ShowTransferWindow { get; set; } = false;
|
||||||
|
public bool UseNotificationsForDownloads { get; set; } = true;
|
||||||
public bool ShowUploading { get; set; } = true;
|
public bool ShowUploading { get; set; } = true;
|
||||||
public bool ShowUploadingBigText { get; set; } = true;
|
public bool ShowUploadingBigText { get; set; } = true;
|
||||||
public bool ShowVisibleUsersSeparately { get; set; } = true;
|
public bool ShowVisibleUsersSeparately { get; set; } = true;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Dalamud.Game;
|
using Dalamud.Game;
|
||||||
using Dalamud.Game.ClientState.Objects;
|
using Dalamud.Game.ClientState.Objects;
|
||||||
using Dalamud.Interface.ImGuiFileDialog;
|
using Dalamud.Interface.ImGuiFileDialog;
|
||||||
using Dalamud.Interface.Windowing;
|
using Dalamud.Interface.Windowing;
|
||||||
@@ -175,6 +175,11 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddSingleton((s) => new NotificationService(s.GetRequiredService<ILogger<NotificationService>>(),
|
collection.AddSingleton((s) => new NotificationService(s.GetRequiredService<ILogger<NotificationService>>(),
|
||||||
s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<DalamudUtilService>(),
|
s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<DalamudUtilService>(),
|
||||||
notificationManager, chatGui, s.GetRequiredService<LightlessConfigService>()));
|
notificationManager, chatGui, s.GetRequiredService<LightlessConfigService>()));
|
||||||
|
collection.AddSingleton((s) => new LightlessNotificationService(
|
||||||
|
s.GetRequiredService<ILogger<LightlessNotificationService>>(),
|
||||||
|
s.GetRequiredService<LightlessConfigService>(),
|
||||||
|
s.GetRequiredService<DalamudUtilService>(),
|
||||||
|
s.GetRequiredService<LightlessMediator>()));
|
||||||
collection.AddSingleton((s) =>
|
collection.AddSingleton((s) =>
|
||||||
{
|
{
|
||||||
var httpClient = new HttpClient();
|
var httpClient = new HttpClient();
|
||||||
@@ -235,6 +240,11 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddScoped<WindowMediatorSubscriberBase, BroadcastUI>((s) => new BroadcastUI(s.GetRequiredService<ILogger<BroadcastUI>>(), s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<PerformanceCollectorService>(), s.GetRequiredService<BroadcastService>(), s.GetRequiredService<LightlessConfigService>(), s.GetRequiredService<UiSharedService>(), s.GetRequiredService<ApiController>(), s.GetRequiredService<BroadcastScannerService>()));
|
collection.AddScoped<WindowMediatorSubscriberBase, BroadcastUI>((s) => new BroadcastUI(s.GetRequiredService<ILogger<BroadcastUI>>(), s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<PerformanceCollectorService>(), s.GetRequiredService<BroadcastService>(), s.GetRequiredService<LightlessConfigService>(), s.GetRequiredService<UiSharedService>(), s.GetRequiredService<ApiController>(), s.GetRequiredService<BroadcastScannerService>()));
|
||||||
collection.AddScoped<WindowMediatorSubscriberBase, SyncshellFinderUI>((s) => new SyncshellFinderUI(s.GetRequiredService<ILogger<SyncshellFinderUI>>(), s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<PerformanceCollectorService>(), s.GetRequiredService<BroadcastService>(), s.GetRequiredService<UiSharedService>(), s.GetRequiredService<ApiController>(), s.GetRequiredService<BroadcastScannerService>(), s.GetRequiredService<PairManager>(), s.GetRequiredService<DalamudUtilService>()));
|
collection.AddScoped<WindowMediatorSubscriberBase, SyncshellFinderUI>((s) => new SyncshellFinderUI(s.GetRequiredService<ILogger<SyncshellFinderUI>>(), s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<PerformanceCollectorService>(), s.GetRequiredService<BroadcastService>(), s.GetRequiredService<UiSharedService>(), s.GetRequiredService<ApiController>(), s.GetRequiredService<BroadcastScannerService>(), s.GetRequiredService<PairManager>(), s.GetRequiredService<DalamudUtilService>()));
|
||||||
collection.AddScoped<IPopupHandler, BanUserPopupHandler>();
|
collection.AddScoped<IPopupHandler, BanUserPopupHandler>();
|
||||||
|
collection.AddScoped<WindowMediatorSubscriberBase, LightlessNotificationUI>((s) =>
|
||||||
|
new LightlessNotificationUI(
|
||||||
|
s.GetRequiredService<ILogger<LightlessNotificationUI>>(),
|
||||||
|
s.GetRequiredService<LightlessMediator>(),
|
||||||
|
s.GetRequiredService<PerformanceCollectorService>()));
|
||||||
collection.AddScoped<IPopupHandler, CensusPopupHandler>();
|
collection.AddScoped<IPopupHandler, CensusPopupHandler>();
|
||||||
collection.AddScoped<CacheCreationService>();
|
collection.AddScoped<CacheCreationService>();
|
||||||
collection.AddScoped<PlayerDataFactory>();
|
collection.AddScoped<PlayerDataFactory>();
|
||||||
@@ -242,7 +252,9 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddScoped((s) => new UiService(s.GetRequiredService<ILogger<UiService>>(), pluginInterface.UiBuilder, s.GetRequiredService<LightlessConfigService>(),
|
collection.AddScoped((s) => new UiService(s.GetRequiredService<ILogger<UiService>>(), pluginInterface.UiBuilder, s.GetRequiredService<LightlessConfigService>(),
|
||||||
s.GetRequiredService<WindowSystem>(), s.GetServices<WindowMediatorSubscriberBase>(),
|
s.GetRequiredService<WindowSystem>(), s.GetServices<WindowMediatorSubscriberBase>(),
|
||||||
s.GetRequiredService<UiFactory>(),
|
s.GetRequiredService<UiFactory>(),
|
||||||
s.GetRequiredService<FileDialogManager>(), s.GetRequiredService<LightlessMediator>()));
|
s.GetRequiredService<FileDialogManager>(),
|
||||||
|
s.GetRequiredService<LightlessMediator>(),
|
||||||
|
s.GetRequiredService<LightlessNotificationService>()));
|
||||||
collection.AddScoped((s) => new CommandManagerService(commandManager, s.GetRequiredService<PerformanceCollectorService>(),
|
collection.AddScoped((s) => new CommandManagerService(commandManager, s.GetRequiredService<PerformanceCollectorService>(),
|
||||||
s.GetRequiredService<ServerConfigurationManager>(), s.GetRequiredService<CacheMonitor>(), s.GetRequiredService<ApiController>(),
|
s.GetRequiredService<ServerConfigurationManager>(), s.GetRequiredService<CacheMonitor>(), s.GetRequiredService<ApiController>(),
|
||||||
s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<LightlessConfigService>()));
|
s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<LightlessConfigService>()));
|
||||||
@@ -261,6 +273,7 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddHostedService(p => p.GetRequiredService<FileCacheManager>());
|
collection.AddHostedService(p => p.GetRequiredService<FileCacheManager>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<ConfigurationMigrator>());
|
collection.AddHostedService(p => p.GetRequiredService<ConfigurationMigrator>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<DalamudUtilService>());
|
collection.AddHostedService(p => p.GetRequiredService<DalamudUtilService>());
|
||||||
|
collection.AddHostedService(p => p.GetRequiredService<LightlessNotificationService>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<PerformanceCollectorService>());
|
collection.AddHostedService(p => p.GetRequiredService<PerformanceCollectorService>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<DtrEntry>());
|
collection.AddHostedService(p => p.GetRequiredService<DtrEntry>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<EventAggregator>());
|
collection.AddHostedService(p => p.GetRequiredService<EventAggregator>());
|
||||||
|
|||||||
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.Data;
|
||||||
using LightlessSync.API.Dto;
|
using LightlessSync.API.Dto;
|
||||||
using LightlessSync.API.Dto.CharaData;
|
using LightlessSync.API.Dto.CharaData;
|
||||||
@@ -53,6 +53,8 @@ public record NotificationMessage
|
|||||||
public record CreateCacheForObjectMessage(GameObjectHandler ObjectToCreateFor) : SameThreadMessage;
|
public record CreateCacheForObjectMessage(GameObjectHandler ObjectToCreateFor) : SameThreadMessage;
|
||||||
public record ClearCacheForObjectMessage(GameObjectHandler ObjectToCreateFor) : SameThreadMessage;
|
public record ClearCacheForObjectMessage(GameObjectHandler ObjectToCreateFor) : SameThreadMessage;
|
||||||
public record CharacterDataCreatedMessage(CharacterData CharacterData) : 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 CharacterDataAnalyzedMessage : MessageBase;
|
||||||
public record PenumbraStartRedrawMessage(IntPtr Address) : MessageBase;
|
public record PenumbraStartRedrawMessage(IntPtr Address) : MessageBase;
|
||||||
public record PenumbraEndRedrawMessage(IntPtr Address) : MessageBase;
|
public record PenumbraEndRedrawMessage(IntPtr Address) : MessageBase;
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ public sealed class UiService : DisposableMediatorSubscriberBase
|
|||||||
LightlessConfigService lightlessConfigService, WindowSystem windowSystem,
|
LightlessConfigService lightlessConfigService, WindowSystem windowSystem,
|
||||||
IEnumerable<WindowMediatorSubscriberBase> windows,
|
IEnumerable<WindowMediatorSubscriberBase> windows,
|
||||||
UiFactory uiFactory, FileDialogManager fileDialogManager,
|
UiFactory uiFactory, FileDialogManager fileDialogManager,
|
||||||
LightlessMediator lightlessMediator) : base(logger, lightlessMediator)
|
LightlessMediator lightlessMediator,
|
||||||
|
LightlessNotificationService lightlessNotificationService) : base(logger, lightlessMediator)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_logger.LogTrace("Creating {type}", GetType().Name);
|
_logger.LogTrace("Creating {type}", GetType().Name);
|
||||||
@@ -40,6 +41,12 @@ public sealed class UiService : DisposableMediatorSubscriberBase
|
|||||||
foreach (var window in windows)
|
foreach (var window in windows)
|
||||||
{
|
{
|
||||||
_windowSystem.AddWindow(window);
|
_windowSystem.AddWindow(window);
|
||||||
|
|
||||||
|
// Connect the notification service to the notification UI
|
||||||
|
if (window is LightlessNotificationUI notificationUI)
|
||||||
|
{
|
||||||
|
lightlessNotificationService.SetNotificationUI(notificationUI);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mediator.Subscribe<ProfileOpenStandaloneMessage>(this, (msg) =>
|
Mediator.Subscribe<ProfileOpenStandaloneMessage>(this, (msg) =>
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
IpcManager ipcManager,
|
IpcManager ipcManager,
|
||||||
BroadcastService broadcastService,
|
BroadcastService broadcastService,
|
||||||
CharacterAnalyzer characterAnalyzer,
|
CharacterAnalyzer characterAnalyzer,
|
||||||
PlayerPerformanceConfigService playerPerformanceConfig, PairRequestService pairRequestService, DalamudUtilService dalamudUtilService) : base(logger, mediator, "###LightlessSyncMainUI", performanceCollectorService)
|
PlayerPerformanceConfigService playerPerformanceConfig, PairRequestService pairRequestService, DalamudUtilService dalamudUtilService, LightlessNotificationService lightlessNotificationService) : base(logger, mediator, "###LightlessSyncMainUI", performanceCollectorService)
|
||||||
{
|
{
|
||||||
_uiSharedService = uiShared;
|
_uiSharedService = uiShared;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
@@ -105,7 +105,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
_renamePairTagUi = renameTagUi;
|
_renamePairTagUi = renameTagUi;
|
||||||
_ipcManager = ipcManager;
|
_ipcManager = ipcManager;
|
||||||
_broadcastService = broadcastService;
|
_broadcastService = broadcastService;
|
||||||
_tabMenu = new TopTabMenu(Mediator, _apiController, _pairManager, _uiSharedService, pairRequestService, dalamudUtilService);
|
_tabMenu = new TopTabMenu(Mediator, _apiController, _pairManager, _uiSharedService, pairRequestService, dalamudUtilService, lightlessNotificationService);
|
||||||
|
|
||||||
AllowPinning = true;
|
AllowPinning = true;
|
||||||
AllowClickthrough = false;
|
AllowClickthrough = false;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Interface.Colors;
|
using Dalamud.Interface.Colors;
|
||||||
using LightlessSync.LightlessConfiguration;
|
using LightlessSync.LightlessConfiguration;
|
||||||
@@ -22,9 +22,12 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
private readonly UiSharedService _uiShared;
|
private readonly UiSharedService _uiShared;
|
||||||
private readonly PairProcessingLimiter _pairProcessingLimiter;
|
private readonly PairProcessingLimiter _pairProcessingLimiter;
|
||||||
private readonly ConcurrentDictionary<GameObjectHandler, bool> _uploadingPlayers = new();
|
private readonly ConcurrentDictionary<GameObjectHandler, bool> _uploadingPlayers = new();
|
||||||
|
private readonly LightlessNotificationService _notificationService;
|
||||||
|
private bool _notificationDismissed = true;
|
||||||
|
|
||||||
public DownloadUi(ILogger<DownloadUi> logger, DalamudUtilService dalamudUtilService, LightlessConfigService configService,
|
public DownloadUi(ILogger<DownloadUi> logger, DalamudUtilService dalamudUtilService, LightlessConfigService configService,
|
||||||
PairProcessingLimiter pairProcessingLimiter, FileUploadManager fileTransferManager, LightlessMediator mediator, UiSharedService uiShared, PerformanceCollectorService performanceCollectorService)
|
PairProcessingLimiter pairProcessingLimiter, FileUploadManager fileTransferManager, LightlessMediator mediator, UiSharedService uiShared,
|
||||||
|
PerformanceCollectorService performanceCollectorService, LightlessNotificationService notificationService)
|
||||||
: base(logger, mediator, "Lightless Sync Downloads", performanceCollectorService)
|
: base(logger, mediator, "Lightless Sync Downloads", performanceCollectorService)
|
||||||
{
|
{
|
||||||
_dalamudUtilService = dalamudUtilService;
|
_dalamudUtilService = dalamudUtilService;
|
||||||
@@ -32,6 +35,7 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
_pairProcessingLimiter = pairProcessingLimiter;
|
_pairProcessingLimiter = pairProcessingLimiter;
|
||||||
_fileTransferManager = fileTransferManager;
|
_fileTransferManager = fileTransferManager;
|
||||||
_uiShared = uiShared;
|
_uiShared = uiShared;
|
||||||
|
_notificationService = notificationService;
|
||||||
|
|
||||||
SizeConstraints = new WindowSizeConstraints()
|
SizeConstraints = new WindowSizeConstraints()
|
||||||
{
|
{
|
||||||
@@ -56,7 +60,14 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
IsOpen = true;
|
IsOpen = true;
|
||||||
|
|
||||||
Mediator.Subscribe<DownloadStartedMessage>(this, (msg) => _currentDownloads[msg.DownloadId] = msg.DownloadStatus);
|
Mediator.Subscribe<DownloadStartedMessage>(this, (msg) => _currentDownloads[msg.DownloadId] = msg.DownloadStatus);
|
||||||
Mediator.Subscribe<DownloadFinishedMessage>(this, (msg) => _currentDownloads.TryRemove(msg.DownloadId, out _));
|
Mediator.Subscribe<DownloadFinishedMessage>(this, (msg) =>
|
||||||
|
{
|
||||||
|
_currentDownloads.TryRemove(msg.DownloadId, out _);
|
||||||
|
if (!_currentDownloads.Any())
|
||||||
|
{
|
||||||
|
_notificationService.DismissPairDownloadNotification();
|
||||||
|
}
|
||||||
|
});
|
||||||
Mediator.Subscribe<GposeStartMessage>(this, (_) => IsOpen = false);
|
Mediator.Subscribe<GposeStartMessage>(this, (_) => IsOpen = false);
|
||||||
Mediator.Subscribe<GposeEndMessage>(this, (_) => IsOpen = true);
|
Mediator.Subscribe<GposeEndMessage>(this, (_) => IsOpen = true);
|
||||||
Mediator.Subscribe<PlayerUploadingMessage>(this, (msg) =>
|
Mediator.Subscribe<PlayerUploadingMessage>(this, (msg) =>
|
||||||
@@ -122,6 +133,23 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (_configService.Current.UseNotificationsForDownloads)
|
||||||
|
{
|
||||||
|
// Use new notification stuff
|
||||||
|
if (_currentDownloads.Any())
|
||||||
|
{
|
||||||
|
UpdateDownloadNotification();
|
||||||
|
_notificationDismissed = false;
|
||||||
|
}
|
||||||
|
else if (!_notificationDismissed)
|
||||||
|
{
|
||||||
|
_notificationService.DismissPairDownloadNotification();
|
||||||
|
_notificationDismissed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// text overlay
|
||||||
foreach (var item in _currentDownloads.ToList())
|
foreach (var item in _currentDownloads.ToList())
|
||||||
{
|
{
|
||||||
var dlSlot = item.Value.Count(c => c.Value.DownloadStatus == DownloadStatus.WaitingForSlot);
|
var dlSlot = item.Value.Count(c => c.Value.DownloadStatus == DownloadStatus.WaitingForSlot);
|
||||||
@@ -146,6 +174,7 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
ImGuiColors.DalamudWhite, new Vector4(0, 0, 0, 255), 1);
|
ImGuiColors.DalamudWhite, new Vector4(0, 0, 0, 255), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// ignore errors thrown from UI
|
// ignore errors thrown from UI
|
||||||
@@ -262,4 +291,37 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
MaximumSize = new Vector2(300, maxHeight),
|
MaximumSize = new Vector2(300, maxHeight),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateDownloadNotification()
|
||||||
|
{
|
||||||
|
var downloadStatus = new List<(string playerName, float progress, string status)>();
|
||||||
|
|
||||||
|
foreach (var item in _currentDownloads.ToList())
|
||||||
|
{
|
||||||
|
var dlSlot = item.Value.Count(c => c.Value.DownloadStatus == DownloadStatus.WaitingForSlot);
|
||||||
|
var dlQueue = item.Value.Count(c => c.Value.DownloadStatus == DownloadStatus.WaitingForQueue);
|
||||||
|
var dlProg = item.Value.Count(c => c.Value.DownloadStatus == DownloadStatus.Downloading);
|
||||||
|
var dlDecomp = item.Value.Count(c => c.Value.DownloadStatus == DownloadStatus.Decompressing);
|
||||||
|
var totalFiles = item.Value.Sum(c => c.Value.TotalFiles);
|
||||||
|
var transferredFiles = item.Value.Sum(c => c.Value.TransferredFiles);
|
||||||
|
var totalBytes = item.Value.Sum(c => c.Value.TotalBytes);
|
||||||
|
var transferredBytes = item.Value.Sum(c => c.Value.TransferredBytes);
|
||||||
|
|
||||||
|
var progress = totalBytes > 0 ? (float)transferredBytes / totalBytes : 0f;
|
||||||
|
|
||||||
|
string status;
|
||||||
|
if (dlDecomp > 0) status = "decompressing";
|
||||||
|
else if (dlProg > 0) status = "downloading";
|
||||||
|
else if (dlQueue > 0) status = "queued";
|
||||||
|
else if (dlSlot > 0) status = "waiting";
|
||||||
|
else status = "completed";
|
||||||
|
|
||||||
|
downloadStatus.Add((item.Key.Name, progress, status));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (downloadStatus.Any())
|
||||||
|
{
|
||||||
|
_notificationService.ShowPairDownloadNotification(downloadStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
469
LightlessSync/UI/LightlessNotificationUI.cs
Normal file
469
LightlessSync/UI/LightlessNotificationUI.cs
Normal file
@@ -0,0 +1,469 @@
|
|||||||
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Colors;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
|
using Dalamud.Interface.Utility.Raii;
|
||||||
|
using Dalamud.Interface.Windowing;
|
||||||
|
using LightlessSync.LightlessConfiguration.Models;
|
||||||
|
using LightlessSync.Services;
|
||||||
|
using LightlessSync.Services.Mediator;
|
||||||
|
using LightlessSync.UI.Models;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Numerics;
|
||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
|
|
||||||
|
namespace LightlessSync.UI;
|
||||||
|
|
||||||
|
public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||||
|
{
|
||||||
|
private readonly List<LightlessNotification> _notifications = new();
|
||||||
|
private readonly object _notificationLock = new();
|
||||||
|
|
||||||
|
private const float NotificationWidth = 350f;
|
||||||
|
private const float NotificationMinHeight = 60f;
|
||||||
|
private const float NotificationSpacing = 8f;
|
||||||
|
private const float AnimationSpeed = 10f;
|
||||||
|
private const float EdgeXMargin = 0;
|
||||||
|
private const float EdgeYMargin = 30f;
|
||||||
|
private const float SlideDistance = 100f;
|
||||||
|
|
||||||
|
public LightlessNotificationUI(ILogger<LightlessNotificationUI> logger, LightlessMediator mediator, PerformanceCollectorService performanceCollector)
|
||||||
|
: base(logger, mediator, "Lightless Notifications##LightlessNotifications", performanceCollector)
|
||||||
|
{
|
||||||
|
Flags = ImGuiWindowFlags.NoDecoration |
|
||||||
|
ImGuiWindowFlags.NoMove |
|
||||||
|
ImGuiWindowFlags.NoResize |
|
||||||
|
ImGuiWindowFlags.NoSavedSettings |
|
||||||
|
ImGuiWindowFlags.NoFocusOnAppearing |
|
||||||
|
ImGuiWindowFlags.NoNav |
|
||||||
|
ImGuiWindowFlags.NoBackground |
|
||||||
|
ImGuiWindowFlags.NoCollapse |
|
||||||
|
ImGuiWindowFlags.AlwaysAutoResize;
|
||||||
|
|
||||||
|
var viewport = ImGui.GetMainViewport();
|
||||||
|
if (viewport.WorkSize.X > 0)
|
||||||
|
{
|
||||||
|
Position = new Vector2(viewport.WorkPos.X + viewport.WorkSize.X - NotificationWidth - EdgeXMargin,
|
||||||
|
viewport.WorkPos.Y + EdgeYMargin);
|
||||||
|
PositionCondition = ImGuiCond.Always;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size = new Vector2(NotificationWidth, 100);
|
||||||
|
SizeCondition = ImGuiCond.FirstUseEver;
|
||||||
|
IsOpen = false;
|
||||||
|
RespectCloseHotkey = false;
|
||||||
|
DisableWindowSounds = true;
|
||||||
|
|
||||||
|
Mediator.Subscribe<LightlessNotificationMessage>(this, HandleNotificationMessage);
|
||||||
|
Mediator.Subscribe<LightlessNotificationDismissMessage>(this, HandleNotificationDismissMessage);
|
||||||
|
}
|
||||||
|
private void HandleNotificationMessage(LightlessNotificationMessage message)
|
||||||
|
{
|
||||||
|
AddNotification(message.Notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleNotificationDismissMessage(LightlessNotificationDismissMessage message)
|
||||||
|
{
|
||||||
|
RemoveNotification(message.NotificationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddNotification(LightlessNotification notification)
|
||||||
|
{
|
||||||
|
lock (_notificationLock)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_notifications.Add(notification);
|
||||||
|
_logger.LogDebug("Added new notification: {Title}", notification.Title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsOpen)
|
||||||
|
{
|
||||||
|
IsOpen = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveNotification(string id)
|
||||||
|
{
|
||||||
|
lock (_notificationLock)
|
||||||
|
{
|
||||||
|
var notification = _notifications.FirstOrDefault(n => n.Id == id);
|
||||||
|
if (notification != null)
|
||||||
|
{
|
||||||
|
notification.IsAnimatingOut = true;
|
||||||
|
notification.IsAnimatingIn = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DrawInternal()
|
||||||
|
{
|
||||||
|
lock (_notificationLock)
|
||||||
|
{
|
||||||
|
UpdateNotifications();
|
||||||
|
|
||||||
|
if (_notifications.Count == 0)
|
||||||
|
{
|
||||||
|
IsOpen = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var viewport = ImGui.GetMainViewport();
|
||||||
|
var windowPos = new Vector2(
|
||||||
|
viewport.WorkPos.X + viewport.WorkSize.X - NotificationWidth - EdgeXMargin,
|
||||||
|
viewport.WorkPos.Y + EdgeYMargin
|
||||||
|
);
|
||||||
|
ImGui.SetWindowPos(windowPos);
|
||||||
|
|
||||||
|
for (int i = 0; i < _notifications.Count; i++)
|
||||||
|
{
|
||||||
|
DrawNotification(_notifications[i], i);
|
||||||
|
|
||||||
|
if (i < _notifications.Count - 1)
|
||||||
|
{
|
||||||
|
ImGui.Dummy(new Vector2(0, NotificationSpacing));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateNotifications()
|
||||||
|
{
|
||||||
|
var deltaTime = ImGui.GetIO().DeltaTime;
|
||||||
|
|
||||||
|
for (int i = _notifications.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var notification = _notifications[i];
|
||||||
|
|
||||||
|
if (notification.IsAnimatingIn && notification.AnimationProgress < 1f)
|
||||||
|
{
|
||||||
|
notification.AnimationProgress = Math.Min(1f, notification.AnimationProgress + deltaTime * AnimationSpeed);
|
||||||
|
}
|
||||||
|
else if (notification.IsAnimatingOut && notification.AnimationProgress > 0f)
|
||||||
|
{
|
||||||
|
notification.AnimationProgress = Math.Max(0f, notification.AnimationProgress - deltaTime * (AnimationSpeed * 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)
|
||||||
|
{
|
||||||
|
_notifications.RemoveAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawNotification(LightlessNotification notification, int index)
|
||||||
|
{
|
||||||
|
var alpha = notification.AnimationProgress;
|
||||||
|
if (alpha <= 0f) return;
|
||||||
|
|
||||||
|
var slideOffset = (1f - alpha) * SlideDistance;
|
||||||
|
var originalCursorPos = ImGui.GetCursorPos();
|
||||||
|
ImGui.SetCursorPosX(originalCursorPos.X + slideOffset);
|
||||||
|
|
||||||
|
var notificationHeight = CalculateNotificationHeight(notification);
|
||||||
|
|
||||||
|
using var child = ImRaii.Child($"notification_{notification.Id}",
|
||||||
|
new Vector2(NotificationWidth - slideOffset, notificationHeight),
|
||||||
|
false, ImGuiWindowFlags.NoScrollbar);
|
||||||
|
|
||||||
|
if (child.Success)
|
||||||
|
{
|
||||||
|
DrawNotificationContent(notification, alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawNotificationContent(LightlessNotification notification, float alpha)
|
||||||
|
{
|
||||||
|
var drawList = ImGui.GetWindowDrawList();
|
||||||
|
var windowPos = ImGui.GetWindowPos();
|
||||||
|
var windowSize = ImGui.GetWindowSize();
|
||||||
|
|
||||||
|
var bgColor = new Vector4(30f/255f, 30f/255f, 30f/255f, 0.95f * alpha);
|
||||||
|
var accentColor = GetNotificationAccentColor(notification.Type);
|
||||||
|
var progressBarColor = UIColors.Get("LightlessBlue");
|
||||||
|
accentColor.W *= alpha;
|
||||||
|
|
||||||
|
var shadowOffset = new Vector2(1f, 1f);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
bgColor = bgColor * 1.1f;
|
||||||
|
bgColor.W = Math.Min(bgColor.W, 0.98f);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawList.AddRectFilled(
|
||||||
|
windowPos,
|
||||||
|
windowPos + windowSize,
|
||||||
|
ImGui.ColorConvertFloat4ToU32(bgColor),
|
||||||
|
3f
|
||||||
|
);
|
||||||
|
|
||||||
|
var accentWidth = 3f;
|
||||||
|
drawList.AddRectFilled(
|
||||||
|
windowPos,
|
||||||
|
windowPos + new Vector2(accentWidth, windowSize.Y),
|
||||||
|
ImGui.ColorConvertFloat4ToU32(accentColor),
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
var elapsed = DateTime.UtcNow - notification.CreatedAt;
|
||||||
|
var progress = Math.Min(1.0f, (float)(elapsed.TotalSeconds / notification.Duration.TotalSeconds));
|
||||||
|
|
||||||
|
var progressHeight = 2f;
|
||||||
|
var progressY = windowPos.Y + windowSize.Y - progressHeight;
|
||||||
|
var progressWidth = windowSize.X * progress;
|
||||||
|
|
||||||
|
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),
|
||||||
|
new Vector2(windowPos.X + windowSize.X, progressY + progressHeight),
|
||||||
|
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 DrawNotificationText(LightlessNotification notification, float alpha)
|
||||||
|
{
|
||||||
|
var padding = new Vector2(10f, 6f);
|
||||||
|
var contentPos = new Vector2(6f, 0f) + padding;
|
||||||
|
var windowSize = ImGui.GetWindowSize();
|
||||||
|
var contentSize = windowSize - padding * 2 - new Vector2(6f, 0f);
|
||||||
|
|
||||||
|
ImGui.SetCursorPos(contentPos);
|
||||||
|
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.Text, new Vector4(1f, 1f, 1f, alpha)))
|
||||||
|
{
|
||||||
|
ImGui.Text(notification.Title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(notification.Message))
|
||||||
|
{
|
||||||
|
ImGui.SetCursorPos(contentPos + new Vector2(0f, 18f));
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notification.ShowProgress)
|
||||||
|
{
|
||||||
|
ImGui.Spacing();
|
||||||
|
var progressColor = GetNotificationAccentColor(notification.Type);
|
||||||
|
progressColor.W *= alpha;
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.PlotHistogram, progressColor))
|
||||||
|
{
|
||||||
|
ImGui.ProgressBar(notification.Progress, new Vector2(contentSize.X, 2f), "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notification.Actions.Count > 0)
|
||||||
|
{
|
||||||
|
ImGui.Spacing();
|
||||||
|
ImGui.SetCursorPosX(contentPos.X);
|
||||||
|
DrawNotificationActions(notification, contentSize.X, alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawNotificationActions(LightlessNotification notification, float availableWidth, float alpha)
|
||||||
|
{
|
||||||
|
var buttonSpacing = 8f;
|
||||||
|
var rightPadding = 10f;
|
||||||
|
var usableWidth = availableWidth - rightPadding;
|
||||||
|
var totalSpacing = (notification.Actions.Count - 1) * buttonSpacing;
|
||||||
|
var buttonWidth = (usableWidth - totalSpacing) / notification.Actions.Count;
|
||||||
|
|
||||||
|
_logger.LogDebug("Drawing {ActionCount} notification actions, buttonWidth: {ButtonWidth}, availableWidth: {AvailableWidth}",
|
||||||
|
notification.Actions.Count, buttonWidth, availableWidth);
|
||||||
|
|
||||||
|
var startCursorPos = ImGui.GetCursorPos();
|
||||||
|
|
||||||
|
for (int i = 0; i < notification.Actions.Count; i++)
|
||||||
|
{
|
||||||
|
var action = notification.Actions[i];
|
||||||
|
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
ImGui.SameLine();
|
||||||
|
var currentX = startCursorPos.X + i * (buttonWidth + buttonSpacing);
|
||||||
|
ImGui.SetCursorPosX(currentX);
|
||||||
|
}
|
||||||
|
DrawActionButton(action, notification, alpha, buttonWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawActionButton(LightlessNotificationAction action, LightlessNotification notification, float alpha, float buttonWidth)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Drawing action button: {ActionId} - {ActionLabel}, width: {ButtonWidth}", action.Id, action.Label, buttonWidth);
|
||||||
|
|
||||||
|
var buttonColor = action.Color;
|
||||||
|
buttonColor.W *= alpha;
|
||||||
|
|
||||||
|
var hoveredColor = buttonColor * 1.1f;
|
||||||
|
hoveredColor.W = buttonColor.W;
|
||||||
|
|
||||||
|
var activeColor = buttonColor * 0.9f;
|
||||||
|
activeColor.W = buttonColor.W;
|
||||||
|
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.Button, buttonColor))
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.ButtonHovered, hoveredColor))
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.ButtonActive, activeColor))
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.Text, new Vector4(1f, 1f, 1f, alpha)))
|
||||||
|
{
|
||||||
|
var buttonPressed = false;
|
||||||
|
|
||||||
|
if (action.Icon != FontAwesomeIcon.None)
|
||||||
|
{
|
||||||
|
buttonPressed = DrawIconTextButton(action.Icon, action.Label, buttonWidth, alpha);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buttonPressed = ImGui.Button(action.Label, new Vector2(buttonWidth, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogDebug("Button {ActionId} pressed: {ButtonPressed}", action.Id, buttonPressed);
|
||||||
|
|
||||||
|
if (buttonPressed)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Executing action: {ActionId}", action.Id);
|
||||||
|
action.OnClick(notification);
|
||||||
|
_logger.LogDebug("Action executed successfully: {ActionId}", action.Id);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error executing notification action: {ActionId}", action.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool DrawIconTextButton(FontAwesomeIcon icon, string text, float width, float alpha)
|
||||||
|
{
|
||||||
|
var drawList = ImGui.GetWindowDrawList();
|
||||||
|
var cursorPos = ImGui.GetCursorScreenPos();
|
||||||
|
var frameHeight = ImGui.GetFrameHeight();
|
||||||
|
|
||||||
|
Vector2 iconSize;
|
||||||
|
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||||
|
{
|
||||||
|
iconSize = ImGui.CalcTextSize(icon.ToIconString());
|
||||||
|
}
|
||||||
|
|
||||||
|
var textSize = ImGui.CalcTextSize(text);
|
||||||
|
var spacing = 3f * ImGuiHelpers.GlobalScale;
|
||||||
|
var totalTextWidth = iconSize.X + spacing + textSize.X;
|
||||||
|
|
||||||
|
var buttonPressed = ImGui.InvisibleButton($"btn_{icon}_{text}", new Vector2(width, frameHeight));
|
||||||
|
|
||||||
|
var buttonMin = ImGui.GetItemRectMin();
|
||||||
|
var buttonMax = ImGui.GetItemRectMax();
|
||||||
|
var buttonSize = buttonMax - buttonMin;
|
||||||
|
|
||||||
|
var buttonColor = ImGui.GetColorU32(ImGuiCol.Button);
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
|
buttonColor = ImGui.GetColorU32(ImGuiCol.ButtonHovered);
|
||||||
|
if (ImGui.IsItemActive())
|
||||||
|
buttonColor = ImGui.GetColorU32(ImGuiCol.ButtonActive);
|
||||||
|
|
||||||
|
drawList.AddRectFilled(buttonMin, buttonMax, buttonColor, 3f);
|
||||||
|
|
||||||
|
var iconPos = buttonMin + new Vector2((buttonSize.X - totalTextWidth) / 2f, (buttonSize.Y - iconSize.Y) / 2f);
|
||||||
|
var textPos = iconPos + new Vector2(iconSize.X + spacing, (iconSize.Y - textSize.Y) / 2f);
|
||||||
|
|
||||||
|
var textColor = ImGui.GetColorU32(ImGuiCol.Text);
|
||||||
|
|
||||||
|
// Draw icon
|
||||||
|
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||||
|
{
|
||||||
|
drawList.AddText(iconPos, textColor, icon.ToIconString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw text
|
||||||
|
drawList.AddText(textPos, textColor, text);
|
||||||
|
|
||||||
|
return buttonPressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float CalculateNotificationHeight(LightlessNotification notification)
|
||||||
|
{
|
||||||
|
var height = 40f;
|
||||||
|
if (!string.IsNullOrEmpty(notification.Message))
|
||||||
|
{
|
||||||
|
var textSize = ImGui.CalcTextSize(notification.Message, true, NotificationWidth - 35f);
|
||||||
|
height += textSize.Y + 4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notification.ShowProgress)
|
||||||
|
{
|
||||||
|
height += 12f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notification.Actions.Count > 0)
|
||||||
|
{
|
||||||
|
height += 28f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.Max(height, NotificationMinHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector4 GetNotificationAccentColor(NotificationType type)
|
||||||
|
{
|
||||||
|
return type switch
|
||||||
|
{
|
||||||
|
NotificationType.Info => UIColors.Get("LightlessPurple"),
|
||||||
|
NotificationType.Warning => UIColors.Get("LightlessYellow"),
|
||||||
|
NotificationType.Error => UIColors.Get("DimRed"),
|
||||||
|
_ => UIColors.Get("LightlessPurple")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
34
LightlessSync/UI/Models/LightlessNotification.cs
Normal file
34
LightlessSync/UI/Models/LightlessNotification.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using Dalamud.Interface;
|
||||||
|
using LightlessSync.LightlessConfiguration.Models;
|
||||||
|
using System.Numerics;
|
||||||
|
namespace LightlessSync.UI.Models;
|
||||||
|
public class LightlessNotification
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = Guid.NewGuid().ToString();
|
||||||
|
public string Title { get; set; } = string.Empty;
|
||||||
|
public string Message { get; set; } = string.Empty;
|
||||||
|
public NotificationType Type { get; set; } = NotificationType.Info;
|
||||||
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
public TimeSpan Duration { get; set; } = TimeSpan.FromSeconds(5);
|
||||||
|
public bool IsExpired => DateTime.UtcNow - CreatedAt > Duration;
|
||||||
|
public bool IsDismissed { get; set; } = false;
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Animation properties
|
||||||
|
public float AnimationProgress { get; set; } = 0f;
|
||||||
|
public bool IsAnimatingIn { get; set; } = true;
|
||||||
|
public bool IsAnimatingOut { get; set; } = false;
|
||||||
|
}
|
||||||
|
public class LightlessNotificationAction
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = Guid.NewGuid().ToString();
|
||||||
|
public string Label { get; set; } = string.Empty;
|
||||||
|
public FontAwesomeIcon Icon { get; set; } = FontAwesomeIcon.None;
|
||||||
|
public Vector4 Color { get; set; } = Vector4.One;
|
||||||
|
public Action<LightlessNotification> OnClick { get; set; } = _ => { };
|
||||||
|
public bool IsPrimary { get; set; } = false;
|
||||||
|
public bool IsDestructive { get; set; } = false;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Game.Text;
|
using Dalamud.Game.Text;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Colors;
|
using Dalamud.Interface.Colors;
|
||||||
@@ -351,6 +351,14 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
_uiShared.UnderlinedBigText("Transfer UI", UIColors.Get("LightlessBlue"));
|
_uiShared.UnderlinedBigText("Transfer UI", UIColors.Get("LightlessBlue"));
|
||||||
ImGuiHelpers.ScaledDummy(5);
|
ImGuiHelpers.ScaledDummy(5);
|
||||||
|
|
||||||
|
bool useNotificationsForDownloads = _configService.Current.UseNotificationsForDownloads;
|
||||||
|
if (ImGui.Checkbox("Use notifications for download progress", ref useNotificationsForDownloads))
|
||||||
|
{
|
||||||
|
_configService.Current.UseNotificationsForDownloads = useNotificationsForDownloads;
|
||||||
|
_configService.Save();
|
||||||
|
}
|
||||||
|
_uiShared.DrawHelpText("Show download progress as clean notifications instead of overlay text. Notifications update in real-time.");
|
||||||
|
|
||||||
bool showTransferWindow = _configService.Current.ShowTransferWindow;
|
bool showTransferWindow = _configService.Current.ShowTransferWindow;
|
||||||
if (ImGui.Checkbox("Show separate transfer window", ref showTransferWindow))
|
if (ImGui.Checkbox("Show separate transfer window", ref showTransferWindow))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,13 +33,14 @@ public class TopTabMenu
|
|||||||
private bool _pairRequestsExpanded; // useless for now
|
private bool _pairRequestsExpanded; // useless for now
|
||||||
private int _lastRequestCount;
|
private int _lastRequestCount;
|
||||||
private readonly UiSharedService _uiSharedService;
|
private readonly UiSharedService _uiSharedService;
|
||||||
|
private readonly LightlessNotificationService _lightlessNotificationService;
|
||||||
private string _filter = string.Empty;
|
private string _filter = string.Empty;
|
||||||
private int _globalControlCountdown = 0;
|
private int _globalControlCountdown = 0;
|
||||||
private float _pairRequestsHeight = 150f;
|
private float _pairRequestsHeight = 150f;
|
||||||
private string _pairToAdd = string.Empty;
|
private string _pairToAdd = string.Empty;
|
||||||
|
|
||||||
private SelectedTab _selectedTab = SelectedTab.None;
|
private SelectedTab _selectedTab = SelectedTab.None;
|
||||||
public TopTabMenu(LightlessMediator lightlessMediator, ApiController apiController, PairManager pairManager, UiSharedService uiSharedService, PairRequestService pairRequestService, DalamudUtilService dalamudUtilService)
|
public TopTabMenu(LightlessMediator lightlessMediator, ApiController apiController, PairManager pairManager, UiSharedService uiSharedService, PairRequestService pairRequestService, DalamudUtilService dalamudUtilService, LightlessNotificationService lightlessNotificationService)
|
||||||
{
|
{
|
||||||
_lightlessMediator = lightlessMediator;
|
_lightlessMediator = lightlessMediator;
|
||||||
_apiController = apiController;
|
_apiController = apiController;
|
||||||
@@ -47,6 +48,7 @@ public class TopTabMenu
|
|||||||
_pairRequestService = pairRequestService;
|
_pairRequestService = pairRequestService;
|
||||||
_dalamudUtilService = dalamudUtilService;
|
_dalamudUtilService = dalamudUtilService;
|
||||||
_uiSharedService = uiSharedService;
|
_uiSharedService = uiSharedService;
|
||||||
|
_lightlessNotificationService = lightlessNotificationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum SelectedTab
|
private enum SelectedTab
|
||||||
@@ -199,15 +201,79 @@ public class TopTabMenu
|
|||||||
if (TabSelection != SelectedTab.None) ImGuiHelpers.ScaledDummy(3f);
|
if (TabSelection != SelectedTab.None) ImGuiHelpers.ScaledDummy(3f);
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (ImGui.Button("Add Test Pair Request"))
|
if (ImGui.Button("Test Pair Request"))
|
||||||
{
|
{
|
||||||
var fakeCid = Guid.NewGuid().ToString("N");
|
_lightlessNotificationService.ShowPairRequestNotification(
|
||||||
var display = _pairRequestService.RegisterIncomingRequest(fakeCid, "Debug pair request");
|
"Debug User",
|
||||||
_lightlessMediator.Publish(new NotificationMessage(
|
"debug-user-id",
|
||||||
"Pair request received (debug)",
|
onAccept: () =>
|
||||||
display.Message,
|
{
|
||||||
|
_lightlessNotificationService.ShowNotification(
|
||||||
|
"Pair Accepted",
|
||||||
|
"Debug pair request was accepted!",
|
||||||
NotificationType.Info,
|
NotificationType.Info,
|
||||||
TimeSpan.FromSeconds(5)));
|
TimeSpan.FromSeconds(3));
|
||||||
|
},
|
||||||
|
onDecline: () =>
|
||||||
|
{
|
||||||
|
_lightlessNotificationService.ShowNotification(
|
||||||
|
"Pair Declined",
|
||||||
|
"Debug pair request was declined.",
|
||||||
|
NotificationType.Warning,
|
||||||
|
TimeSpan.FromSeconds(3));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("Test Info"))
|
||||||
|
{
|
||||||
|
_lightlessNotificationService.ShowNotification(
|
||||||
|
"Information",
|
||||||
|
"This is a test ifno notification with some longer text to see how it wraps. This is a test ifno notification with some longer text to see how it wraps. This is a test ifno notification with some longer text to see how it wraps. This is a test ifno notification with some longer text to see how it wraps.",
|
||||||
|
NotificationType.Info,
|
||||||
|
TimeSpan.FromSeconds(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("Test Warning"))
|
||||||
|
{
|
||||||
|
_lightlessNotificationService.ShowNotification(
|
||||||
|
"Warning",
|
||||||
|
"This is a test warning notification.",
|
||||||
|
NotificationType.Warning,
|
||||||
|
TimeSpan.FromSeconds(7));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("Test Error"))
|
||||||
|
{
|
||||||
|
_lightlessNotificationService.ShowNotification(
|
||||||
|
"Error",
|
||||||
|
"This is a test error notification erp police",
|
||||||
|
NotificationType.Error,
|
||||||
|
TimeSpan.FromSeconds(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Button("Test Download Progress"))
|
||||||
|
{
|
||||||
|
var downloadStatus = new List<(string playerName, float progress, string status)>
|
||||||
|
{
|
||||||
|
("Mauwmauw Nekochan", 0.85f, "downloading"),
|
||||||
|
("Raelynn Kitsune", 0.34f, "downloading"),
|
||||||
|
("Jaina Elraeth", 0.67f, "downloading"),
|
||||||
|
("Vaelstra Bloodthorn", 0.19f, "downloading"),
|
||||||
|
("Lydia Hera Moondrop", 0.86f, "downloading"),
|
||||||
|
("C'liina Star", 1.0f, "completed")
|
||||||
|
};
|
||||||
|
|
||||||
|
_lightlessNotificationService.ShowPairDownloadNotification(downloadStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("Dismiss Download"))
|
||||||
|
{
|
||||||
|
_lightlessNotificationService.DismissPairDownloadNotification();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using LightlessSync.API.Dto.Group;
|
|||||||
using LightlessSync.API.Dto.User;
|
using LightlessSync.API.Dto.User;
|
||||||
using LightlessSync.LightlessConfiguration.Models;
|
using LightlessSync.LightlessConfiguration.Models;
|
||||||
using LightlessSync.Services.Mediator;
|
using LightlessSync.Services.Mediator;
|
||||||
|
using LightlessSync.Utils;
|
||||||
using Microsoft.AspNetCore.SignalR.Client;
|
using Microsoft.AspNetCore.SignalR.Client;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
@@ -104,7 +105,6 @@ public partial class ApiController
|
|||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Client_ReceiveBroadcastPairRequest(UserPairNotificationDto dto)
|
public Task Client_ReceiveBroadcastPairRequest(UserPairNotificationDto dto)
|
||||||
{
|
{
|
||||||
if (dto == null)
|
if (dto == null)
|
||||||
@@ -112,17 +112,55 @@ public partial class ApiController
|
|||||||
|
|
||||||
var request = _pairRequestService.RegisterIncomingRequest(dto.myHashedCid, dto.message ?? string.Empty);
|
var request = _pairRequestService.RegisterIncomingRequest(dto.myHashedCid, dto.message ?? string.Empty);
|
||||||
|
|
||||||
Mediator.Publish(new NotificationMessage(
|
// Use the new interactive notification system for pair requests
|
||||||
"Pair request received",
|
var senderName = string.IsNullOrEmpty(request.DisplayName) ? "Unknown User" : request.DisplayName;
|
||||||
request.Message,
|
_lightlessNotificationService.ShowPairRequestNotification(
|
||||||
|
senderName,
|
||||||
|
request.HashedCid,
|
||||||
|
onAccept: () =>
|
||||||
|
{
|
||||||
|
// Fire and forget async operation
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var myCidHash = (await _dalamudUtil.GetCIDAsync().ConfigureAwait(false)).ToString().GetHash256();
|
||||||
|
await TryPairWithContentId(request.HashedCid, myCidHash).ConfigureAwait(false);
|
||||||
|
_pairRequestService.RemoveRequest(request.HashedCid);
|
||||||
|
|
||||||
|
_lightlessNotificationService.ShowNotification(
|
||||||
|
"Pair Request Accepted",
|
||||||
|
$"Sent a pair request back to {senderName}.",
|
||||||
NotificationType.Info,
|
NotificationType.Info,
|
||||||
TimeSpan.FromSeconds(5)));
|
TimeSpan.FromSeconds(3));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_lightlessNotificationService.ShowNotification(
|
||||||
|
"Failed to Accept Pair Request",
|
||||||
|
ex.Message,
|
||||||
|
NotificationType.Error,
|
||||||
|
TimeSpan.FromSeconds(5));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onDecline: () =>
|
||||||
|
{
|
||||||
|
_pairRequestService.RemoveRequest(request.HashedCid);
|
||||||
|
_lightlessNotificationService.ShowNotification(
|
||||||
|
"Pair Request Declined",
|
||||||
|
$"Declined {senderName}'s pair request.",
|
||||||
|
NotificationType.Info,
|
||||||
|
TimeSpan.FromSeconds(3));
|
||||||
|
});
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Client_UpdateSystemInfo(SystemInfoDto systemInfo)
|
public Task Client_UpdateSystemInfo(SystemInfoDto systemInfo)
|
||||||
{
|
{
|
||||||
SystemInfoDto = systemInfo;
|
SystemInfoDto = systemInfo;
|
||||||
|
//Mediator.Publish(new UpdateSystemInfoMessage(systemInfo));
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL
|
|||||||
private readonly ServerConfigurationManager _serverManager;
|
private readonly ServerConfigurationManager _serverManager;
|
||||||
private readonly TokenProvider _tokenProvider;
|
private readonly TokenProvider _tokenProvider;
|
||||||
private readonly LightlessConfigService _lightlessConfigService;
|
private readonly LightlessConfigService _lightlessConfigService;
|
||||||
|
private readonly LightlessNotificationService _lightlessNotificationService;
|
||||||
private CancellationTokenSource _connectionCancellationTokenSource;
|
private CancellationTokenSource _connectionCancellationTokenSource;
|
||||||
private ConnectionDto? _connectionDto;
|
private ConnectionDto? _connectionDto;
|
||||||
private bool _doNotNotifyOnNextInfo = false;
|
private bool _doNotNotifyOnNextInfo = false;
|
||||||
@@ -44,7 +45,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL
|
|||||||
|
|
||||||
public ApiController(ILogger<ApiController> logger, HubFactory hubFactory, DalamudUtilService dalamudUtil,
|
public ApiController(ILogger<ApiController> logger, HubFactory hubFactory, DalamudUtilService dalamudUtil,
|
||||||
PairManager pairManager, PairRequestService pairRequestService, ServerConfigurationManager serverManager, LightlessMediator mediator,
|
PairManager pairManager, PairRequestService pairRequestService, ServerConfigurationManager serverManager, LightlessMediator mediator,
|
||||||
TokenProvider tokenProvider, LightlessConfigService lightlessConfigService) : base(logger, mediator)
|
TokenProvider tokenProvider, LightlessConfigService lightlessConfigService, LightlessNotificationService lightlessNotificationService) : base(logger, mediator)
|
||||||
{
|
{
|
||||||
_hubFactory = hubFactory;
|
_hubFactory = hubFactory;
|
||||||
_dalamudUtil = dalamudUtil;
|
_dalamudUtil = dalamudUtil;
|
||||||
@@ -53,6 +54,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL
|
|||||||
_serverManager = serverManager;
|
_serverManager = serverManager;
|
||||||
_tokenProvider = tokenProvider;
|
_tokenProvider = tokenProvider;
|
||||||
_lightlessConfigService = lightlessConfigService;
|
_lightlessConfigService = lightlessConfigService;
|
||||||
|
_lightlessNotificationService = lightlessNotificationService;
|
||||||
_connectionCancellationTokenSource = new CancellationTokenSource();
|
_connectionCancellationTokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
Mediator.Subscribe<DalamudLoginMessage>(this, (_) => DalamudUtilOnLogIn());
|
Mediator.Subscribe<DalamudLoginMessage>(this, (_) => DalamudUtilOnLogIn());
|
||||||
|
|||||||
Reference in New Issue
Block a user