4 Commits

Author SHA1 Message Date
seba
2c18f91d68 changed var to explicit type
changed title on SendMessageForm
handling error codes
added credentials handling
added icon to context menu item
2024-12-18 20:39:19 +01:00
seba
c7e02655b0 #7 add simple send dialog 2024-12-17 22:54:24 +01:00
Lucas Bortoli
cb55d0148d Merge pull request #11 from alexhorner/master
Add adjustable reconnects and settings revisions
2023-12-28 12:14:50 -03:00
Alexander Horner
0155cfb8fc Add adjustable reconnects and settings revisions 2023-10-09 21:11:07 +01:00
12 changed files with 952 additions and 337 deletions

View File

@@ -29,209 +29,220 @@ namespace ntfysh_client
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.subscribeNewTopic = new System.Windows.Forms.Button();
this.removeSelectedTopics = new System.Windows.Forms.Button();
this.notificationTopics = new System.Windows.Forms.ListBox();
this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components);
this.trayContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
this.showControlWindowToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exitToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.ntfyshWebsiteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.label1 = new System.Windows.Forms.Label();
this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.trayContextMenu.SuspendLayout();
this.menuStrip1.SuspendLayout();
this.SuspendLayout();
subscribeNewTopic = new System.Windows.Forms.Button();
removeSelectedTopics = new System.Windows.Forms.Button();
notificationTopics = new System.Windows.Forms.ListBox();
topicContextMenu = new System.Windows.Forms.ContextMenuStrip(components);
sendNotificationMenuItem = new System.Windows.Forms.ToolStripMenuItem();
notifyIcon = new System.Windows.Forms.NotifyIcon(components);
trayContextMenu = new System.Windows.Forms.ContextMenuStrip(components);
showControlWindowToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
menuStrip1 = new System.Windows.Forms.MenuStrip();
fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
exitToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
ntfyshWebsiteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
label1 = new System.Windows.Forms.Label();
toolTip = new System.Windows.Forms.ToolTip(components);
topicContextMenu.SuspendLayout();
trayContextMenu.SuspendLayout();
menuStrip1.SuspendLayout();
SuspendLayout();
//
// subscribeNewTopic
//
this.subscribeNewTopic.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.subscribeNewTopic.Location = new System.Drawing.Point(211, 251);
this.subscribeNewTopic.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.subscribeNewTopic.Name = "subscribeNewTopic";
this.subscribeNewTopic.Size = new System.Drawing.Size(188, 27);
this.subscribeNewTopic.TabIndex = 2;
this.subscribeNewTopic.Text = "Add";
this.subscribeNewTopic.UseVisualStyleBackColor = true;
this.subscribeNewTopic.Click += new System.EventHandler(this.subscribeNewTopic_Click);
subscribeNewTopic.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
subscribeNewTopic.Location = new System.Drawing.Point(211, 251);
subscribeNewTopic.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
subscribeNewTopic.Name = "subscribeNewTopic";
subscribeNewTopic.Size = new System.Drawing.Size(188, 27);
subscribeNewTopic.TabIndex = 2;
subscribeNewTopic.Text = "Add";
subscribeNewTopic.UseVisualStyleBackColor = true;
subscribeNewTopic.Click += subscribeNewTopic_Click;
//
// removeSelectedTopics
//
this.removeSelectedTopics.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.removeSelectedTopics.Enabled = false;
this.removeSelectedTopics.Location = new System.Drawing.Point(13, 251);
this.removeSelectedTopics.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.removeSelectedTopics.Name = "removeSelectedTopics";
this.removeSelectedTopics.Size = new System.Drawing.Size(188, 27);
this.removeSelectedTopics.TabIndex = 0;
this.removeSelectedTopics.Text = "Remove selected";
this.removeSelectedTopics.UseVisualStyleBackColor = true;
this.removeSelectedTopics.Click += new System.EventHandler(this.removeSelectedTopics_Click);
removeSelectedTopics.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
removeSelectedTopics.Enabled = false;
removeSelectedTopics.Location = new System.Drawing.Point(13, 251);
removeSelectedTopics.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
removeSelectedTopics.Name = "removeSelectedTopics";
removeSelectedTopics.Size = new System.Drawing.Size(188, 27);
removeSelectedTopics.TabIndex = 0;
removeSelectedTopics.Text = "Remove selected";
removeSelectedTopics.UseVisualStyleBackColor = true;
removeSelectedTopics.Click += removeSelectedTopics_Click;
//
// notificationTopics
//
this.notificationTopics.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.notificationTopics.FormattingEnabled = true;
this.notificationTopics.ItemHeight = 15;
this.notificationTopics.Location = new System.Drawing.Point(13, 46);
this.notificationTopics.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.notificationTopics.Name = "notificationTopics";
this.notificationTopics.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended;
this.notificationTopics.Size = new System.Drawing.Size(386, 199);
this.notificationTopics.TabIndex = 3;
this.notificationTopics.Click += new System.EventHandler(this.notificationTopics_Click);
this.notificationTopics.SelectedValueChanged += new System.EventHandler(this.notificationTopics_SelectedValueChanged);
notificationTopics.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
notificationTopics.ContextMenuStrip = topicContextMenu;
notificationTopics.FormattingEnabled = true;
notificationTopics.ItemHeight = 15;
notificationTopics.Location = new System.Drawing.Point(13, 46);
notificationTopics.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
notificationTopics.Name = "notificationTopics";
notificationTopics.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended;
notificationTopics.Size = new System.Drawing.Size(386, 199);
notificationTopics.TabIndex = 3;
toolTip.SetToolTip(notificationTopics, "Double click topic to send message");
notificationTopics.Click += notificationTopics_Click;
notificationTopics.SelectedValueChanged += notificationTopics_SelectedValueChanged;
notificationTopics.MouseDoubleClick += notificationTopics_MouseDoubleClick;
//
// topicContextMenu
//
topicContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { sendNotificationMenuItem });
topicContextMenu.Name = "topicContextMenu";
topicContextMenu.Size = new System.Drawing.Size(181, 48);
//
// sendNotificationMenuItem
//
sendNotificationMenuItem.Image = (System.Drawing.Image)resources.GetObject("sendNotificationMenuItem.Image");
sendNotificationMenuItem.Name = "sendNotificationMenuItem";
sendNotificationMenuItem.Size = new System.Drawing.Size(180, 22);
sendNotificationMenuItem.Text = "Send Notification";
sendNotificationMenuItem.Click += SendNotificationMenuItem_Click;
//
// notifyIcon
//
this.notifyIcon.ContextMenuStrip = this.trayContextMenu;
this.notifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon.Icon")));
this.notifyIcon.Text = "ntfy.sh";
this.notifyIcon.Visible = true;
this.notifyIcon.Click += new System.EventHandler(this.notifyIcon_Click);
notifyIcon.ContextMenuStrip = trayContextMenu;
notifyIcon.Icon = (System.Drawing.Icon)resources.GetObject("notifyIcon.Icon");
notifyIcon.Text = "ntfy.sh";
notifyIcon.Visible = true;
notifyIcon.Click += notifyIcon_Click;
//
// trayContextMenu
//
this.trayContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.showControlWindowToolStripMenuItem,
this.exitToolStripMenuItem});
this.trayContextMenu.Name = "trayContextMenu";
this.trayContextMenu.Size = new System.Drawing.Size(190, 48);
trayContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { showControlWindowToolStripMenuItem, exitToolStripMenuItem });
trayContextMenu.Name = "trayContextMenu";
trayContextMenu.Size = new System.Drawing.Size(190, 48);
//
// showControlWindowToolStripMenuItem
//
this.showControlWindowToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("showControlWindowToolStripMenuItem.Image")));
this.showControlWindowToolStripMenuItem.Name = "showControlWindowToolStripMenuItem";
this.showControlWindowToolStripMenuItem.Size = new System.Drawing.Size(189, 22);
this.showControlWindowToolStripMenuItem.Text = "Show control window";
this.showControlWindowToolStripMenuItem.Click += new System.EventHandler(this.showControlWindowToolStripMenuItem_Click);
showControlWindowToolStripMenuItem.Image = (System.Drawing.Image)resources.GetObject("showControlWindowToolStripMenuItem.Image");
showControlWindowToolStripMenuItem.Name = "showControlWindowToolStripMenuItem";
showControlWindowToolStripMenuItem.Size = new System.Drawing.Size(189, 22);
showControlWindowToolStripMenuItem.Text = "Show control window";
showControlWindowToolStripMenuItem.Click += showControlWindowToolStripMenuItem_Click;
//
// exitToolStripMenuItem
//
this.exitToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("exitToolStripMenuItem.Image")));
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
this.exitToolStripMenuItem.Size = new System.Drawing.Size(189, 22);
this.exitToolStripMenuItem.Text = "Exit";
this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click);
exitToolStripMenuItem.Image = (System.Drawing.Image)resources.GetObject("exitToolStripMenuItem.Image");
exitToolStripMenuItem.Name = "exitToolStripMenuItem";
exitToolStripMenuItem.Size = new System.Drawing.Size(189, 22);
exitToolStripMenuItem.Text = "Exit";
exitToolStripMenuItem.Click += exitToolStripMenuItem_Click;
//
// menuStrip1
//
this.menuStrip1.BackColor = System.Drawing.Color.White;
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.fileToolStripMenuItem,
this.helpToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Padding = new System.Windows.Forms.Padding(7, 2, 0, 2);
this.menuStrip1.Size = new System.Drawing.Size(412, 24);
this.menuStrip1.TabIndex = 4;
this.menuStrip1.Text = "menuStrip1";
menuStrip1.BackColor = System.Drawing.Color.White;
menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { fileToolStripMenuItem, helpToolStripMenuItem });
menuStrip1.Location = new System.Drawing.Point(0, 0);
menuStrip1.Name = "menuStrip1";
menuStrip1.Padding = new System.Windows.Forms.Padding(7, 2, 0, 2);
menuStrip1.Size = new System.Drawing.Size(412, 24);
menuStrip1.TabIndex = 4;
menuStrip1.Text = "menuStrip1";
//
// fileToolStripMenuItem
//
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.exitToolStripMenuItem1,
this.settingsToolStripMenuItem});
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
this.fileToolStripMenuItem.Text = "File";
fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { exitToolStripMenuItem1, settingsToolStripMenuItem });
fileToolStripMenuItem.Name = "fileToolStripMenuItem";
fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
fileToolStripMenuItem.Text = "File";
//
// exitToolStripMenuItem1
//
this.exitToolStripMenuItem1.Image = ((System.Drawing.Image)(resources.GetObject("exitToolStripMenuItem1.Image")));
this.exitToolStripMenuItem1.Name = "exitToolStripMenuItem1";
this.exitToolStripMenuItem1.Size = new System.Drawing.Size(180, 22);
this.exitToolStripMenuItem1.Text = "Exit";
this.exitToolStripMenuItem1.Click += new System.EventHandler(this.exitToolStripMenuItem1_Click);
//
// helpToolStripMenuItem
//
this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.ntfyshWebsiteToolStripMenuItem,
this.toolStripMenuItem1,
this.aboutToolStripMenuItem});
this.helpToolStripMenuItem.Name = "helpToolStripMenuItem";
this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20);
this.helpToolStripMenuItem.Text = "Help";
//
// ntfyshWebsiteToolStripMenuItem
//
this.ntfyshWebsiteToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("ntfyshWebsiteToolStripMenuItem.Image")));
this.ntfyshWebsiteToolStripMenuItem.Name = "ntfyshWebsiteToolStripMenuItem";
this.ntfyshWebsiteToolStripMenuItem.Size = new System.Drawing.Size(185, 22);
this.ntfyshWebsiteToolStripMenuItem.Text = "Open ntfy.sh website";
this.ntfyshWebsiteToolStripMenuItem.Click += new System.EventHandler(this.ntfyshWebsiteToolStripMenuItem_Click);
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(182, 6);
//
// aboutToolStripMenuItem
//
this.aboutToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("aboutToolStripMenuItem.Image")));
this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem";
this.aboutToolStripMenuItem.Size = new System.Drawing.Size(185, 22);
this.aboutToolStripMenuItem.Text = "About";
this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(13, 27);
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(170, 15);
this.label1.TabIndex = 1;
this.label1.Text = "Subscribed Notification Topics:";
exitToolStripMenuItem1.Image = (System.Drawing.Image)resources.GetObject("exitToolStripMenuItem1.Image");
exitToolStripMenuItem1.Name = "exitToolStripMenuItem1";
exitToolStripMenuItem1.Size = new System.Drawing.Size(180, 22);
exitToolStripMenuItem1.Text = "Exit";
exitToolStripMenuItem1.Click += exitToolStripMenuItem1_Click;
//
// settingsToolStripMenuItem
//
this.settingsToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("settingsToolStripMenuItem.Image")));
this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
this.settingsToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.settingsToolStripMenuItem.Text = "Settings";
this.settingsToolStripMenuItem.Click += new System.EventHandler(this.settingsToolStripMenuItem_Click);
settingsToolStripMenuItem.Image = (System.Drawing.Image)resources.GetObject("settingsToolStripMenuItem.Image");
settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
settingsToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
settingsToolStripMenuItem.Text = "Settings";
settingsToolStripMenuItem.Click += settingsToolStripMenuItem_Click;
//
// helpToolStripMenuItem
//
helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { ntfyshWebsiteToolStripMenuItem, toolStripMenuItem1, aboutToolStripMenuItem });
helpToolStripMenuItem.Name = "helpToolStripMenuItem";
helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20);
helpToolStripMenuItem.Text = "Help";
//
// ntfyshWebsiteToolStripMenuItem
//
ntfyshWebsiteToolStripMenuItem.Image = (System.Drawing.Image)resources.GetObject("ntfyshWebsiteToolStripMenuItem.Image");
ntfyshWebsiteToolStripMenuItem.Name = "ntfyshWebsiteToolStripMenuItem";
ntfyshWebsiteToolStripMenuItem.Size = new System.Drawing.Size(185, 22);
ntfyshWebsiteToolStripMenuItem.Text = "Open ntfy.sh website";
ntfyshWebsiteToolStripMenuItem.Click += ntfyshWebsiteToolStripMenuItem_Click;
//
// toolStripMenuItem1
//
toolStripMenuItem1.Name = "toolStripMenuItem1";
toolStripMenuItem1.Size = new System.Drawing.Size(182, 6);
//
// aboutToolStripMenuItem
//
aboutToolStripMenuItem.Image = (System.Drawing.Image)resources.GetObject("aboutToolStripMenuItem.Image");
aboutToolStripMenuItem.Name = "aboutToolStripMenuItem";
aboutToolStripMenuItem.Size = new System.Drawing.Size(185, 22);
aboutToolStripMenuItem.Text = "About";
aboutToolStripMenuItem.Click += aboutToolStripMenuItem_Click;
//
// label1
//
label1.AutoSize = true;
label1.Location = new System.Drawing.Point(13, 27);
label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label1.Name = "label1";
label1.Size = new System.Drawing.Size(171, 15);
label1.TabIndex = 1;
label1.Text = "Subscribed Notification Topics:";
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(412, 288);
this.Controls.Add(this.menuStrip1);
this.Controls.Add(this.notificationTopics);
this.Controls.Add(this.removeSelectedTopics);
this.Controls.Add(this.subscribeNewTopic);
this.Controls.Add(this.label1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.KeyPreview = true;
this.MainMenuStrip = this.menuStrip1;
this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "MainForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "ntfy.sh";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing);
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.MainForm_FormClosed);
this.Load += new System.EventHandler(this.MainForm_Load);
this.trayContextMenu.ResumeLayout(false);
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
BackColor = System.Drawing.Color.White;
ClientSize = new System.Drawing.Size(412, 288);
Controls.Add(menuStrip1);
Controls.Add(notificationTopics);
Controls.Add(removeSelectedTopics);
Controls.Add(subscribeNewTopic);
Controls.Add(label1);
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
Icon = (System.Drawing.Icon)resources.GetObject("$this.Icon");
KeyPreview = true;
MainMenuStrip = menuStrip1;
Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
MaximizeBox = false;
MinimizeBox = false;
Name = "MainForm";
StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
Text = "ntfy.sh";
FormClosing += MainForm_FormClosing;
FormClosed += MainForm_FormClosed;
Load += MainForm_Load;
topicContextMenu.ResumeLayout(false);
trayContextMenu.ResumeLayout(false);
menuStrip1.ResumeLayout(false);
menuStrip1.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
#endregion
@@ -251,6 +262,9 @@ namespace ntfysh_client
private System.Windows.Forms.ToolStripMenuItem ntfyshWebsiteToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
private System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem;
private System.Windows.Forms.ContextMenuStrip topicContextMenu;
private System.Windows.Forms.ToolStripMenuItem sendNotificationMenuItem;
private System.Windows.Forms.ToolTip toolTip;
}
}

