using C4IT.Graphics; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Windows.Forms; using static C4IT.Logging.cLogManager; namespace FasdDesktopUi.Basics.Helper { internal sealed class TrayTicketNotificationManager { private readonly NotifyIcon _notifyIcon; private readonly object _syncRoot = new object(); private string _baseTooltip; private string _currentTooltip; private bool _overlayInitialized; private const string OverlayKey = "TicketChanges"; private const string OverlaySetName = "OverlayTicketChanges"; public TrayTicketNotificationManager(NotifyIcon notifyIcon) { _notifyIcon = notifyIcon ?? throw new ArgumentNullException(nameof(notifyIcon)); } public bool HasNotification { get { lock (_syncRoot) return !string.IsNullOrWhiteSpace(_currentTooltip); } } public void CaptureBaseTooltip() { lock (_syncRoot) { _baseTooltip = _notifyIcon.Text; } } public void Show(string message) { if (string.IsNullOrWhiteSpace(message)) { Clear(); return; } EnsureOverlaySet(); lock (_syncRoot) { _currentTooltip = BuildTooltip(message); } NotifyerSupport.SetNotifyIconOverlay(OverlayKey, OverlaySetName, NotifyerSupport.enumIconAlignment.TopRight, priority: 100); ApplyTooltip(); } public void Clear() { lock (_syncRoot) { _currentTooltip = null; } NotifyerSupport.SetNotifyIconOverlay(OverlayKey, null, NotifyerSupport.enumIconAlignment.TopRight); ApplyTooltip(); } public void ApplyTooltip() { if (_notifyIcon == null) return; string tooltip; lock (_syncRoot) { tooltip = string.IsNullOrWhiteSpace(_currentTooltip) ? _baseTooltip : $"F4SD - {_currentTooltip}"; } _notifyIcon.Text = TrimTooltip(tooltip); } private void EnsureOverlaySet() { if (_overlayInitialized) return; try { var overlayFactories = new Dictionary>(); var sizeMap = new SortedDictionary(); foreach (var size in NotifyerSupport.DefaultIconSizes) { var overlaySize = CalculateOverlayDiameter(size); if (overlaySize <= 0) continue; sizeMap[size] = overlaySize; if (!overlayFactories.ContainsKey(overlaySize)) { var localSize = overlaySize; overlayFactories[localSize] = () => CreateBadgeBitmap(localSize); } } var iconSet = NotifyerSupport.RegisterDynamicSet(OverlaySetName, overlayFactories, NoRefresh: true) ?? NotifyerSupport.GetIconSet(OverlaySetName); if (iconSet != null) { iconSet.SizeMap = sizeMap; _overlayInitialized = true; } } catch (Exception ex) { LogException(ex); } } private static string BuildTooltip(string message) { try { var parts = message .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) .Select(part => part.Trim()) .Where(part => part.Length > 0); var summary = string.Join(" | ", parts); if (summary.Length > 140) summary = summary.Substring(0, 139) + "…"; return summary; } catch { return message; } } private static string TrimTooltip(string tooltip) { if (string.IsNullOrWhiteSpace(tooltip)) return tooltip; tooltip = tooltip.Replace("\r", " ").Replace("\n", " "); tooltip = tooltip.Trim(); return tooltip.Length <= 63 ? tooltip : tooltip.Substring(0, 63); } private static int CalculateOverlayDiameter(int baseSize) { if (baseSize <= 0) return 0; if (baseSize <= 18) return 8; if (baseSize <= 26) return 10; if (baseSize <= 36) return 11; var diameter = (int)Math.Round(baseSize * 0.22f); return Math.Max(9, Math.Min(diameter, baseSize)); } private static Bitmap CreateBadgeBitmap(int size) { var diameter = Math.Max(2, size); var bitmap = new Bitmap(diameter, diameter, System.Drawing.Imaging.PixelFormat.Format32bppArgb); bitmap.SetResolution(96f, 96f); using (var graphics = Graphics.FromImage(bitmap)) { graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.Clear(Color.Transparent); int margin = 0; if (diameter >= 12) margin = Math.Max(1, (int)Math.Round(diameter * 0.08f)); else if (diameter >= 9) margin = 1; var circleSize = Math.Max(1, diameter - (margin * 2)); var circleRect = new Rectangle(margin, margin, circleSize, circleSize); using (var brush = new SolidBrush(Color.FromArgb(235, 220, 0, 0))) { graphics.FillEllipse(brush, circleRect); } } return bitmap; } } }