Compare commits
1 Commits
notificati
...
zura-patch
| Author | SHA1 | Date | |
|---|---|---|---|
| 18b93a0bde |
@@ -86,7 +86,6 @@ public class LightlessConfig : ILightlessConfiguration
|
|||||||
public NotificationLocation LightlessErrorNotification { get; set; } = NotificationLocation.ChatAndLightlessUi;
|
public NotificationLocation LightlessErrorNotification { get; set; } = NotificationLocation.ChatAndLightlessUi;
|
||||||
public NotificationLocation LightlessPairRequestNotification { get; set; } = NotificationLocation.LightlessUi;
|
public NotificationLocation LightlessPairRequestNotification { get; set; } = NotificationLocation.LightlessUi;
|
||||||
public NotificationLocation LightlessDownloadNotification { get; set; } = NotificationLocation.TextOverlay;
|
public NotificationLocation LightlessDownloadNotification { get; set; } = NotificationLocation.TextOverlay;
|
||||||
public NotificationLocation LightlessPerformanceNotification { get; set; } = NotificationLocation.LightlessUi;
|
|
||||||
|
|
||||||
// Basic Settings
|
// Basic Settings
|
||||||
public float NotificationOpacity { get; set; } = 0.95f;
|
public float NotificationOpacity { get; set; } = 0.95f;
|
||||||
@@ -96,7 +95,6 @@ public class LightlessConfig : ILightlessConfiguration
|
|||||||
public bool ShowNotificationTimestamp { get; set; } = false;
|
public bool ShowNotificationTimestamp { get; set; } = false;
|
||||||
|
|
||||||
// Position & Layout
|
// Position & Layout
|
||||||
public NotificationCorner NotificationCorner { get; set; } = NotificationCorner.Right;
|
|
||||||
public int NotificationOffsetY { get; set; } = 50;
|
public int NotificationOffsetY { get; set; } = 50;
|
||||||
public int NotificationOffsetX { get; set; } = 0;
|
public int NotificationOffsetX { get; set; } = 0;
|
||||||
public float NotificationWidth { get; set; } = 350f;
|
public float NotificationWidth { get; set; } = 350f;
|
||||||
@@ -104,7 +102,6 @@ public class LightlessConfig : ILightlessConfiguration
|
|||||||
|
|
||||||
// Animation & Effects
|
// Animation & Effects
|
||||||
public float NotificationAnimationSpeed { get; set; } = 10f;
|
public float NotificationAnimationSpeed { get; set; } = 10f;
|
||||||
public float NotificationSlideSpeed { get; set; } = 10f;
|
|
||||||
public float NotificationAccentBarWidth { get; set; } = 3f;
|
public float NotificationAccentBarWidth { get; set; } = 3f;
|
||||||
|
|
||||||
// Duration per Type
|
// Duration per Type
|
||||||
@@ -113,19 +110,16 @@ public class LightlessConfig : ILightlessConfiguration
|
|||||||
public int ErrorNotificationDurationSeconds { get; set; } = 20;
|
public int ErrorNotificationDurationSeconds { get; set; } = 20;
|
||||||
public int PairRequestDurationSeconds { get; set; } = 180;
|
public int PairRequestDurationSeconds { get; set; } = 180;
|
||||||
public int DownloadNotificationDurationSeconds { get; set; } = 300;
|
public int DownloadNotificationDurationSeconds { get; set; } = 300;
|
||||||
public int PerformanceNotificationDurationSeconds { get; set; } = 20;
|
|
||||||
public uint CustomInfoSoundId { get; set; } = 2; // Se2
|
public uint CustomInfoSoundId { get; set; } = 2; // Se2
|
||||||
public uint CustomWarningSoundId { get; set; } = 16; // Se15
|
public uint CustomWarningSoundId { get; set; } = 16; // Se15
|
||||||
public uint CustomErrorSoundId { get; set; } = 16; // Se15
|
public uint CustomErrorSoundId { get; set; } = 16; // Se15
|
||||||
public uint PairRequestSoundId { get; set; } = 5; // Se5
|
public uint PairRequestSoundId { get; set; } = 5; // Se5
|
||||||
public uint PerformanceSoundId { get; set; } = 16; // Se15
|
public uint DownloadSoundId { get; set; } = 15; // Se14
|
||||||
public bool DisableInfoSound { get; set; } = true;
|
public bool DisableInfoSound { get; set; } = true;
|
||||||
public bool DisableWarningSound { get; set; } = true;
|
public bool DisableWarningSound { get; set; } = true;
|
||||||
public bool DisableErrorSound { get; set; } = true;
|
public bool DisableErrorSound { get; set; } = true;
|
||||||
public bool DisablePairRequestSound { get; set; } = true;
|
public bool DisablePairRequestSound { get; set; } = true;
|
||||||
public bool DisablePerformanceSound { get; set; } = true;
|
public bool DisableDownloadSound { get; set; } = true;
|
||||||
public bool ShowPerformanceNotificationActions { get; set; } = true;
|
|
||||||
public bool ShowPairRequestNotificationActions { get; set; } = true;
|
|
||||||
public bool UseFocusTarget { get; set; } = false;
|
public bool UseFocusTarget { get; set; } = false;
|
||||||
public bool overrideFriendColor { get; set; } = false;
|
public bool overrideFriendColor { get; set; } = false;
|
||||||
public bool overridePartyColor { get; set; } = false;
|
public bool overridePartyColor { get; set; } = false;
|
||||||
|
|||||||
@@ -17,12 +17,5 @@ public enum NotificationType
|
|||||||
Warning,
|
Warning,
|
||||||
Error,
|
Error,
|
||||||
PairRequest,
|
PairRequest,
|
||||||
Download,
|
Download
|
||||||
Performance
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum NotificationCorner
|
|
||||||
{
|
|
||||||
Right,
|
|
||||||
Left
|
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors></Authors>
|
<Authors></Authors>
|
||||||
<Company></Company>
|
<Company></Company>
|
||||||
<Version>1.12.3</Version>
|
<Version>1.12.2</Version>
|
||||||
<Description></Description>
|
<Description></Description>
|
||||||
<Copyright></Copyright>
|
<Copyright></Copyright>
|
||||||
<PackageProjectUrl>https://github.com/Light-Public-Syncshells/LightlessClient</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/Light-Public-Syncshells/LightlessClient</PackageProjectUrl>
|
||||||
|
|||||||
@@ -98,19 +98,7 @@ public class PlayerDataFactory
|
|||||||
|
|
||||||
private unsafe bool CheckForNullDrawObjectUnsafe(IntPtr playerPointer)
|
private unsafe bool CheckForNullDrawObjectUnsafe(IntPtr playerPointer)
|
||||||
{
|
{
|
||||||
if (playerPointer == IntPtr.Zero)
|
return ((Character*)playerPointer)->GameObject.DrawObject == null;
|
||||||
return true;
|
|
||||||
|
|
||||||
var character = (Character*)playerPointer;
|
|
||||||
|
|
||||||
if (character == null)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
var gameObject = &character->GameObject;
|
|
||||||
if (gameObject == null)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return gameObject->DrawObject == null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<CharacterDataFragment> CreateCharacterData(GameObjectHandler playerRelatedObject, CancellationToken ct)
|
private async Task<CharacterDataFragment> CreateCharacterData(GameObjectHandler playerRelatedObject, CancellationToken ct)
|
||||||
|
|||||||
@@ -190,8 +190,7 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
notificationManager,
|
notificationManager,
|
||||||
chatGui,
|
chatGui,
|
||||||
s.GetRequiredService<LightlessMediator>(),
|
s.GetRequiredService<LightlessMediator>(),
|
||||||
s.GetRequiredService<PairRequestService>(),
|
s.GetRequiredService<PairRequestService>()));
|
||||||
s.GetRequiredService<BroadcastService>()));
|
|
||||||
collection.AddSingleton((s) =>
|
collection.AddSingleton((s) =>
|
||||||
{
|
{
|
||||||
var httpClient = new HttpClient();
|
var httpClient = new HttpClient();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using LightlessSync.API.Dto.Group;
|
using LightlessSync.API.Dto.Group;
|
||||||
using LightlessSync.API.Dto.User;
|
using LightlessSync.API.Dto.User;
|
||||||
using LightlessSync.LightlessConfiguration;
|
using LightlessSync.LightlessConfiguration;
|
||||||
using LightlessSync.Services.Mediator;
|
using LightlessSync.Services.Mediator;
|
||||||
@@ -394,10 +394,6 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
|||||||
if (!IsLightFinderAvailable)
|
if (!IsLightFinderAvailable)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("ToggleBroadcast - Lightfinder is not available.");
|
_logger.LogWarning("ToggleBroadcast - Lightfinder is not available.");
|
||||||
_mediator.Publish(new NotificationMessage(
|
|
||||||
"Broadcast Unavailable",
|
|
||||||
"Lightfinder is not available on this server.",
|
|
||||||
LightlessConfiguration.Models.NotificationType.Error));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,10 +403,6 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
|||||||
if (!_config.Current.BroadcastEnabled && cooldown is { } cd && cd > TimeSpan.Zero)
|
if (!_config.Current.BroadcastEnabled && cooldown is { } cd && cd > TimeSpan.Zero)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Cooldown active. Must wait {Remaining}s before re-enabling.", cd.TotalSeconds);
|
_logger.LogWarning("Cooldown active. Must wait {Remaining}s before re-enabling.", cd.TotalSeconds);
|
||||||
_mediator.Publish(new NotificationMessage(
|
|
||||||
"Broadcast Cooldown",
|
|
||||||
$"Please wait {cd.TotalSeconds:F0} seconds before re-enabling broadcast.",
|
|
||||||
LightlessConfiguration.Models.NotificationType.Warning));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,19 +427,10 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
|||||||
_logger.LogDebug("Toggling broadcast. Server currently broadcasting: {ServerStatus}, setting to: {NewStatus}", isCurrentlyBroadcasting, newStatus);
|
_logger.LogDebug("Toggling broadcast. Server currently broadcasting: {ServerStatus}, setting to: {NewStatus}", isCurrentlyBroadcasting, newStatus);
|
||||||
|
|
||||||
_mediator.Publish(new EnableBroadcastMessage(hashedCid, newStatus));
|
_mediator.Publish(new EnableBroadcastMessage(hashedCid, newStatus));
|
||||||
|
|
||||||
_mediator.Publish(new NotificationMessage(
|
|
||||||
newStatus ? "Broadcast Enabled" : "Broadcast Disabled",
|
|
||||||
newStatus ? "Your Lightfinder broadcast has been enabled." : "Your Lightfinder broadcast has been disabled.",
|
|
||||||
LightlessConfiguration.Models.NotificationType.Info));
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Failed to determine current broadcast status for toggle");
|
_logger.LogError(ex, "Failed to determine current broadcast status for toggle");
|
||||||
_mediator.Publish(new NotificationMessage(
|
|
||||||
"Broadcast Failed",
|
|
||||||
$"Failed to toggle broadcast: {ex.Message}",
|
|
||||||
LightlessConfiguration.Models.NotificationType.Error));
|
|
||||||
}
|
}
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@@ -510,7 +493,6 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
|||||||
{
|
{
|
||||||
_logger.LogDebug("Broadcast TTL expired. Disabling broadcast locally.");
|
_logger.LogDebug("Broadcast TTL expired. Disabling broadcast locally.");
|
||||||
ApplyBroadcastDisabled(forcePublish: true);
|
ApplyBroadcastDisabled(forcePublish: true);
|
||||||
_mediator.Publish(new BroadcastExpiredMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -48,23 +48,20 @@ public record PetNamesMessage(string PetNicknamesData) : MessageBase;
|
|||||||
public record HonorificReadyMessage : MessageBase;
|
public record HonorificReadyMessage : MessageBase;
|
||||||
public record TransientResourceChangedMessage(IntPtr Address) : MessageBase;
|
public record TransientResourceChangedMessage(IntPtr Address) : MessageBase;
|
||||||
public record HaltScanMessage(string Source) : MessageBase;
|
public record HaltScanMessage(string Source) : MessageBase;
|
||||||
|
public record ResumeScanMessage(string Source) : MessageBase;
|
||||||
public record NotificationMessage
|
public record NotificationMessage
|
||||||
(string Title, string Message, NotificationType Type, TimeSpan? TimeShownOnScreen = null) : MessageBase;
|
(string Title, string Message, NotificationType Type, TimeSpan? TimeShownOnScreen = null) : MessageBase;
|
||||||
public record PerformanceNotificationMessage
|
|
||||||
(string Title, string Message, UserData UserData, bool IsPaused, string PlayerName) : MessageBase;
|
|
||||||
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 LightlessNotificationMessage(LightlessSync.UI.Models.LightlessNotification Notification) : MessageBase;
|
||||||
public record LightlessNotificationDismissMessage(string NotificationId) : MessageBase;
|
public record LightlessNotificationDismissMessage(string NotificationId) : MessageBase;
|
||||||
public record ClearAllNotificationsMessage : 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;
|
||||||
public record HubReconnectingMessage(Exception? Exception) : SameThreadMessage;
|
public record HubReconnectingMessage(Exception? Exception) : SameThreadMessage;
|
||||||
public record HubReconnectedMessage(string? Arg) : SameThreadMessage;
|
public record HubReconnectedMessage(string? Arg) : SameThreadMessage;
|
||||||
public record HubClosedMessage(Exception? Exception) : SameThreadMessage;
|
public record HubClosedMessage(Exception? Exception) : SameThreadMessage;
|
||||||
public record ResumeScanMessage(string Source) : MessageBase;
|
|
||||||
public record DownloadReadyMessage(Guid RequestId) : MessageBase;
|
public record DownloadReadyMessage(Guid RequestId) : MessageBase;
|
||||||
public record DownloadStartedMessage(GameObjectHandler DownloadId, Dictionary<string, FileDownloadStatus> DownloadStatus) : MessageBase;
|
public record DownloadStartedMessage(GameObjectHandler DownloadId, Dictionary<string, FileDownloadStatus> DownloadStatus) : MessageBase;
|
||||||
public record DownloadFinishedMessage(GameObjectHandler DownloadId) : MessageBase;
|
public record DownloadFinishedMessage(GameObjectHandler DownloadId) : MessageBase;
|
||||||
@@ -108,8 +105,6 @@ public record EnableBroadcastMessage(string HashedCid, bool Enabled) : MessageBa
|
|||||||
public record BroadcastStatusChangedMessage(bool Enabled, TimeSpan? Ttl) : MessageBase;
|
public record BroadcastStatusChangedMessage(bool Enabled, TimeSpan? Ttl) : MessageBase;
|
||||||
public record SyncshellBroadcastsUpdatedMessage : MessageBase;
|
public record SyncshellBroadcastsUpdatedMessage : MessageBase;
|
||||||
public record PairRequestsUpdatedMessage : MessageBase;
|
public record PairRequestsUpdatedMessage : MessageBase;
|
||||||
public record PairRequestReceivedMessage(string SenderName, string SenderId) : MessageBase;
|
|
||||||
public record BroadcastExpiredMessage : MessageBase;
|
|
||||||
public record VisibilityChange : MessageBase;
|
public record VisibilityChange : MessageBase;
|
||||||
#pragma warning restore S2094
|
#pragma warning restore S2094
|
||||||
#pragma warning restore MA0048 // File name must match type name
|
#pragma warning restore MA0048 // File name must match type name
|
||||||
@@ -10,11 +10,9 @@ using LightlessSync.UI.Models;
|
|||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||||
using LightlessSync.API.Data;
|
|
||||||
using NotificationType = LightlessSync.LightlessConfiguration.Models.NotificationType;
|
using NotificationType = LightlessSync.LightlessConfiguration.Models.NotificationType;
|
||||||
|
|
||||||
namespace LightlessSync.Services;
|
namespace LightlessSync.Services;
|
||||||
|
|
||||||
public class NotificationService : DisposableMediatorSubscriberBase, IHostedService
|
public class NotificationService : DisposableMediatorSubscriberBase, IHostedService
|
||||||
{
|
{
|
||||||
private readonly ILogger<NotificationService> _logger;
|
private readonly ILogger<NotificationService> _logger;
|
||||||
@@ -23,7 +21,6 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
|||||||
private readonly INotificationManager _notificationManager;
|
private readonly INotificationManager _notificationManager;
|
||||||
private readonly IChatGui _chatGui;
|
private readonly IChatGui _chatGui;
|
||||||
private readonly PairRequestService _pairRequestService;
|
private readonly PairRequestService _pairRequestService;
|
||||||
private readonly BroadcastService _broadcastService;
|
|
||||||
private readonly HashSet<string> _shownPairRequestNotifications = new();
|
private readonly HashSet<string> _shownPairRequestNotifications = new();
|
||||||
|
|
||||||
public NotificationService(
|
public NotificationService(
|
||||||
@@ -33,8 +30,7 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
|||||||
INotificationManager notificationManager,
|
INotificationManager notificationManager,
|
||||||
IChatGui chatGui,
|
IChatGui chatGui,
|
||||||
LightlessMediator mediator,
|
LightlessMediator mediator,
|
||||||
PairRequestService pairRequestService,
|
PairRequestService pairRequestService) : base(logger, mediator)
|
||||||
BroadcastService broadcastService) : base(logger, mediator)
|
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
@@ -42,16 +38,12 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
|||||||
_notificationManager = notificationManager;
|
_notificationManager = notificationManager;
|
||||||
_chatGui = chatGui;
|
_chatGui = chatGui;
|
||||||
_pairRequestService = pairRequestService;
|
_pairRequestService = pairRequestService;
|
||||||
_broadcastService = broadcastService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
Mediator.Subscribe<NotificationMessage>(this, HandleNotificationMessage);
|
Mediator.Subscribe<NotificationMessage>(this, HandleNotificationMessage);
|
||||||
Mediator.Subscribe<PairRequestsUpdatedMessage>(this, HandlePairRequestsUpdated);
|
Mediator.Subscribe<PairRequestsUpdatedMessage>(this, HandlePairRequestsUpdated);
|
||||||
Mediator.Subscribe<PairRequestReceivedMessage>(this, HandlePairRequestReceived);
|
|
||||||
Mediator.Subscribe<PerformanceNotificationMessage>(this, HandlePerformanceNotification);
|
|
||||||
Mediator.Subscribe<BroadcastExpiredMessage>(this, HandleBroadcastExpired);
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,19 +106,6 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void ShowPairRequestNotification(string senderName, string senderId, Action onAccept, Action onDecline)
|
public void ShowPairRequestNotification(string senderName, string senderId, Action onAccept, Action onDecline)
|
||||||
{
|
|
||||||
var location = GetNotificationLocation(NotificationType.PairRequest);
|
|
||||||
|
|
||||||
// Show in chat if configured
|
|
||||||
if (location == NotificationLocation.Chat || location == NotificationLocation.ChatAndLightlessUi)
|
|
||||||
{
|
|
||||||
ShowChat(new NotificationMessage("Pair Request Received", $"{senderName} wants to directly pair with you.", NotificationType.PairRequest));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show Lightless notification if configured and action buttons are enabled
|
|
||||||
if ((location == NotificationLocation.LightlessUi || location == NotificationLocation.ChatAndLightlessUi)
|
|
||||||
&& _configService.Current.UseLightlessNotifications
|
|
||||||
&& _configService.Current.ShowPairRequestNotificationActions)
|
|
||||||
{
|
{
|
||||||
var notification = new LightlessNotification
|
var notification = new LightlessNotification
|
||||||
{
|
{
|
||||||
@@ -146,12 +125,6 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
|||||||
|
|
||||||
Mediator.Publish(new LightlessNotificationMessage(notification));
|
Mediator.Publish(new LightlessNotificationMessage(notification));
|
||||||
}
|
}
|
||||||
else if (location != NotificationLocation.Nowhere && location != NotificationLocation.Chat)
|
|
||||||
{
|
|
||||||
// Fall back to regular notification without action buttons
|
|
||||||
HandleNotificationMessage(new NotificationMessage("Pair Request Received", $"{senderName} wants to directly pair with you.", NotificationType.PairRequest));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private uint? GetPairRequestSoundId() =>
|
private uint? GetPairRequestSoundId() =>
|
||||||
!_configService.Current.DisablePairRequestSound ? _configService.Current.PairRequestSoundId : null;
|
!_configService.Current.DisablePairRequestSound ? _configService.Current.PairRequestSoundId : null;
|
||||||
@@ -383,7 +356,6 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
|||||||
NotificationType.Error => TimeSpan.FromSeconds(_configService.Current.ErrorNotificationDurationSeconds),
|
NotificationType.Error => TimeSpan.FromSeconds(_configService.Current.ErrorNotificationDurationSeconds),
|
||||||
NotificationType.PairRequest => TimeSpan.FromSeconds(_configService.Current.PairRequestDurationSeconds),
|
NotificationType.PairRequest => TimeSpan.FromSeconds(_configService.Current.PairRequestDurationSeconds),
|
||||||
NotificationType.Download => TimeSpan.FromSeconds(_configService.Current.DownloadNotificationDurationSeconds),
|
NotificationType.Download => TimeSpan.FromSeconds(_configService.Current.DownloadNotificationDurationSeconds),
|
||||||
NotificationType.Performance => TimeSpan.FromSeconds(_configService.Current.PerformanceNotificationDurationSeconds),
|
|
||||||
_ => TimeSpan.FromSeconds(10)
|
_ => TimeSpan.FromSeconds(10)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -399,8 +371,7 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
|||||||
NotificationType.Info => _configService.Current.DisableInfoSound,
|
NotificationType.Info => _configService.Current.DisableInfoSound,
|
||||||
NotificationType.Warning => _configService.Current.DisableWarningSound,
|
NotificationType.Warning => _configService.Current.DisableWarningSound,
|
||||||
NotificationType.Error => _configService.Current.DisableErrorSound,
|
NotificationType.Error => _configService.Current.DisableErrorSound,
|
||||||
NotificationType.Performance => _configService.Current.DisablePerformanceSound,
|
NotificationType.Download => _configService.Current.DisableDownloadSound,
|
||||||
NotificationType.Download => true, // Download sounds always disabled
|
|
||||||
_ => false
|
_ => false
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -409,7 +380,7 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
|||||||
NotificationType.Info => _configService.Current.CustomInfoSoundId,
|
NotificationType.Info => _configService.Current.CustomInfoSoundId,
|
||||||
NotificationType.Warning => _configService.Current.CustomWarningSoundId,
|
NotificationType.Warning => _configService.Current.CustomWarningSoundId,
|
||||||
NotificationType.Error => _configService.Current.CustomErrorSoundId,
|
NotificationType.Error => _configService.Current.CustomErrorSoundId,
|
||||||
NotificationType.Performance => _configService.Current.PerformanceSoundId,
|
NotificationType.Download => _configService.Current.DownloadSoundId,
|
||||||
_ => NotificationSounds.GetDefaultSound(type)
|
_ => NotificationSounds.GetDefaultSound(type)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -447,7 +418,6 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
|||||||
NotificationType.Error => _configService.Current.LightlessErrorNotification,
|
NotificationType.Error => _configService.Current.LightlessErrorNotification,
|
||||||
NotificationType.PairRequest => _configService.Current.LightlessPairRequestNotification,
|
NotificationType.PairRequest => _configService.Current.LightlessPairRequestNotification,
|
||||||
NotificationType.Download => _configService.Current.LightlessDownloadNotification,
|
NotificationType.Download => _configService.Current.LightlessDownloadNotification,
|
||||||
NotificationType.Performance => _configService.Current.LightlessPerformanceNotification,
|
|
||||||
_ => NotificationLocation.LightlessUi
|
_ => NotificationLocation.LightlessUi
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -535,18 +505,6 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
|||||||
case NotificationType.Error:
|
case NotificationType.Error:
|
||||||
PrintErrorChat(msg.Message);
|
PrintErrorChat(msg.Message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NotificationType.PairRequest:
|
|
||||||
PrintPairRequestChat(msg.Title, msg.Message);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NotificationType.Performance:
|
|
||||||
PrintPerformanceChat(msg.Title, msg.Message);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Download notifications don't support chat output, will be a giga spam otherwise
|
|
||||||
case NotificationType.Download:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,32 +528,6 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
|||||||
_chatGui.Print(se.BuiltString);
|
_chatGui.Print(se.BuiltString);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintPairRequestChat(string? title, string? message)
|
|
||||||
{
|
|
||||||
SeStringBuilder se = new SeStringBuilder().AddText("[Lightless Sync] ")
|
|
||||||
.AddUiForeground("Pair Request: ", 541).AddUiForegroundOff()
|
|
||||||
.AddText(title ?? message ?? string.Empty);
|
|
||||||
_chatGui.Print(se.BuiltString);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PrintPerformanceChat(string? title, string? message)
|
|
||||||
{
|
|
||||||
SeStringBuilder se = new SeStringBuilder().AddText("[Lightless Sync] ")
|
|
||||||
.AddUiForeground("Performance: ", 508).AddUiForegroundOff()
|
|
||||||
.AddText(title ?? message ?? string.Empty);
|
|
||||||
_chatGui.Print(se.BuiltString);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandlePairRequestReceived(PairRequestReceivedMessage msg)
|
|
||||||
{
|
|
||||||
ShowPairRequestNotification(
|
|
||||||
msg.SenderName,
|
|
||||||
msg.SenderId,
|
|
||||||
() => _pairRequestService.AcceptPairRequest(msg.SenderId, msg.SenderName),
|
|
||||||
() => _pairRequestService.DeclinePairRequest(msg.SenderId)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandlePairRequestsUpdated(PairRequestsUpdatedMessage _)
|
private void HandlePairRequestsUpdated(PairRequestsUpdatedMessage _)
|
||||||
{
|
{
|
||||||
var activeRequests = _pairRequestService.GetActiveRequests();
|
var activeRequests = _pairRequestService.GetActiveRequests();
|
||||||
@@ -613,219 +545,17 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
|||||||
_shownPairRequestNotifications.Remove(hashedCid);
|
_shownPairRequestNotifications.Remove(hashedCid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track active requests
|
// Show/update notifications for all active requests
|
||||||
foreach (var request in activeRequests)
|
foreach (var request in activeRequests)
|
||||||
{
|
{
|
||||||
_shownPairRequestNotifications.Add(request.HashedCid);
|
_shownPairRequestNotifications.Add(request.HashedCid);
|
||||||
|
ShowPairRequestNotification(
|
||||||
|
request.DisplayName,
|
||||||
|
request.HashedCid,
|
||||||
|
() => _pairRequestService.AcceptPairRequest(request.HashedCid, request.DisplayName),
|
||||||
|
() => _pairRequestService.DeclinePairRequest(request.HashedCid)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandlePerformanceNotification(PerformanceNotificationMessage msg)
|
|
||||||
{
|
|
||||||
var location = GetNotificationLocation(NotificationType.Performance);
|
|
||||||
|
|
||||||
// Show in chat if configured
|
|
||||||
if (location == NotificationLocation.Chat || location == NotificationLocation.ChatAndLightlessUi)
|
|
||||||
{
|
|
||||||
ShowChat(new NotificationMessage(msg.Title, msg.Message, NotificationType.Performance));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show Lightless notification if configured and action buttons are enabled
|
|
||||||
if ((location == NotificationLocation.LightlessUi || location == NotificationLocation.ChatAndLightlessUi)
|
|
||||||
&& _configService.Current.UseLightlessNotifications
|
|
||||||
&& _configService.Current.ShowPerformanceNotificationActions)
|
|
||||||
{
|
|
||||||
var actions = CreatePerformanceActions(msg.UserData, msg.IsPaused, msg.PlayerName);
|
|
||||||
var notification = new LightlessNotification
|
|
||||||
{
|
|
||||||
Title = msg.Title,
|
|
||||||
Message = msg.Message,
|
|
||||||
Type = NotificationType.Performance,
|
|
||||||
Duration = TimeSpan.FromSeconds(_configService.Current.PerformanceNotificationDurationSeconds),
|
|
||||||
Actions = actions,
|
|
||||||
SoundEffectId = GetSoundEffectId(NotificationType.Performance, null)
|
|
||||||
};
|
|
||||||
|
|
||||||
if (notification.SoundEffectId.HasValue)
|
|
||||||
{
|
|
||||||
PlayNotificationSound(notification.SoundEffectId.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Mediator.Publish(new LightlessNotificationMessage(notification));
|
|
||||||
}
|
|
||||||
else if (location != NotificationLocation.Nowhere && location != NotificationLocation.Chat)
|
|
||||||
{
|
|
||||||
// Fall back to regular notification without action buttons
|
|
||||||
HandleNotificationMessage(new NotificationMessage(msg.Title, msg.Message, NotificationType.Performance));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<LightlessNotificationAction> CreatePerformanceActions(UserData userData, bool isPaused, string playerName)
|
|
||||||
{
|
|
||||||
var actions = new List<LightlessNotificationAction>();
|
|
||||||
|
|
||||||
if (isPaused)
|
|
||||||
{
|
|
||||||
actions.Add(new LightlessNotificationAction
|
|
||||||
{
|
|
||||||
Label = "Unpause",
|
|
||||||
Icon = FontAwesomeIcon.Play,
|
|
||||||
Color = UIColors.Get("LightlessGreen"),
|
|
||||||
IsPrimary = true,
|
|
||||||
OnClick = (notification) =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Mediator.Publish(new CyclePauseMessage(userData));
|
|
||||||
DismissNotification(notification);
|
|
||||||
|
|
||||||
var displayName = GetUserDisplayName(userData, playerName);
|
|
||||||
ShowNotification(
|
|
||||||
"Player Unpaused",
|
|
||||||
$"Successfully unpaused {displayName}",
|
|
||||||
NotificationType.Info,
|
|
||||||
TimeSpan.FromSeconds(3));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Failed to unpause player {uid}", userData.UID);
|
|
||||||
var displayName = GetUserDisplayName(userData, playerName);
|
|
||||||
ShowNotification(
|
|
||||||
"Unpause Failed",
|
|
||||||
$"Failed to unpause {displayName}",
|
|
||||||
NotificationType.Error,
|
|
||||||
TimeSpan.FromSeconds(5));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
actions.Add(new LightlessNotificationAction
|
|
||||||
{
|
|
||||||
Label = "Pause",
|
|
||||||
Icon = FontAwesomeIcon.Pause,
|
|
||||||
Color = UIColors.Get("LightlessOrange"),
|
|
||||||
IsPrimary = true,
|
|
||||||
OnClick = (notification) =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Mediator.Publish(new PauseMessage(userData));
|
|
||||||
DismissNotification(notification);
|
|
||||||
|
|
||||||
var displayName = GetUserDisplayName(userData, playerName);
|
|
||||||
ShowNotification(
|
|
||||||
"Player Paused",
|
|
||||||
$"Successfully paused {displayName}",
|
|
||||||
NotificationType.Info,
|
|
||||||
TimeSpan.FromSeconds(3));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Failed to pause player {uid}", userData.UID);
|
|
||||||
var displayName = GetUserDisplayName(userData, playerName);
|
|
||||||
ShowNotification(
|
|
||||||
"Pause Failed",
|
|
||||||
$"Failed to pause {displayName}",
|
|
||||||
NotificationType.Error,
|
|
||||||
TimeSpan.FromSeconds(5));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add dismiss button
|
|
||||||
actions.Add(new LightlessNotificationAction
|
|
||||||
{
|
|
||||||
Label = "Dismiss",
|
|
||||||
Icon = FontAwesomeIcon.Times,
|
|
||||||
Color = UIColors.Get("DimRed"),
|
|
||||||
IsPrimary = false,
|
|
||||||
OnClick = (notification) =>
|
|
||||||
{
|
|
||||||
DismissNotification(notification);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return actions;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetUserDisplayName(UserData userData, string playerName)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(userData.Alias) && !string.Equals(userData.Alias, userData.UID, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
return $"{playerName} ({userData.Alias})";
|
|
||||||
}
|
|
||||||
return $"{playerName} ({userData.UID})";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleBroadcastExpired(BroadcastExpiredMessage _)
|
|
||||||
{
|
|
||||||
var location = GetNotificationLocation(NotificationType.Warning);
|
|
||||||
|
|
||||||
if (location == NotificationLocation.Chat || location == NotificationLocation.ChatAndLightlessUi)
|
|
||||||
{
|
|
||||||
ShowChat(new NotificationMessage("Broadcast Expired", "Your Lightfinder broadcast has expired after 3 hours.", NotificationType.Warning));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((location == NotificationLocation.LightlessUi || location == NotificationLocation.ChatAndLightlessUi)
|
|
||||||
&& _configService.Current.UseLightlessNotifications)
|
|
||||||
{
|
|
||||||
var notification = new LightlessNotification
|
|
||||||
{
|
|
||||||
Id = "broadcast_expired",
|
|
||||||
Title = "Broadcast Expired",
|
|
||||||
Message = "Your Lightfinder broadcast has expired after 3 hours. Would you like to re-enable it?",
|
|
||||||
Type = NotificationType.Warning,
|
|
||||||
Duration = TimeSpan.FromSeconds(_configService.Current.WarningNotificationDurationSeconds),
|
|
||||||
SoundEffectId = GetSoundEffectId(NotificationType.Warning, null),
|
|
||||||
Actions = CreateBroadcastExpiredActions()
|
|
||||||
};
|
|
||||||
|
|
||||||
if (notification.SoundEffectId.HasValue)
|
|
||||||
{
|
|
||||||
PlayNotificationSound(notification.SoundEffectId.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Mediator.Publish(new LightlessNotificationMessage(notification));
|
|
||||||
}
|
|
||||||
else if (location != NotificationLocation.Nowhere && location != NotificationLocation.Chat)
|
|
||||||
{
|
|
||||||
HandleNotificationMessage(new NotificationMessage("Broadcast Expired", "Your Lightfinder broadcast has expired after 3 hours.", NotificationType.Warning));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<LightlessNotificationAction> CreateBroadcastExpiredActions()
|
|
||||||
{
|
|
||||||
return new List<LightlessNotificationAction>
|
|
||||||
{
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
Id = "re_enable",
|
|
||||||
Label = "Re-enable Broadcast",
|
|
||||||
Icon = FontAwesomeIcon.Plus,
|
|
||||||
Color = UIColors.Get("LightlessGreen"),
|
|
||||||
IsPrimary = true,
|
|
||||||
OnClick = (n) =>
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Re-enabling broadcast from notification");
|
|
||||||
_broadcastService.ToggleBroadcast();
|
|
||||||
DismissNotification(n);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
Id = "close",
|
|
||||||
Label = "Close",
|
|
||||||
Icon = FontAwesomeIcon.Times,
|
|
||||||
Color = UIColors.Get("DimRed"),
|
|
||||||
OnClick = (n) =>
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Broadcast expiration notification dismissed");
|
|
||||||
DismissNotification(n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -70,10 +70,6 @@ public sealed class PairRequestService : DisposableMediatorSubscriberBase
|
|||||||
: _dalamudUtil.RunOnFrameworkThread(() => ToDisplay(entry)).GetAwaiter().GetResult();
|
: _dalamudUtil.RunOnFrameworkThread(() => ToDisplay(entry)).GetAwaiter().GetResult();
|
||||||
|
|
||||||
Mediator.Publish(new PairRequestsUpdatedMessage());
|
Mediator.Publish(new PairRequestsUpdatedMessage());
|
||||||
|
|
||||||
var senderName = string.IsNullOrEmpty(display.DisplayName) ? "Unknown User" : display.DisplayName;
|
|
||||||
Mediator.Publish(new PairRequestReceivedMessage(senderName, display.HashedCid));
|
|
||||||
|
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,26 +78,23 @@ public class PlayerPerformanceService
|
|||||||
string warningText = string.Empty;
|
string warningText = string.Empty;
|
||||||
if (exceedsTris && !exceedsVram)
|
if (exceedsTris && !exceedsVram)
|
||||||
{
|
{
|
||||||
warningText = $"Player {pairHandler.Pair.PlayerName} ({pairHandler.Pair.UserData.AliasOrUID}) exceeds your configured triangle warning threshold\n" +
|
warningText = $"Player {pairHandler.Pair.PlayerName} ({pairHandler.Pair.UserData.AliasOrUID}) exceeds your configured triangle warning threshold (" +
|
||||||
$"{triUsage}/{config.TrisWarningThresholdThousands * 1000} triangles";
|
$"{triUsage}/{config.TrisWarningThresholdThousands * 1000} triangles).";
|
||||||
}
|
}
|
||||||
else if (!exceedsTris)
|
else if (!exceedsTris)
|
||||||
{
|
{
|
||||||
warningText = $"Player {pairHandler.Pair.PlayerName} ({pairHandler.Pair.UserData.AliasOrUID}) exceeds your configured VRAM warning threshold\n" +
|
warningText = $"Player {pairHandler.Pair.PlayerName} ({pairHandler.Pair.UserData.AliasOrUID}) exceeds your configured VRAM warning threshold (" +
|
||||||
$"{UiSharedService.ByteToString(vramUsage, true)}/{config.VRAMSizeWarningThresholdMiB} MiB";
|
$"{UiSharedService.ByteToString(vramUsage, true)}/{config.VRAMSizeWarningThresholdMiB} MiB).";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
warningText = $"Player {pairHandler.Pair.PlayerName} ({pairHandler.Pair.UserData.AliasOrUID}) exceeds both VRAM warning threshold and triangle warning threshold\n" +
|
warningText = $"Player {pairHandler.Pair.PlayerName} ({pairHandler.Pair.UserData.AliasOrUID}) exceeds both VRAM warning threshold (" +
|
||||||
$"{UiSharedService.ByteToString(vramUsage, true)}/{config.VRAMSizeWarningThresholdMiB} MiB and {triUsage}/{config.TrisWarningThresholdThousands * 1000} triangles";
|
$"{UiSharedService.ByteToString(vramUsage, true)}/{config.VRAMSizeWarningThresholdMiB} MiB) and " +
|
||||||
|
$"triangle warning threshold ({triUsage}/{config.TrisWarningThresholdThousands * 1000} triangles).";
|
||||||
}
|
}
|
||||||
|
|
||||||
_mediator.Publish(new PerformanceNotificationMessage(
|
_mediator.Publish(new NotificationMessage($"{pairHandler.Pair.PlayerName} ({pairHandler.Pair.UserData.AliasOrUID}) exceeds performance threshold(s)",
|
||||||
$"{pairHandler.Pair.PlayerName} ({pairHandler.Pair.UserData.AliasOrUID}) exceeds performance threshold(s)",
|
warningText, LightlessConfiguration.Models.NotificationType.Warning));
|
||||||
warningText,
|
|
||||||
pairHandler.Pair.UserData,
|
|
||||||
pairHandler.Pair.IsPaused,
|
|
||||||
pairHandler.Pair.PlayerName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -141,15 +138,11 @@ public class PlayerPerformanceService
|
|||||||
if (CheckForThreshold(config.AutoPausePlayersExceedingThresholds, config.TrisAutoPauseThresholdThousands * 1000,
|
if (CheckForThreshold(config.AutoPausePlayersExceedingThresholds, config.TrisAutoPauseThresholdThousands * 1000,
|
||||||
triUsage, config.AutoPausePlayersWithPreferredPermissionsExceedingThresholds, isPrefPerm))
|
triUsage, config.AutoPausePlayersWithPreferredPermissionsExceedingThresholds, isPrefPerm))
|
||||||
{
|
{
|
||||||
var message = $"Player {pair.PlayerName} ({pair.UserData.AliasOrUID}) exceeded your configured triangle auto pause threshold and has been automatically paused\n" +
|
_mediator.Publish(new NotificationMessage($"{pair.PlayerName} ({pair.UserData.AliasOrUID}) automatically paused",
|
||||||
$"{triUsage}/{config.TrisAutoPauseThresholdThousands * 1000} triangles";
|
$"Player {pair.PlayerName} ({pair.UserData.AliasOrUID}) exceeded your configured triangle auto pause threshold (" +
|
||||||
|
$"{triUsage}/{config.TrisAutoPauseThresholdThousands * 1000} triangles)" +
|
||||||
_mediator.Publish(new PerformanceNotificationMessage(
|
$" and has been automatically paused.",
|
||||||
$"{pair.PlayerName} ({pair.UserData.AliasOrUID}) automatically paused",
|
LightlessConfiguration.Models.NotificationType.Warning));
|
||||||
message,
|
|
||||||
pair.UserData,
|
|
||||||
true,
|
|
||||||
pair.PlayerName));
|
|
||||||
|
|
||||||
_mediator.Publish(new EventMessage(new Event(pair.PlayerName, pair.UserData, nameof(PlayerPerformanceService), EventSeverity.Warning,
|
_mediator.Publish(new EventMessage(new Event(pair.PlayerName, pair.UserData, nameof(PlayerPerformanceService), EventSeverity.Warning,
|
||||||
$"Exceeds triangle threshold: automatically paused ({triUsage}/{config.TrisAutoPauseThresholdThousands * 1000} triangles)")));
|
$"Exceeds triangle threshold: automatically paused ({triUsage}/{config.TrisAutoPauseThresholdThousands * 1000} triangles)")));
|
||||||
@@ -221,15 +214,11 @@ public class PlayerPerformanceService
|
|||||||
if (CheckForThreshold(config.AutoPausePlayersExceedingThresholds, config.VRAMSizeAutoPauseThresholdMiB * 1024 * 1024,
|
if (CheckForThreshold(config.AutoPausePlayersExceedingThresholds, config.VRAMSizeAutoPauseThresholdMiB * 1024 * 1024,
|
||||||
vramUsage, config.AutoPausePlayersWithPreferredPermissionsExceedingThresholds, isPrefPerm))
|
vramUsage, config.AutoPausePlayersWithPreferredPermissionsExceedingThresholds, isPrefPerm))
|
||||||
{
|
{
|
||||||
var message = $"Player {pair.PlayerName} ({pair.UserData.AliasOrUID}) exceeded your configured VRAM auto pause threshold and has been automatically paused\n" +
|
_mediator.Publish(new NotificationMessage($"{pair.PlayerName} ({pair.UserData.AliasOrUID}) automatically paused",
|
||||||
$"{UiSharedService.ByteToString(vramUsage, addSuffix: true)}/{config.VRAMSizeAutoPauseThresholdMiB}MiB";
|
$"Player {pair.PlayerName} ({pair.UserData.AliasOrUID}) exceeded your configured VRAM auto pause threshold (" +
|
||||||
|
$"{UiSharedService.ByteToString(vramUsage, addSuffix: true)}/{config.VRAMSizeAutoPauseThresholdMiB}MiB)" +
|
||||||
_mediator.Publish(new PerformanceNotificationMessage(
|
$" and has been automatically paused.",
|
||||||
$"{pair.PlayerName} ({pair.UserData.AliasOrUID}) automatically paused",
|
LightlessConfiguration.Models.NotificationType.Warning));
|
||||||
message,
|
|
||||||
pair.UserData,
|
|
||||||
true,
|
|
||||||
pair.PlayerName));
|
|
||||||
|
|
||||||
_mediator.Publish(new PauseMessage(pair.UserData));
|
_mediator.Publish(new PauseMessage(pair.UserData));
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
private readonly ConcurrentDictionary<GameObjectHandler, bool> _uploadingPlayers = new();
|
private readonly ConcurrentDictionary<GameObjectHandler, bool> _uploadingPlayers = new();
|
||||||
private readonly NotificationService _notificationService;
|
private readonly NotificationService _notificationService;
|
||||||
private bool _notificationDismissed = true;
|
private bool _notificationDismissed = true;
|
||||||
private int _lastDownloadStateHash = 0;
|
|
||||||
|
|
||||||
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,
|
PairProcessingLimiter pairProcessingLimiter, FileUploadManager fileTransferManager, LightlessMediator mediator, UiSharedService uiShared,
|
||||||
@@ -66,7 +65,7 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
_currentDownloads.TryRemove(msg.DownloadId, out _);
|
_currentDownloads.TryRemove(msg.DownloadId, out _);
|
||||||
if (!_currentDownloads.Any())
|
if (!_currentDownloads.Any())
|
||||||
{
|
{
|
||||||
Mediator.Publish(new LightlessNotificationDismissMessage("pair_download_progress"));
|
_notificationService.DismissPairDownloadNotification();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Mediator.Subscribe<GposeStartMessage>(this, (_) => IsOpen = false);
|
Mediator.Subscribe<GposeStartMessage>(this, (_) => IsOpen = false);
|
||||||
@@ -117,7 +116,7 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Error drawing upload progress");
|
// ignore errors thrown from UI
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -132,19 +131,17 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
// Use notification system
|
// Use notification system
|
||||||
if (_currentDownloads.Any())
|
if (_currentDownloads.Any())
|
||||||
{
|
{
|
||||||
UpdateDownloadNotificationIfChanged(limiterSnapshot);
|
UpdateDownloadNotification(limiterSnapshot);
|
||||||
_notificationDismissed = false;
|
_notificationDismissed = false;
|
||||||
}
|
}
|
||||||
else if (!_notificationDismissed)
|
else if (!_notificationDismissed)
|
||||||
{
|
{
|
||||||
Mediator.Publish(new LightlessNotificationDismissMessage("pair_download_progress"));
|
_notificationService.DismissPairDownloadNotification();
|
||||||
_notificationDismissed = true;
|
_notificationDismissed = true;
|
||||||
_lastDownloadStateHash = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Use text overlay
|
|
||||||
if (limiterSnapshot.IsEnabled)
|
if (limiterSnapshot.IsEnabled)
|
||||||
{
|
{
|
||||||
var queueColor = limiterSnapshot.Waiting > 0 ? ImGuiColors.DalamudYellow : ImGuiColors.DalamudGrey;
|
var queueColor = limiterSnapshot.Waiting > 0 ? ImGuiColors.DalamudYellow : ImGuiColors.DalamudGrey;
|
||||||
@@ -186,7 +183,7 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Error drawing download progress");
|
// ignore errors thrown from UI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +255,7 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Error drawing upload progress");
|
// ignore errors thrown on UI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,34 +298,20 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateDownloadNotificationIfChanged(PairProcessingLimiterSnapshot limiterSnapshot)
|
private void UpdateDownloadNotification(PairProcessingLimiterSnapshot limiterSnapshot)
|
||||||
{
|
{
|
||||||
var downloadStatus = new List<(string playerName, float progress, string status)>(_currentDownloads.Count);
|
var downloadStatus = new List<(string playerName, float progress, string status)>();
|
||||||
var hashCode = new HashCode();
|
|
||||||
|
|
||||||
foreach (var item in _currentDownloads)
|
foreach (var item in _currentDownloads.ToList())
|
||||||
{
|
{
|
||||||
var dlSlot = 0;
|
var dlSlot = item.Value.Count(c => c.Value.DownloadStatus == DownloadStatus.WaitingForSlot);
|
||||||
var dlQueue = 0;
|
var dlQueue = item.Value.Count(c => c.Value.DownloadStatus == DownloadStatus.WaitingForQueue);
|
||||||
var dlProg = 0;
|
var dlProg = item.Value.Count(c => c.Value.DownloadStatus == DownloadStatus.Downloading);
|
||||||
var dlDecomp = 0;
|
var dlDecomp = item.Value.Count(c => c.Value.DownloadStatus == DownloadStatus.Decompressing);
|
||||||
long totalBytes = 0;
|
var totalFiles = item.Value.Sum(c => c.Value.TotalFiles);
|
||||||
long transferredBytes = 0;
|
var transferredFiles = item.Value.Sum(c => c.Value.TransferredFiles);
|
||||||
|
var totalBytes = item.Value.Sum(c => c.Value.TotalBytes);
|
||||||
// Single pass through the dictionary to count everything - avoid multiple LINQ iterations
|
var transferredBytes = item.Value.Sum(c => c.Value.TransferredBytes);
|
||||||
foreach (var entry in item.Value)
|
|
||||||
{
|
|
||||||
var fileStatus = entry.Value;
|
|
||||||
switch (fileStatus.DownloadStatus)
|
|
||||||
{
|
|
||||||
case DownloadStatus.WaitingForSlot: dlSlot++; break;
|
|
||||||
case DownloadStatus.WaitingForQueue: dlQueue++; break;
|
|
||||||
case DownloadStatus.Downloading: dlProg++; break;
|
|
||||||
case DownloadStatus.Decompressing: dlDecomp++; break;
|
|
||||||
}
|
|
||||||
totalBytes += fileStatus.TotalBytes;
|
|
||||||
transferredBytes += fileStatus.TransferredBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
var progress = totalBytes > 0 ? (float)transferredBytes / totalBytes : 0f;
|
var progress = totalBytes > 0 ? (float)transferredBytes / totalBytes : 0f;
|
||||||
|
|
||||||
@@ -340,28 +323,14 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
else status = "completed";
|
else status = "completed";
|
||||||
|
|
||||||
downloadStatus.Add((item.Key.Name, progress, status));
|
downloadStatus.Add((item.Key.Name, progress, status));
|
||||||
|
|
||||||
// Build hash from meaningful state
|
|
||||||
hashCode.Add(item.Key.Name);
|
|
||||||
hashCode.Add(transferredBytes);
|
|
||||||
hashCode.Add(totalBytes);
|
|
||||||
hashCode.Add(status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pass queue waiting count separately, show notification if there are downloads or queue items
|
||||||
var queueWaiting = limiterSnapshot.IsEnabled ? limiterSnapshot.Waiting : 0;
|
var queueWaiting = limiterSnapshot.IsEnabled ? limiterSnapshot.Waiting : 0;
|
||||||
hashCode.Add(queueWaiting);
|
if (downloadStatus.Any() || queueWaiting > 0)
|
||||||
|
|
||||||
var currentHash = hashCode.ToHashCode();
|
|
||||||
|
|
||||||
// Only update notification if state has actually changed
|
|
||||||
if (currentHash != _lastDownloadStateHash)
|
|
||||||
{
|
|
||||||
_lastDownloadStateHash = currentHash;
|
|
||||||
if (downloadStatus.Count > 0 || queueWaiting > 0)
|
|
||||||
{
|
{
|
||||||
_notificationService.ShowPairDownloadNotification(downloadStatus, queueWaiting);
|
_notificationService.ShowPairDownloadNotification(downloadStatus, queueWaiting);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -22,16 +22,10 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
|||||||
private const float WindowPaddingOffset = 6f;
|
private const float WindowPaddingOffset = 6f;
|
||||||
private const float SlideAnimationDistance = 100f;
|
private const float SlideAnimationDistance = 100f;
|
||||||
private const float OutAnimationSpeedMultiplier = 0.7f;
|
private const float OutAnimationSpeedMultiplier = 0.7f;
|
||||||
private const float ContentPaddingX = 10f;
|
|
||||||
private const float ContentPaddingY = 6f;
|
|
||||||
private const float TitleMessageSpacing = 4f;
|
|
||||||
private const float ActionButtonSpacing = 8f;
|
|
||||||
|
|
||||||
private readonly List<LightlessNotification> _notifications = new();
|
private readonly List<LightlessNotification> _notifications = new();
|
||||||
private readonly object _notificationLock = new();
|
private readonly object _notificationLock = new();
|
||||||
private readonly LightlessConfigService _configService;
|
private readonly LightlessConfigService _configService;
|
||||||
private readonly Dictionary<string, float> _notificationYOffsets = new();
|
|
||||||
private readonly Dictionary<string, float> _notificationTargetYOffsets = new();
|
|
||||||
|
|
||||||
public LightlessNotificationUI(ILogger<LightlessNotificationUI> logger, LightlessMediator mediator, PerformanceCollectorService performanceCollector, LightlessConfigService configService)
|
public LightlessNotificationUI(ILogger<LightlessNotificationUI> logger, LightlessMediator mediator, PerformanceCollectorService performanceCollector, LightlessConfigService configService)
|
||||||
: base(logger, mediator, "Lightless Notifications##LightlessNotifications", performanceCollector)
|
: base(logger, mediator, "Lightless Notifications##LightlessNotifications", performanceCollector)
|
||||||
@@ -55,11 +49,12 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
Mediator.Subscribe<LightlessNotificationMessage>(this, HandleNotificationMessage);
|
Mediator.Subscribe<LightlessNotificationMessage>(this, HandleNotificationMessage);
|
||||||
Mediator.Subscribe<LightlessNotificationDismissMessage>(this, HandleNotificationDismissMessage);
|
Mediator.Subscribe<LightlessNotificationDismissMessage>(this, HandleNotificationDismissMessage);
|
||||||
Mediator.Subscribe<ClearAllNotificationsMessage>(this, HandleClearAllNotifications);
|
|
||||||
}
|
}
|
||||||
private void HandleNotificationMessage(LightlessNotificationMessage message) => AddNotification(message.Notification);
|
private void HandleNotificationMessage(LightlessNotificationMessage message) =>
|
||||||
private void HandleNotificationDismissMessage(LightlessNotificationDismissMessage message) => RemoveNotification(message.NotificationId);
|
AddNotification(message.Notification);
|
||||||
private void HandleClearAllNotifications(ClearAllNotificationsMessage message) => ClearAllNotifications();
|
|
||||||
|
private void HandleNotificationDismissMessage(LightlessNotificationDismissMessage message) =>
|
||||||
|
RemoveNotification(message.NotificationId);
|
||||||
|
|
||||||
public void AddNotification(LightlessNotification notification)
|
public void AddNotification(LightlessNotification notification)
|
||||||
{
|
{
|
||||||
@@ -101,26 +96,12 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearAllNotifications()
|
|
||||||
{
|
|
||||||
lock (_notificationLock)
|
|
||||||
{
|
|
||||||
foreach (var notification in _notifications)
|
|
||||||
{
|
|
||||||
StartOutAnimation(notification);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StartOutAnimation(LightlessNotification notification)
|
private void StartOutAnimation(LightlessNotification notification)
|
||||||
{
|
{
|
||||||
notification.IsAnimatingOut = true;
|
notification.IsAnimatingOut = true;
|
||||||
notification.IsAnimatingIn = false;
|
notification.IsAnimatingIn = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ShouldRemoveNotification(LightlessNotification notification) =>
|
|
||||||
notification.IsAnimatingOut && notification.AnimationProgress <= 0.01f;
|
|
||||||
|
|
||||||
protected override void DrawInternal()
|
protected override void DrawInternal()
|
||||||
{
|
{
|
||||||
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
|
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
|
||||||
@@ -137,11 +118,7 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
var viewport = ImGui.GetMainViewport();
|
var viewport = ImGui.GetMainViewport();
|
||||||
|
|
||||||
// Window auto-resizes based on content (AlwaysAutoResize flag)
|
|
||||||
Position = CalculateWindowPosition(viewport);
|
Position = CalculateWindowPosition(viewport);
|
||||||
PositionCondition = ImGuiCond.Always;
|
|
||||||
|
|
||||||
DrawAllNotifications();
|
DrawAllNotifications();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,32 +127,24 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
private Vector2 CalculateWindowPosition(ImGuiViewportPtr viewport)
|
private Vector2 CalculateWindowPosition(ImGuiViewportPtr viewport)
|
||||||
{
|
{
|
||||||
var corner = _configService.Current.NotificationCorner;
|
var x = viewport.WorkPos.X + viewport.WorkSize.X -
|
||||||
var offsetX = _configService.Current.NotificationOffsetX;
|
_configService.Current.NotificationWidth -
|
||||||
var width = _configService.Current.NotificationWidth;
|
_configService.Current.NotificationOffsetX -
|
||||||
|
WindowPaddingOffset;
|
||||||
float posX = corner == NotificationCorner.Left
|
var y = viewport.WorkPos.Y + _configService.Current.NotificationOffsetY;
|
||||||
? viewport.WorkPos.X + offsetX - WindowPaddingOffset
|
return new Vector2(x, y);
|
||||||
: viewport.WorkPos.X + viewport.WorkSize.X - width - offsetX - WindowPaddingOffset;
|
|
||||||
|
|
||||||
return new Vector2(posX, viewport.WorkPos.Y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawAllNotifications()
|
private void DrawAllNotifications()
|
||||||
{
|
{
|
||||||
var offsetY = _configService.Current.NotificationOffsetY;
|
|
||||||
var startY = ImGui.GetCursorPosY() + offsetY;
|
|
||||||
|
|
||||||
for (int i = 0; i < _notifications.Count; i++)
|
for (int i = 0; i < _notifications.Count; i++)
|
||||||
{
|
{
|
||||||
var notification = _notifications[i];
|
DrawNotification(_notifications[i], i);
|
||||||
|
|
||||||
if (_notificationYOffsets.TryGetValue(notification.Id, out var yOffset))
|
if (i < _notifications.Count - 1)
|
||||||
{
|
{
|
||||||
ImGui.SetCursorPosY(startY + yOffset);
|
ImGui.Dummy(new Vector2(0, _configService.Current.NotificationSpacing));
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawNotification(notification, i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,65 +174,18 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
private void UpdateAnimationsAndRemoveExpired(float deltaTime)
|
private void UpdateAnimationsAndRemoveExpired(float deltaTime)
|
||||||
{
|
{
|
||||||
UpdateTargetYPositions();
|
|
||||||
|
|
||||||
for (int i = _notifications.Count - 1; i >= 0; i--)
|
for (int i = _notifications.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
var notification = _notifications[i];
|
var notification = _notifications[i];
|
||||||
UpdateNotificationAnimation(notification, deltaTime);
|
UpdateNotificationAnimation(notification, deltaTime);
|
||||||
UpdateNotificationYOffset(notification, deltaTime);
|
|
||||||
|
|
||||||
if (ShouldRemoveNotification(notification))
|
if (ShouldRemoveNotification(notification))
|
||||||
{
|
{
|
||||||
_notifications.RemoveAt(i);
|
_notifications.RemoveAt(i);
|
||||||
_notificationYOffsets.Remove(notification.Id);
|
|
||||||
_notificationTargetYOffsets.Remove(notification.Id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateTargetYPositions()
|
|
||||||
{
|
|
||||||
float currentY = 0f;
|
|
||||||
|
|
||||||
for (int i = 0; i < _notifications.Count; i++)
|
|
||||||
{
|
|
||||||
var notification = _notifications[i];
|
|
||||||
|
|
||||||
if (!_notificationTargetYOffsets.ContainsKey(notification.Id))
|
|
||||||
{
|
|
||||||
_notificationTargetYOffsets[notification.Id] = currentY;
|
|
||||||
_notificationYOffsets[notification.Id] = currentY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_notificationTargetYOffsets[notification.Id] = currentY;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentY += CalculateNotificationHeight(notification) + _configService.Current.NotificationSpacing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateNotificationYOffset(LightlessNotification notification, float deltaTime)
|
|
||||||
{
|
|
||||||
if (!_notificationYOffsets.ContainsKey(notification.Id) || !_notificationTargetYOffsets.ContainsKey(notification.Id))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var current = _notificationYOffsets[notification.Id];
|
|
||||||
var target = _notificationTargetYOffsets[notification.Id];
|
|
||||||
var diff = target - current;
|
|
||||||
|
|
||||||
if (Math.Abs(diff) < 0.5f)
|
|
||||||
{
|
|
||||||
_notificationYOffsets[notification.Id] = target;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var speed = _configService.Current.NotificationSlideSpeed;
|
|
||||||
_notificationYOffsets[notification.Id] = current + (diff * deltaTime * speed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateNotificationAnimation(LightlessNotification notification, float deltaTime)
|
private void UpdateNotificationAnimation(LightlessNotification notification, float deltaTime)
|
||||||
{
|
{
|
||||||
if (notification.IsAnimatingIn && notification.AnimationProgress < 1f)
|
if (notification.IsAnimatingIn && notification.AnimationProgress < 1f)
|
||||||
@@ -287,24 +209,20 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector2 CalculateSlideOffset(float alpha)
|
private bool ShouldRemoveNotification(LightlessNotification notification) =>
|
||||||
{
|
notification.IsAnimatingOut && notification.AnimationProgress <= 0.01f;
|
||||||
var distance = (1f - alpha) * SlideAnimationDistance;
|
|
||||||
var corner = _configService.Current.NotificationCorner;
|
|
||||||
return corner == NotificationCorner.Left ? new Vector2(-distance, 0) : new Vector2(distance, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawNotification(LightlessNotification notification, int index)
|
private void DrawNotification(LightlessNotification notification, int index)
|
||||||
{
|
{
|
||||||
var alpha = notification.AnimationProgress;
|
var alpha = notification.AnimationProgress;
|
||||||
if (alpha <= 0f) return;
|
if (alpha <= 0f) return;
|
||||||
|
|
||||||
var slideOffset = CalculateSlideOffset(alpha);
|
var slideOffset = (1f - alpha) * SlideAnimationDistance;
|
||||||
var originalCursorPos = ImGui.GetCursorPos();
|
var originalCursorPos = ImGui.GetCursorPos();
|
||||||
ImGui.SetCursorPos(originalCursorPos + slideOffset);
|
ImGui.SetCursorPosX(originalCursorPos.X + slideOffset);
|
||||||
|
|
||||||
var notificationHeight = CalculateNotificationHeight(notification);
|
var notificationHeight = CalculateNotificationHeight(notification);
|
||||||
var notificationWidth = _configService.Current.NotificationWidth;
|
var notificationWidth = _configService.Current.NotificationWidth - slideOffset;
|
||||||
|
|
||||||
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
|
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
|
||||||
|
|
||||||
@@ -390,29 +308,16 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
|||||||
private void DrawAccentBar(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, Vector4 accentColor)
|
private void DrawAccentBar(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, Vector4 accentColor)
|
||||||
{
|
{
|
||||||
var accentWidth = _configService.Current.NotificationAccentBarWidth;
|
var accentWidth = _configService.Current.NotificationAccentBarWidth;
|
||||||
if (accentWidth <= 0f) return;
|
if (accentWidth > 0f)
|
||||||
|
|
||||||
var corner = _configService.Current.NotificationCorner;
|
|
||||||
Vector2 accentStart, accentEnd;
|
|
||||||
|
|
||||||
if (corner == NotificationCorner.Left)
|
|
||||||
{
|
{
|
||||||
accentStart = windowPos + new Vector2(windowSize.X - accentWidth, 0);
|
|
||||||
accentEnd = windowPos + windowSize;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
accentStart = windowPos;
|
|
||||||
accentEnd = windowPos + new Vector2(accentWidth, windowSize.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
drawList.AddRectFilled(
|
drawList.AddRectFilled(
|
||||||
accentStart,
|
windowPos,
|
||||||
accentEnd,
|
windowPos + new Vector2(accentWidth, windowSize.Y),
|
||||||
ImGui.ColorConvertFloat4ToU32(accentColor),
|
ImGui.ColorConvertFloat4ToU32(accentColor),
|
||||||
3f
|
3f
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawDurationProgressBar(LightlessNotification notification, float alpha, Vector2 windowPos, Vector2 windowSize, ImDrawListPtr drawList)
|
private void DrawDurationProgressBar(LightlessNotification notification, float alpha, Vector2 windowPos, Vector2 windowSize, ImDrawListPtr drawList)
|
||||||
{
|
{
|
||||||
@@ -466,113 +371,82 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
private void DrawNotificationText(LightlessNotification notification, float alpha)
|
private void DrawNotificationText(LightlessNotification notification, float alpha)
|
||||||
{
|
{
|
||||||
var contentPos = new Vector2(ContentPaddingX, ContentPaddingY);
|
var padding = new Vector2(10f, 6f);
|
||||||
|
var contentPos = new Vector2(padding.X, padding.Y);
|
||||||
var windowSize = ImGui.GetWindowSize();
|
var windowSize = ImGui.GetWindowSize();
|
||||||
var contentWidth = CalculateContentWidth(windowSize.X);
|
var contentSize = new Vector2(windowSize.X - padding.X, windowSize.Y - padding.Y * 2);
|
||||||
|
|
||||||
ImGui.SetCursorPos(contentPos);
|
ImGui.SetCursorPos(contentPos);
|
||||||
|
|
||||||
var titleHeight = DrawTitle(notification, contentWidth, alpha);
|
var titleHeight = DrawTitle(notification, contentSize.X, alpha);
|
||||||
DrawMessage(notification, contentPos, contentWidth, titleHeight, alpha);
|
DrawMessage(notification, contentPos, contentSize.X, titleHeight, alpha);
|
||||||
|
|
||||||
if (HasActions(notification))
|
if (notification.Actions.Count > 0)
|
||||||
{
|
{
|
||||||
PositionActionsAtBottom(windowSize.Y);
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetStyle().ItemSpacing.Y);
|
||||||
DrawNotificationActions(notification, contentWidth, alpha);
|
ImGui.SetCursorPosX(contentPos.X);
|
||||||
|
DrawNotificationActions(notification, contentSize.X, alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private float CalculateContentWidth(float windowWidth) =>
|
|
||||||
windowWidth - (ContentPaddingX * 2);
|
|
||||||
|
|
||||||
private bool HasActions(LightlessNotification notification) =>
|
|
||||||
notification.Actions.Count > 0;
|
|
||||||
|
|
||||||
private void PositionActionsAtBottom(float windowHeight)
|
|
||||||
{
|
|
||||||
var actionHeight = ImGui.GetFrameHeight();
|
|
||||||
var bottomY = windowHeight - ContentPaddingY - actionHeight;
|
|
||||||
ImGui.SetCursorPosY(bottomY);
|
|
||||||
ImGui.SetCursorPosX(ContentPaddingX);
|
|
||||||
}
|
|
||||||
|
|
||||||
private float DrawTitle(LightlessNotification notification, float contentWidth, float alpha)
|
private float DrawTitle(LightlessNotification notification, float contentWidth, float alpha)
|
||||||
{
|
{
|
||||||
var titleColor = new Vector4(1f, 1f, 1f, alpha);
|
using (ImRaii.PushColor(ImGuiCol.Text, new Vector4(1f, 1f, 1f, alpha)))
|
||||||
var titleText = FormatTitleText(notification);
|
|
||||||
|
|
||||||
using (ImRaii.PushColor(ImGuiCol.Text, titleColor))
|
|
||||||
{
|
{
|
||||||
return DrawWrappedText(titleText, contentWidth);
|
ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + contentWidth);
|
||||||
}
|
var titleStartY = ImGui.GetCursorPosY();
|
||||||
}
|
|
||||||
|
|
||||||
private string FormatTitleText(LightlessNotification notification)
|
var titleText = _configService.Current.ShowNotificationTimestamp
|
||||||
{
|
? $"[{notification.CreatedAt.ToLocalTime():HH:mm:ss}] {notification.Title}"
|
||||||
if (!_configService.Current.ShowNotificationTimestamp)
|
: notification.Title;
|
||||||
return notification.Title;
|
|
||||||
|
|
||||||
var timestamp = notification.CreatedAt.ToLocalTime().ToString("HH:mm:ss");
|
ImGui.TextWrapped(titleText);
|
||||||
return $"[{timestamp}] {notification.Title}";
|
var titleHeight = ImGui.GetCursorPosY() - titleStartY;
|
||||||
}
|
|
||||||
|
|
||||||
private float DrawWrappedText(string text, float wrapWidth)
|
|
||||||
{
|
|
||||||
ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + wrapWidth);
|
|
||||||
var startY = ImGui.GetCursorPosY();
|
|
||||||
ImGui.TextWrapped(text);
|
|
||||||
var height = ImGui.GetCursorPosY() - startY;
|
|
||||||
ImGui.PopTextWrapPos();
|
ImGui.PopTextWrapPos();
|
||||||
return height;
|
return titleHeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawMessage(LightlessNotification notification, Vector2 contentPos, float contentWidth, float titleHeight, float alpha)
|
private void DrawMessage(LightlessNotification notification, Vector2 contentPos, float contentWidth, float titleHeight, float alpha)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(notification.Message)) return;
|
if (string.IsNullOrEmpty(notification.Message)) return;
|
||||||
|
|
||||||
var messagePos = contentPos + new Vector2(0f, titleHeight + TitleMessageSpacing);
|
ImGui.SetCursorPos(contentPos + new Vector2(0f, titleHeight + 4f));
|
||||||
var messageColor = new Vector4(0.9f, 0.9f, 0.9f, alpha);
|
ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + contentWidth);
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.Text, new Vector4(0.9f, 0.9f, 0.9f, alpha)))
|
||||||
ImGui.SetCursorPos(messagePos);
|
|
||||||
|
|
||||||
using (ImRaii.PushColor(ImGuiCol.Text, messageColor))
|
|
||||||
{
|
{
|
||||||
DrawWrappedText(notification.Message, contentWidth);
|
ImGui.TextWrapped(notification.Message);
|
||||||
}
|
}
|
||||||
|
ImGui.PopTextWrapPos();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawNotificationActions(LightlessNotification notification, float availableWidth, float alpha)
|
private void DrawNotificationActions(LightlessNotification notification, float availableWidth, float alpha)
|
||||||
{
|
{
|
||||||
var buttonWidth = CalculateActionButtonWidth(notification.Actions.Count, availableWidth);
|
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}",
|
_logger.LogDebug("Drawing {ActionCount} notification actions, buttonWidth: {ButtonWidth}, availableWidth: {AvailableWidth}",
|
||||||
notification.Actions.Count, buttonWidth, availableWidth);
|
notification.Actions.Count, buttonWidth, availableWidth);
|
||||||
|
|
||||||
var startX = ImGui.GetCursorPosX();
|
var startCursorPos = ImGui.GetCursorPos();
|
||||||
|
|
||||||
for (int i = 0; i < notification.Actions.Count; i++)
|
for (int i = 0; i < notification.Actions.Count; i++)
|
||||||
{
|
{
|
||||||
|
var action = notification.Actions[i];
|
||||||
|
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
{
|
{
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
PositionActionButton(i, startX, buttonWidth);
|
var currentX = startCursorPos.X + i * (buttonWidth + buttonSpacing);
|
||||||
|
ImGui.SetCursorPosX(currentX);
|
||||||
}
|
}
|
||||||
DrawActionButton(notification.Actions[i], notification, alpha, buttonWidth);
|
DrawActionButton(action, notification, alpha, buttonWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private float CalculateActionButtonWidth(int actionCount, float availableWidth)
|
|
||||||
{
|
|
||||||
var totalSpacing = (actionCount - 1) * ActionButtonSpacing;
|
|
||||||
return (availableWidth - totalSpacing) / actionCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PositionActionButton(int index, float startX, float buttonWidth)
|
|
||||||
{
|
|
||||||
var xPosition = startX + index * (buttonWidth + ActionButtonSpacing);
|
|
||||||
ImGui.SetCursorPosX(xPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawActionButton(LightlessNotificationAction action, LightlessNotification notification, float alpha, float 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);
|
_logger.LogDebug("Drawing action button: {ActionId} - {ActionLabel}, width: {ButtonWidth}", action.Id, action.Label, buttonWidth);
|
||||||
@@ -669,7 +543,7 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
private float CalculateNotificationHeight(LightlessNotification notification)
|
private float CalculateNotificationHeight(LightlessNotification notification)
|
||||||
{
|
{
|
||||||
var contentWidth = CalculateContentWidth(_configService.Current.NotificationWidth);
|
var contentWidth = _configService.Current.NotificationWidth - 35f;
|
||||||
var height = 12f;
|
var height = 12f;
|
||||||
|
|
||||||
height += CalculateTitleHeight(notification, contentWidth);
|
height += CalculateTitleHeight(notification, contentWidth);
|
||||||
@@ -716,8 +590,6 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
|||||||
NotificationType.Error => UIColors.Get("DimRed"),
|
NotificationType.Error => UIColors.Get("DimRed"),
|
||||||
NotificationType.PairRequest => UIColors.Get("LightlessBlue"),
|
NotificationType.PairRequest => UIColors.Get("LightlessBlue"),
|
||||||
NotificationType.Download => UIColors.Get("LightlessGreen"),
|
NotificationType.Download => UIColors.Get("LightlessGreen"),
|
||||||
NotificationType.Performance => UIColors.Get("LightlessOrange"),
|
|
||||||
|
|
||||||
_ => UIColors.Get("LightlessPurple")
|
_ => UIColors.Get("LightlessPurple")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1990,7 +1990,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
("LightlessBlue", "Secondary Blue", "Secondary title colors, visable pairs"),
|
("LightlessBlue", "Secondary Blue", "Secondary title colors, visable pairs"),
|
||||||
("LightlessGreen", "Success Green", "Join buttons and success messages"),
|
("LightlessGreen", "Success Green", "Join buttons and success messages"),
|
||||||
("LightlessYellow", "Warning Yellow", "Warning colors"),
|
("LightlessYellow", "Warning Yellow", "Warning colors"),
|
||||||
("LightlessOrange", "Performance Orange", "Performance notifications and warnings"),
|
("LightlessYellow2", "Warning Yellow (Alt)", "Warning colors"),
|
||||||
("PairBlue", "Syncshell Blue", "Syncshell headers, toggle highlights, and moderator actions"),
|
("PairBlue", "Syncshell Blue", "Syncshell headers, toggle highlights, and moderator actions"),
|
||||||
("DimRed", "Error Red", "Error and offline colors")
|
("DimRed", "Error Red", "Error and offline colors")
|
||||||
};
|
};
|
||||||
@@ -3493,192 +3493,69 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
if (useLightlessNotifications)
|
if (useLightlessNotifications)
|
||||||
{
|
{
|
||||||
// Lightless notification locations
|
// Lightless notification locations
|
||||||
|
ImGui.Indent();
|
||||||
|
|
||||||
var lightlessLocations = GetLightlessNotificationLocations();
|
var lightlessLocations = GetLightlessNotificationLocations();
|
||||||
var downloadLocations = GetDownloadNotificationLocations();
|
|
||||||
|
|
||||||
if (ImGui.BeginTable("##NotificationLocationTable", 3, ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit))
|
|
||||||
{
|
|
||||||
ImGui.TableSetupColumn("Notification Type", ImGuiTableColumnFlags.WidthFixed, 200f * ImGuiHelpers.GlobalScale);
|
|
||||||
ImGui.TableSetupColumn("Location", ImGuiTableColumnFlags.WidthStretch);
|
|
||||||
ImGui.TableSetupColumn("Test", ImGuiTableColumnFlags.WidthFixed, 40f * ImGuiHelpers.GlobalScale);
|
|
||||||
ImGui.TableHeadersRow();
|
|
||||||
|
|
||||||
ImGui.TableNextRow();
|
|
||||||
ImGui.TableSetColumnIndex(0);
|
|
||||||
ImGui.AlignTextToFramePadding();
|
ImGui.AlignTextToFramePadding();
|
||||||
ImGui.TextUnformatted("Info Notifications");
|
ImGui.TextUnformatted("Info Notifications:");
|
||||||
ImGui.TableSetColumnIndex(1);
|
ImGui.SameLine();
|
||||||
ImGui.SetNextItemWidth(-1);
|
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
|
||||||
_uiShared.DrawCombo("###enhanced_info", lightlessLocations, GetNotificationLocationLabel, (location) =>
|
_uiShared.DrawCombo("###enhanced_info", lightlessLocations, GetNotificationLocationLabel, (location) =>
|
||||||
{
|
{
|
||||||
_configService.Current.LightlessInfoNotification = location;
|
_configService.Current.LightlessInfoNotification = location;
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
}, _configService.Current.LightlessInfoNotification);
|
}, _configService.Current.LightlessInfoNotification);
|
||||||
ImGui.TableSetColumnIndex(2);
|
|
||||||
var availableWidth = ImGui.GetContentRegionAvail().X;
|
|
||||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
|
||||||
{
|
|
||||||
if (ImGui.Button($"{FontAwesomeIcon.Play.ToIconString()}##test_info", new Vector2(availableWidth, 0)))
|
|
||||||
{
|
|
||||||
Mediator.Publish(new NotificationMessage("Test Info",
|
|
||||||
"This is a test info notification to let you know Chocola is cute :3", NotificationType.Info));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UiSharedService.AttachToolTip("Test info notification");
|
|
||||||
|
|
||||||
ImGui.TableNextRow();
|
|
||||||
ImGui.TableSetColumnIndex(0);
|
|
||||||
ImGui.AlignTextToFramePadding();
|
ImGui.AlignTextToFramePadding();
|
||||||
ImGui.TextUnformatted("Warning Notifications");
|
ImGui.TextUnformatted("Warning Notifications:");
|
||||||
ImGui.TableSetColumnIndex(1);
|
ImGui.SameLine();
|
||||||
ImGui.SetNextItemWidth(-1);
|
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
|
||||||
_uiShared.DrawCombo("###enhanced_warning", lightlessLocations, GetNotificationLocationLabel,
|
_uiShared.DrawCombo("###enhanced_warning", lightlessLocations, GetNotificationLocationLabel,
|
||||||
(location) =>
|
(location) =>
|
||||||
{
|
{
|
||||||
_configService.Current.LightlessWarningNotification = location;
|
_configService.Current.LightlessWarningNotification = location;
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
}, _configService.Current.LightlessWarningNotification);
|
}, _configService.Current.LightlessWarningNotification);
|
||||||
ImGui.TableSetColumnIndex(2);
|
|
||||||
availableWidth = ImGui.GetContentRegionAvail().X;
|
|
||||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
|
||||||
{
|
|
||||||
if (ImGui.Button($"{FontAwesomeIcon.Play.ToIconString()}##test_warning", new Vector2(availableWidth, 0)))
|
|
||||||
{
|
|
||||||
Mediator.Publish(new NotificationMessage("Test Warning", "This is a test warning notification!",
|
|
||||||
NotificationType.Warning));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UiSharedService.AttachToolTip("Test warning notification");
|
|
||||||
|
|
||||||
ImGui.TableNextRow();
|
|
||||||
ImGui.TableSetColumnIndex(0);
|
|
||||||
ImGui.AlignTextToFramePadding();
|
ImGui.AlignTextToFramePadding();
|
||||||
ImGui.TextUnformatted("Error Notifications");
|
ImGui.TextUnformatted("Error Notifications:");
|
||||||
ImGui.TableSetColumnIndex(1);
|
ImGui.SameLine();
|
||||||
ImGui.SetNextItemWidth(-1);
|
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
|
||||||
_uiShared.DrawCombo("###enhanced_error", lightlessLocations, GetNotificationLocationLabel, (location) =>
|
_uiShared.DrawCombo("###enhanced_error", lightlessLocations, GetNotificationLocationLabel, (location) =>
|
||||||
{
|
{
|
||||||
_configService.Current.LightlessErrorNotification = location;
|
_configService.Current.LightlessErrorNotification = location;
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
}, _configService.Current.LightlessErrorNotification);
|
}, _configService.Current.LightlessErrorNotification);
|
||||||
ImGui.TableSetColumnIndex(2);
|
|
||||||
availableWidth = ImGui.GetContentRegionAvail().X;
|
|
||||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
|
||||||
{
|
|
||||||
if (ImGui.Button($"{FontAwesomeIcon.Play.ToIconString()}##test_error", new Vector2(availableWidth, 0)))
|
|
||||||
{
|
|
||||||
Mediator.Publish(new NotificationMessage("Test Error", "This is a test error notification!",
|
|
||||||
NotificationType.Error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UiSharedService.AttachToolTip("Test error notification");
|
|
||||||
|
|
||||||
ImGui.TableNextRow();
|
ImGuiHelpers.ScaledDummy(3);
|
||||||
ImGui.TableSetColumnIndex(0);
|
_uiShared.DrawHelpText("Special notification types:");
|
||||||
|
|
||||||
ImGui.AlignTextToFramePadding();
|
ImGui.AlignTextToFramePadding();
|
||||||
ImGui.TextUnformatted("Pair Request Notifications");
|
ImGui.TextUnformatted("Pair Request Notifications:");
|
||||||
ImGui.TableSetColumnIndex(1);
|
ImGui.SameLine();
|
||||||
ImGui.SetNextItemWidth(-1);
|
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
|
||||||
_uiShared.DrawCombo("###enhanced_pairrequest", lightlessLocations, GetNotificationLocationLabel,
|
_uiShared.DrawCombo("###enhanced_pairrequest", lightlessLocations, GetNotificationLocationLabel,
|
||||||
(location) =>
|
(location) =>
|
||||||
{
|
{
|
||||||
_configService.Current.LightlessPairRequestNotification = location;
|
_configService.Current.LightlessPairRequestNotification = location;
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
}, _configService.Current.LightlessPairRequestNotification);
|
}, _configService.Current.LightlessPairRequestNotification);
|
||||||
ImGui.TableSetColumnIndex(2);
|
|
||||||
availableWidth = ImGui.GetContentRegionAvail().X;
|
|
||||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
|
||||||
{
|
|
||||||
if (ImGui.Button($"{FontAwesomeIcon.Play.ToIconString()}##test_pair", new Vector2(availableWidth, 0)))
|
|
||||||
{
|
|
||||||
_lightlessNotificationService.ShowPairRequestNotification(
|
|
||||||
"Test User",
|
|
||||||
"test-uid-123",
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
Mediator.Publish(new NotificationMessage("Accepted", "You accepted the test pair request.",
|
|
||||||
NotificationType.Info));
|
|
||||||
},
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
Mediator.Publish(new NotificationMessage("Declined", "You declined the test pair request.",
|
|
||||||
NotificationType.Info));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UiSharedService.AttachToolTip("Test pair request notification");
|
|
||||||
|
|
||||||
ImGui.TableNextRow();
|
|
||||||
ImGui.TableSetColumnIndex(0);
|
|
||||||
ImGui.AlignTextToFramePadding();
|
ImGui.AlignTextToFramePadding();
|
||||||
ImGui.TextUnformatted("Download Progress Notifications");
|
ImGui.TextUnformatted("Download Progress Notifications:");
|
||||||
ImGui.TableSetColumnIndex(1);
|
ImGui.SameLine();
|
||||||
ImGui.SetNextItemWidth(-1);
|
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
|
||||||
|
var downloadLocations = GetDownloadNotificationLocations();
|
||||||
_uiShared.DrawCombo("###enhanced_download", downloadLocations, GetNotificationLocationLabel,
|
_uiShared.DrawCombo("###enhanced_download", downloadLocations, GetNotificationLocationLabel,
|
||||||
(location) =>
|
(location) =>
|
||||||
{
|
{
|
||||||
_configService.Current.LightlessDownloadNotification = location;
|
_configService.Current.LightlessDownloadNotification = location;
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
}, _configService.Current.LightlessDownloadNotification);
|
}, _configService.Current.LightlessDownloadNotification);
|
||||||
ImGui.TableSetColumnIndex(2);
|
|
||||||
availableWidth = ImGui.GetContentRegionAvail().X;
|
|
||||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
|
||||||
{
|
|
||||||
if (ImGui.Button($"{FontAwesomeIcon.Play.ToIconString()}##test_download", new Vector2(availableWidth, 0)))
|
|
||||||
{
|
|
||||||
_lightlessNotificationService.ShowPairDownloadNotification(
|
|
||||||
new List<(string playerName, float progress, string status)>
|
|
||||||
{
|
|
||||||
("Player One", 0.35f, "downloading"),
|
|
||||||
("Player Two", 0.75f, "downloading"),
|
|
||||||
("Player Three", 1.0f, "downloading")
|
|
||||||
},
|
|
||||||
queueWaiting: 2
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UiSharedService.AttachToolTip("Test download progress notification");
|
|
||||||
|
|
||||||
ImGui.TableNextRow();
|
|
||||||
ImGui.TableSetColumnIndex(0);
|
|
||||||
ImGui.AlignTextToFramePadding();
|
|
||||||
ImGui.TextUnformatted("Performance Notifications");
|
|
||||||
ImGui.TableSetColumnIndex(1);
|
|
||||||
ImGui.SetNextItemWidth(-1);
|
|
||||||
_uiShared.DrawCombo("###enhanced_performance", lightlessLocations, GetNotificationLocationLabel,
|
|
||||||
(location) =>
|
|
||||||
{
|
|
||||||
_configService.Current.LightlessPerformanceNotification = location;
|
|
||||||
_configService.Save();
|
|
||||||
}, _configService.Current.LightlessPerformanceNotification);
|
|
||||||
ImGui.TableSetColumnIndex(2);
|
|
||||||
availableWidth = ImGui.GetContentRegionAvail().X;
|
|
||||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
|
||||||
{
|
|
||||||
if (ImGui.Button($"{FontAwesomeIcon.Play.ToIconString()}##test_performance", new Vector2(availableWidth, 0)))
|
|
||||||
{
|
|
||||||
var testUserData = new UserData("TEST123", "TestUser", false, false, false, null, null);
|
|
||||||
Mediator.Publish(new PerformanceNotificationMessage(
|
|
||||||
"Test Player (TestUser) exceeds performance threshold(s)",
|
|
||||||
"Player Test Player (TestUser) exceeds your configured VRAM warning threshold\n500 MB/300 MB",
|
|
||||||
testUserData,
|
|
||||||
false,
|
|
||||||
"Test Player"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UiSharedService.AttachToolTip("Test performance notification");
|
|
||||||
|
|
||||||
ImGui.EndTable();
|
ImGui.Unindent();
|
||||||
}
|
|
||||||
|
|
||||||
ImGuiHelpers.ScaledDummy(5);
|
|
||||||
if (_uiShared.IconTextButton(FontAwesomeIcon.Trash, "Clear All Notifications"))
|
|
||||||
{
|
|
||||||
Mediator.Publish(new ClearAllNotificationsMessage());
|
|
||||||
}
|
|
||||||
_uiShared.DrawHelpText("Dismiss all active notifications immediately.");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -3725,6 +3602,73 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
if (useLightlessNotifications)
|
if (useLightlessNotifications)
|
||||||
{
|
{
|
||||||
|
if (_uiShared.MediumTreeNode("Test Notifications", UIColors.Get("LightlessPurple")))
|
||||||
|
{
|
||||||
|
ImGui.Indent();
|
||||||
|
|
||||||
|
// Test notification buttons
|
||||||
|
if (_uiShared.IconTextButton(FontAwesomeIcon.Bell, "Test Info"))
|
||||||
|
{
|
||||||
|
Mediator.Publish(new NotificationMessage("Test Info",
|
||||||
|
"This is a test info notification to let you know Chocola is cute :3", NotificationType.Info));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (_uiShared.IconTextButton(FontAwesomeIcon.ExclamationTriangle, "Test Warning"))
|
||||||
|
{
|
||||||
|
Mediator.Publish(new NotificationMessage("Test Warning", "This is a test warning notification!",
|
||||||
|
NotificationType.Warning));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (_uiShared.IconTextButton(FontAwesomeIcon.ExclamationCircle, "Test Error"))
|
||||||
|
{
|
||||||
|
Mediator.Publish(new NotificationMessage("Test Error", "This is a test error notification!",
|
||||||
|
NotificationType.Error));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(3);
|
||||||
|
if (_uiShared.IconTextButton(FontAwesomeIcon.UserPlus, "Test Pair Request"))
|
||||||
|
{
|
||||||
|
_lightlessNotificationService.ShowPairRequestNotification(
|
||||||
|
"Test User",
|
||||||
|
"test-uid-123",
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
Mediator.Publish(new NotificationMessage("Accepted", "You accepted the test pair request.",
|
||||||
|
NotificationType.Info));
|
||||||
|
},
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
Mediator.Publish(new NotificationMessage("Declined", "You declined the test pair request.",
|
||||||
|
NotificationType.Info));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (_uiShared.IconTextButton(FontAwesomeIcon.Download, "Test Download Progress"))
|
||||||
|
{
|
||||||
|
_lightlessNotificationService.ShowPairDownloadNotification(
|
||||||
|
new List<(string playerName, float progress, string status)>
|
||||||
|
{
|
||||||
|
("Player One", 0.35f, "downloading"),
|
||||||
|
("Player Two", 0.75f, "downloading"),
|
||||||
|
("Player Three", 1.0f, "downloading")
|
||||||
|
},
|
||||||
|
queueWaiting: 2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_uiShared.DrawHelpText("Preview how notifications will appear with your current settings.");
|
||||||
|
|
||||||
|
ImGui.Unindent();
|
||||||
|
|
||||||
|
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
|
||||||
|
ImGui.TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
if (_uiShared.MediumTreeNode("Basic Settings", UIColors.Get("LightlessPurple")))
|
if (_uiShared.MediumTreeNode("Basic Settings", UIColors.Get("LightlessPurple")))
|
||||||
{
|
{
|
||||||
int maxNotifications = _configService.Current.MaxSimultaneousNotifications;
|
int maxNotifications = _configService.Current.MaxSimultaneousNotifications;
|
||||||
@@ -3824,28 +3768,10 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.Spacing();
|
ImGui.Spacing();
|
||||||
ImGui.TextUnformatted("Position");
|
ImGui.TextUnformatted("Position");
|
||||||
|
|
||||||
var currentCorner = _configService.Current.NotificationCorner;
|
|
||||||
if (ImGui.BeginCombo("Notification Position", GetNotificationCornerLabel(currentCorner)))
|
|
||||||
{
|
|
||||||
foreach (NotificationCorner corner in Enum.GetValues(typeof(NotificationCorner)))
|
|
||||||
{
|
|
||||||
bool isSelected = currentCorner == corner;
|
|
||||||
if (ImGui.Selectable(GetNotificationCornerLabel(corner), isSelected))
|
|
||||||
{
|
|
||||||
_configService.Current.NotificationCorner = corner;
|
|
||||||
_configService.Save();
|
|
||||||
}
|
|
||||||
if (isSelected)
|
|
||||||
ImGui.SetItemDefaultFocus();
|
|
||||||
}
|
|
||||||
ImGui.EndCombo();
|
|
||||||
}
|
|
||||||
_uiShared.DrawHelpText("Choose which corner of the screen notifications appear in.");
|
|
||||||
|
|
||||||
int offsetY = _configService.Current.NotificationOffsetY;
|
int offsetY = _configService.Current.NotificationOffsetY;
|
||||||
if (ImGui.SliderInt("Vertical Offset", ref offsetY, 0, 1000))
|
if (ImGui.SliderInt("Vertical Offset", ref offsetY, 0, 500))
|
||||||
{
|
{
|
||||||
_configService.Current.NotificationOffsetY = Math.Clamp(offsetY, 0, 1000);
|
_configService.Current.NotificationOffsetY = Math.Clamp(offsetY, 0, 500);
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
}
|
}
|
||||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||||
@@ -3855,7 +3781,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
if (ImGui.IsItemHovered())
|
if (ImGui.IsItemHovered())
|
||||||
ImGui.SetTooltip("Right click to reset to default (50).");
|
ImGui.SetTooltip("Right click to reset to default (50).");
|
||||||
_uiShared.DrawHelpText("Distance from the top edge of the screen.");
|
_uiShared.DrawHelpText("Move notifications down from the top-right corner.");
|
||||||
|
|
||||||
int offsetX = _configService.Current.NotificationOffsetX;
|
int offsetX = _configService.Current.NotificationOffsetX;
|
||||||
if (ImGui.SliderInt("Horizontal Offset", ref offsetX, 0, 500))
|
if (ImGui.SliderInt("Horizontal Offset", ref offsetX, 0, 500))
|
||||||
@@ -3876,9 +3802,9 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.TextUnformatted("Animation Settings");
|
ImGui.TextUnformatted("Animation Settings");
|
||||||
|
|
||||||
float animSpeed = _configService.Current.NotificationAnimationSpeed;
|
float animSpeed = _configService.Current.NotificationAnimationSpeed;
|
||||||
if (ImGui.SliderFloat("Animation Speed", ref animSpeed, 1f, 20f, "%.1f"))
|
if (ImGui.SliderFloat("Animation Speed", ref animSpeed, 1f, 30f, "%.1f"))
|
||||||
{
|
{
|
||||||
_configService.Current.NotificationAnimationSpeed = Math.Clamp(animSpeed, 1f, 20f);
|
_configService.Current.NotificationAnimationSpeed = Math.Clamp(animSpeed, 1f, 30f);
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
}
|
}
|
||||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||||
@@ -3890,21 +3816,6 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.SetTooltip("Right click to reset to default (10).");
|
ImGui.SetTooltip("Right click to reset to default (10).");
|
||||||
_uiShared.DrawHelpText("How fast notifications slide in/out. Higher = faster.");
|
_uiShared.DrawHelpText("How fast notifications slide in/out. Higher = faster.");
|
||||||
|
|
||||||
float slideSpeed = _configService.Current.NotificationSlideSpeed;
|
|
||||||
if (ImGui.SliderFloat("Slide Speed", ref slideSpeed, 1f, 20f, "%.1f"))
|
|
||||||
{
|
|
||||||
_configService.Current.NotificationSlideSpeed = Math.Clamp(slideSpeed, 1f, 20f);
|
|
||||||
_configService.Save();
|
|
||||||
}
|
|
||||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
|
||||||
{
|
|
||||||
_configService.Current.NotificationSlideSpeed = 10f;
|
|
||||||
_configService.Save();
|
|
||||||
}
|
|
||||||
if (ImGui.IsItemHovered())
|
|
||||||
ImGui.SetTooltip("Right click to reset to default (10).");
|
|
||||||
_uiShared.DrawHelpText("How fast notifications slide into position when others disappear. Higher = faster.");
|
|
||||||
|
|
||||||
ImGui.Spacing();
|
ImGui.Spacing();
|
||||||
ImGui.TextUnformatted("Visual Effects");
|
ImGui.TextUnformatted("Visual Effects");
|
||||||
|
|
||||||
@@ -4004,20 +3915,6 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
if (ImGui.IsItemHovered())
|
if (ImGui.IsItemHovered())
|
||||||
ImGui.SetTooltip("Right click to reset to default (300).");
|
ImGui.SetTooltip("Right click to reset to default (300).");
|
||||||
|
|
||||||
int performanceDuration = _configService.Current.PerformanceNotificationDurationSeconds;
|
|
||||||
if (ImGui.SliderInt("Performance Duration (seconds)", ref performanceDuration, 5, 60))
|
|
||||||
{
|
|
||||||
_configService.Current.PerformanceNotificationDurationSeconds = Math.Clamp(performanceDuration, 5, 60);
|
|
||||||
_configService.Save();
|
|
||||||
}
|
|
||||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
|
||||||
{
|
|
||||||
_configService.Current.PerformanceNotificationDurationSeconds = 20;
|
|
||||||
_configService.Save();
|
|
||||||
}
|
|
||||||
if (ImGui.IsItemHovered())
|
|
||||||
ImGui.SetTooltip("Right click to reset to default (20).");
|
|
||||||
|
|
||||||
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
|
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
|
||||||
ImGui.TreePop();
|
ImGui.TreePop();
|
||||||
}
|
}
|
||||||
@@ -4085,38 +3982,6 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.TreePop();
|
ImGui.TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_uiShared.MediumTreeNode("Pair Request Notifications", UIColors.Get("PairBlue")))
|
|
||||||
{
|
|
||||||
var showPairRequestActions = _configService.Current.ShowPairRequestNotificationActions;
|
|
||||||
if (ImGui.Checkbox("Show action buttons on pair requests", ref showPairRequestActions))
|
|
||||||
{
|
|
||||||
_configService.Current.ShowPairRequestNotificationActions = showPairRequestActions;
|
|
||||||
_configService.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
_uiShared.DrawHelpText(
|
|
||||||
"When you receive a pair request, show Accept/Decline buttons in the notification.");
|
|
||||||
|
|
||||||
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
|
|
||||||
ImGui.TreePop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_uiShared.MediumTreeNode("Performance Notifications", UIColors.Get("LightlessOrange")))
|
|
||||||
{
|
|
||||||
var showPerformanceActions = _configService.Current.ShowPerformanceNotificationActions;
|
|
||||||
if (ImGui.Checkbox("Show action buttons on performance warnings", ref showPerformanceActions))
|
|
||||||
{
|
|
||||||
_configService.Current.ShowPerformanceNotificationActions = showPerformanceActions;
|
|
||||||
_configService.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
_uiShared.DrawHelpText(
|
|
||||||
"When a player exceeds performance thresholds or is auto-paused, show Pause/Unpause buttons in the notification.");
|
|
||||||
|
|
||||||
_uiShared.ColoredSeparator(UIColors.Get("LightlessOrange"), 1.5f);
|
|
||||||
ImGui.TreePop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_uiShared.MediumTreeNode("System Notifications", UIColors.Get("LightlessYellow")))
|
if (_uiShared.MediumTreeNode("System Notifications", UIColors.Get("LightlessYellow")))
|
||||||
{
|
{
|
||||||
var disableOptionalPluginWarnings = _configService.Current.DisableOptionalPluginWarnings;
|
var disableOptionalPluginWarnings = _configService.Current.DisableOptionalPluginWarnings;
|
||||||
@@ -4134,7 +3999,6 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
// Location descriptions removed - information is now inline with each setting
|
// Location descriptions removed - information is now inline with each setting
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4150,7 +4014,8 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
NotificationLocation.LightlessUi, NotificationLocation.TextOverlay, NotificationLocation.Nowhere
|
NotificationLocation.LightlessUi, NotificationLocation.ChatAndLightlessUi,
|
||||||
|
NotificationLocation.TextOverlay, NotificationLocation.Nowhere
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4178,16 +4043,6 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetNotificationCornerLabel(NotificationCorner corner)
|
|
||||||
{
|
|
||||||
return corner switch
|
|
||||||
{
|
|
||||||
NotificationCorner.Right => "Right",
|
|
||||||
NotificationCorner.Left => "Left",
|
|
||||||
_ => corner.ToString()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawSoundTable()
|
private void DrawSoundTable()
|
||||||
{
|
{
|
||||||
var soundEffects = new[]
|
var soundEffects = new[]
|
||||||
@@ -4213,7 +4068,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
("Warning", 1, _configService.Current.CustomWarningSoundId, _configService.Current.DisableWarningSound, 16u),
|
("Warning", 1, _configService.Current.CustomWarningSoundId, _configService.Current.DisableWarningSound, 16u),
|
||||||
("Error", 2, _configService.Current.CustomErrorSoundId, _configService.Current.DisableErrorSound, 16u),
|
("Error", 2, _configService.Current.CustomErrorSoundId, _configService.Current.DisableErrorSound, 16u),
|
||||||
("Pair Request", 3, _configService.Current.PairRequestSoundId, _configService.Current.DisablePairRequestSound, 5u),
|
("Pair Request", 3, _configService.Current.PairRequestSoundId, _configService.Current.DisablePairRequestSound, 5u),
|
||||||
("Performance", 4, _configService.Current.PerformanceSoundId, _configService.Current.DisablePerformanceSound, 16u)
|
("Download", 4, _configService.Current.DownloadSoundId, _configService.Current.DisableDownloadSound, 15u)
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var (typeName, typeIndex, currentSoundId, isDisabled, defaultSoundId) in soundTypes)
|
foreach (var (typeName, typeIndex, currentSoundId, isDisabled, defaultSoundId) in soundTypes)
|
||||||
@@ -4232,7 +4087,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
var currentIndex = Array.FindIndex(soundEffects, s => s.Item1 == currentSoundId);
|
var currentIndex = Array.FindIndex(soundEffects, s => s.Item1 == currentSoundId);
|
||||||
if (currentIndex == -1) currentIndex = 1;
|
if (currentIndex == -1) currentIndex = 1;
|
||||||
|
|
||||||
ImGui.SetNextItemWidth(-1);
|
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
|
||||||
if (ImGui.Combo($"##sound_{typeIndex}", ref currentIndex,
|
if (ImGui.Combo($"##sound_{typeIndex}", ref currentIndex,
|
||||||
soundEffects.Select(s => s.Item2).ToArray(), soundEffects.Length))
|
soundEffects.Select(s => s.Item2).ToArray(), soundEffects.Length))
|
||||||
{
|
{
|
||||||
@@ -4243,7 +4098,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
case 1: _configService.Current.CustomWarningSoundId = newSoundId; break;
|
case 1: _configService.Current.CustomWarningSoundId = newSoundId; break;
|
||||||
case 2: _configService.Current.CustomErrorSoundId = newSoundId; break;
|
case 2: _configService.Current.CustomErrorSoundId = newSoundId; break;
|
||||||
case 3: _configService.Current.PairRequestSoundId = newSoundId; break;
|
case 3: _configService.Current.PairRequestSoundId = newSoundId; break;
|
||||||
case 4: _configService.Current.PerformanceSoundId = newSoundId; break;
|
case 4: _configService.Current.DownloadSoundId = newSoundId; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
@@ -4297,7 +4152,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
case 1: _configService.Current.DisableWarningSound = newDisabled; break;
|
case 1: _configService.Current.DisableWarningSound = newDisabled; break;
|
||||||
case 2: _configService.Current.DisableErrorSound = newDisabled; break;
|
case 2: _configService.Current.DisableErrorSound = newDisabled; break;
|
||||||
case 3: _configService.Current.DisablePairRequestSound = newDisabled; break;
|
case 3: _configService.Current.DisablePairRequestSound = newDisabled; break;
|
||||||
case 4: _configService.Current.DisablePerformanceSound = newDisabled; break;
|
case 4: _configService.Current.DisableDownloadSound = newDisabled; break;
|
||||||
}
|
}
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
}
|
}
|
||||||
@@ -4323,7 +4178,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
case 1: _configService.Current.CustomWarningSoundId = defaultSoundId; break;
|
case 1: _configService.Current.CustomWarningSoundId = defaultSoundId; break;
|
||||||
case 2: _configService.Current.CustomErrorSoundId = defaultSoundId; break;
|
case 2: _configService.Current.CustomErrorSoundId = defaultSoundId; break;
|
||||||
case 3: _configService.Current.PairRequestSoundId = defaultSoundId; break;
|
case 3: _configService.Current.PairRequestSoundId = defaultSoundId; break;
|
||||||
case 4: _configService.Current.PerformanceSoundId = defaultSoundId; break;
|
case 4: _configService.Current.DownloadSoundId = defaultSoundId; break;
|
||||||
}
|
}
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
|||||||
ImGuiHelpers.ScaledDummy(0.5f);
|
ImGuiHelpers.ScaledDummy(0.5f);
|
||||||
|
|
||||||
ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 10.0f);
|
ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 10.0f);
|
||||||
ImGui.PushStyleColor(ImGuiCol.Button, UIColors.Get("PairBlue"));
|
ImGui.PushStyleColor(ImGuiCol.Button, UIColors.Get("LightlessYellow2"));
|
||||||
|
|
||||||
if (ImGui.Button("Open Lightfinder", new Vector2(200 * ImGuiHelpers.GlobalScale, 0)))
|
if (ImGui.Button("Open Lightfinder", new Vector2(200 * ImGuiHelpers.GlobalScale, 0)))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -196,6 +196,82 @@ public class TopTabMenu
|
|||||||
|
|
||||||
if (TabSelection != SelectedTab.None) ImGuiHelpers.ScaledDummy(3f);
|
if (TabSelection != SelectedTab.None) ImGuiHelpers.ScaledDummy(3f);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if (ImGui.Button("Test Pair Request"))
|
||||||
|
{
|
||||||
|
_lightlessNotificationService.ShowPairRequestNotification(
|
||||||
|
"Debug User",
|
||||||
|
"debug-user-id",
|
||||||
|
onAccept: () =>
|
||||||
|
{
|
||||||
|
_lightlessMediator.Publish(new NotificationMessage(
|
||||||
|
"Pair Accepted",
|
||||||
|
"Debug pair request was accepted!",
|
||||||
|
NotificationType.Info,
|
||||||
|
TimeSpan.FromSeconds(3)));
|
||||||
|
},
|
||||||
|
onDecline: () =>
|
||||||
|
{
|
||||||
|
_lightlessMediator.Publish(new NotificationMessage(
|
||||||
|
"Pair Declined",
|
||||||
|
"Debug pair request was declined.",
|
||||||
|
NotificationType.Warning,
|
||||||
|
TimeSpan.FromSeconds(3)));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("Test Info"))
|
||||||
|
{
|
||||||
|
_lightlessMediator.Publish(new NotificationMessage(
|
||||||
|
"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"))
|
||||||
|
{
|
||||||
|
_lightlessMediator.Publish(new NotificationMessage(
|
||||||
|
"Warning",
|
||||||
|
"This is a test warning notification.",
|
||||||
|
NotificationType.Warning,
|
||||||
|
TimeSpan.FromSeconds(7)));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("Test Error"))
|
||||||
|
{
|
||||||
|
_lightlessMediator.Publish(new NotificationMessage(
|
||||||
|
"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
|
||||||
|
|
||||||
DrawIncomingPairRequests(availableWidth);
|
DrawIncomingPairRequests(availableWidth);
|
||||||
|
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
|
|||||||
@@ -11,17 +11,21 @@ namespace LightlessSync.UI
|
|||||||
{ "LightlessPurple", "#ad8af5" },
|
{ "LightlessPurple", "#ad8af5" },
|
||||||
{ "LightlessPurpleActive", "#be9eff" },
|
{ "LightlessPurpleActive", "#be9eff" },
|
||||||
{ "LightlessPurpleDefault", "#9375d1" },
|
{ "LightlessPurpleDefault", "#9375d1" },
|
||||||
|
|
||||||
{ "ButtonDefault", "#323232" },
|
{ "ButtonDefault", "#323232" },
|
||||||
{ "FullBlack", "#000000" },
|
{ "FullBlack", "#000000" },
|
||||||
|
|
||||||
{ "LightlessBlue", "#a6c2ff" },
|
{ "LightlessBlue", "#a6c2ff" },
|
||||||
{ "LightlessYellow", "#ffe97a" },
|
{ "LightlessYellow", "#ffe97a" },
|
||||||
|
{ "LightlessYellow2", "#cfbd63" },
|
||||||
{ "LightlessGreen", "#7cd68a" },
|
{ "LightlessGreen", "#7cd68a" },
|
||||||
{ "LightlessOrange", "#ffb366" },
|
|
||||||
{ "PairBlue", "#88a2db" },
|
{ "PairBlue", "#88a2db" },
|
||||||
{ "DimRed", "#d44444" },
|
{ "DimRed", "#d44444" },
|
||||||
|
|
||||||
{ "LightlessAdminText", "#ffd663" },
|
{ "LightlessAdminText", "#ffd663" },
|
||||||
{ "LightlessAdminGlow", "#b09343" },
|
{ "LightlessAdminGlow", "#b09343" },
|
||||||
{ "LightlessModeratorText", "#94ffda" },
|
{ "LightlessModeratorText", "#94ffda" },
|
||||||
|
{ "LightlessModeratorGlow", "#599c84" },
|
||||||
|
|
||||||
{ "Lightfinder", "#ad8af5" },
|
{ "Lightfinder", "#ad8af5" },
|
||||||
{ "LightfinderEdge", "#000000" },
|
{ "LightfinderEdge", "#000000" },
|
||||||
|
|||||||
@@ -110,7 +110,14 @@ public partial class ApiController
|
|||||||
if (dto == null)
|
if (dto == null)
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
_pairRequestService.RegisterIncomingRequest(dto.myHashedCid, dto.message ?? string.Empty);
|
var request = _pairRequestService.RegisterIncomingRequest(dto.myHashedCid, dto.message ?? string.Empty);
|
||||||
|
var senderName = string.IsNullOrEmpty(request.DisplayName) ? "Unknown User" : request.DisplayName;
|
||||||
|
|
||||||
|
_lightlessNotificationService.ShowPairRequestNotification(
|
||||||
|
senderName,
|
||||||
|
request.HashedCid,
|
||||||
|
onAccept: () => _pairRequestService.AcceptPairRequest(request.HashedCid, senderName),
|
||||||
|
onDecline: () => _pairRequestService.DeclinePairRequest(request.HashedCid));
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# Lightless Sync Dalamud Plugin
|
# Lightless Sync Dalamud Plugin
|
||||||
|
|
||||||
Available at [This dalamud Repo](https://raw.githubusercontent.com/Light-Public-Syncshells/LightlessSync/refs/heads/main/plogonmaster.json)
|
Available at [This dalamud Repo](https://repo.lightless-sync.org/)
|
||||||
|
|
||||||
# [Lightless Sync Discord](https://discord.gg/dsbjcXMnhA)
|
# [Lightless Sync Discord](https://discord.gg/Lightless)
|
||||||
|
|
||||||
Readme TBD
|
|
||||||
Reference in New Issue
Block a user