View File

@@ -4,7 +4,9 @@ using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;
using ntfysh_client.Notifications;
@@ -93,14 +95,18 @@ namespace ntfysh_client
//Do not subscribe on cancelled dialog
if (result != DialogResult.OK) return;
//Convert the reconnection values to ints
int reconnectAttempts = Convert.ToInt32(Math.Ceiling(Program.Settings.ReconnectAttempts));
int reconnectAttemptDelay = Convert.ToInt32(Math.Ceiling(Program.Settings.ReconnectAttemptDelay));
//Subscribe
if (dialog.UseWebsockets)
{
_notificationListener.SubscribeToTopicUsingWebsocket(dialog.Unique, dialog.TopicId, dialog.ServerUrl, dialog.Username, dialog.Password);
_notificationListener.SubscribeToTopicUsingWebsocket(dialog.Unique, dialog.TopicId, dialog.ServerUrl, dialog.Username, dialog.Password, reconnectAttempts, reconnectAttemptDelay);
}
else
{
_notificationListener.SubscribeToTopicUsingLongHttpJson(dialog.Unique, dialog.TopicId, dialog.ServerUrl, dialog.Username, dialog.Password);
_notificationListener.SubscribeToTopicUsingLongHttpJson(dialog.Unique, dialog.TopicId, dialog.ServerUrl, dialog.Username, dialog.Password, reconnectAttempts, reconnectAttemptDelay);
}
//Add to the user visible list
@@ -129,6 +135,8 @@ namespace ntfysh_client
//Load current settings into dialog
dialog.Timeout = Program.Settings.Timeout;
dialog.ReconnectAttempts = Program.Settings.ReconnectAttempts;
dialog.ReconnectAttemptDelay = Program.Settings.ReconnectAttemptDelay;
//Show dialog
DialogResult result = dialog.ShowDialog();
@@ -138,6 +146,8 @@ namespace ntfysh_client
//Read new settings from dialog
Program.Settings.Timeout = dialog.Timeout;
Program.Settings.ReconnectAttempts = dialog.ReconnectAttempts;
Program.Settings.ReconnectAttemptDelay = dialog.ReconnectAttemptDelay;
//Save new settings persistently
SaveSettingsToFile();
@@ -259,6 +269,10 @@ namespace ntfysh_client
return;
}
//Convert the reconnection values to ints
int reconnectAttempts = Convert.ToInt32(Math.Ceiling(Program.Settings.ReconnectAttempts));
int reconnectAttemptDelay = Convert.ToInt32(Math.Ceiling(Program.Settings.ReconnectAttemptDelay));
//Load them in
foreach (SubscribedTopic topic in topics)
{
@@ -268,12 +282,12 @@ namespace ntfysh_client
{
case "ws":
case "wss":
_notificationListener.SubscribeToTopicUsingWebsocket($"{topic.TopicId}@{topic.ServerUrl}", topic.TopicId, topic.ServerUrl, topic.Username, topic.Password);
_notificationListener.SubscribeToTopicUsingWebsocket($"{topic.TopicId}@{topic.ServerUrl}", topic.TopicId, topic.ServerUrl, topic.Username, topic.Password, reconnectAttempts, reconnectAttemptDelay);
break;
case "http":
case "https":
_notificationListener.SubscribeToTopicUsingLongHttpJson($"{topic.TopicId}@{topic.ServerUrl}", topic.TopicId, topic.ServerUrl, topic.Username, topic.Password);
_notificationListener.SubscribeToTopicUsingLongHttpJson($"{topic.TopicId}@{topic.ServerUrl}", topic.TopicId, topic.ServerUrl, topic.Username, topic.Password, reconnectAttempts, reconnectAttemptDelay);
break;
default:
@@ -286,17 +300,34 @@ namespace ntfysh_client
private SettingsModel GetDefaultSettings() => new()
{
Timeout = 5
Revision = 1,
Timeout = 5,
ReconnectAttempts = 10,
ReconnectAttemptDelay = 3
};
private void MergeSettingsRevisions(SettingsModel older, SettingsModel newer)
{
//Apply settings introduced in Revision 1
if (older.Revision < 1)
{
older.ReconnectAttempts = newer.ReconnectAttempts;
older.ReconnectAttemptDelay = newer.ReconnectAttemptDelay;
}
//Update the revision
older.Revision = newer.Revision;
}
private void LoadSettings()
{
string settingsFilePath = GetSettingsFilePath();
SettingsModel defaultSettings = GetDefaultSettings();
//Check if we have any settings file on disk to load. If we don't, initialise defaults
if (!File.Exists(settingsFilePath))
{
Program.Settings = GetDefaultSettings();
Program.Settings = defaultSettings;
SaveSettingsToFile();
@@ -309,7 +340,7 @@ namespace ntfysh_client
//Check if the file is empty. If it is, initialise default settings
if (string.IsNullOrWhiteSpace(settingsSerialised))
{
Program.Settings = GetDefaultSettings();
Program.Settings = defaultSettings;
SaveSettingsToFile();
@@ -322,7 +353,7 @@ namespace ntfysh_client
//Check if the deserialise succeeded. If it didn't, initialise default settings
if (settings is null)
{
Program.Settings = GetDefaultSettings();
Program.Settings = defaultSettings;
SaveSettingsToFile();
@@ -330,6 +361,13 @@ 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)
{
MergeSettingsRevisions(Program.Settings, defaultSettings);
SaveSettingsToFile();
}
}
private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
@@ -373,5 +411,36 @@ namespace ntfysh_client
_trueExit = true;
Close();
}
private async void SendNotificationMenuItem_Click(object sender, System.EventArgs e)
{
await SendMessage();
}
private async void notificationTopics_MouseDoubleClick(object sender, MouseEventArgs e)
{
await SendMessage();
}
private async Task SendMessage()
{
if (notificationTopics.SelectedItem != null && string.IsNullOrEmpty(notificationTopics.SelectedItem as string) == false)
{
try
{
SendMessageForm dlg = new SendMessageForm();
DialogResult r = dlg.ShowDialog(this);
if (r == DialogResult.OK)
{
string key = notificationTopics.SelectedItem.ToString();
await _notificationListener.SendNotification(key, dlg.Title, dlg.Message);
}
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK);
}
}
}
}
}

