improved settings with sounds bug fix
This commit is contained in:
@@ -72,9 +72,7 @@ public class LightlessConfig : ILightlessConfiguration
|
||||
public NotificationLocation WarningNotification { get; set; } = NotificationLocation.Both;
|
||||
|
||||
// Lightless Notification Configuration
|
||||
// TODO: clean these
|
||||
public bool UseLightlessNotifications { get; set; } = true;
|
||||
public int DefaultNotificationDurationSeconds { get; set; } = 10;
|
||||
public bool ShowNotificationProgress { get; set; } = true;
|
||||
public NotificationLocation LightlessInfoNotification { get; set; } = NotificationLocation.LightlessUi;
|
||||
public NotificationLocation LightlessWarningNotification { get; set; } = NotificationLocation.LightlessUi;
|
||||
@@ -82,23 +80,45 @@ public class LightlessConfig : ILightlessConfiguration
|
||||
public NotificationLocation LightlessPairRequestNotification { get; set; } = NotificationLocation.LightlessUi;
|
||||
public NotificationLocation LightlessDownloadNotification { get; set; } = NotificationLocation.TextOverlay;
|
||||
|
||||
// Basic Settings
|
||||
public float NotificationOpacity { get; set; } = 0.95f;
|
||||
public bool EnableNotificationAnimations { get; set; } = true;
|
||||
public int MaxSimultaneousNotifications { get; set; } = 5;
|
||||
public bool AutoDismissOnAction { get; set; } = true;
|
||||
public bool DismissNotificationOnClick { get; set; } = false;
|
||||
public bool ShowNotificationTimestamp { get; set; } = false;
|
||||
public int NotificationOffsetY { get; set; } = 50;
|
||||
|
||||
// Position & Layout
|
||||
public int NotificationOffsetY { get; set; } = 50;
|
||||
public int NotificationOffsetX { get; set; } = 0;
|
||||
public float NotificationWidth { get; set; } = 350f;
|
||||
public float NotificationSpacing { get; set; } = 8f;
|
||||
public bool NotificationStackUpwards { get; set; } = false;
|
||||
|
||||
// Animation & Effects
|
||||
public float NotificationAnimationSpeed { get; set; } = 10f;
|
||||
public float NotificationAccentBarWidth { get; set; } = 3f;
|
||||
|
||||
// Typography
|
||||
public float NotificationFontScale { get; set; } = 1.0f;
|
||||
|
||||
// Duration per Type
|
||||
public int InfoNotificationDurationSeconds { get; set; } = 10;
|
||||
public int WarningNotificationDurationSeconds { get; set; } = 15;
|
||||
public int ErrorNotificationDurationSeconds { get; set; } = 20;
|
||||
public int PairRequestDurationSeconds { get; set; } = 180;
|
||||
public int DownloadNotificationDurationSeconds { get; set; } = 300;
|
||||
|
||||
// Sound Settings
|
||||
public uint CustomInfoSoundId { get; set; } = 2; // Se2
|
||||
public uint CustomWarningSoundId { get; set; } = 15; // Se15
|
||||
public uint CustomErrorSoundId { get; set; } = 16; // Se16
|
||||
public uint CustomWarningSoundId { get; set; } = 16; // Se15
|
||||
public uint CustomErrorSoundId { get; set; } = 16; // Se15
|
||||
public uint PairRequestSoundId { get; set; } = 5; // Se5
|
||||
public uint DownloadSoundId { get; set; } = 15; // Se14
|
||||
public bool DisableInfoSound { get; set; } = false;
|
||||
public bool DisableWarningSound { get; set; } = false;
|
||||
public bool DisableErrorSound { get; set; } = false;
|
||||
public bool DisablePairRequestSound { get; set; } = false;
|
||||
// till here c:
|
||||
public bool DisableDownloadSound { get; set; } = true; // Disabled by default
|
||||
public bool UseFocusTarget { get; set; } = false;
|
||||
public bool overrideFriendColor { get; set; } = false;
|
||||
public bool overridePartyColor { get; set; } = false;
|
||||
|
||||
@@ -51,7 +51,7 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
||||
Title = title,
|
||||
Message = message,
|
||||
Type = type,
|
||||
Duration = duration ?? TimeSpan.FromSeconds(_configService.Current.DefaultNotificationDurationSeconds),
|
||||
Duration = duration ?? GetDefaultDurationForType(type),
|
||||
Actions = actions ?? new List<LightlessNotificationAction>(),
|
||||
SoundEffectId = GetSoundEffectId(type, soundEffectId),
|
||||
ShowProgress = _configService.Current.ShowNotificationProgress,
|
||||
@@ -87,9 +87,9 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
||||
var notification = new LightlessNotification
|
||||
{
|
||||
Title = "Pair Request Received",
|
||||
Message = $"{senderName} wants to pair with you.",
|
||||
Message = $"{senderName} wants to directly pair with you.",
|
||||
Type = NotificationType.PairRequest,
|
||||
Duration = TimeSpan.FromSeconds(180),
|
||||
Duration = TimeSpan.FromSeconds(_configService.Current.PairRequestDurationSeconds),
|
||||
SoundEffectId = !_configService.Current.DisablePairRequestSound ? _configService.Current.PairRequestSoundId : null,
|
||||
Actions = new List<LightlessNotificationAction>
|
||||
{
|
||||
@@ -268,7 +268,7 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
||||
Title = "Downloading Pair Data",
|
||||
Message = message,
|
||||
Type = NotificationType.Download,
|
||||
Duration = TimeSpan.FromMinutes(5),
|
||||
Duration = TimeSpan.FromSeconds(_configService.Current.DownloadNotificationDurationSeconds),
|
||||
ShowProgress = true,
|
||||
Progress = totalProgress
|
||||
};
|
||||
@@ -284,6 +284,19 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
||||
Mediator.Publish(new LightlessNotificationDismissMessage("pair_download_progress"));
|
||||
}
|
||||
|
||||
private TimeSpan GetDefaultDurationForType(NotificationType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
NotificationType.Info => TimeSpan.FromSeconds(_configService.Current.InfoNotificationDurationSeconds),
|
||||
NotificationType.Warning => TimeSpan.FromSeconds(_configService.Current.WarningNotificationDurationSeconds),
|
||||
NotificationType.Error => TimeSpan.FromSeconds(_configService.Current.ErrorNotificationDurationSeconds),
|
||||
NotificationType.PairRequest => TimeSpan.FromSeconds(_configService.Current.PairRequestDurationSeconds),
|
||||
NotificationType.Download => TimeSpan.FromSeconds(_configService.Current.DownloadNotificationDurationSeconds),
|
||||
_ => TimeSpan.FromSeconds(10) // Fallback for any unknown types
|
||||
};
|
||||
}
|
||||
|
||||
private uint? GetSoundEffectId(NotificationType type, uint? overrideSoundId)
|
||||
{
|
||||
if (overrideSoundId.HasValue)
|
||||
@@ -295,6 +308,7 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
||||
NotificationType.Info => _configService.Current.DisableInfoSound,
|
||||
NotificationType.Warning => _configService.Current.DisableWarningSound,
|
||||
NotificationType.Error => _configService.Current.DisableErrorSound,
|
||||
NotificationType.Download => _configService.Current.DisableDownloadSound,
|
||||
_ => false
|
||||
};
|
||||
|
||||
@@ -307,6 +321,7 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
||||
NotificationType.Info => _configService.Current.CustomInfoSoundId,
|
||||
NotificationType.Warning => _configService.Current.CustomWarningSoundId,
|
||||
NotificationType.Error => _configService.Current.CustomErrorSoundId,
|
||||
NotificationType.Download => _configService.Current.DownloadSoundId,
|
||||
_ => NotificationSounds.GetDefaultSound(type)
|
||||
};
|
||||
}
|
||||
@@ -387,7 +402,7 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
||||
|
||||
private void ShowLightlessNotification(NotificationMessage msg)
|
||||
{
|
||||
var duration = msg.TimeShownOnScreen ?? TimeSpan.FromSeconds(_configService.Current.DefaultNotificationDurationSeconds);
|
||||
var duration = msg.TimeShownOnScreen ?? GetDefaultDurationForType(msg.Type);
|
||||
// GetSoundEffectId will handle checking if the sound is disabled
|
||||
ShowNotification(msg.Title ?? "Lightless Sync", msg.Message ?? string.Empty, msg.Type, duration, null, null);
|
||||
}
|
||||
|
||||
@@ -21,15 +21,8 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
private readonly object _notificationLock = new();
|
||||
private readonly LightlessConfigService _configService;
|
||||
|
||||
private const float NotificationWidth = 350f;
|
||||
private const float NotificationMinHeight = 60f;
|
||||
private const float NotificationMaxHeight = 200f;
|
||||
private const float NotificationSpacing = 8f;
|
||||
private const float AnimationSpeed = 10f;
|
||||
|
||||
private const float EdgeXMargin = 0;
|
||||
private const float EdgeYMargin = 30f;
|
||||
private const float SlideDistance = 100f;
|
||||
private const float NotificationMaxHeight = 250f;
|
||||
|
||||
public LightlessNotificationUI(ILogger<LightlessNotificationUI> logger, LightlessMediator mediator, PerformanceCollectorService performanceCollector, LightlessConfigService configService)
|
||||
: base(logger, mediator, "Lightless Notifications##LightlessNotifications", performanceCollector)
|
||||
@@ -47,7 +40,7 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
|
||||
PositionCondition = ImGuiCond.Always;
|
||||
|
||||
Size = new Vector2(NotificationWidth, 100);
|
||||
Size = new Vector2(_configService.Current.NotificationWidth, 100);
|
||||
SizeCondition = ImGuiCond.FirstUseEver;
|
||||
IsOpen = false;
|
||||
RespectCloseHotkey = false;
|
||||
@@ -124,7 +117,7 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
var viewport = ImGui.GetMainViewport();
|
||||
|
||||
// Always position at top (choco doesnt know how to handle top positions how fitting)
|
||||
var baseX = viewport.WorkPos.X + viewport.WorkSize.X - NotificationWidth;
|
||||
var baseX = viewport.WorkPos.X + viewport.WorkSize.X - _configService.Current.NotificationWidth - _configService.Current.NotificationOffsetX;
|
||||
var baseY = viewport.WorkPos.Y;
|
||||
|
||||
// Apply Y offset
|
||||
@@ -139,7 +132,7 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
|
||||
if (i < _notifications.Count - 1)
|
||||
{
|
||||
ImGui.Dummy(new Vector2(0, NotificationSpacing));
|
||||
ImGui.Dummy(new Vector2(0, _configService.Current.NotificationSpacing));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,11 +163,11 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
|
||||
if (notification.IsAnimatingIn && notification.AnimationProgress < 1f)
|
||||
{
|
||||
notification.AnimationProgress = Math.Min(1f, notification.AnimationProgress + deltaTime * AnimationSpeed);
|
||||
notification.AnimationProgress = Math.Min(1f, notification.AnimationProgress + deltaTime * _configService.Current.NotificationAnimationSpeed);
|
||||
}
|
||||
else if (notification.IsAnimatingOut && notification.AnimationProgress > 0f)
|
||||
{
|
||||
notification.AnimationProgress = Math.Max(0f, notification.AnimationProgress - deltaTime * (AnimationSpeed * 0.7f));
|
||||
notification.AnimationProgress = Math.Max(0f, notification.AnimationProgress - deltaTime * (_configService.Current.NotificationAnimationSpeed * 0.7f));
|
||||
}
|
||||
else if (!notification.IsAnimatingOut && !notification.IsDismissed)
|
||||
{
|
||||
@@ -198,14 +191,10 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
{
|
||||
var alpha = notification.AnimationProgress;
|
||||
|
||||
if (_configService.Current.EnableNotificationAnimations && alpha <= 0f)
|
||||
if (alpha <= 0f)
|
||||
return;
|
||||
|
||||
var slideOffset = 0f;
|
||||
if (_configService.Current.EnableNotificationAnimations)
|
||||
{
|
||||
slideOffset = (1f - alpha) * SlideDistance;
|
||||
}
|
||||
var slideOffset = (1f - alpha) * 100f; // Fixed slide distance
|
||||
|
||||
var originalCursorPos = ImGui.GetCursorPos();
|
||||
ImGui.SetCursorPosX(originalCursorPos.X + slideOffset);
|
||||
@@ -215,7 +204,7 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
|
||||
|
||||
using var child = ImRaii.Child($"notification_{notification.Id}",
|
||||
new Vector2(NotificationWidth - slideOffset, notificationHeight),
|
||||
new Vector2(_configService.Current.NotificationWidth - slideOffset, notificationHeight),
|
||||
false, ImGuiWindowFlags.NoScrollbar);
|
||||
|
||||
if (child.Success)
|
||||
@@ -233,16 +222,16 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
var windowSize = ImGui.GetWindowSize();
|
||||
|
||||
var baseOpacity = _configService.Current.NotificationOpacity;
|
||||
var finalOpacity = _configService.Current.EnableNotificationAnimations ? baseOpacity * alpha : baseOpacity;
|
||||
var finalOpacity = baseOpacity * alpha;
|
||||
var bgColor = new Vector4(30f/255f, 30f/255f, 30f/255f, finalOpacity);
|
||||
var accentColor = GetNotificationAccentColor(notification.Type);
|
||||
var progressBarColor = UIColors.Get("LightlessBlue");
|
||||
|
||||
var finalAccentAlpha = _configService.Current.EnableNotificationAnimations ? alpha : 1f;
|
||||
accentColor.W *= finalAccentAlpha;
|
||||
accentColor.W *= alpha;
|
||||
|
||||
// Draw shadow with fixed intensity
|
||||
var shadowOffset = new Vector2(1f, 1f);
|
||||
var shadowAlpha = _configService.Current.EnableNotificationAnimations ? 0.4f * alpha : 0.4f;
|
||||
var shadowAlpha = 0.4f * alpha;
|
||||
var shadowColor = new Vector4(0f, 0f, 0f, shadowAlpha);
|
||||
drawList.AddRectFilled(
|
||||
windowPos + shadowOffset,
|
||||
@@ -252,6 +241,7 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
);
|
||||
|
||||
var isHovered = ImGui.IsWindowHovered();
|
||||
|
||||
if (isHovered)
|
||||
{
|
||||
bgColor = bgColor * 1.1f;
|
||||
@@ -274,14 +264,17 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
3f
|
||||
);
|
||||
|
||||
// Draw accent bar on left side of the notif
|
||||
var accentWidth = 3f;
|
||||
// Draw accent bar on left side of the notif (only if width > 0)
|
||||
var accentWidth = _configService.Current.NotificationAccentBarWidth;
|
||||
if (accentWidth > 0f)
|
||||
{
|
||||
drawList.AddRectFilled(
|
||||
windowPos,
|
||||
windowPos + new Vector2(accentWidth, windowSize.Y),
|
||||
ImGui.ColorConvertFloat4ToU32(accentColor),
|
||||
3f
|
||||
);
|
||||
}
|
||||
|
||||
DrawDurationProgressBar(notification, alpha, windowPos, windowSize, progressBarColor, drawList);
|
||||
|
||||
@@ -289,9 +282,18 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
}
|
||||
|
||||
private void DrawDurationProgressBar(LightlessNotification notification, float alpha, Vector2 windowPos, Vector2 windowSize, Vector4 progressBarColor, ImDrawListPtr drawList)
|
||||
{
|
||||
// For download notifications, use download progress instead of duration
|
||||
float progress;
|
||||
if (notification.Type == NotificationType.Download && notification.ShowProgress)
|
||||
{
|
||||
progress = Math.Clamp(notification.Progress, 0f, 1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
var elapsed = DateTime.UtcNow - notification.CreatedAt;
|
||||
var progress = Math.Min(1.0f, (float)(elapsed.TotalSeconds / notification.Duration.TotalSeconds));
|
||||
progress = Math.Min(1.0f, (float)(elapsed.TotalSeconds / notification.Duration.TotalSeconds));
|
||||
}
|
||||
|
||||
var progressHeight = 2f;
|
||||
var progressY = windowPos.Y + windowSize.Y - progressHeight;
|
||||
@@ -361,21 +363,10 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
ImGui.PopTextWrapPos();
|
||||
}
|
||||
|
||||
if (notification.ShowProgress)
|
||||
{
|
||||
ImGui.Spacing();
|
||||
var progressColor = GetNotificationAccentColor(notification.Type);
|
||||
progressColor.W *= alpha;
|
||||
using (ImRaii.PushColor(ImGuiCol.PlotHistogram, progressColor))
|
||||
{
|
||||
// Use full window width for progress bar
|
||||
ImGui.ProgressBar(notification.Progress, new Vector2(windowSize.X - padding.X * 2 - 6f, 2f), "");
|
||||
}
|
||||
}
|
||||
|
||||
if (notification.Actions.Count > 0)
|
||||
{
|
||||
ImGui.Spacing();
|
||||
var spacingHeight = ImGui.GetStyle().ItemSpacing.Y;
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + spacingHeight);
|
||||
ImGui.SetCursorPosX(contentPos.X);
|
||||
DrawNotificationActions(notification, contentSize.X, alpha);
|
||||
}
|
||||
@@ -504,8 +495,8 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
|
||||
private float CalculateNotificationHeight(LightlessNotification notification)
|
||||
{
|
||||
var contentWidth = NotificationWidth - 35f; // Account for padding and accent bar
|
||||
var height = 20f; // Base height for padding
|
||||
var contentWidth = _configService.Current.NotificationWidth - 35f; // Account for padding and accent bar
|
||||
var height = 12f; // Base height for padding (top + bottom)
|
||||
|
||||
var titleText = notification.Title;
|
||||
if (_configService.Current.ShowNotificationTimestamp)
|
||||
@@ -515,13 +506,14 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
}
|
||||
|
||||
var titleSize = ImGui.CalcTextSize(titleText, true, contentWidth);
|
||||
height += titleSize.Y + 4f; // Title height + spacing
|
||||
height += titleSize.Y; // Title height
|
||||
|
||||
// Calculate message height
|
||||
if (!string.IsNullOrEmpty(notification.Message))
|
||||
{
|
||||
var messageSize = ImGui.CalcTextSize(notification.Message, true, contentWidth);
|
||||
height += messageSize.Y + 4f; // Message height + spacing
|
||||
height += 4f; // Spacing between title and message
|
||||
var messageSize = ImGui.CalcTextSize(notification.Message, true, contentWidth); // This is cringe
|
||||
height += messageSize.Y; // Message height
|
||||
}
|
||||
|
||||
// Add height for progress bar
|
||||
@@ -533,7 +525,9 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
|
||||
// Add height for action buttons
|
||||
if (notification.Actions.Count > 0)
|
||||
{
|
||||
height += 28f;
|
||||
height += ImGui.GetStyle().ItemSpacing.Y; // Spacing before buttons
|
||||
height += ImGui.GetFrameHeight(); // Button height
|
||||
height += 12f; // Bottom padding for buttons
|
||||
}
|
||||
|
||||
// Allow notifications to grow taller but cap at maximum height
|
||||
|
||||
@@ -16,8 +16,6 @@ public class LightlessNotification
|
||||
public bool ShowProgress { get; set; } = false;
|
||||
public float Progress { get; set; } = 0f;
|
||||
public bool IsMinimized { get; set; } = false;
|
||||
|
||||
// Animation properties
|
||||
public float AnimationProgress { get; set; } = 0f;
|
||||
public bool IsAnimatingIn { get; set; } = true;
|
||||
public bool IsAnimatingOut { get; set; } = false;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using LightlessSync.LightlessConfiguration.Models;
|
||||
using LightlessSync.LightlessConfiguration.Models;
|
||||
|
||||
namespace LightlessSync.UI.Models;
|
||||
|
||||
@@ -16,18 +16,18 @@ public static class NotificationSounds
|
||||
public const uint Se2 = 2; // Higher chime
|
||||
public const uint Se3 = 3; // Bell tone
|
||||
public const uint Se4 = 4; // Harp tone
|
||||
public const uint Se5 = 5; // Drum / percussion
|
||||
public const uint Se6 = 6; // Mechanical click
|
||||
public const uint Se5 = 5; // Mechanical click
|
||||
public const uint Se6 = 6; // Drum / percussion
|
||||
public const uint Se7 = 7; // Metallic chime
|
||||
public const uint Se8 = 8; // Wooden tone
|
||||
public const uint Se9 = 9; // Wind / flute tone
|
||||
public const uint Se10 = 10; // Magical sparkle
|
||||
public const uint Se11 = 11; // Metallic ring
|
||||
public const uint Se12 = 12; // Deep thud
|
||||
public const uint Se13 = 13; // "Tell received" ping
|
||||
public const uint Se14 = 14; // Success fanfare short
|
||||
public const uint Se15 = 15; // System warning
|
||||
public const uint Se16 = 16; // Error / failure──────────────────────────────────────────
|
||||
public const uint Se10 = 11; // Magical sparkle (ID 10 is skipped in game)
|
||||
public const uint Se11 = 12; // Metallic ring
|
||||
public const uint Se12 = 13; // Deep thud
|
||||
public const uint Se13 = 14; // "Tell received" ping
|
||||
public const uint Se14 = 15; // Success fanfare
|
||||
public const uint Se15 = 16; // System warning
|
||||
// Note: Se16 doesn't exist - Se15 is the last available sound
|
||||
|
||||
/// <summary>
|
||||
/// General notification sound (<se.2>)
|
||||
@@ -40,9 +40,9 @@ public static class NotificationSounds
|
||||
public const uint Warning = Se15;
|
||||
|
||||
/// <summary>
|
||||
/// Error sound (<se.16>)
|
||||
/// Error sound (<se.15> - System warning, used for errors)
|
||||
/// </summary>
|
||||
public const uint Error = Se16;
|
||||
public const uint Error = Se15;
|
||||
|
||||
/// <summary>
|
||||
/// Success sound (<se.14>)
|
||||
|
||||
@@ -3140,24 +3140,20 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
ImGui.Separator();
|
||||
if (_uiShared.MediumTreeNode("Basic Settings", UIColors.Get("LightlessPurple")))
|
||||
{
|
||||
|
||||
int defaultDuration = _configService.Current.DefaultNotificationDurationSeconds;
|
||||
if (ImGui.SliderInt("Default Duration (seconds)", ref defaultDuration, 3, 60))
|
||||
int maxNotifications = _configService.Current.MaxSimultaneousNotifications;
|
||||
if (ImGui.SliderInt("Max Simultaneous Notifications", ref maxNotifications, 1, 10))
|
||||
{
|
||||
_configService.Current.DefaultNotificationDurationSeconds = defaultDuration;
|
||||
_configService.Current.MaxSimultaneousNotifications = maxNotifications;
|
||||
_configService.Save();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_configService.Current.DefaultNotificationDurationSeconds = 10;
|
||||
_configService.Current.MaxSimultaneousNotifications = 5;
|
||||
_configService.Save();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Right click to reset to default (10 seconds).");
|
||||
|
||||
_uiShared.DrawHelpText("How long notifications stay visible by default.");
|
||||
ImGui.SetTooltip("Right click to reset to default (5).");
|
||||
_uiShared.DrawHelpText("Maximum number of notifications that can be shown at once.");
|
||||
|
||||
bool showTimestamp = _configService.Current.ShowNotificationTimestamp;
|
||||
if (ImGui.Checkbox("Show Timestamps", ref showTimestamp))
|
||||
@@ -3205,32 +3201,38 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
|
||||
_uiShared.DrawHelpText("Transparency level of notification windows.");
|
||||
|
||||
bool enableAnimations = _configService.Current.EnableNotificationAnimations;
|
||||
if (ImGui.Checkbox("Enable Animations", ref enableAnimations))
|
||||
ImGui.Spacing();
|
||||
ImGui.TextUnformatted("Size & Layout");
|
||||
|
||||
float notifWidth = _configService.Current.NotificationWidth;
|
||||
if (ImGui.SliderFloat("Notification Width", ref notifWidth, 250f, 600f, "%.0f"))
|
||||
{
|
||||
_configService.Current.EnableNotificationAnimations = enableAnimations;
|
||||
_configService.Current.NotificationWidth = notifWidth;
|
||||
_configService.Save();
|
||||
}
|
||||
|
||||
_uiShared.DrawHelpText("Enable slide-in/out animations for notifications.");
|
||||
|
||||
int maxNotifications = _configService.Current.MaxSimultaneousNotifications;
|
||||
if (ImGui.SliderInt("Max Simultaneous Notifications", ref maxNotifications, 1, 10))
|
||||
{
|
||||
_configService.Current.MaxSimultaneousNotifications = maxNotifications;
|
||||
_configService.Save();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_configService.Current.MaxSimultaneousNotifications = 5;
|
||||
_configService.Current.NotificationWidth = 350f;
|
||||
_configService.Save();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Right click to reset to default (5).");
|
||||
ImGui.SetTooltip("Right click to reset to default (350).");
|
||||
_uiShared.DrawHelpText("Width of notification windows.");
|
||||
|
||||
_uiShared.DrawHelpText("Maximum number of notifications that can be shown at once.");
|
||||
float notifSpacing = _configService.Current.NotificationSpacing;
|
||||
if (ImGui.SliderFloat("Notification Spacing", ref notifSpacing, 0f, 30f, "%.0f"))
|
||||
{
|
||||
_configService.Current.NotificationSpacing = notifSpacing;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_configService.Current.NotificationSpacing = 8f;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Right click to reset to default (8).");
|
||||
_uiShared.DrawHelpText("Gap between stacked notifications.");
|
||||
|
||||
ImGui.Spacing();
|
||||
ImGui.TextUnformatted("Position");
|
||||
@@ -3241,23 +3243,151 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
_configService.Current.NotificationOffsetY = offsetY;
|
||||
_configService.Save();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_configService.Current.NotificationOffsetY = 50;
|
||||
_configService.Save();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Right click to reset to default (50).");
|
||||
_uiShared.DrawHelpText("Move notifications down from the top-right corner.");
|
||||
|
||||
_uiShared.DrawHelpText("Move notifications down from the top-right corner. 0 aligns to the very top.");
|
||||
int offsetX = _configService.Current.NotificationOffsetX;
|
||||
if (ImGui.SliderInt("Horizontal Offset", ref offsetX, 0, 500))
|
||||
{
|
||||
_configService.Current.NotificationOffsetX = offsetX;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_configService.Current.NotificationOffsetX = 0;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Right click to reset to default (0).");
|
||||
_uiShared.DrawHelpText("Move notifications left from the right edge.");
|
||||
|
||||
ImGui.Spacing();
|
||||
ImGui.TextUnformatted("Animation Settings");
|
||||
|
||||
float animSpeed = _configService.Current.NotificationAnimationSpeed;
|
||||
if (ImGui.SliderFloat("Animation Speed", ref animSpeed, 1f, 30f, "%.1f"))
|
||||
{
|
||||
_configService.Current.NotificationAnimationSpeed = animSpeed;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_configService.Current.NotificationAnimationSpeed = 10f;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Right click to reset to default (10).");
|
||||
_uiShared.DrawHelpText("How fast notifications slide in/out. Higher = faster.");
|
||||
|
||||
ImGui.Spacing();
|
||||
ImGui.TextUnformatted("Visual Effects");
|
||||
|
||||
float accentWidth = _configService.Current.NotificationAccentBarWidth;
|
||||
if (ImGui.SliderFloat("Accent Bar Width", ref accentWidth, 0f, 10f, "%.1f"))
|
||||
{
|
||||
_configService.Current.NotificationAccentBarWidth = accentWidth;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_configService.Current.NotificationAccentBarWidth = 3f;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Right click to reset to default (3).");
|
||||
_uiShared.DrawHelpText("Width of the colored accent bar on the left side.");
|
||||
|
||||
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
|
||||
ImGui.TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
if (_uiShared.MediumTreeNode("Duration Settings", UIColors.Get("LightlessPurple")))
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("Configure how long each notification type stays visible.", ImGuiColors.DalamudGrey);
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
|
||||
int infoDuration = _configService.Current.InfoNotificationDurationSeconds;
|
||||
if (ImGui.SliderInt("Info Duration (seconds)", ref infoDuration, 3, 60))
|
||||
{
|
||||
_configService.Current.InfoNotificationDurationSeconds = infoDuration;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_configService.Current.InfoNotificationDurationSeconds = 10;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Right click to reset to default (10).");
|
||||
|
||||
int warningDuration = _configService.Current.WarningNotificationDurationSeconds;
|
||||
if (ImGui.SliderInt("Warning Duration (seconds)", ref warningDuration, 3, 60))
|
||||
{
|
||||
_configService.Current.WarningNotificationDurationSeconds = warningDuration;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_configService.Current.WarningNotificationDurationSeconds = 15;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Right click to reset to default (15).");
|
||||
|
||||
int errorDuration = _configService.Current.ErrorNotificationDurationSeconds;
|
||||
if (ImGui.SliderInt("Error Duration (seconds)", ref errorDuration, 3, 120))
|
||||
{
|
||||
_configService.Current.ErrorNotificationDurationSeconds = errorDuration;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_configService.Current.ErrorNotificationDurationSeconds = 20;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Right click to reset to default (20).");
|
||||
|
||||
int pairRequestDuration = _configService.Current.PairRequestDurationSeconds;
|
||||
if (ImGui.SliderInt("Pair Request Duration (seconds)", ref pairRequestDuration, 30, 600))
|
||||
{
|
||||
_configService.Current.PairRequestDurationSeconds = pairRequestDuration;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_configService.Current.PairRequestDurationSeconds = 180;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Right click to reset to default (180).");
|
||||
|
||||
int downloadDuration = _configService.Current.DownloadNotificationDurationSeconds;
|
||||
if (ImGui.SliderInt("Download Duration (seconds)", ref downloadDuration, 60, 600))
|
||||
{
|
||||
_configService.Current.DownloadNotificationDurationSeconds = downloadDuration;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
_configService.Current.DownloadNotificationDurationSeconds = 300;
|
||||
_configService.Save();
|
||||
}
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Right click to reset to default (300).");
|
||||
|
||||
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
|
||||
ImGui.TreePop();
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
if (_uiShared.MediumTreeNode("Sound Settings", UIColors.Get("LightlessPurple")))
|
||||
{
|
||||
@@ -3399,10 +3529,10 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
var soundEffects = new[]
|
||||
{
|
||||
(1u, "Se1 - Soft chime"), (2u, "Se2 - Higher chime"), (3u, "Se3 - Bell tone"), (4u, "Se4 - Harp tone"),
|
||||
(5u, "Se5 - Drum/percussion"), (6u, "Se6 - Mechanical click"), (7u, "Se7 - Metallic chime"),
|
||||
(8u, "Se8 - Wooden tone"), (9u, "Se9 - Wind/flute tone"), (10u, "Se10 - Magical sparkle"),
|
||||
(11u, "Se11 - Metallic ring"), (12u, "Se12 - Deep thud"), (13u, "Se13 - Tell received ping"),
|
||||
(14u, "Se14 - Success fanfare"), (15u, "Se15 - System warning"), (16u, "Se16 - Error/failure")
|
||||
(5u, "Se5 - Mechanical click"), (6u, "Se6 - Drum/percussion"), (7u, "Se7 - Metallic chime"),
|
||||
(8u, "Se8 - Wooden tone"), (9u, "Se9 - Wind/flute tone"), (11u, "Se10 - Magical sparkle"),
|
||||
(12u, "Se11 - Metallic ring"), (13u, "Se12 - Deep thud"), (14u, "Se13 - Tell received ping"),
|
||||
(15u, "Se14 - Success fanfare"), (16u, "Se15 - System warning")
|
||||
};
|
||||
|
||||
if (ImGui.BeginTable("##SoundTable", 3,
|
||||
@@ -3410,15 +3540,16 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
{
|
||||
ImGui.TableSetupColumn("Type", ImGuiTableColumnFlags.WidthFixed, 120 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableSetupColumn("Sound", ImGuiTableColumnFlags.WidthStretch, 280 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, 80 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, 120 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
var soundTypes = new[]
|
||||
{
|
||||
("Info", 0, _configService.Current.CustomInfoSoundId, _configService.Current.DisableInfoSound, 2u),
|
||||
("Warning", 1, _configService.Current.CustomWarningSoundId, _configService.Current.DisableWarningSound, 15u),
|
||||
("Warning", 1, _configService.Current.CustomWarningSoundId, _configService.Current.DisableWarningSound, 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),
|
||||
("Download", 4, _configService.Current.DownloadSoundId, _configService.Current.DisableDownloadSound, 15u)
|
||||
};
|
||||
|
||||
foreach (var (typeName, typeIndex, currentSoundId, isDisabled, defaultSoundId) in soundTypes)
|
||||
@@ -3448,14 +3579,25 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
case 1: _configService.Current.CustomWarningSoundId = newSoundId; break;
|
||||
case 2: _configService.Current.CustomErrorSoundId = newSoundId; break;
|
||||
case 3: _configService.Current.PairRequestSoundId = newSoundId; break;
|
||||
case 4: _configService.Current.DownloadSoundId = newSoundId; break;
|
||||
}
|
||||
|
||||
_configService.Save();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.PushID($"test_{typeIndex}");
|
||||
if (_uiShared.IconButton(FontAwesomeIcon.Play))
|
||||
// Actions column
|
||||
ImGui.TableSetColumnIndex(2);
|
||||
var availableWidth = ImGui.GetContentRegionAvail().X;
|
||||
var buttonWidth = (availableWidth - ImGui.GetStyle().ItemSpacing.X * 2) / 3;
|
||||
|
||||
// Play button
|
||||
using var playId = ImRaii.PushId($"Play_{typeIndex}");
|
||||
using (ImRaii.Disabled(isDisabled))
|
||||
{
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
if (ImGui.Button(FontAwesomeIcon.Play.ToIconString(), new Vector2(buttonWidth, 0)))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -3466,38 +3608,9 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
_logger.LogWarning(ex, "Failed to play test sound");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.PopID();
|
||||
}
|
||||
}
|
||||
UiSharedService.AttachToolTip("Test this sound");
|
||||
}
|
||||
|
||||
// Actions column
|
||||
ImGui.TableSetColumnIndex(2);
|
||||
var availableWidth = ImGui.GetContentRegionAvail().X;
|
||||
var buttonWidth = (availableWidth - ImGui.GetStyle().ItemSpacing.X) / 2;
|
||||
|
||||
// Reset button
|
||||
using var resetId = ImRaii.PushId($"Reset_{typeIndex}");
|
||||
bool isDefault = currentSoundId == defaultSoundId;
|
||||
|
||||
using (ImRaii.Disabled(isDefault))
|
||||
{
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
if (ImGui.Button(FontAwesomeIcon.Undo.ToIconString(), new Vector2(buttonWidth, 0)))
|
||||
{
|
||||
switch (typeIndex)
|
||||
{
|
||||
case 0: _configService.Current.CustomInfoSoundId = defaultSoundId; break;
|
||||
case 1: _configService.Current.CustomWarningSoundId = defaultSoundId; break;
|
||||
case 2: _configService.Current.CustomErrorSoundId = defaultSoundId; break;
|
||||
case 3: _configService.Current.PairRequestSoundId = defaultSoundId; break;
|
||||
}
|
||||
_configService.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
UiSharedService.AttachToolTip(isDefault ? "Sound is already at default value" : "Reset to default sound");
|
||||
|
||||
// Disable toggle button
|
||||
ImGui.SameLine();
|
||||
@@ -3520,6 +3633,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
case 1: _configService.Current.DisableWarningSound = newDisabled; break;
|
||||
case 2: _configService.Current.DisableErrorSound = newDisabled; break;
|
||||
case 3: _configService.Current.DisablePairRequestSound = newDisabled; break;
|
||||
case 4: _configService.Current.DisableDownloadSound = newDisabled; break;
|
||||
}
|
||||
_configService.Save();
|
||||
}
|
||||
@@ -3527,6 +3641,31 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
ImGui.PopStyleColor(3);
|
||||
}
|
||||
UiSharedService.AttachToolTip(isDisabled ? "Sound is disabled - click to enable" : "Sound is enabled - click to disable");
|
||||
|
||||
// Reset button
|
||||
ImGui.SameLine();
|
||||
using var resetId = ImRaii.PushId($"Reset_{typeIndex}");
|
||||
bool isDefault = currentSoundId == defaultSoundId;
|
||||
|
||||
using (ImRaii.Disabled(isDefault))
|
||||
{
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
if (ImGui.Button(FontAwesomeIcon.Undo.ToIconString(), new Vector2(buttonWidth, 0)))
|
||||
{
|
||||
switch (typeIndex)
|
||||
{
|
||||
case 0: _configService.Current.CustomInfoSoundId = defaultSoundId; break;
|
||||
case 1: _configService.Current.CustomWarningSoundId = defaultSoundId; break;
|
||||
case 2: _configService.Current.CustomErrorSoundId = defaultSoundId; break;
|
||||
case 3: _configService.Current.PairRequestSoundId = defaultSoundId; break;
|
||||
case 4: _configService.Current.DownloadSoundId = defaultSoundId; break;
|
||||
}
|
||||
_configService.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
UiSharedService.AttachToolTip(isDefault ? "Sound is already at default value" : "Reset to default sound");
|
||||
}
|
||||
|
||||
ImGui.EndTable();
|
||||
|
||||
@@ -121,19 +121,12 @@ public partial class ApiController
|
||||
{
|
||||
// Fire and forget async operation
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
{
|
||||
var myCidHash = (await _dalamudUtil.GetCIDAsync().ConfigureAwait(false)).ToString().GetHash256();
|
||||
try
|
||||
{
|
||||
await TryPairWithContentId(request.HashedCid, myCidHash).ConfigureAwait(false);
|
||||
_pairRequestService.RemoveRequest(request.HashedCid);
|
||||
|
||||
Mediator.Publish(new NotificationMessage(
|
||||
"Pair Request Accepted",
|
||||
$"Sent a pair request back to {senderName}.",
|
||||
NotificationType.Info,
|
||||
TimeSpan.FromSeconds(3)));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -143,17 +136,11 @@ public partial class ApiController
|
||||
NotificationType.Error,
|
||||
TimeSpan.FromSeconds(5)));
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
onDecline: () =>
|
||||
{
|
||||
_pairRequestService.RemoveRequest(request.HashedCid);
|
||||
Mediator.Publish(new NotificationMessage(
|
||||
"Pair Request Declined",
|
||||
$"Declined {senderName}'s pair request.",
|
||||
NotificationType.Info,
|
||||
TimeSpan.FromSeconds(3)));
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
||||
Reference in New Issue
Block a user