diff --git a/ntfysh_client/NotificationDialog.Designer.cs b/ntfysh_client/NotificationDialog.Designer.cs index 681c07c..bc34ea4 100644 --- a/ntfysh_client/NotificationDialog.Designer.cs +++ b/ntfysh_client/NotificationDialog.Designer.cs @@ -32,6 +32,8 @@ button1 = new System.Windows.Forms.Button(); tbMessage = new System.Windows.Forms.RichTextBox(); iconBox = new System.Windows.Forms.PictureBox(); + progressBar1 = new System.Windows.Forms.ProgressBar(); + lbTimeout = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)iconBox).BeginInit(); SuspendLayout(); // @@ -40,23 +42,27 @@ tbTitle.BackColor = System.Drawing.SystemColors.ControlDark; tbTitle.BorderStyle = System.Windows.Forms.BorderStyle.None; tbTitle.Font = new System.Drawing.Font("Segoe UI", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + tbTitle.ForeColor = System.Drawing.SystemColors.ControlLightLight; tbTitle.Location = new System.Drawing.Point(54, 13); tbTitle.Name = "tbTitle"; tbTitle.ReadOnly = true; tbTitle.Size = new System.Drawing.Size(683, 32); tbTitle.TabIndex = 0; + tbTitle.MouseDown += window_MouseDown; // // button1 // button1.BackColor = System.Drawing.SystemColors.ActiveCaptionText; button1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + button1.FlatAppearance.BorderColor = System.Drawing.Color.White; + button1.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Silver; button1.FlatStyle = System.Windows.Forms.FlatStyle.Popup; button1.ForeColor = System.Drawing.SystemColors.ButtonFace; button1.Location = new System.Drawing.Point(759, 7); button1.Name = "button1"; button1.Size = new System.Drawing.Size(29, 38); button1.TabIndex = 1; - button1.Text = "x"; + button1.Text = "X"; button1.UseVisualStyleBackColor = false; button1.Click += btnClose_Click; // @@ -65,12 +71,14 @@ tbMessage.BackColor = System.Drawing.SystemColors.ControlDark; tbMessage.BorderStyle = System.Windows.Forms.BorderStyle.None; tbMessage.Font = new System.Drawing.Font("Segoe UI", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + tbMessage.ForeColor = System.Drawing.SystemColors.ControlLightLight; tbMessage.Location = new System.Drawing.Point(12, 57); tbMessage.Name = "tbMessage"; tbMessage.ReadOnly = true; - tbMessage.Size = new System.Drawing.Size(776, 213); + tbMessage.Size = new System.Drawing.Size(776, 191); tbMessage.TabIndex = 2; tbMessage.Text = ""; + tbMessage.MouseDown += window_MouseDown; // // iconBox // @@ -80,12 +88,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; + // + // lbTimeout + // + lbTimeout.AutoSize = true; + lbTimeout.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + lbTimeout.Location = new System.Drawing.Point(21, 254); + lbTimeout.Name = "lbTimeout"; + lbTimeout.Size = new System.Drawing.Size(43, 17); + lbTimeout.TabIndex = 5; + lbTimeout.Text = "label1"; + lbTimeout.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(lbTimeout); + Controls.Add(progressBar1); Controls.Add(iconBox); Controls.Add(tbMessage); Controls.Add(button1); @@ -93,6 +128,7 @@ FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; Name = "NotificationDialog"; Text = "NotificationDialog"; + Click += window_MouseDown; ((System.ComponentModel.ISupportInitialize)iconBox).EndInit(); ResumeLayout(false); PerformLayout(); @@ -104,5 +140,7 @@ private System.Windows.Forms.Button button1; private System.Windows.Forms.RichTextBox tbMessage; private System.Windows.Forms.PictureBox iconBox; + private System.Windows.Forms.ProgressBar progressBar1; + private System.Windows.Forms.Label lbTimeout; } } \ No newline at end of file diff --git a/ntfysh_client/NotificationDialog.cs b/ntfysh_client/NotificationDialog.cs index c94244d..7607eff 100644 --- a/ntfysh_client/NotificationDialog.cs +++ b/ntfysh_client/NotificationDialog.cs @@ -2,6 +2,9 @@ using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; +using System.ComponentModel; +using Microsoft.Win32; +using System.Diagnostics; namespace ntfysh_client @@ -13,8 +16,21 @@ namespace ntfysh_client private const int ScreenMargin = 20; - private System.Timers.Timer? timer = null; + private int _timeout = 0; + private System.Timers.Timer? displayTimeoutTimer = null; + private System.Windows.Forms.Timer? updateTimer = null; + private Stopwatch? shownStopwatch = null; private ToolTipIcon? _icon; + private int _progress_value = 0; + private int progress + { + get { return this._progress_value; } + set + { + this._progress_value = value; + this.progressBar1.Value = value; + } + } public bool IsVisible { @@ -34,30 +50,69 @@ namespace ntfysh_client { if (this.IsVisible) { + // close the current notification this.handleTimeout(null, null); } + // setup data this._icon = icon; if (this._icon != null) { this.iconBox.Image = ConvertToolTipIconToImage(_icon.Value); } - if (this.timer != null) + this.tbTitle.Text = title; + this.tbMessage.Text = message; + + // setup timers + if (this.displayTimeoutTimer != null) { - this.timer.Stop(); - this.timer.Dispose(); + this.displayTimeoutTimer.Stop(); + this.displayTimeoutTimer.Dispose(); + } + if (this.updateTimer != null) + { + this.updateTimer.Stop(); + this.updateTimer.Dispose(); } if (timeout_ms > 0) { - this.timer = new System.Timers.Timer(timeout_ms); - timer.Elapsed += handleTimeout; - this.timer.Start(); + this.displayTimeoutTimer = new System.Timers.Timer(timeout_ms); + displayTimeoutTimer.Elapsed += handleTimeout; + this.displayTimeoutTimer.Start(); + + this.progress = 100; + this.updateTimer = new System.Windows.Forms.Timer(); + updateTimer.Interval = 100; + this.updateTimer.Tick += this.UpdateProgress; + this.updateTimer.Start(); + + this.shownStopwatch = new Stopwatch(); + this.shownStopwatch.Start(); + + this.progressBar1.Visible = true; + this.lbTimeout.Visible = true; + this._timeout = timeout_ms; } - this.tbTitle.Text = title; - this.tbMessage.Text = message; + else + { + this.progressBar1.Visible = false; + this.lbTimeout.Visible = false; + } + + // ok, show the window this.Show(); this.SetWindowPosition(); } + private void UpdateProgress(object? sender, EventArgs e) + { + if (this.shownStopwatch == null) + { + return; + } + this.progress = (int)((this._timeout - this.shownStopwatch.ElapsedMilliseconds) * 100 / this._timeout); + this.lbTimeout.Text = $"{(int)(this._timeout - this.shownStopwatch.ElapsedMilliseconds) / 1000}"; + } + protected override void SetVisibleCore(bool value) { this.SetWindowPosition(); @@ -99,12 +154,7 @@ namespace ntfysh_client private void handleTimeout(object? sender, EventArgs? e) { - if (this.timer != null) // check if the timer has already been disposed - { - this.timer.Stop(); - this.timer.Dispose(); - this.timer = null; - } + this.cancelTimer(); if (this.InvokeRequired) { // on a background thread, so invoke on the UI thread @@ -159,5 +209,47 @@ namespace ntfysh_client public const int AW_SLIDE = 0x00040000; public const int AW_BLEND = 0x00080000; } + + private void window_MouseDown(object sender, EventArgs e) + { + this.cancelTimer(); + } + + private void cancelTimer() + { + if (this.InvokeRequired) + { + // on a background thread, so invoke on the UI thread + this.Invoke(new Action(() => + { + this.lbTimeout.Visible = false; + this.progressBar1.Visible = false; + })); + } + else + { + // in the UI thread, invoke directly + this.lbTimeout.Visible = false; + this.progressBar1.Visible = false; + } + + if (this.displayTimeoutTimer != null) // check if the timer has already been disposed + { + this.displayTimeoutTimer.Stop(); + this.displayTimeoutTimer.Dispose(); + this.displayTimeoutTimer = null; + } + if (this.updateTimer != null) + { + this.updateTimer.Stop(); + this.updateTimer.Dispose(); + this.updateTimer = null; + } + if (this.shownStopwatch != null) + { + this.shownStopwatch.Stop(); + this.shownStopwatch = null; + } + } } }