View File

@@ -1,4 +1,64 @@
<root>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
@@ -57,29 +117,54 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="topicContextMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>384, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="sendNotificationMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAALtSURBVGhD7ZfPaxNBFMeTkqS9WDyotTHJvjdJ/VUpirQK
elFKa1pSK2lNapOrP8BDPRQEL7X+qFjEg2JBEERrEc2hh0jT6EHUo3+DPSi2tV6E4sGmREaSsHlM1iaZ
lVnJFz6X3TeZ98lLZhObrZZaaqnF0kHEcUR8rTjjtO+iIOIkImYtwiTtvxBEXBAsUJUF2n8hehEAmELE
UZXI9VSeiKZpYU3TmhUjbKqIM/z47Pb9J4BeNwHzRByRF1dt8XTWfubV26a2ENL7kjFHxBF9eY1L5KmL
zj6hNZKRL5KfRIHY3KfNnZcP0DrJyBWhk7DF0+t1kcQdx+DMaKVsCt48QvcRIE+kqb2XEQkpOAemR+he
AuSJbDvY76dNyOCfi7j97V57fO4jaWTNHku+tw8n31WK69TDKN1LgDwRzpaOyE4qUzc0O+317nLTWsnI
FeEIZaKJ+7Tub2w9FG6h1wyQL8IpkomlftQH7wZpjRHOgZkRWzz1raFr4ji9VwJzRDh/ZIaTb+qDt7vo
PSOcp59d4sd27k1Yaei+cYzWCDBPpFL47zN+SBQ+mrH57xuYjHoinApkzBHhZz85hqsnllpxtx710b2s
JxJPZ/lDl+5lPZFY+qfBfxtzRPgzoLFz7HCl5E6ujF7CFZoy2tcckWpwhe712+Lzq0USfQ8GaR1BPRFH
JDFRxiTyqCfCcUQS1zc4iTxqinAau6900GsGqCtSJuWLIGIaEZ8a0CfYSE8vADwSrKsG3lPZIoYAwCoA
nBQINDPGLiBihq6RTGkRxhgf3S/BolI8pxIAcA4R1wS1MskwxoZo/0VhjPUwxm6VAhE/6F6wSAQRL5JJ
LNP1kuihfZcdxtiYSAQAzpNJLPv9/n10vTIRiVhOgoeKCL7YS4FAoJWuUy56EQD4gojrOomvALCbrlEy
ZCJ6lnw+315ar2xKiCxaSoJHILKoadoeWqd8ELENERO5U+ozY6yF1lgqHo9nByJq9Hottfxn+Q2nlJ4k
a2hbYwAAAABJRU5ErkJggg==
</value>
</data>
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>537, 17</value>
</metadata>
<metadata name="notifyIcon.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="trayContextMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>123, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="showControlWindowToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6
JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAA68AAAOvAGVvHJJAAAAiklE
QVQ4T8WPQQqAIBBFvUOrXIhu3dcZOkqtu5R1ia4SdRDrxyyGGKmBIOGBDL6nmk9WCGE9yUpW0q9Ads7V
GuCQ/kHAe79joAEO6dcLFmttpQEO6c+Bvpm2oZ0zwB4zVQBiF8cIsMdMDPCb+G2vA/wgP/z6C6WAhBgo
fUFCDGi4BxIGShLpvy5jDoPes/0oNG3VAAAAAElFTkSuQmCC
JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAA68AAAOvAGVvHJJAAAAgElE
QVQ4T2NgoAZQVFR8oKio+J9E/ADZgP9ycnKSpGCQHuoZoKCg8BiLE/FikB5kF+yXkpISJgWD9BBtQIbp
ykeZZqv+gzCITbIBII0eWsVaIAxi4zQA2SZk24g2AFkhsmKivYDLAGwYqwG4vIANYzWAFIxuwAqQAIl4
BdyAAQUAg96z/bGuwC8AAAAASUVORK5CYII=
</value>
</data>
<data name="exitToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6
JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAA68AAAOvAGVvHJJAAAAgUlE
QVQ4T2OgGjjOLq4AZeIFWNWBBI9yib06zC3uABXCCkDyIHVYDTnMI2pzhEvs5VFucSeoEAo4wiNii08e
DHAZQshwFICumCTNMADyK1gTl2gJiCYUNlgBSDPQ1v8gGipEPKDIBRSFAa6oIsoQQvGM1xCqpESsglgA
seroBRgYAOoOWBJbfVcRAAAAAElFTkSuQmCC
JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAA68AAAOvAGVvHJJAAAAhklE
QVQ4T2NgoBY4zi6ugC6GDWBVBxI8yiX26jC3uAO6HDIAyYPUYTXkMI+ozREusZdHucWd0OVA4AiPiC0+
eTDAZQgucawAXTE6nygA8itYE5doCYgmFDZYAUjzUW7x/yAaXY4goMgF6H5G5+MFuKKKKENwaYYBvIZQ
JSViFcQCiFVHPwAA6g5YEuFUY5cAAAAASUVORK5CYII=
</value>
</data>
<data name="notifyIcon.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
@@ -267,43 +352,43 @@
<data name="exitToolStripMenuItem1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6
JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAA68AAAOvAGVvHJJAAAAgUlE
QVQ4T2OgGjjOLq4AZeIFWNWBBI9yib06zC3uABXCCkDyIHVYDTnMI2pzhEvs5VFucSeoEAo4wiNii08e
DHAZQshwFICumCTNMADyK1gTl2gJiCYUNlgBSDPQ1v8gGipEPKDIBRSFAa6oIsoQQvGM1xCqpESsglgA
seroBRgYAOoOWBJbfVcRAAAAAElFTkSuQmCC
JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAA68AAAOvAGVvHJJAAAAhklE
QVQ4T2NgoBY4zi6ugC6GDWBVBxI8yiX26jC3uAO6HDIAyYPUYTXkMI+ozREusZdHucWd0OVA4AiPiC0+
eTDAZQgucawAXTE6nygA8itYE5doCYgmFDZYAUjzUW7x/yAaXY4goMgF6H5G5+MFuKKKKENwaYYBvIZQ
JSViFcQCiFVHPwAA6g5YEuFUY5cAAAAASUVORK5CYII=
</value>
</data>
<data name="settingsToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6
JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAA7CAAAOwgEVKEqAAAABT0lE
QVQ4T7WTzU3DUBCEXQICcSAYx5bdgKkDEuggF37aIJwJVBBfsCsAux+iII6hgvCNM5GV8HeBlUa73tnZ
fe9lE/ybJUlyC5bG2OmfLY7jK1CGYbiLr/v9/kigQeNcqRqXbxrEJXgBBYJX/DviPE3TY8Xk5vgpmIHP
TUhWKoii6AA/RPygWFBMbmCuAKVlnVG0AzHDnzH1iPheJ/HkiXLEp/rWdSxbGckxRTVYeNoEPFF4mGVZ
CC9uYm4BamksbxssIUe6r46pKRKaDjx97uvkqpXGdNdA5G8NNOSrBmPQcDS9fHsFvms1sVjcnTn9Io00
lq8Mcv2I5xK5yVxQrBwnOCF+o/G+ZZ1BaEkKHRM/0DTFgicPzWkXKss6I7lepClT20XyfXPFzmkHdMpr
yzYN8gJUvV5vD/9M4fYqP34r3jZEetj1n+nG6b+2IPgAzHGHcFUSC1YAAAAASUVORK5CYII=
JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAA69AAAOvQFH+5CtAAABQUlE
QVQ4T7WTTU4CQRCF5whG48KxnfoqMxfAcyjoDdz4cw1xLXoC2AgnULmPBuMST4B5pEigGeNGK+mkp1+/
V1Wva4riv8Ld79x9Eauf460BXAPjlNIu8GpmF1ruPo2zse7kvGUAV8AbMHL3D+DLzDp1XR9r7+4zYAi8
t4oAE12oquoA6JnZo/Za2gPdwEaqJOcXZrYjdTM7q+v6CHhQJZF5oDN3P9W32tkgyyT1DMwj2wB4Tikd
Nk2T3F3YILC57m4YK6dllvpVmcoi4gqP7LNopxPGLrYEBP4moCRtAn09VTi/bEFlSyTIwu4D04tMt2Zj
zcTzMFEis3UTq6o6AT6bptnfICtiSEbxVN2WZ+wFplmY5Pz1QRquBin67UTZOtMMqMqbnL8M4FLqZVnu
AS8to/z0IzmPMHb1M93m+J/FN8xxh3CJx7rTAAAAAElFTkSuQmCC
</value>
</data>
<data name="ntfyshWebsiteToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6
JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAA68AAAOvAGVvHJJAAABDElE
QVQ4T91RO3bCQAzUy3uhChdJnTVlCj5FcMsZsF1jmy4XycPrzl6fBLgEXMFp4srRiF0wcaBP5j0VI2m0
4zH9EwSq8gPP7ELPNFxtpxrbn9vVPkSsykOkqvHi2QxsWwAevhQTzG8eCb1yD7Glv2I5MlM+sLX0GqEq
6+jVPFl6QZz7lOgdJVnzuMq/sEepbsGln2YnR3AAm0IcIE71geJsTO9mcOWAOa3zicxxxGWApXMGabaH
WDLwqhmLj8tR8SYzh2Qz5b3TUQSEF7jkLzysdB2o4tPybU8MxB9DdlFb9gNwAJv30HXQg8sAS/jmLiQD
PWPxkdabvrMzEBBeQOpI35Vw7t8V/yEQfQPXsZpY9UsnYgAAAABJRU5ErkJggg==
JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAA68AAAOvAGVvHJJAAABCUlE
QVQ4T91Ru3LCMBC8yUxcJT+SOhJlCh5FoOUbsKixRcePZJDc2ecvMfwE/ILTxBWZlbFHyBP6sDMqbu/2
br0megzEolzEkg9KcqMkX7zXXPl5qOnhxKI4rUU5Xr5x5PdQq/d8gv6fS5QsjhCHvI/ViKdKchXyDkoU
9fqDX0KekmxBqT1QaprnTfaDOdL2gtrx2rSO4AA2B2JtT5SYMe04unGw44i22cT1saTLAEN9BtocIXYZ
yHKmJJ9Xo/zz5ki6n5I27VIEhAvdX3ja2DoW+fe1rgZiIPl6JW3rkG4BB7B5D76DAboMMIRv9uEysDPS
5kzb/dBZDwSEC0gd6XfP1aa6L/5X+AXXsZpYG9LldQAAAABJRU5ErkJggg==
</value>
</data>
<data name="aboutToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6
JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAA68AAAOvAGVvHJJAAAAwUlE
QVQ4T2OgClBUVHwAxP9JxA+g2sEG/JeTk5MkBYP0QLVTwQAFBYXHIAFSMEgPVDvYBfulpKSEScEgPVDt
dDIA6OTNQHX/YXysBjAxMcUxMjKuBrGB9DIgPxqmARhwOUBD3sD4WA0QERGRBHLvCwoKygLpm6KiohIw
DVBNz5HY2L0AtHkOEE8F4okgvoyMjDSSJsIGsLOzuwKFfnBycppJS0vLAJ39BUQTbQA6RnYBMkY3YAVI
gES8Aqp9QAEDAwCq9oYvtggceQAAAABJRU5ErkJggg==
JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAA68AAAOvAGVvHJJAAAAvklE
QVQ4T8WOPQoCMRBGZ9KELRez4CYxzFzCG3gKwRN4GQs7a1mw9ACew8oFCxtLC7uVAZWwSDCw6MAjP/C9
+QCGGGZumbnLpI0FXQihzkEywwmI6PyhYhLJxA0O1tpRDpL5rYCI9lI9KVBKLRBxJ3dE3Cql5q9ACGFJ
RNekwBhTA8CpLMsJAByrqhrHLZj5khQ8N28QcY2IK3l7712WQGs9A4B7URRT55wnopucXwv6xA1i+oJG
PjJp3oK/zgOq9oYvURh7ngAAAABJRU5ErkJggg==
</value>
</data>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">

