Skip to content

Commit 7ff7914

Browse files
committed
chore: added notifications for vpn lifecycle start/stop
1 parent 29943c8 commit 7ff7914

File tree

1 file changed

+66
-3
lines changed

1 file changed

+66
-3
lines changed

App/Views/TrayWindow.xaml.cs

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
using Microsoft.UI.Xaml.Controls;
1212
using Microsoft.UI.Xaml.Media.Animation;
1313
using System;
14+
using System.Collections.Generic;
1415
using System.Runtime.InteropServices;
16+
using System.Threading;
1517
using System.Threading.Tasks;
1618
using Windows.Graphics;
1719
using Windows.System;
@@ -21,7 +23,7 @@
2123

2224
namespace Coder.Desktop.App.Views;
2325

24-
public sealed partial class TrayWindow : Window
26+
public sealed partial class TrayWindow : Window, INotificationHandler
2527
{
2628
private const int WIDTH = 300;
2729

@@ -33,17 +35,25 @@ public sealed partial class TrayWindow : Window
3335
private int _lastWindowHeight;
3436
private Storyboard? _currentSb;
3537

38+
private VpnLifecycle prevVpnLifecycle = VpnLifecycle.Stopped;
39+
private RpcLifecycle prevRpcLifecycle = RpcLifecycle.Disconnected;
40+
41+
private NativeApi.POINT? _lastActivatePosition;
42+
3643
private readonly IRpcController _rpcController;
3744
private readonly ICredentialManager _credentialManager;
3845
private readonly ISyncSessionController _syncSessionController;
3946
private readonly IUpdateController _updateController;
47+
private readonly IUserNotifier _userNotifier;
4048
private readonly TrayWindowLoadingPage _loadingPage;
4149
private readonly TrayWindowDisconnectedPage _disconnectedPage;
4250
private readonly TrayWindowLoginRequiredPage _loginRequiredPage;
4351
private readonly TrayWindowMainPage _mainPage;
4452

45-
public TrayWindow(IRpcController rpcController, ICredentialManager credentialManager,
53+
public TrayWindow(
54+
IRpcController rpcController, ICredentialManager credentialManager,
4655
ISyncSessionController syncSessionController, IUpdateController updateController,
56+
IUserNotifier userNotifier,
4757
TrayWindowLoadingPage loadingPage,
4858
TrayWindowDisconnectedPage disconnectedPage, TrayWindowLoginRequiredPage loginRequiredPage,
4959
TrayWindowMainPage mainPage)
@@ -52,12 +62,14 @@ public TrayWindow(IRpcController rpcController, ICredentialManager credentialMan
5262
_credentialManager = credentialManager;
5363
_syncSessionController = syncSessionController;
5464
_updateController = updateController;
65+
_userNotifier = userNotifier;
5566
_loadingPage = loadingPage;
5667
_disconnectedPage = disconnectedPage;
5768
_loginRequiredPage = loginRequiredPage;
5869
_mainPage = mainPage;
5970

6071
InitializeComponent();
72+
_userNotifier.RegisterHandler("TrayWindow", this);
6173
AppWindow.Hide();
6274
Activated += Window_Activated;
6375
RootFrame.SizeChanged += RootFrame_SizeChanged;
@@ -142,9 +154,55 @@ private void SetPageByState(RpcModel rpcModel, CredentialModel credentialModel,
142154
}
143155
}
144156

157+
private void NotifyUser(RpcModel rpcModel)
158+
{
159+
// This method is called when the state changes, but we don't want to notify
160+
// the user if the state hasn't changed.
161+
var isRpcLifecycleChanged = rpcModel.RpcLifecycle != RpcLifecycle.Connecting && prevRpcLifecycle != rpcModel.RpcLifecycle;
162+
var isVpnLifecycleChanged = (rpcModel.VpnLifecycle == VpnLifecycle.Started || rpcModel.VpnLifecycle == VpnLifecycle.Stopped) && prevVpnLifecycle != rpcModel.VpnLifecycle;
163+
164+
if (!isRpcLifecycleChanged && !isVpnLifecycleChanged)
165+
{
166+
return;
167+
}
168+
var message = string.Empty;
169+
// Compose the message based on the lifecycle changes
170+
if (isRpcLifecycleChanged)
171+
message += rpcModel.RpcLifecycle switch
172+
{
173+
RpcLifecycle.Connected => "Connected to Coder vpn service.",
174+
RpcLifecycle.Disconnected => "Disconnected from Coder vpn service.",
175+
_ => "" // This will never be hit.
176+
};
177+
178+
if(message.Length > 0 && isVpnLifecycleChanged)
179+
message += " ";
180+
181+
if (isVpnLifecycleChanged)
182+
message += rpcModel.VpnLifecycle switch
183+
{
184+
VpnLifecycle.Started => "Coder Connect started.",
185+
VpnLifecycle.Stopped => "Coder Connect stopped.",
186+
_ => "" // This will never be hit.
187+
};
188+
189+
// Save state for the next notification check
190+
prevRpcLifecycle = rpcModel.RpcLifecycle;
191+
prevVpnLifecycle = rpcModel.VpnLifecycle;
192+
193+
if (_aw.IsVisible)
194+
{
195+
return; // No need to notify if the window is not visible.
196+
}
197+
198+
// Trigger notification
199+
_userNotifier.ShowActionNotification(message, string.Empty, nameof(TrayWindow), null, CancellationToken.None);
200+
}
201+
145202
private void RpcController_StateChanged(object? _, RpcModel model)
146203
{
147204
SetPageByState(model, _credentialManager.GetCachedCredentials(), _syncSessionController.GetState());
205+
NotifyUser(model);
148206
}
149207

150208
private void CredentialManager_CredentialsChanged(object? _, CredentialModel model)
@@ -316,6 +374,11 @@ private void Tray_Exit()
316374
_ = ((App)Application.Current).ExitApplication();
317375
}
318376

377+
public void HandleNotificationActivation(IDictionary<string, string> args)
378+
{
379+
Tray_Open();
380+
}
381+
319382
public static class NativeApi
320383
{
321384
[DllImport("dwmapi.dll")]
@@ -336,7 +399,7 @@ internal enum TaskbarPosition { Left, Top, Right, Bottom }
336399
internal readonly record struct TaskbarInfo(TaskbarPosition Position, int Gap, bool AutoHide);
337400

338401
// -----------------------------------------------------------------------------
339-
// Taskbar helpers ABM_GETTASKBARPOS / ABM_GETSTATE via SHAppBarMessage
402+
// Taskbar helpers ABM_GETTASKBARPOS / ABM_GETSTATE via SHAppBarMessage
340403
// -----------------------------------------------------------------------------
341404
private static TaskbarInfo GetTaskbarInfo(DisplayArea area)
342405
{

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy