Skip to content

Commit 6af0b7b

Browse files
committed
PR comments
1 parent 4819b79 commit 6af0b7b

File tree

6 files changed

+25
-43
lines changed

6 files changed

+25
-43
lines changed

App/ViewModels/TrayWindowViewModel.cs

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@ public partial class TrayWindowViewModel : ObservableObject
2121
private readonly IRpcController _rpcController;
2222
private readonly ICredentialManager _credentialManager;
2323

24-
private ToggleSwitch? _vpnActiveSwitch;
25-
private bool _isProgrammaticStateChange;
26-
2724
private DispatcherQueue? _dispatcherQueue;
2825

2926
[ObservableProperty]
3027
public partial VpnLifecycle VpnLifecycle { get; set; } = VpnLifecycle.Unknown;
3128

29+
// This is a separate property because we need the switch to be 2-way.
30+
[ObservableProperty]
31+
public partial bool VpnSwitchActive { get; set; } = false;
32+
3233
[ObservableProperty]
3334
public partial string? VpnFailedMessage { get; set; } = null;
3435

@@ -83,13 +84,13 @@ private void UpdateFromRpcModel(RpcModel rpcModel)
8384
if (rpcModel.RpcLifecycle is RpcLifecycle.Disconnected)
8485
{
8586
VpnLifecycle = VpnLifecycle.Unknown;
86-
SetVpnSwitch(false);
87+
VpnSwitchActive = false;
8788
Agents = [];
8889
return;
8990
}
9091

9192
VpnLifecycle = rpcModel.VpnLifecycle;
92-
SetVpnSwitch(rpcModel.VpnLifecycle is VpnLifecycle.Starting or VpnLifecycle.Started);
93+
VpnSwitchActive = rpcModel.VpnLifecycle is VpnLifecycle.Starting or VpnLifecycle.Started;
9394

9495
// Get the current dashboard URL.
9596
var credentialModel = _credentialManager.GetCredentials();
@@ -188,42 +189,20 @@ private void UpdateFromCredentialsModel(CredentialModel credentialModel)
188189
DashboardUrl = credentialModel.CoderUrl ?? DefaultDashboardUrl;
189190
}
190191

191-
private void SetVpnSwitch(bool value)
192-
{
193-
if (_vpnActiveSwitch == null) return;
194-
_isProgrammaticStateChange = true;
195-
_vpnActiveSwitch.IsOn = value;
196-
_isProgrammaticStateChange = false;
197-
}
198-
199-
// HACK: using a two-way bool to store the VPN active state results in
200-
// erroneous events being sent (even outside our change handlers). This
201-
// sucks and breaks the ViewModel separation but is necessary for the
202-
// switch to function correctly.
203-
public void VpnSwitch_Loaded(object sender, RoutedEventArgs e)
204-
{
205-
if (sender is not ToggleSwitch toggleSwitch) return;
206-
_vpnActiveSwitch = toggleSwitch;
207-
SetVpnSwitch(VpnLifecycle is VpnLifecycle.Starting or VpnLifecycle.Started);
208-
}
209-
210192
public void VpnSwitch_Toggled(object sender, RoutedEventArgs e)
211193
{
212194
if (sender is not ToggleSwitch toggleSwitch) return;
213195

214-
// HACK: the toggled event gets fired even when the switch state is
215-
// changed from code, so we ignore all events while we're performing
216-
// changes.
217-
if (_isProgrammaticStateChange) return;
218-
219196
VpnFailedMessage = "";
220197
try
221198
{
222199
// The start/stop methods will call back to update the state.
223-
if (toggleSwitch.IsOn)
200+
if (toggleSwitch.IsOn && VpnLifecycle is VpnLifecycle.Stopped)
224201
_rpcController.StartVpn();
225-
else
202+
else if (!toggleSwitch.IsOn && VpnLifecycle is VpnLifecycle.Started)
226203
_rpcController.StopVpn();
204+
else
205+
toggleSwitch.IsOn = VpnLifecycle is VpnLifecycle.Starting or VpnLifecycle.Started;
227206
}
228207
catch
229208
{

App/Views/Pages/TrayWindowMainPage.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@
5757
Grid.Column="2"
5858
OnContent=""
5959
OffContent=""
60+
IsOn="{x:Bind ViewModel.VpnSwitchActive, Mode=TwoWay}"
6061
IsEnabled="{x:Bind ViewModel.VpnLifecycle, Converter={StaticResource NotConnectingBoolConverter}, Mode=OneWay}"
61-
Loaded="{x:Bind ViewModel.VpnSwitch_Loaded}"
6262
Toggled="{x:Bind ViewModel.VpnSwitch_Toggled}"
6363
Margin="0,0,-110,0"
6464
HorizontalAlignment="Right" />

App/packages.lock.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,6 @@
3535
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1"
3636
}
3737
},
38-
"Microsoft.NET.ILLink.Tasks": {
39-
"type": "Direct",
40-
"requested": "[8.0.12, )",
41-
"resolved": "8.0.12",
42-
"contentHash": "FV4HnQ3JI15PHnJ5PGTbz+rYvrih42oLi/7UMIshNwCwUZhTq13UzrggtXk4ygrcMcN+4jsS6hhshx2p/Zd0ig=="
43-
},
4438
"Microsoft.WindowsAppSDK": {
4539
"type": "Direct",
4640
"requested": "[1.6.250108002, )",

CoderSdk/CoderApiClient.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ public override string ConvertName(string name)
1717
}
1818
}
1919

20+
[JsonSerializable(typeof(BuildInfo))]
21+
[JsonSerializable(typeof(User))]
22+
public partial class CoderSdkJsonContext : JsonSerializerContext
23+
{
24+
}
25+
2026
/// <summary>
2127
/// Provides a limited selection of API methods for a Coder instance.
2228
/// </summary>
@@ -37,6 +43,7 @@ public CoderApiClient(Uri baseUrl)
3743
_httpClient.BaseAddress = baseUrl;
3844
_jsonOptions = new JsonSerializerOptions
3945
{
46+
TypeInfoResolver = CoderSdkJsonContext.Default,
4047
PropertyNameCaseInsensitive = true,
4148
PropertyNamingPolicy = new SnakeCaseNamingPolicy(),
4249
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
@@ -53,17 +60,19 @@ public void SetSessionToken(string token)
5360
_httpClient.DefaultRequestHeaders.Remove("Coder-Session-Token");
5461
_httpClient.DefaultRequestHeaders.Add("Coder-Session-Token", token);
5562
}
63+
private async Task<TResponse> SendRequestNoBodyAsync<TResponse>(HttpMethod method, string path, CancellationToken ct = default) =>
64+
await SendRequestAsync<object, TResponse>(method, path, null, ct);
5665

57-
private async Task<TResponse> SendRequestAsync<TResponse>(HttpMethod method, string path,
58-
object? payload, CancellationToken ct = default)
66+
private async Task<TResponse> SendRequestAsync<TRequest, TResponse>(HttpMethod method, string path,
67+
TRequest? payload, CancellationToken ct = default)
5968
{
6069
try
6170
{
6271
var request = new HttpRequestMessage(method, path);
6372

6473
if (payload is not null)
6574
{
66-
var json = JsonSerializer.Serialize(payload, _jsonOptions);
75+
var json = JsonSerializer.Serialize(payload, typeof(TRequest), _jsonOptions);
6776
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
6877
}
6978

CoderSdk/Deployment.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ public partial class CoderApiClient
1717
{
1818
public Task<BuildInfo> GetBuildInfo(CancellationToken ct = default)
1919
{
20-
return SendRequestAsync<BuildInfo>(HttpMethod.Get, "/api/v2/buildinfo", null, ct);
20+
return SendRequestNoBodyAsync<BuildInfo>(HttpMethod.Get, "/api/v2/buildinfo", ct);
2121
}
2222
}

CoderSdk/Users.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ public partial class CoderApiClient
1212
{
1313
public Task<User> GetUser(string user, CancellationToken ct = default)
1414
{
15-
return SendRequestAsync<User>(HttpMethod.Get, $"/api/v2/users/{user}", null, ct);
15+
return SendRequestNoBodyAsync<User>(HttpMethod.Get, $"/api/v2/users/{user}", ct);
1616
}
1717
}

0 commit comments

Comments
 (0)