View File

@@ -6,6 +6,7 @@ using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
@@ -31,16 +32,16 @@ namespace ntfysh_client.Notifications
ServicePointManager.DefaultConnectionLimit = 100;
}
private async Task ListenToTopicWithHttpLongJsonAsync(HttpRequestMessage message, CancellationToken cancellationToken, SubscribedTopic topic)
private async Task ListenToTopicWithHttpLongJsonAsync(HttpRequestMessage message, SubscribedTopic topic, int reconnectAttempts = 10, int reconnectAttemptDelay = 3, CancellationToken cancellationToken = default)
{
int connectionAttempts = 0;
while (!cancellationToken.IsCancellationRequested)
{
//See if we have exceeded maximum attempts
if (connectionAttempts >= 10)
if (reconnectAttempts != 0 && connectionAttempts >= reconnectAttempts)
{
//10 connection failures (1 initial + 9 reattempts)! Do not retry
//<reconnectAttempts> connection failures (1 initial + (<reconnectAttempts> - 1) reattempts)! Do not retry
OnConnectionMultiAttemptFailure?.Invoke(this, topic);
return;
}
@@ -119,16 +120,16 @@ namespace ntfysh_client.Notifications
}
finally
{
//We land here if we fail to connect or our connection gets closed (and if we are canceeling, but that gets ignored)
//We land here if we fail to connect or our connection gets closed (and if we are canceling, but that gets ignored)
if (!cancellationToken.IsCancellationRequested)
{
//Not cancelling, legitimate connection failure or termination
if (connectionAttempts != 0)
if (reconnectAttempts == 0 || connectionAttempts != 0)
{
//On our first reconnect attempt, try instantly. On consecutive, wait 3 seconds before each attempt
await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken);
//On our first reconnect attempt, try instantly (unless we have infinite retries). On consecutive, wait <reconnectAttemptDelay> seconds before each attempt
await Task.Delay(TimeSpan.FromSeconds(reconnectAttemptDelay), cancellationToken);
}
//Increment attempts
@@ -140,16 +141,16 @@ namespace ntfysh_client.Notifications
}
}
private async Task ListenToTopicWithWebsocketAsync(Uri uri, string? credentials, CancellationToken cancellationToken, SubscribedTopic topic)
private async Task ListenToTopicWithWebsocketAsync(Uri uri, string? credentials, SubscribedTopic topic, int reconnectAttempts = 10, int reconnectAttemptDelay = 3, CancellationToken cancellationToken = default)
{
int connectionAttempts = 0;
while (!cancellationToken.IsCancellationRequested)
{
//See if we have exceeded maximum attempts
if (connectionAttempts >= 10)
if (reconnectAttempts != 0 && connectionAttempts >= reconnectAttempts)
{
//10 connection failures (1 initial + 9 reattempts)! Do not retry
//<reconnectAttempts> connection failures (1 initial + (<reconnectAttempts> - 1) reattempts)! Do not retry
OnConnectionMultiAttemptFailure?.Invoke(this, topic);
return;
}
@@ -223,16 +224,16 @@ namespace ntfysh_client.Notifications
}
finally
{
//We land here if we fail to connect or our connection gets closed (and if we are canceeling, but that gets ignored)
//We land here if we fail to connect or our connection gets closed (and if we are canceling, but that gets ignored)
if (!cancellationToken.IsCancellationRequested)
{
//Not cancelling, legitimate connection failure or termination
if (connectionAttempts != 0)
if (reconnectAttempts == 0 || connectionAttempts != 0)
{
//On our first reconnect attempt, try instantly. On consecutive, wait 3 seconds before each attempt
await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken);
//On our first reconnect attempt, try instantly (unless we have infinite retries). On consecutive, wait <reconnectAttemptDelay> seconds before each attempt
await Task.Delay(TimeSpan.FromSeconds(reconnectAttemptDelay), cancellationToken);
}
//Increment attempts
@@ -261,13 +262,16 @@ namespace ntfysh_client.Notifications
}
}
public void SubscribeToTopicUsingLongHttpJson(string unique, string topicId, string serverUrl, string? username, string? password)
public void SubscribeToTopicUsingLongHttpJson(string unique, string topicId, string serverUrl, string? username, string? password, int reconnectAttempts, int reconnectAttemptDelay)
{
if (SubscribedTopicsByUnique.ContainsKey(unique)) throw new InvalidOperationException("A topic with this unique already exists");
if (SubscribedTopicsByUnique.ContainsKey(unique)) throw new ArgumentException("A topic with this unique already exists", nameof(unique));
if (string.IsNullOrWhiteSpace(username)) username = null;
if (string.IsNullOrWhiteSpace(password)) password = null;
if (reconnectAttempts < 0) throw new ArgumentException("Reconnect attempts must be 0 or more", nameof(reconnectAttempts));
if (reconnectAttemptDelay < 0) throw new ArgumentException("Reconnect attempt delay; must be 0 or more", nameof(reconnectAttemptDelay));
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, $"{serverUrl}/{HttpUtility.UrlEncode(topicId)}/json");
if (username is not null && password is not null)
@@ -280,20 +284,23 @@ namespace ntfysh_client.Notifications
SubscribedTopic newTopic = new(topicId, serverUrl, username, password);
CancellationTokenSource listenCanceller = new();
Task listenTask = ListenToTopicWithHttpLongJsonAsync(message, listenCanceller.Token, newTopic);
Task listenTask = ListenToTopicWithHttpLongJsonAsync(message, newTopic, reconnectAttempts, reconnectAttemptDelay, listenCanceller.Token);
newTopic.SetAssociatedRunner(listenTask, listenCanceller);
SubscribedTopicsByUnique.Add(unique, newTopic);
}
public void SubscribeToTopicUsingWebsocket(string unique, string topicId, string serverUrl, string? username, string? password)
public void SubscribeToTopicUsingWebsocket(string unique, string topicId, string serverUrl, string? username, string? password, int reconnectAttempts, int reconnectAttemptDelay)
{
if (SubscribedTopicsByUnique.ContainsKey(unique)) throw new InvalidOperationException("A topic with this unique already exists");
if (SubscribedTopicsByUnique.ContainsKey(unique)) throw new ArgumentException("A topic with this unique already exists", nameof(unique));
if (string.IsNullOrWhiteSpace(username)) username = null;
if (string.IsNullOrWhiteSpace(password)) password = null;
if (reconnectAttempts < 0) throw new ArgumentException("Reconnect attempts must be 0 or more", nameof(reconnectAttempts));
if (reconnectAttemptDelay < 0) throw new ArgumentException("Reconnect attempt delay; must be 0 or more", nameof(reconnectAttemptDelay));
SubscribedTopic newTopic = new(topicId, serverUrl, username, password);
string? credentials = null;
@@ -306,7 +313,7 @@ namespace ntfysh_client.Notifications
}
CancellationTokenSource listenCanceller = new();
Task listenTask = ListenToTopicWithWebsocketAsync(new Uri($"{serverUrl}/{HttpUtility.UrlEncode(topicId)}/ws"), credentials, listenCanceller.Token, newTopic);
Task listenTask = ListenToTopicWithWebsocketAsync(new Uri($"{serverUrl}/{HttpUtility.UrlEncode(topicId)}/ws"), credentials, newTopic, reconnectAttempts, reconnectAttemptDelay, listenCanceller.Token);
newTopic.SetAssociatedRunner(listenTask, listenCanceller);
@@ -344,5 +351,25 @@ namespace ntfysh_client.Notifications
//Remove the old topic
SubscribedTopicsByUnique.Remove(topicUniqueString);
}
public async Task SendNotification(string key, string title, string message)
{
if (SubscribedTopicsByUnique.TryGetValue(key, out SubscribedTopic topic))
{
HttpClient httpClient = new HttpClient();
PublishEvent notification = new PublishEvent();
notification.Title = title;
notification.Message = message;
notification.Topic = topic.TopicId;
if (!string.IsNullOrEmpty(topic.Username) || !string.IsNullOrEmpty(topic.Password))
{
string value = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{topic.Username}:{topic.Password}"));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", value);
}
HttpResponseMessage response = await httpClient.PostAsJsonAsync<PublishEvent>(topic.ServerUrl.Replace("wss://", "https://"), notification);
response.EnsureSuccessStatusCode();
}
}
}
}

