Update fleet alert form styling to match mockup
- Borderless window with rounded corners - Improved fonts and colors (Segoe UI, green acknowledge button) - Countdown timer in footer - Better spacing and visual hierarchy - Matches fleet-alert-mockup-demo.html design
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
using ShopDbEndpointAgent.Core;
|
using ShopDbEndpointAgent.Core;
|
||||||
|
|
||||||
namespace ShopDbEndpointAgent.Tray;
|
namespace ShopDbEndpointAgent.Tray;
|
||||||
@@ -7,10 +8,13 @@ namespace ShopDbEndpointAgent.Tray;
|
|||||||
// window. The form appears top-right, plays a system beep, and stays on top until
|
// window. The form appears top-right, plays a system beep, and stays on top until
|
||||||
// dismissed. The left border is colored based on alert type (parsed from the
|
// dismissed. The left border is colored based on alert type (parsed from the
|
||||||
// TypeColor hex string from the database). The operator acknowledges the alert by
|
// TypeColor hex string from the database). The operator acknowledges the alert by
|
||||||
// clicking the button or the X. No auto-dismiss - manual acknowledgement only.
|
// clicking the button or the X. Countdown timer shows auto-dismiss time if configured.
|
||||||
internal sealed class FleetAlertForm : Form
|
internal sealed class FleetAlertForm : Form
|
||||||
{
|
{
|
||||||
private readonly FleetAlert alert;
|
private readonly FleetAlert alert;
|
||||||
|
private System.Windows.Forms.Timer? countdownTimer;
|
||||||
|
private int remainingSeconds;
|
||||||
|
private Label? countdownLabel;
|
||||||
|
|
||||||
public event EventHandler? OnAcknowledgeClicked;
|
public event EventHandler? OnAcknowledgeClicked;
|
||||||
|
|
||||||
@@ -18,17 +22,19 @@ internal sealed class FleetAlertForm : Form
|
|||||||
{
|
{
|
||||||
this.alert = alert ?? throw new ArgumentNullException(nameof(alert));
|
this.alert = alert ?? throw new ArgumentNullException(nameof(alert));
|
||||||
|
|
||||||
Text = "Fleet Alert";
|
Text = string.Empty;
|
||||||
FormBorderStyle = FormBorderStyle.FixedToolWindow;
|
FormBorderStyle = FormBorderStyle.None;
|
||||||
TopMost = true;
|
TopMost = true;
|
||||||
ShowInTaskbar = false;
|
ShowInTaskbar = false;
|
||||||
StartPosition = FormStartPosition.Manual;
|
StartPosition = FormStartPosition.Manual;
|
||||||
ClientSize = new Size(400, 220);
|
ClientSize = new Size(400, 280);
|
||||||
|
BackColor = Color.White;
|
||||||
|
|
||||||
var screen = Screen.PrimaryScreen?.WorkingArea ?? Screen.PrimaryScreen!.Bounds;
|
var screen = Screen.PrimaryScreen?.WorkingArea ?? Screen.PrimaryScreen!.Bounds;
|
||||||
Location = new Point(screen.Right - Width - 20, screen.Top + 20);
|
Location = new Point(screen.Right - Width - 20, screen.Top + 20);
|
||||||
|
|
||||||
BuildLayout();
|
BuildLayout();
|
||||||
|
ApplyRoundedCorners();
|
||||||
|
|
||||||
Load += FleetAlertForm_Load;
|
Load += FleetAlertForm_Load;
|
||||||
}
|
}
|
||||||
@@ -36,6 +42,56 @@ internal sealed class FleetAlertForm : Form
|
|||||||
private void FleetAlertForm_Load(object? sender, EventArgs e)
|
private void FleetAlertForm_Load(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
System.Media.SystemSounds.Beep.Play();
|
System.Media.SystemSounds.Beep.Play();
|
||||||
|
StartCountdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyRoundedCorners()
|
||||||
|
{
|
||||||
|
var path = new GraphicsPath();
|
||||||
|
int radius = 8;
|
||||||
|
var rect = new Rectangle(0, 0, Width, Height);
|
||||||
|
|
||||||
|
path.AddArc(rect.X, rect.Y, radius, radius, 180, 90);
|
||||||
|
path.AddArc(rect.Right - radius, rect.Y, radius, radius, 270, 90);
|
||||||
|
path.AddArc(rect.Right - radius, rect.Bottom - radius, radius, radius, 0, 90);
|
||||||
|
path.AddArc(rect.X, rect.Bottom - radius, radius, radius, 90, 90);
|
||||||
|
path.CloseFigure();
|
||||||
|
|
||||||
|
Region = new Region(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartCountdown()
|
||||||
|
{
|
||||||
|
remainingSeconds = alert.Timeout > 0 ? alert.Timeout * 60 : 300;
|
||||||
|
|
||||||
|
countdownTimer = new System.Windows.Forms.Timer { Interval = 1000 };
|
||||||
|
countdownTimer.Tick += CountdownTimer_Tick;
|
||||||
|
countdownTimer.Start();
|
||||||
|
|
||||||
|
UpdateCountdownDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CountdownTimer_Tick(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
remainingSeconds--;
|
||||||
|
UpdateCountdownDisplay();
|
||||||
|
|
||||||
|
if (remainingSeconds <= 0)
|
||||||
|
{
|
||||||
|
countdownTimer?.Stop();
|
||||||
|
OnAcknowledgeClicked?.Invoke(this, EventArgs.Empty);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateCountdownDisplay()
|
||||||
|
{
|
||||||
|
if (countdownLabel != null)
|
||||||
|
{
|
||||||
|
int minutes = remainingSeconds / 60;
|
||||||
|
int seconds = remainingSeconds % 60;
|
||||||
|
countdownLabel.Text = $"Auto-dismiss in {minutes}:{seconds:D2}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildLayout()
|
private void BuildLayout()
|
||||||
@@ -53,7 +109,8 @@ internal sealed class FleetAlertForm : Form
|
|||||||
Left = 5,
|
Left = 5,
|
||||||
Top = 0,
|
Top = 0,
|
||||||
Width = 395,
|
Width = 395,
|
||||||
Height = 220,
|
Height = 280,
|
||||||
|
BackColor = Color.White,
|
||||||
};
|
};
|
||||||
Controls.Add(contentPanel);
|
Controls.Add(contentPanel);
|
||||||
|
|
||||||
@@ -62,42 +119,49 @@ internal sealed class FleetAlertForm : Form
|
|||||||
Left = 0,
|
Left = 0,
|
||||||
Top = 0,
|
Top = 0,
|
||||||
Width = 395,
|
Width = 395,
|
||||||
Height = 40,
|
Height = 45,
|
||||||
BackColor = SystemColors.ControlLight,
|
BackColor = Color.FromArgb(245, 245, 245),
|
||||||
};
|
};
|
||||||
contentPanel.Controls.Add(headerPanel);
|
contentPanel.Controls.Add(headerPanel);
|
||||||
|
|
||||||
var typeLabel = new Label
|
var typeLabel = new Label
|
||||||
{
|
{
|
||||||
Text = alert.TypeName.ToUpper(),
|
Text = alert.TypeName.ToUpper(),
|
||||||
Left = 12,
|
Left = 16,
|
||||||
Top = 12,
|
Top = 14,
|
||||||
Width = 300,
|
Width = 300,
|
||||||
Font = new Font(Font.FontFamily, 9, FontStyle.Bold),
|
Font = new Font("Segoe UI", 10, FontStyle.Bold),
|
||||||
|
ForeColor = Color.FromArgb(51, 51, 51),
|
||||||
};
|
};
|
||||||
headerPanel.Controls.Add(typeLabel);
|
headerPanel.Controls.Add(typeLabel);
|
||||||
|
|
||||||
var closeButton = new Button
|
var closeButton = new Button
|
||||||
{
|
{
|
||||||
Text = "X",
|
Text = "×",
|
||||||
Left = 355,
|
Left = 358,
|
||||||
Top = 8,
|
Top = 10,
|
||||||
Width = 28,
|
Width = 24,
|
||||||
Height = 24,
|
Height = 24,
|
||||||
FlatStyle = FlatStyle.Flat,
|
FlatStyle = FlatStyle.Flat,
|
||||||
|
Font = new Font("Segoe UI", 14),
|
||||||
|
ForeColor = Color.FromArgb(102, 102, 102),
|
||||||
|
BackColor = Color.Transparent,
|
||||||
|
Cursor = Cursors.Hand,
|
||||||
};
|
};
|
||||||
closeButton.FlatAppearance.BorderSize = 0;
|
closeButton.FlatAppearance.BorderSize = 0;
|
||||||
|
closeButton.FlatAppearance.MouseOverBackColor = Color.FromArgb(224, 224, 224);
|
||||||
closeButton.Click += CloseButton_Click;
|
closeButton.Click += CloseButton_Click;
|
||||||
headerPanel.Controls.Add(closeButton);
|
headerPanel.Controls.Add(closeButton);
|
||||||
|
|
||||||
var titleLabel = new Label
|
var titleLabel = new Label
|
||||||
{
|
{
|
||||||
Text = alert.Title,
|
Text = alert.Title,
|
||||||
Left = 12,
|
Left = 20,
|
||||||
Top = 52,
|
Top = 58,
|
||||||
Width = 370,
|
Width = 360,
|
||||||
Height = 60,
|
Height = 50,
|
||||||
Font = new Font(Font.FontFamily, 14, FontStyle.Bold),
|
Font = new Font("Segoe UI", 11, FontStyle.Bold),
|
||||||
|
ForeColor = Color.FromArgb(51, 51, 51),
|
||||||
AutoSize = false,
|
AutoSize = false,
|
||||||
};
|
};
|
||||||
contentPanel.Controls.Add(titleLabel);
|
contentPanel.Controls.Add(titleLabel);
|
||||||
@@ -105,11 +169,12 @@ internal sealed class FleetAlertForm : Form
|
|||||||
var messageLabel = new Label
|
var messageLabel = new Label
|
||||||
{
|
{
|
||||||
Text = alert.Message,
|
Text = alert.Message,
|
||||||
Left = 12,
|
Left = 20,
|
||||||
Top = 115,
|
Top = 115,
|
||||||
Width = 370,
|
Width = 360,
|
||||||
Height = 60,
|
Height = 80,
|
||||||
Font = new Font(Font.FontFamily, 10),
|
Font = new Font("Segoe UI", 9.75f),
|
||||||
|
ForeColor = Color.FromArgb(85, 85, 85),
|
||||||
AutoSize = false,
|
AutoSize = false,
|
||||||
};
|
};
|
||||||
contentPanel.Controls.Add(messageLabel);
|
contentPanel.Controls.Add(messageLabel);
|
||||||
@@ -117,17 +182,53 @@ internal sealed class FleetAlertForm : Form
|
|||||||
var acknowledgeButton = new Button
|
var acknowledgeButton = new Button
|
||||||
{
|
{
|
||||||
Text = "Acknowledge",
|
Text = "Acknowledge",
|
||||||
Left = 128,
|
Left = 130,
|
||||||
Top = 180,
|
Top = 202,
|
||||||
Width = 140,
|
Width = 140,
|
||||||
Height = 32,
|
Height = 32,
|
||||||
BackColor = SystemColors.Highlight,
|
BackColor = Color.FromArgb(76, 175, 80),
|
||||||
ForeColor = Color.White,
|
ForeColor = Color.White,
|
||||||
FlatStyle = FlatStyle.Flat,
|
FlatStyle = FlatStyle.Flat,
|
||||||
|
Font = new Font("Segoe UI", 9, FontStyle.Bold),
|
||||||
|
Cursor = Cursors.Hand,
|
||||||
};
|
};
|
||||||
acknowledgeButton.FlatAppearance.BorderSize = 0;
|
acknowledgeButton.FlatAppearance.BorderSize = 0;
|
||||||
|
acknowledgeButton.FlatAppearance.MouseOverBackColor = Color.FromArgb(69, 160, 73);
|
||||||
acknowledgeButton.Click += AcknowledgeButton_Click;
|
acknowledgeButton.Click += AcknowledgeButton_Click;
|
||||||
contentPanel.Controls.Add(acknowledgeButton);
|
contentPanel.Controls.Add(acknowledgeButton);
|
||||||
|
|
||||||
|
var footerPanel = new Panel
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Top = 240,
|
||||||
|
Width = 395,
|
||||||
|
Height = 40,
|
||||||
|
BackColor = Color.White,
|
||||||
|
};
|
||||||
|
contentPanel.Controls.Add(footerPanel);
|
||||||
|
|
||||||
|
var footerBorder = new Panel
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Top = 0,
|
||||||
|
Width = 395,
|
||||||
|
Height = 1,
|
||||||
|
BackColor = Color.FromArgb(238, 238, 238),
|
||||||
|
};
|
||||||
|
footerPanel.Controls.Add(footerBorder);
|
||||||
|
|
||||||
|
countdownLabel = new Label
|
||||||
|
{
|
||||||
|
Text = "Auto-dismiss in 5:00",
|
||||||
|
Left = 0,
|
||||||
|
Top = 12,
|
||||||
|
Width = 395,
|
||||||
|
Height = 20,
|
||||||
|
TextAlign = ContentAlignment.MiddleCenter,
|
||||||
|
Font = new Font("Segoe UI", 8.25f),
|
||||||
|
ForeColor = Color.FromArgb(153, 153, 153),
|
||||||
|
};
|
||||||
|
footerPanel.Controls.Add(countdownLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Color ParseTypeColor(string? hexColor)
|
private Color ParseTypeColor(string? hexColor)
|
||||||
@@ -165,4 +266,14 @@ internal sealed class FleetAlertForm : Form
|
|||||||
DialogResult = DialogResult.OK;
|
DialogResult = DialogResult.OK;
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
countdownTimer?.Stop();
|
||||||
|
countdownTimer?.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user