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.Drawing2D;
|
||||
using ShopDbEndpointAgent.Core;
|
||||
|
||||
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
|
||||
// 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
|
||||
// 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
|
||||
{
|
||||
private readonly FleetAlert alert;
|
||||
private System.Windows.Forms.Timer? countdownTimer;
|
||||
private int remainingSeconds;
|
||||
private Label? countdownLabel;
|
||||
|
||||
public event EventHandler? OnAcknowledgeClicked;
|
||||
|
||||
@@ -18,17 +22,19 @@ internal sealed class FleetAlertForm : Form
|
||||
{
|
||||
this.alert = alert ?? throw new ArgumentNullException(nameof(alert));
|
||||
|
||||
Text = "Fleet Alert";
|
||||
FormBorderStyle = FormBorderStyle.FixedToolWindow;
|
||||
Text = string.Empty;
|
||||
FormBorderStyle = FormBorderStyle.None;
|
||||
TopMost = true;
|
||||
ShowInTaskbar = false;
|
||||
StartPosition = FormStartPosition.Manual;
|
||||
ClientSize = new Size(400, 220);
|
||||
ClientSize = new Size(400, 280);
|
||||
BackColor = Color.White;
|
||||
|
||||
var screen = Screen.PrimaryScreen?.WorkingArea ?? Screen.PrimaryScreen!.Bounds;
|
||||
Location = new Point(screen.Right - Width - 20, screen.Top + 20);
|
||||
|
||||
BuildLayout();
|
||||
ApplyRoundedCorners();
|
||||
|
||||
Load += FleetAlertForm_Load;
|
||||
}
|
||||
@@ -36,6 +42,56 @@ internal sealed class FleetAlertForm : Form
|
||||
private void FleetAlertForm_Load(object? sender, EventArgs e)
|
||||
{
|
||||
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()
|
||||
@@ -53,7 +109,8 @@ internal sealed class FleetAlertForm : Form
|
||||
Left = 5,
|
||||
Top = 0,
|
||||
Width = 395,
|
||||
Height = 220,
|
||||
Height = 280,
|
||||
BackColor = Color.White,
|
||||
};
|
||||
Controls.Add(contentPanel);
|
||||
|
||||
@@ -62,42 +119,49 @@ internal sealed class FleetAlertForm : Form
|
||||
Left = 0,
|
||||
Top = 0,
|
||||
Width = 395,
|
||||
Height = 40,
|
||||
BackColor = SystemColors.ControlLight,
|
||||
Height = 45,
|
||||
BackColor = Color.FromArgb(245, 245, 245),
|
||||
};
|
||||
contentPanel.Controls.Add(headerPanel);
|
||||
|
||||
var typeLabel = new Label
|
||||
{
|
||||
Text = alert.TypeName.ToUpper(),
|
||||
Left = 12,
|
||||
Top = 12,
|
||||
Left = 16,
|
||||
Top = 14,
|
||||
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);
|
||||
|
||||
var closeButton = new Button
|
||||
{
|
||||
Text = "X",
|
||||
Left = 355,
|
||||
Top = 8,
|
||||
Width = 28,
|
||||
Text = "×",
|
||||
Left = 358,
|
||||
Top = 10,
|
||||
Width = 24,
|
||||
Height = 24,
|
||||
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.MouseOverBackColor = Color.FromArgb(224, 224, 224);
|
||||
closeButton.Click += CloseButton_Click;
|
||||
headerPanel.Controls.Add(closeButton);
|
||||
|
||||
var titleLabel = new Label
|
||||
{
|
||||
Text = alert.Title,
|
||||
Left = 12,
|
||||
Top = 52,
|
||||
Width = 370,
|
||||
Height = 60,
|
||||
Font = new Font(Font.FontFamily, 14, FontStyle.Bold),
|
||||
Left = 20,
|
||||
Top = 58,
|
||||
Width = 360,
|
||||
Height = 50,
|
||||
Font = new Font("Segoe UI", 11, FontStyle.Bold),
|
||||
ForeColor = Color.FromArgb(51, 51, 51),
|
||||
AutoSize = false,
|
||||
};
|
||||
contentPanel.Controls.Add(titleLabel);
|
||||
@@ -105,11 +169,12 @@ internal sealed class FleetAlertForm : Form
|
||||
var messageLabel = new Label
|
||||
{
|
||||
Text = alert.Message,
|
||||
Left = 12,
|
||||
Left = 20,
|
||||
Top = 115,
|
||||
Width = 370,
|
||||
Height = 60,
|
||||
Font = new Font(Font.FontFamily, 10),
|
||||
Width = 360,
|
||||
Height = 80,
|
||||
Font = new Font("Segoe UI", 9.75f),
|
||||
ForeColor = Color.FromArgb(85, 85, 85),
|
||||
AutoSize = false,
|
||||
};
|
||||
contentPanel.Controls.Add(messageLabel);
|
||||
@@ -117,17 +182,53 @@ internal sealed class FleetAlertForm : Form
|
||||
var acknowledgeButton = new Button
|
||||
{
|
||||
Text = "Acknowledge",
|
||||
Left = 128,
|
||||
Top = 180,
|
||||
Left = 130,
|
||||
Top = 202,
|
||||
Width = 140,
|
||||
Height = 32,
|
||||
BackColor = SystemColors.Highlight,
|
||||
BackColor = Color.FromArgb(76, 175, 80),
|
||||
ForeColor = Color.White,
|
||||
FlatStyle = FlatStyle.Flat,
|
||||
Font = new Font("Segoe UI", 9, FontStyle.Bold),
|
||||
Cursor = Cursors.Hand,
|
||||
};
|
||||
acknowledgeButton.FlatAppearance.BorderSize = 0;
|
||||
acknowledgeButton.FlatAppearance.MouseOverBackColor = Color.FromArgb(69, 160, 73);
|
||||
acknowledgeButton.Click += AcknowledgeButton_Click;
|
||||
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)
|
||||
@@ -165,4 +266,14 @@ internal sealed class FleetAlertForm : Form
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
countdownTimer?.Stop();
|
||||
countdownTimer?.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user