View File

@@ -0,0 +1,50 @@
using Newtonsoft.Json;
using System.Text.Json.Nodes;
namespace ntfysh_client.Notifications
{
internal class PublishEvent
{
[JsonProperty("topic")]
public string Topic { get; set; } = null!;
[JsonProperty("message")]
public string? Message { get; set; } = null;
[JsonProperty("title")]
public string? Title { get; set; } = null;
[JsonProperty("tags")]
public string[] Tags { get; set; } = null!;
[JsonProperty("priority")]
public NotificationPriority? Priority { get; set; } = null;
[JsonProperty("actions")]
public JsonArray? Actions { get; set; } = null;
[JsonProperty("click")]
public string? Click { get; set; } = null;
[JsonProperty("attach")]
public string? Attach { get; set; } = null;
[JsonProperty("markdown")]
public bool? Markdown { get; set; } = null;
[JsonProperty("icon")]
public string? Icon { get; set; } = null;
[JsonProperty("filename")]
public string? Filename { get; set; } = null;
[JsonProperty("delay")]
public string? Delay { get; set; } = null;
[JsonProperty("email")]
public string? Email { get; set; } = null;
[JsonProperty("call")]
public string? Call { get; set; } = null;
}
}

108
ntfysh_client/SendMessageForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,108 @@
namespace ntfysh_client
{
partial class SendMessageForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
richTextBox = new System.Windows.Forms.RichTextBox();
button2 = new System.Windows.Forms.Button();
textBox = new System.Windows.Forms.TextBox();
label1 = new System.Windows.Forms.Label();
label2 = new System.Windows.Forms.Label();
SuspendLayout();
//
// richTextBox
//
richTextBox.Location = new System.Drawing.Point(12, 71);
richTextBox.Name = "richTextBox";
richTextBox.Size = new System.Drawing.Size(365, 165);
richTextBox.TabIndex = 0;
richTextBox.Text = "";
//
// button2
//
button2.Location = new System.Drawing.Point(302, 242);
button2.Name = "button2";
button2.Size = new System.Drawing.Size(75, 23);
button2.TabIndex = 2;
button2.Text = "Send";
button2.UseVisualStyleBackColor = true;
button2.Click += button2_Click;
//
// textBox
//
textBox.Location = new System.Drawing.Point(12, 27);
textBox.Name = "textBox";
textBox.Size = new System.Drawing.Size(365, 23);
textBox.TabIndex = 3;
//
// label1
//
label1.AutoSize = true;
label1.Location = new System.Drawing.Point(12, 53);
label1.Name = "label1";
label1.Size = new System.Drawing.Size(56, 15);
label1.TabIndex = 4;
label1.Text = "Message:";
//
// label2
//
label2.AutoSize = true;
label2.Location = new System.Drawing.Point(12, 9);
label2.Name = "label2";
label2.Size = new System.Drawing.Size(33, 15);
label2.TabIndex = 5;
label2.Text = "Title:";
//
// SendMessageForm
//
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
ClientSize = new System.Drawing.Size(389, 277);
Controls.Add(label2);
Controls.Add(label1);
Controls.Add(textBox);
Controls.Add(button2);
Controls.Add(richTextBox);
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
MaximizeBox = false;
MinimizeBox = false;
Name = "SendMessageForm";
Text = "Send Message";
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.RichTextBox richTextBox;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.TextBox textBox;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
}
}

