diff --git a/ntfysh_client/MainForm.cs b/ntfysh_client/MainForm.cs
index cc2cdfa..10198ea 100644
--- a/ntfysh_client/MainForm.cs
+++ b/ntfysh_client/MainForm.cs
@@ -16,6 +16,7 @@ namespace ntfysh_client
private readonly NotificationListener _notificationListener;
private bool _startInTray;
private bool _trueExit;
+ private NotificationDialog _notificationDialog;
public MainForm(NotificationListener notificationListener, bool startInTray = false)
{
@@ -32,6 +33,8 @@ namespace ntfysh_client
{
LoadSettings();
LoadTopics();
+
+ _notificationDialog = new NotificationDialog();
}
protected override void SetVisibleCore(bool value)
@@ -69,8 +72,24 @@ namespace ntfysh_client
};
string finalTitle = string.IsNullOrWhiteSpace(e.Title) ? $"{e.Sender.TopicId}@{e.Sender.ServerUrl}" : e.Title;
-
- notifyIcon.ShowBalloonTip((int)TimeSpan.FromSeconds((double)Program.Settings.Timeout).TotalMilliseconds, finalTitle, e.Message, priorityIcon);
+
+ if (Program.Settings.NotificationsMethod == SettingsModel.NotificationsType.NativeWindows)
+ {
+ notifyIcon.ShowBalloonTip((int)TimeSpan.FromSeconds((double)Program.Settings.Timeout).TotalMilliseconds, finalTitle, e.Message, priorityIcon);
+ }
+ else
+ {
+
+ _notificationDialog.ShowNotification(
+ title: finalTitle,
+ message: e.Message,
+ timeoutSeconds: (int)Program.Settings.Timeout,
+ icon: priorityIcon,
+ showTimeOutBar: Program.Settings.CustomTrayNotificationsShowTimeoutBar,
+ showInDarkMode: Program.Settings.CustomTrayNotificationsShowInDarkMode,
+ playNotificationSound: Program.Settings.CustomTrayNotificationsPlayDefaultWindowsSound
+ );
+ }
}
private void OnConnectionMultiAttemptFailure(NotificationListener sender, SubscribedTopic topic)
@@ -132,10 +151,15 @@ namespace ntfysh_client
using SettingsDialog dialog = new();
//Load current settings into dialog
- dialog.Timeout = Program.Settings.Timeout;
dialog.ReconnectAttempts = Program.Settings.ReconnectAttempts;
dialog.ReconnectAttemptDelay = Program.Settings.ReconnectAttemptDelay;
-
+ dialog.UseNativeWindowsNotifications = Program.Settings.NotificationsMethod == SettingsModel.NotificationsType.NativeWindows;
+ dialog.UseCustomTrayNotifications = Program.Settings.NotificationsMethod == SettingsModel.NotificationsType.CustomTray;
+ dialog.CustomTrayNotificationsShowTimeoutBar = Program.Settings.CustomTrayNotificationsShowTimeoutBar;
+ dialog.CustomTrayNotificationsShowInDarkMode = Program.Settings.CustomTrayNotificationsShowInDarkMode;
+ dialog.CustomTrayNotificationsPlayDefaultWindowsSound = Program.Settings.CustomTrayNotificationsPlayDefaultWindowsSound;
+ dialog.Timeout = Program.Settings.Timeout; // set timeout last so bounds are setup before setting value
+
//Show dialog
DialogResult result = dialog.ShowDialog();
@@ -146,7 +170,11 @@ namespace ntfysh_client
Program.Settings.Timeout = dialog.Timeout;
Program.Settings.ReconnectAttempts = dialog.ReconnectAttempts;
Program.Settings.ReconnectAttemptDelay = dialog.ReconnectAttemptDelay;
-
+ Program.Settings.NotificationsMethod = (dialog.UseNativeWindowsNotifications)? SettingsModel.NotificationsType.NativeWindows : SettingsModel.NotificationsType.CustomTray;
+ Program.Settings.CustomTrayNotificationsShowTimeoutBar = dialog.CustomTrayNotificationsShowTimeoutBar;
+ Program.Settings.CustomTrayNotificationsShowInDarkMode = dialog.CustomTrayNotificationsShowInDarkMode;
+ Program.Settings.CustomTrayNotificationsPlayDefaultWindowsSound = dialog.CustomTrayNotificationsPlayDefaultWindowsSound;
+
//Save new settings persistently
SaveSettingsToFile();
}
@@ -298,10 +326,14 @@ namespace ntfysh_client
private SettingsModel GetDefaultSettings() => new()
{
- Revision = 1,
+ Revision = 2,
Timeout = 5,
ReconnectAttempts = 10,
- ReconnectAttemptDelay = 3
+ ReconnectAttemptDelay = 3,
+ NotificationsMethod = SettingsModel.NotificationsType.NativeWindows,
+ CustomTrayNotificationsShowTimeoutBar = true,
+ CustomTrayNotificationsShowInDarkMode = false,
+ CustomTrayNotificationsPlayDefaultWindowsSound = true,
};
private void MergeSettingsRevisions(SettingsModel older, SettingsModel newer)
@@ -313,6 +345,15 @@ namespace ntfysh_client
older.ReconnectAttemptDelay = newer.ReconnectAttemptDelay;
}
+ //Apply settings introduced in Revision 2 (Native vs custom notifications)
+ if (older.Revision < 2)
+ {
+ older.NotificationsMethod = newer.NotificationsMethod;
+ older.CustomTrayNotificationsShowTimeoutBar = newer.CustomTrayNotificationsShowTimeoutBar;
+ older.CustomTrayNotificationsShowInDarkMode = newer.CustomTrayNotificationsShowInDarkMode;
+ older.CustomTrayNotificationsPlayDefaultWindowsSound = newer.CustomTrayNotificationsPlayDefaultWindowsSound;
+ }
+
//Update the revision
older.Revision = newer.Revision;
}
@@ -361,7 +402,7 @@ namespace ntfysh_client
Program.Settings = settings;
//Check the settings revision. If it is older than the current latest revision, apply the settings defaults missing from previous revision
- if (Program.Settings.Revision < defaultSettings.ReconnectAttempts)
+ if (Program.Settings.Revision < defaultSettings.Revision)
{
MergeSettingsRevisions(Program.Settings, defaultSettings);
SaveSettingsToFile();
diff --git a/ntfysh_client/NotificationDialog.Designer.cs b/ntfysh_client/NotificationDialog.Designer.cs
new file mode 100644
index 0000000..40b8faa
--- /dev/null
+++ b/ntfysh_client/NotificationDialog.Designer.cs
@@ -0,0 +1,146 @@
+namespace ntfysh_client
+{
+ partial class NotificationDialog
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ TxBTitle = new System.Windows.Forms.TextBox();
+ ButtonClose = new System.Windows.Forms.Button();
+ TxBMessage = new System.Windows.Forms.RichTextBox();
+ IconBox = new System.Windows.Forms.PictureBox();
+ ProgressBar1 = new System.Windows.Forms.ProgressBar();
+ LblTimeout = new System.Windows.Forms.Label();
+ ((System.ComponentModel.ISupportInitialize)IconBox).BeginInit();
+ SuspendLayout();
+ //
+ // TxBTitle
+ //
+ TxBTitle.BackColor = System.Drawing.SystemColors.ControlDark;
+ TxBTitle.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ TxBTitle.Font = new System.Drawing.Font("Segoe UI", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
+ TxBTitle.ForeColor = System.Drawing.SystemColors.ControlLightLight;
+ TxBTitle.Location = new System.Drawing.Point(54, 13);
+ TxBTitle.Name = "TxBTitle";
+ TxBTitle.ReadOnly = true;
+ TxBTitle.Size = new System.Drawing.Size(683, 32);
+ TxBTitle.TabIndex = 0;
+ TxBTitle.MouseDown += window_MouseDown;
+ //
+ // ButtonClose
+ //
+ ButtonClose.BackColor = System.Drawing.SystemColors.ActiveCaptionText;
+ ButtonClose.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
+ ButtonClose.FlatAppearance.BorderSize = 0;
+ ButtonClose.FlatAppearance.MouseOverBackColor = System.Drawing.Color.DimGray;
+ ButtonClose.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+ ButtonClose.ForeColor = System.Drawing.SystemColors.ButtonFace;
+ ButtonClose.Location = new System.Drawing.Point(759, 7);
+ ButtonClose.Name = "ButtonClose";
+ ButtonClose.Size = new System.Drawing.Size(29, 38);
+ ButtonClose.TabIndex = 1;
+ ButtonClose.Text = "X";
+ ButtonClose.UseVisualStyleBackColor = false;
+ ButtonClose.Click += ButtonClose_ClickHandler;
+ //
+ // TxBMessage
+ //
+ TxBMessage.BackColor = System.Drawing.SystemColors.ControlDark;
+ TxBMessage.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ TxBMessage.Font = new System.Drawing.Font("Segoe UI", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
+ TxBMessage.ForeColor = System.Drawing.SystemColors.ControlLightLight;
+ TxBMessage.Location = new System.Drawing.Point(12, 57);
+ TxBMessage.Name = "TxBMessage";
+ TxBMessage.ReadOnly = true;
+ TxBMessage.Size = new System.Drawing.Size(776, 191);
+ TxBMessage.TabIndex = 2;
+ TxBMessage.Text = "";
+ TxBMessage.MouseDown += window_MouseDown;
+ //
+ // IconBox
+ //
+ IconBox.Location = new System.Drawing.Point(12, 12);
+ IconBox.Name = "IconBox";
+ IconBox.Size = new System.Drawing.Size(36, 39);
+ IconBox.TabIndex = 3;
+ IconBox.TabStop = false;
+ //
+ // ProgressBar1
+ //
+ ProgressBar1.BackColor = System.Drawing.SystemColors.ControlDarkDark;
+ ProgressBar1.Enabled = false;
+ ProgressBar1.ForeColor = System.Drawing.SystemColors.WindowFrame;
+ ProgressBar1.Location = new System.Drawing.Point(70, 254);
+ ProgressBar1.MarqueeAnimationSpeed = 1;
+ ProgressBar1.Name = "ProgressBar1";
+ ProgressBar1.Size = new System.Drawing.Size(718, 23);
+ ProgressBar1.Step = 1;
+ ProgressBar1.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
+ ProgressBar1.TabIndex = 4;
+ ProgressBar1.Value = 100;
+ //
+ // LblTimeout
+ //
+ LblTimeout.AutoSize = true;
+ LblTimeout.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
+ LblTimeout.Location = new System.Drawing.Point(21, 254);
+ LblTimeout.Name = "LblTimeout";
+ LblTimeout.Size = new System.Drawing.Size(43, 17);
+ LblTimeout.TabIndex = 5;
+ LblTimeout.Text = "label1";
+ LblTimeout.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ //
+ // NotificationDialog
+ //
+ AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
+ AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ BackColor = System.Drawing.SystemColors.ControlDark;
+ ClientSize = new System.Drawing.Size(800, 289);
+ Controls.Add(LblTimeout);
+ Controls.Add(ProgressBar1);
+ Controls.Add(IconBox);
+ Controls.Add(TxBMessage);
+ Controls.Add(ButtonClose);
+ Controls.Add(TxBTitle);
+ FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+ Name = "NotificationDialog";
+ Text = "NotificationDialog";
+ Click += window_MouseDown;
+ ((System.ComponentModel.ISupportInitialize)IconBox).EndInit();
+ ResumeLayout(false);
+ PerformLayout();
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TextBox TxBTitle;
+ private System.Windows.Forms.Button ButtonClose;
+ private System.Windows.Forms.RichTextBox TxBMessage;
+ private System.Windows.Forms.PictureBox IconBox;
+ private System.Windows.Forms.ProgressBar ProgressBar1;
+ private System.Windows.Forms.Label LblTimeout;
+ }
+}
\ No newline at end of file
diff --git a/ntfysh_client/NotificationDialog.cs b/ntfysh_client/NotificationDialog.cs
new file mode 100644
index 0000000..d856f2c
--- /dev/null
+++ b/ntfysh_client/NotificationDialog.cs
@@ -0,0 +1,295 @@
+using System;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+using System.Diagnostics;
+using ntfysh_client.Themes;
+using Microsoft.Win32;
+using System.Media;
+
+
+namespace ntfysh_client
+{
+ public partial class NotificationDialog : Form
+ {
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ private static extern bool AnimateWindow(IntPtr hWnd, int time, int flags);
+
+ private const int ScreenMargin = 20;
+
+ private int _timeoutSeconds = 0;
+ private System.Timers.Timer? _displayTimeoutTimer = null;
+ private System.Windows.Forms.Timer? _updateTimer = null;
+ private Stopwatch? _shownStopwatch = null;
+
+ private readonly BaseTheme _darkModeTheme = new DarkModeTheme();
+ private readonly BaseTheme _defaultTheme = new DefaultTheme();
+ private BaseTheme? _theme = null;
+
+ public NotificationDialog()
+ {
+ ShowInTaskbar = false;
+ Visible = false;
+ TopMost = true;
+ InitializeComponent();
+ InitializeWindowHidden();
+ }
+
+ public void ShowNotification(string title, string message, int timeoutSeconds = 0, ToolTipIcon? icon = null, bool showTimeOutBar = true, bool showInDarkMode = true, bool playNotificationSound = false)
+ {
+ if (Visible)
+ {
+ // close the current notification
+ HandleTimeout(null, null);
+ }
+
+ _theme = showInDarkMode ? _darkModeTheme : _defaultTheme;
+
+ ApplyTheme();
+
+ // setup data
+ IconBox.Image = (icon is null) ? null : ConvertToolTipIconToImage(icon.Value);
+
+ TxBTitle.Text = title;
+ TxBMessage.Text = message;
+
+ // setup timers
+ if (_displayTimeoutTimer != null)
+ {
+ _displayTimeoutTimer.Stop();
+ _displayTimeoutTimer.Dispose();
+ }
+
+ if (_updateTimer != null)
+ {
+ _updateTimer.Stop();
+ _updateTimer.Dispose();
+ }
+
+ if (timeoutSeconds > 0)
+ {
+ _displayTimeoutTimer = new System.Timers.Timer(timeoutSeconds * 1000);
+ _displayTimeoutTimer.Elapsed += HandleTimeout;
+ _displayTimeoutTimer.Start();
+
+ if (showTimeOutBar)
+ {
+ ProgressBar1.Value = 100;
+ _updateTimer = new System.Windows.Forms.Timer();
+ _updateTimer.Interval = 100;
+ _updateTimer.Tick += UpdateProgress;
+ _updateTimer.Start();
+
+ _shownStopwatch = new Stopwatch();
+ _shownStopwatch.Start();
+
+ ProgressBar1.Visible = true;
+ LblTimeout.Visible = true;
+ _timeoutSeconds = timeoutSeconds;
+ }
+ else
+ {
+ ProgressBar1.Visible = false;
+ LblTimeout.Visible = false;
+ }
+ }
+ else
+ {
+ ProgressBar1.Visible = false;
+ LblTimeout.Visible = false;
+ }
+
+ // ok, show the window
+ Show();
+ ButtonClose.Focus(); // make sure the window is focused, not the title box.
+ SetWindowPosition();
+
+ if (playNotificationSound) PlayNotificationSound();
+ }
+
+ private void ApplyTheme()
+ {
+ _theme ??= _defaultTheme;
+
+ // back colors
+ BackColor = _theme.BackgroundColor;
+ TxBTitle.BackColor = _theme.BackgroundColor;
+ TxBMessage.BackColor = _theme.BackgroundColor;
+ LblTimeout.BackColor = _theme.BackgroundColor;
+ ProgressBar1.BackColor = _theme.BackgroundColor;
+
+ // this one is not "hiding"
+ ButtonClose.BackColor = _theme.ControlBackGroundColor;
+ ButtonClose.ForeColor = _theme.BackgroundColor;
+ // handle mouse over
+ ButtonClose.FlatAppearance.MouseOverBackColor = _theme.ControlMouseOverBackgroundColor;
+
+ // fore colors
+ ForeColor = _theme.ForegroundColor;
+ TxBTitle.ForeColor = _theme.ForegroundColor;
+ TxBMessage.ForeColor = _theme.ForegroundColor;
+ LblTimeout.ForeColor = _theme.ForegroundColor;
+ ProgressBar1.ForeColor = _theme.ForegroundColor;
+ }
+
+ private void UpdateProgress(object? sender, EventArgs e)
+ {
+ if (_shownStopwatch is null) return;
+
+ ProgressBar1.Value = (_timeoutSeconds - _shownStopwatch.Elapsed.Seconds) * 100 / _timeoutSeconds;
+ LblTimeout.Text = $@"{_timeoutSeconds - _shownStopwatch.Elapsed.Seconds}";
+ }
+
+ protected override void SetVisibleCore(bool value)
+ {
+ SetWindowPosition();
+
+ if (value)
+ {
+ BringToFront();
+
+ AnimateWindow(
+ Handle,
+ time: 250,
+ flags: NFWinUserAnimateWindowConstants.AW_SLIDE | NFWinUserAnimateWindowConstants.AW_VER_NEGATIVE
+ );
+ }
+
+ base.SetVisibleCore(value);
+ }
+
+ private void SetWindowPosition()
+ {
+ var workingTop = Screen.PrimaryScreen.WorkingArea.Height - Height;
+ Top = workingTop - NotificationDialog.ScreenMargin;
+
+ var workingLeft = Screen.PrimaryScreen.WorkingArea.Width - Width;
+ Left = workingLeft - NotificationDialog.ScreenMargin;
+ }
+
+ private void UIThreadAnimatedHideWindow(object? sender, EventArgs? e)
+ {
+
+ AnimateWindow(
+ Handle,
+ time: 250,
+ flags: NFWinUserAnimateWindowConstants.AW_SLIDE | NFWinUserAnimateWindowConstants.AW_VER_POSITIVE | NFWinUserAnimateWindowConstants.AW_HIDE
+ );
+
+ Visible = false;
+ }
+
+ private void HandleTimeout(object? sender, EventArgs? e)
+ {
+ CancelTimer();
+
+ if (InvokeRequired)
+ {
+ // on a background thread, so invoke on the UI thread
+ Invoke(new Action(() => UIThreadAnimatedHideWindow(sender, e)));
+ }
+ else
+ {
+ // in the UI thread, invoke directly
+ UIThreadAnimatedHideWindow(sender, e);
+ }
+ }
+
+ private Image? ConvertToolTipIconToImage(ToolTipIcon icon) => icon switch
+ {
+ ToolTipIcon.Info => SystemIcons.Information.ToBitmap(),
+ ToolTipIcon.Warning => SystemIcons.Warning.ToBitmap(),
+ ToolTipIcon.Error => SystemIcons.Error.ToBitmap(),
+ _ => null
+ };
+
+ private void InitializeWindowHidden()
+ {
+ Opacity = 0;
+ ShowNotification("Title", "Message");
+ ButtonClose.Focus();
+ Visible = false;
+ Opacity = 1;
+ }
+
+ private void ButtonClose_ClickHandler(object sender, EventArgs e)
+ {
+ // don't animate, immediately "close"
+ Visible = false;
+ }
+
+ private class NFWinUserAnimateWindowConstants
+ {
+ public const int AW_HOR_POSITIVE = 0x00000001;
+ public const int AW_HOR_NEGATIVE = 0x00000002;
+ public const int AW_VER_POSITIVE = 0x00000004;
+ public const int AW_VER_NEGATIVE = 0x00000008;
+ public const int AW_CENTER = 0x00000010;
+ public const int AW_HIDE = 0x00010000;
+ public const int AW_ACTIVATE = 0x00020000;
+ public const int AW_SLIDE = 0x00040000;
+ public const int AW_BLEND = 0x00080000;
+ }
+
+ private void window_MouseDown(object sender, EventArgs e) => CancelTimer();
+
+ private void CancelTimer()
+ {
+ if (InvokeRequired)
+ {
+ // on a background thread, so invoke on the UI thread
+ Invoke(new Action(() =>
+ {
+ LblTimeout.Visible = false;
+ ProgressBar1.Visible = false;
+ }));
+ }
+ else
+ {
+ // in the UI thread, invoke directly
+ LblTimeout.Visible = false;
+ ProgressBar1.Visible = false;
+ }
+
+ if (_displayTimeoutTimer != null) // check if the timer has already been disposed
+ {
+ _displayTimeoutTimer.Stop();
+ _displayTimeoutTimer.Dispose();
+ _displayTimeoutTimer = null;
+ }
+
+ if (_updateTimer != null)
+ {
+ _updateTimer.Stop();
+ _updateTimer.Dispose();
+ _updateTimer = null;
+ }
+
+ if (_shownStopwatch != null)
+ {
+ _shownStopwatch.Stop();
+ _shownStopwatch = null;
+ }
+ }
+
+ private void PlayNotificationSound()
+ {
+ try
+ {
+ using RegistryKey? defaultSoundPathKey = Registry.CurrentUser.OpenSubKey(@"AppEvents\Schemes\Apps\.Default\Notification.Default\.Current");
+
+ if (defaultSoundPathKey is null) throw new Exception();
+
+ if (defaultSoundPathKey.GetValue(null) is not string defaultSoundPath) throw new Exception();
+
+ SoundPlayer loadedSound = new(defaultSoundPath);
+
+ loadedSound.Play();
+ }
+ catch
+ {
+ SystemSounds.Beep.Play(); // consolation prize
+ }
+ }
+ }
+}
diff --git a/ntfysh_client/NotificationDialog.resx b/ntfysh_client/NotificationDialog.resx
new file mode 100644
index 0000000..8b2ff64
--- /dev/null
+++ b/ntfysh_client/NotificationDialog.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/ntfysh_client/SettingsDialog.Designer.cs b/ntfysh_client/SettingsDialog.Designer.cs
index 8f240fe..428625a 100644
--- a/ntfysh_client/SettingsDialog.Designer.cs
+++ b/ntfysh_client/SettingsDialog.Designer.cs
@@ -38,10 +38,20 @@ namespace ntfysh_client
reconnectAttemptsLabel = new System.Windows.Forms.Label();
reconnectAttemptDelay = new System.Windows.Forms.NumericUpDown();
reconnectAttemptDelayLabel = new System.Windows.Forms.Label();
+ nativeVersusCustomNotificationsGroupBox = new System.Windows.Forms.GroupBox();
+ useCustomTrayNotifications = new System.Windows.Forms.RadioButton();
+ useNativeWindowsNotifications = new System.Windows.Forms.RadioButton();
+ groupCustomNotificationSettings = new System.Windows.Forms.GroupBox();
+ customNotificationsPlayWindowsNotificationAudio = new System.Windows.Forms.CheckBox();
+ customNotificationsShowInDarkMode = new System.Windows.Forms.CheckBox();
+ customNotificationsShowTimeoutBar = new System.Windows.Forms.CheckBox();
+ label1 = new System.Windows.Forms.Label();
buttonPanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)timeout).BeginInit();
((System.ComponentModel.ISupportInitialize)reconnectAttempts).BeginInit();
((System.ComponentModel.ISupportInitialize)reconnectAttemptDelay).BeginInit();
+ nativeVersusCustomNotificationsGroupBox.SuspendLayout();
+ groupCustomNotificationSettings.SuspendLayout();
SuspendLayout();
//
// buttonPanel
@@ -50,7 +60,7 @@ namespace ntfysh_client
buttonPanel.Controls.Add(cancelButton);
buttonPanel.Controls.Add(saveButton);
buttonPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
- buttonPanel.Location = new System.Drawing.Point(0, 150);
+ buttonPanel.Location = new System.Drawing.Point(0, 336);
buttonPanel.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
buttonPanel.Name = "buttonPanel";
buttonPanel.Size = new System.Drawing.Size(531, 51);
@@ -82,9 +92,9 @@ namespace ntfysh_client
timeoutLabel.Location = new System.Drawing.Point(13, 9);
timeoutLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
timeoutLabel.Name = "timeoutLabel";
- timeoutLabel.Size = new System.Drawing.Size(488, 15);
+ timeoutLabel.Size = new System.Drawing.Size(401, 15);
timeoutLabel.TabIndex = 3;
- timeoutLabel.Text = "Notification Toast Timeout (seconds, may be ignored by OS based on accessibility settings):";
+ timeoutLabel.Text = "Notification Toast Timeout (seconds, use -1 to require closing notification):";
//
// timeout
//
@@ -108,7 +118,7 @@ namespace ntfysh_client
reconnectAttemptsLabel.Location = new System.Drawing.Point(12, 54);
reconnectAttemptsLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
reconnectAttemptsLabel.Name = "reconnectAttemptsLabel";
- reconnectAttemptsLabel.Size = new System.Drawing.Size(198, 15);
+ reconnectAttemptsLabel.Size = new System.Drawing.Size(287, 15);
reconnectAttemptsLabel.TabIndex = 5;
reconnectAttemptsLabel.Text = "Maximum reconnect retry attempts (requires restart):";
//
@@ -126,16 +136,102 @@ namespace ntfysh_client
reconnectAttemptDelayLabel.Location = new System.Drawing.Point(12, 99);
reconnectAttemptDelayLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
reconnectAttemptDelayLabel.Name = "reconnectAttemptDelayLabel";
- reconnectAttemptDelayLabel.Size = new System.Drawing.Size(191, 15);
+ reconnectAttemptDelayLabel.Size = new System.Drawing.Size(275, 15);
reconnectAttemptDelayLabel.TabIndex = 7;
reconnectAttemptDelayLabel.Text = "Delay between attempts (seconds, requires restart):";
//
+ // nativeVersusCustomNotificationsGroupBox
+ //
+ nativeVersusCustomNotificationsGroupBox.Controls.Add(useCustomTrayNotifications);
+ nativeVersusCustomNotificationsGroupBox.Controls.Add(useNativeWindowsNotifications);
+ nativeVersusCustomNotificationsGroupBox.Location = new System.Drawing.Point(12, 147);
+ nativeVersusCustomNotificationsGroupBox.Name = "nativeVersusCustomNotificationsGroupBox";
+ nativeVersusCustomNotificationsGroupBox.Size = new System.Drawing.Size(506, 67);
+ nativeVersusCustomNotificationsGroupBox.TabIndex = 9;
+ nativeVersusCustomNotificationsGroupBox.TabStop = false;
+ //
+ // useCustomTrayNotifications
+ //
+ useCustomTrayNotifications.AutoSize = true;
+ useCustomTrayNotifications.Location = new System.Drawing.Point(6, 40);
+ useCustomTrayNotifications.Name = "useCustomTrayNotifications";
+ useCustomTrayNotifications.Size = new System.Drawing.Size(267, 19);
+ useCustomTrayNotifications.TabIndex = 1;
+ useCustomTrayNotifications.TabStop = true;
+ useCustomTrayNotifications.Text = "Use ntfysh-windows custom tray notifications";
+ useCustomTrayNotifications.UseVisualStyleBackColor = true;
+ useCustomTrayNotifications.CheckedChanged += UseCustomTrayNotifications_CheckedChanged;
+ //
+ // useNativeWindowsNotifications
+ //
+ useNativeWindowsNotifications.AutoSize = true;
+ useNativeWindowsNotifications.Location = new System.Drawing.Point(6, 15);
+ useNativeWindowsNotifications.Name = "useNativeWindowsNotifications";
+ useNativeWindowsNotifications.Size = new System.Drawing.Size(203, 19);
+ useNativeWindowsNotifications.TabIndex = 0;
+ useNativeWindowsNotifications.TabStop = true;
+ useNativeWindowsNotifications.Text = "Use Windows' native notifications";
+ useNativeWindowsNotifications.UseVisualStyleBackColor = true;
+ //
+ // groupCustomNotificationSettings
+ //
+ groupCustomNotificationSettings.Controls.Add(customNotificationsPlayWindowsNotificationAudio);
+ groupCustomNotificationSettings.Controls.Add(customNotificationsShowInDarkMode);
+ groupCustomNotificationSettings.Controls.Add(customNotificationsShowTimeoutBar);
+ groupCustomNotificationSettings.Location = new System.Drawing.Point(12, 243);
+ groupCustomNotificationSettings.Name = "groupCustomNotificationSettings";
+ groupCustomNotificationSettings.Size = new System.Drawing.Size(504, 87);
+ groupCustomNotificationSettings.TabIndex = 10;
+ groupCustomNotificationSettings.TabStop = false;
+ //
+ // customNotificationsPlayWindowsNotificationAudio
+ //
+ customNotificationsPlayWindowsNotificationAudio.AutoSize = true;
+ customNotificationsPlayWindowsNotificationAudio.Location = new System.Drawing.Point(4, 59);
+ customNotificationsPlayWindowsNotificationAudio.Name = "customNotificationsPlayWindowsNotificationAudio";
+ customNotificationsPlayWindowsNotificationAudio.Size = new System.Drawing.Size(200, 19);
+ customNotificationsPlayWindowsNotificationAudio.TabIndex = 2;
+ customNotificationsPlayWindowsNotificationAudio.Text = "Play Windows notification sound";
+ customNotificationsPlayWindowsNotificationAudio.UseVisualStyleBackColor = true;
+ //
+ // customNotificationsShowInDarkMode
+ //
+ customNotificationsShowInDarkMode.AutoSize = true;
+ customNotificationsShowInDarkMode.Location = new System.Drawing.Point(6, 37);
+ customNotificationsShowInDarkMode.Name = "customNotificationsShowInDarkMode";
+ customNotificationsShowInDarkMode.Size = new System.Drawing.Size(197, 19);
+ customNotificationsShowInDarkMode.TabIndex = 1;
+ customNotificationsShowInDarkMode.Text = "Show notifications in dark mode";
+ customNotificationsShowInDarkMode.UseVisualStyleBackColor = true;
+ //
+ // customNotificationsShowTimeoutBar
+ //
+ customNotificationsShowTimeoutBar.AutoSize = true;
+ customNotificationsShowTimeoutBar.Location = new System.Drawing.Point(6, 14);
+ customNotificationsShowTimeoutBar.Name = "customNotificationsShowTimeoutBar";
+ customNotificationsShowTimeoutBar.Size = new System.Drawing.Size(211, 19);
+ customNotificationsShowTimeoutBar.TabIndex = 0;
+ customNotificationsShowTimeoutBar.Text = "Show time-out bar on notifications";
+ customNotificationsShowTimeoutBar.UseVisualStyleBackColor = true;
+ //
+ // label1
+ //
+ label1.AutoSize = true;
+ label1.Location = new System.Drawing.Point(12, 227);
+ label1.Name = "label1";
+ label1.Size = new System.Drawing.Size(180, 15);
+ label1.TabIndex = 11;
+ label1.Text = "Custom tray notification settings";
+ //
// SettingsDialog
//
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
BackColor = System.Drawing.Color.White;
- ClientSize = new System.Drawing.Size(531, 201);
+ ClientSize = new System.Drawing.Size(531, 387);
+ Controls.Add(label1);
+ Controls.Add(groupCustomNotificationSettings);
+ Controls.Add(nativeVersusCustomNotificationsGroupBox);
Controls.Add(reconnectAttemptDelay);
Controls.Add(reconnectAttemptDelayLabel);
Controls.Add(reconnectAttempts);
@@ -156,6 +252,10 @@ namespace ntfysh_client
((System.ComponentModel.ISupportInitialize)timeout).EndInit();
((System.ComponentModel.ISupportInitialize)reconnectAttempts).EndInit();
((System.ComponentModel.ISupportInitialize)reconnectAttemptDelay).EndInit();
+ nativeVersusCustomNotificationsGroupBox.ResumeLayout(false);
+ nativeVersusCustomNotificationsGroupBox.PerformLayout();
+ groupCustomNotificationSettings.ResumeLayout(false);
+ groupCustomNotificationSettings.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
@@ -171,5 +271,13 @@ namespace ntfysh_client
private System.Windows.Forms.Label reconnectAttemptsLabel;
private System.Windows.Forms.NumericUpDown reconnectAttemptDelay;
private System.Windows.Forms.Label reconnectAttemptDelayLabel;
+ private System.Windows.Forms.GroupBox nativeVersusCustomNotificationsGroupBox;
+ private System.Windows.Forms.RadioButton useCustomTrayNotifications;
+ private System.Windows.Forms.RadioButton useNativeWindowsNotifications;
+ private System.Windows.Forms.GroupBox groupCustomNotificationSettings;
+ private System.Windows.Forms.CheckBox customNotificationsShowTimeoutBar;
+ private System.Windows.Forms.CheckBox customNotificationsShowInDarkMode;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.CheckBox customNotificationsPlayWindowsNotificationAudio;
}
}
\ No newline at end of file
diff --git a/ntfysh_client/SettingsDialog.cs b/ntfysh_client/SettingsDialog.cs
index 6568d9d..2d4d0ec 100644
--- a/ntfysh_client/SettingsDialog.cs
+++ b/ntfysh_client/SettingsDialog.cs
@@ -1,10 +1,13 @@
using System;
using System.Windows.Forms;
+using static ntfysh_client.SettingsModel;
namespace ntfysh_client
{
public partial class SettingsDialog : Form
{
+ public NotificationsType NotificationsMethod { get; set; }
+
public decimal Timeout
{
get => timeout.Value;
@@ -23,9 +26,53 @@ namespace ntfysh_client
set => reconnectAttemptDelay.Value = value;
}
+ #region: Native vs custom notifications options. Because these are in a group box, these are mutualy exclusive.
+ public bool UseNativeWindowsNotifications
+ {
+ get => useNativeWindowsNotifications.Checked;
+ set
+ {
+ useNativeWindowsNotifications.Checked = value;
+ groupCustomNotificationSettings.Enabled = !value;
+ NotificationsMethod = (value) ? NotificationsType.NativeWindows : NotificationsType.CustomTray;
+ }
+ }
+
+ public bool UseCustomTrayNotifications
+ {
+ get => useCustomTrayNotifications.Checked;
+ set {
+ useCustomTrayNotifications.Checked = value;
+ groupCustomNotificationSettings.Enabled = value;
+ NotificationsMethod = (value) ? NotificationsType.NativeWindows : NotificationsType.CustomTray;
+ }
+ }
+ #endregion
+
+ #region: Custom tray notification options
+ public bool CustomTrayNotificationsShowTimeoutBar
+ {
+ get => customNotificationsShowTimeoutBar.Checked;
+ set => customNotificationsShowTimeoutBar.Checked = value;
+ }
+
+ public bool CustomTrayNotificationsShowInDarkMode
+ {
+ get => customNotificationsShowInDarkMode.Checked;
+ set => customNotificationsShowInDarkMode.Checked = value;
+ }
+
+ public bool CustomTrayNotificationsPlayDefaultWindowsSound
+ {
+ get => customNotificationsPlayWindowsNotificationAudio.Checked;
+ set => customNotificationsPlayWindowsNotificationAudio.Checked = value;
+ }
+ #endregion
+
public SettingsDialog()
{
InitializeComponent();
+ SetNotificationsUiElements();
}
private void saveButton_Click(object sender, EventArgs e)
@@ -37,5 +84,19 @@ namespace ntfysh_client
{
DialogResult = DialogResult.Cancel;
}
+
+ private void SetNotificationsUiElements()
+ {
+ groupCustomNotificationSettings.Enabled = useCustomTrayNotifications.Checked;
+ timeoutLabel.Text = useCustomTrayNotifications.Checked ? _customNotificationsTimeout : _windowsNotificationsTimeout;
+ }
+
+ private void UseCustomTrayNotifications_CheckedChanged(object sender, EventArgs e)
+ {
+ SetNotificationsUiElements();
+ }
+
+ private const string _windowsNotificationsTimeout = "Notification Toast Timeout (seconds, may be ignored by OS based on accessibility settings):";
+ private const string _customNotificationsTimeout = "Notification Toast Timeout (seconds, use 0 to require closing notification):";
}
}
diff --git a/ntfysh_client/SettingsDialog.resx b/ntfysh_client/SettingsDialog.resx
index af32865..8b2ff64 100644
--- a/ntfysh_client/SettingsDialog.resx
+++ b/ntfysh_client/SettingsDialog.resx
@@ -1,7 +1,7 @@