View File

@@ -0,0 +1,21 @@
using System.Windows.Forms;
namespace ntfysh_client
{
public partial class SendMessageForm : Form
{
public string Message => richTextBox.Text;
public string Title => textBox.Text;
public SendMessageForm()
{
InitializeComponent();
}
private void button2_Click(object sender, System.EventArgs e)
{
DialogResult = DialogResult.OK;
Close();
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -29,101 +29,147 @@ namespace ntfysh_client
/// </summary>
private void InitializeComponent()
{
this.panel1 = new System.Windows.Forms.Panel();
this.cancelButton = new System.Windows.Forms.Button();
this.saveButton = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.timeout = new System.Windows.Forms.NumericUpDown();
this.panel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.timeout)).BeginInit();
this.SuspendLayout();
buttonPanel = new System.Windows.Forms.Panel();
cancelButton = new System.Windows.Forms.Button();
saveButton = new System.Windows.Forms.Button();
timeoutLabel = new System.Windows.Forms.Label();
timeout = new System.Windows.Forms.NumericUpDown();
reconnectAttempts = new System.Windows.Forms.NumericUpDown();
reconnectAttemptsLabel = new System.Windows.Forms.Label();
reconnectAttemptDelay = new System.Windows.Forms.NumericUpDown();
reconnectAttemptDelayLabel = new System.Windows.Forms.Label();
buttonPanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)timeout).BeginInit();
((System.ComponentModel.ISupportInitialize)reconnectAttempts).BeginInit();
((System.ComponentModel.ISupportInitialize)reconnectAttemptDelay).BeginInit();
SuspendLayout();
//
// panel1
// buttonPanel
//
this.panel1.BackColor = System.Drawing.SystemColors.Control;
this.panel1.Controls.Add(this.cancelButton);
this.panel1.Controls.Add(this.saveButton);
this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panel1.Location = new System.Drawing.Point(0, 61);
this.panel1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(531, 51);
this.panel1.TabIndex = 9;
buttonPanel.BackColor = System.Drawing.SystemColors.Control;
buttonPanel.Controls.Add(cancelButton);
buttonPanel.Controls.Add(saveButton);
buttonPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
buttonPanel.Location = new System.Drawing.Point(0, 150);
buttonPanel.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
buttonPanel.Name = "buttonPanel";
buttonPanel.Size = new System.Drawing.Size(531, 51);
buttonPanel.TabIndex = 0;
//
// cancelButton
//
this.cancelButton.Location = new System.Drawing.Point(363, 16);
this.cancelButton.Name = "cancelButton";
this.cancelButton.Size = new System.Drawing.Size(75, 23);
this.cancelButton.TabIndex = 1;
this.cancelButton.Text = "Cancel";
this.cancelButton.UseVisualStyleBackColor = true;
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
cancelButton.Location = new System.Drawing.Point(363, 16);
cancelButton.Name = "cancelButton";
cancelButton.Size = new System.Drawing.Size(75, 23);
cancelButton.TabIndex = 2;
cancelButton.Text = "Cancel";
cancelButton.UseVisualStyleBackColor = true;
cancelButton.Click += cancelButton_Click;
//
// saveButton
//
this.saveButton.Location = new System.Drawing.Point(444, 16);
this.saveButton.Name = "saveButton";
this.saveButton.Size = new System.Drawing.Size(75, 23);
this.saveButton.TabIndex = 0;
this.saveButton.Text = "Save";
this.saveButton.UseVisualStyleBackColor = true;
this.saveButton.Click += new System.EventHandler(this.saveButton_Click);
saveButton.Location = new System.Drawing.Point(444, 16);
saveButton.Name = "saveButton";
saveButton.Size = new System.Drawing.Size(75, 23);
saveButton.TabIndex = 1;
saveButton.Text = "Save";
saveButton.UseVisualStyleBackColor = true;
saveButton.Click += saveButton_Click;
//
// label1
// timeoutLabel
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(13, 9);
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(488, 15);
this.label1.TabIndex = 11;
this.label1.Text = "Notification Toast Timeout (seconds, may be ignored by OS based on accessibility " +
"settings):";
timeoutLabel.AutoSize = true;
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.TabIndex = 3;
timeoutLabel.Text = "Notification Toast Timeout (seconds, may be ignored by OS based on accessibility settings):";
//
// timeout
//
this.timeout.Location = new System.Drawing.Point(13, 27);
this.timeout.Maximum = new decimal(new int[] {
-1981284353,
-1966660860,
0,
0});
this.timeout.Name = "timeout";
this.timeout.Size = new System.Drawing.Size(506, 23);
this.timeout.TabIndex = 12;
timeout.Location = new System.Drawing.Point(13, 28);
timeout.Maximum = new decimal(new int[] { -1981284353, -1966660860, 0, 0 });
timeout.Name = "timeout";
timeout.Size = new System.Drawing.Size(506, 23);
timeout.TabIndex = 4;
//
// reconnectAttempts
//
reconnectAttempts.Location = new System.Drawing.Point(12, 73);
reconnectAttempts.Maximum = new decimal(new int[] { -1981284353, -1966660860, 0, 0 });
reconnectAttempts.Name = "reconnectAttempts";
reconnectAttempts.Size = new System.Drawing.Size(506, 23);
reconnectAttempts.TabIndex = 6;
//
// reconnectAttemptsLabel
//
reconnectAttemptsLabel.AutoSize = true;
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.TabIndex = 5;
reconnectAttemptsLabel.Text = "Maximum reconnect retry attempts (requires restart):";
//
// reconnectAttemptDelay
//
reconnectAttemptDelay.Location = new System.Drawing.Point(12, 118);
reconnectAttemptDelay.Maximum = new decimal(new int[] { -1981284353, -1966660860, 0, 0 });
reconnectAttemptDelay.Name = "reconnectAttemptDelay";
reconnectAttemptDelay.Size = new System.Drawing.Size(506, 23);
reconnectAttemptDelay.TabIndex = 8;
//
// reconnectAttemptDelayLabel
//
reconnectAttemptDelayLabel.AutoSize = true;
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.TabIndex = 7;
reconnectAttemptDelayLabel.Text = "Delay between attempts (seconds, requires restart):";
//
// SettingsDialog
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(531, 112);
this.Controls.Add(this.timeout);
this.Controls.Add(this.label1);
this.Controls.Add(this.panel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "SettingsDialog";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Settings";
this.panel1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.timeout)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
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);
Controls.Add(reconnectAttemptDelay);
Controls.Add(reconnectAttemptDelayLabel);
Controls.Add(reconnectAttempts);
Controls.Add(reconnectAttemptsLabel);
Controls.Add(timeout);
Controls.Add(timeoutLabel);
Controls.Add(buttonPanel);
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
MaximizeBox = false;
MinimizeBox = false;
Name = "SettingsDialog";
ShowIcon = false;
ShowInTaskbar = false;
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
Text = "Settings";
buttonPanel.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)timeout).EndInit();
((System.ComponentModel.ISupportInitialize)reconnectAttempts).EndInit();
((System.ComponentModel.ISupportInitialize)reconnectAttemptDelay).EndInit();
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Panel buttonPanel;
private System.Windows.Forms.Label timeoutLabel;
private System.Windows.Forms.NumericUpDown timeout;
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Button saveButton;
private System.Windows.Forms.NumericUpDown reconnectAttempts;
private System.Windows.Forms.Label reconnectAttemptsLabel;
private System.Windows.Forms.NumericUpDown reconnectAttemptDelay;
private System.Windows.Forms.Label reconnectAttemptDelayLabel;
}
}

View File

@@ -11,6 +11,18 @@ namespace ntfysh_client
set => timeout.Value = value;
}
public decimal ReconnectAttempts
{
get => reconnectAttempts.Value;
set => reconnectAttempts.Value = value;
}
public decimal ReconnectAttemptDelay
{
get => reconnectAttemptDelay.Value;
set => reconnectAttemptDelay.Value = value;
}
public SettingsDialog()
{
InitializeComponent();

View File

@@ -1,4 +1,64 @@
<root>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">

View File

@@ -2,6 +2,9 @@
{
public class SettingsModel
{
public uint Revision { get; set; }
public decimal Timeout { get; set; }
public decimal ReconnectAttempts { get; set; }
public decimal ReconnectAttemptDelay { get; set; }
}
}