Skip to content

Commit c2c3d51

Browse files
committed
WIP
1 parent 45e506f commit c2c3d51

File tree

7 files changed

+135
-40
lines changed

7 files changed

+135
-40
lines changed

App/App.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
<ItemGroup>
5858
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
5959
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.2.250402" />
60+
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.2.250402" />
6061
<PackageReference Include="CommunityToolkit.WinUI.Extensions" Version="8.2.250402" />
6162
<PackageReference Include="DependencyPropertyGenerator" Version="1.5.0">
6263
<PrivateAssets>all</PrivateAssets>

App/App.xaml.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ public partial class App : Application
4444
private readonly ILogger<App> _logger;
4545
private readonly IUriHandler _uriHandler;
4646

47+
private readonly ISettingsManager _settingsManager;
48+
4749
public App()
4850
{
4951
var builder = Host.CreateApplicationBuilder();
@@ -115,6 +117,7 @@ public App()
115117
_services = services.BuildServiceProvider();
116118
_logger = (ILogger<App>)_services.GetService(typeof(ILogger<App>))!;
117119
_uriHandler = (IUriHandler)_services.GetService(typeof(IUriHandler))!;
120+
_settingsManager = (ISettingsManager)_services.GetService(typeof(ISettingsManager))!;
118121

119122
InitializeComponent();
120123
}
@@ -150,6 +153,22 @@ protected override void OnLaunched(LaunchActivatedEventArgs args)
150153
Debug.WriteLine(t.Exception);
151154
Debugger.Break();
152155
#endif
156+
} else
157+
{
158+
if (rpcController.GetState().RpcLifecycle == RpcLifecycle.Disconnected)
159+
{
160+
if (_settingsManager.Read(SettingsManager.ConnectOnLaunchKey, false))
161+
{
162+
_logger.LogInformation("RPC lifecycle is disconnected, but ConnectOnLaunch is enabled; attempting to connect");
163+
_ = rpcController.StartVpn(CancellationToken.None).ContinueWith(connectTask =>
164+
{
165+
if (connectTask.Exception != null)
166+
{
167+
_logger.LogError(connectTask.Exception, "failed to connect on launch");
168+
}
169+
});
170+
}
171+
}
153172
}
154173
});
155174

@@ -178,9 +197,6 @@ protected override void OnLaunched(LaunchActivatedEventArgs args)
178197
if (t.IsCanceled || t.Exception != null)
179198
{
180199
_logger.LogError(t.Exception, "failed to refresh sync state (canceled = {canceled})", t.IsCanceled);
181-
#if DEBUG
182-
Debugger.Break();
183-
#endif
184200
}
185201

186202
syncSessionCts.Dispose();

App/Services/SettingsManager.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,11 @@ public sealed class SettingsManager : ISettingsManager
3232
private readonly object _lock = new();
3333
private Dictionary<string, JsonElement> _cache;
3434

35+
public static readonly string ConnectOnLaunchKey = "ConnectOnLaunch";
36+
public static readonly string StartOnLoginKey = "StartOnLogin";
37+
3538
/// <param name="appName">
36-
/// Sub‑folder under %LOCALAPPDATA% (e.g. "coder-desktop").
39+
/// Sub‑folder under %LOCALAPPDATA% (e.g. "CoderDesktop").
3740
/// If <c>null</c> the folder name defaults to the executable name.
3841
/// For unit‑tests you can pass an absolute path that already exists.
3942
/// </param>

App/ViewModels/SettingsViewModel.cs

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
using System;
21
using Coder.Desktop.App.Services;
32
using CommunityToolkit.Mvvm.ComponentModel;
43
using CommunityToolkit.Mvvm.Input;
4+
using Microsoft.Extensions.Logging;
55
using Microsoft.UI.Dispatching;
66
using Microsoft.UI.Xaml;
77
using Microsoft.UI.Xaml.Controls;
8+
using System;
89

910
namespace Coder.Desktop.App.ViewModels;
1011

@@ -13,11 +14,48 @@ public partial class SettingsViewModel : ObservableObject
1314
private Window? _window;
1415
private DispatcherQueue? _dispatcherQueue;
1516

17+
private readonly ILogger<SettingsViewModel> _logger;
18+
19+
[ObservableProperty]
20+
public partial bool ConnectOnLaunch { get; set; } = false;
21+
22+
[ObservableProperty]
23+
public partial bool StartOnLogin { get; set; } = false;
24+
1625
private ISettingsManager _settingsManager;
1726

18-
public SettingsViewModel(ISettingsManager settingsManager)
27+
public SettingsViewModel(ILogger<SettingsViewModel> logger, ISettingsManager settingsManager)
1928
{
2029
_settingsManager = settingsManager;
30+
_logger = logger;
31+
ConnectOnLaunch = _settingsManager.Read(SettingsManager.ConnectOnLaunchKey, false);
32+
StartOnLogin = _settingsManager.Read(SettingsManager.StartOnLoginKey, false);
33+
34+
this.PropertyChanged += (_, args) =>
35+
{
36+
if (args.PropertyName == nameof(ConnectOnLaunch))
37+
{
38+
try
39+
{
40+
_settingsManager.Save(SettingsManager.ConnectOnLaunchKey, ConnectOnLaunch);
41+
}
42+
catch (Exception ex)
43+
{
44+
Console.WriteLine($"Error saving {SettingsManager.ConnectOnLaunchKey} setting: {ex.Message}");
45+
}
46+
}
47+
else if (args.PropertyName == nameof(StartOnLogin))
48+
{
49+
try
50+
{
51+
_settingsManager.Save(SettingsManager.StartOnLoginKey, StartOnLogin);
52+
}
53+
catch (Exception ex)
54+
{
55+
Console.WriteLine($"Error saving {SettingsManager.StartOnLoginKey} setting: {ex.Message}");
56+
}
57+
}
58+
};
2159
}
2260

2361
public void Initialize(Window window, DispatcherQueue dispatcherQueue)
@@ -27,28 +65,4 @@ public void Initialize(Window window, DispatcherQueue dispatcherQueue)
2765
if (!_dispatcherQueue.HasThreadAccess)
2866
throw new InvalidOperationException("Initialize must be called from the UI thread");
2967
}
30-
31-
[RelayCommand]
32-
private void SaveSetting()
33-
{
34-
//_settingsManager.Save();
35-
}
36-
37-
[RelayCommand]
38-
private void ShowSettingsDialog()
39-
{
40-
if (_window is null || _dispatcherQueue is null)
41-
throw new InvalidOperationException("Initialize must be called before showing the settings dialog.");
42-
// Here you would typically open a settings dialog or page.
43-
// For example, you could navigate to a SettingsPage in your app.
44-
// This is just a placeholder for demonstration purposes.
45-
// Display MessageBox and show a message
46-
var message = $"Settings dialog opened. Current setting: {_settingsManager.Read("SomeSetting", false)}\n" +
47-
"You can implement your settings dialog here.";
48-
var dialog = new ContentDialog();
49-
dialog.Title = "Settings";
50-
dialog.Content = message;
51-
dialog.XamlRoot = _window.Content.XamlRoot;
52-
_ = dialog.ShowAsync();
53-
}
5468
}

App/Views/Pages/SettingsMainPage.xaml

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,49 @@
88
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
99
xmlns:viewmodels="using:Coder.Desktop.App.ViewModels"
1010
xmlns:converters="using:Coder.Desktop.App.Converters"
11+
xmlns:ui="using:CommunityToolkit.WinUI"
12+
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
13+
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
1114
mc:Ignorable="d"
1215
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
1316

14-
<Grid>
15-
<HyperlinkButton
16-
Command="{x:Bind ViewModel.ShowSettingsDialogCommand, Mode=OneWay}"
17-
HorizontalAlignment="Stretch"
18-
HorizontalContentAlignment="Left">
17+
<Page.Resources>
18+
<!-- These styles can be referenced to create a consistent SettingsPage layout -->
19+
20+
<!-- Spacing between cards -->
21+
<x:Double x:Key="SettingsCardSpacing">4</x:Double>
22+
23+
<!-- Style (inc. the correct spacing) of a section header -->
24+
<Style x:Key="SettingsSectionHeaderTextBlockStyle"
25+
BasedOn="{StaticResource BodyStrongTextBlockStyle}"
26+
TargetType="TextBlock">
27+
<Style.Setters>
28+
<Setter Property="Margin" Value="1,30,0,6" />
29+
</Style.Setters>
30+
</Style>
31+
</Page.Resources>
32+
<ScrollViewer>
33+
<Grid Padding="20, 0, 20, 0">
34+
<StackPanel MaxWidth="1000"
35+
HorizontalAlignment="Stretch"
36+
Spacing="{StaticResource SettingsCardSpacing}">
37+
38+
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="Coder Desktop" />
39+
40+
<controls:SettingsCard Description="This setting controls whether the Coder Desktop app starts on Windows startup."
41+
Header="Start on login"
42+
HeaderIcon="{ui:FontIcon Glyph=&#xE819;}">
43+
<ToggleSwitch IsOn="{x:Bind ViewModel.StartOnLogin, Mode=TwoWay}" />
44+
</controls:SettingsCard>
45+
46+
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="Coder Connect" />
47+
<controls:SettingsCard Description="This setting controls whether Coder Connect automatically starts with Coder Desktop "
48+
Header="Connect on launch"
49+
HeaderIcon="{ui:FontIcon Glyph=&#xE8AF;}">
50+
<ToggleSwitch IsOn="{x:Bind ViewModel.ConnectOnLaunch, Mode=TwoWay}" />
51+
</controls:SettingsCard>
52+
</StackPanel>
53+
</Grid>
54+
</ScrollViewer>
1955

20-
<TextBlock Text="Show settings" Foreground="{ThemeResource DefaultTextForegroundThemeBrush}" />
21-
</HyperlinkButton>
22-
</Grid>
2356
</Page>

App/Views/SettingsWindow.xaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
xmlns:winuiex="using:WinUIEx"
1010
mc:Ignorable="d"
1111
Title="Coder Settings"
12-
Width="1000" Height="300"
13-
MinWidth="1000" MinHeight="300">
12+
Width="600" Height="350"
13+
MinWidth="600" MinHeight="350">
1414

1515
<Window.SystemBackdrop>
1616
<DesktopAcrylicBackdrop />

App/packages.lock.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@
1818
"Microsoft.WindowsAppSDK": "1.6.250108002"
1919
}
2020
},
21+
"CommunityToolkit.WinUI.Controls.SettingsControls": {
22+
"type": "Direct",
23+
"requested": "[8.2.250402, )",
24+
"resolved": "8.2.250402",
25+
"contentHash": "whJNIyxVwwLmmCS63m91r0aL13EYgdKDE0ERh2e0G2U5TUeYQQe2XRODGGr/ceBRvqu6SIvq1sXxVwglSMiJMg==",
26+
"dependencies": {
27+
"CommunityToolkit.WinUI.Triggers": "8.2.250402",
28+
"Microsoft.WindowsAppSDK": "1.6.250108002"
29+
}
30+
},
2131
"CommunityToolkit.WinUI.Extensions": {
2232
"type": "Direct",
2333
"requested": "[8.2.250402, )",
@@ -152,6 +162,24 @@
152162
"resolved": "8.2.1",
153163
"contentHash": "LWuhy8cQKJ/MYcy3XafJ916U3gPH/YDvYoNGWyQWN11aiEKCZszzPOTJAOvBjP9yG8vHmIcCyPUt4L82OK47Iw=="
154164
},
165+
"CommunityToolkit.WinUI.Helpers": {
166+
"type": "Transitive",
167+
"resolved": "8.2.250402",
168+
"contentHash": "DThBXB4hT3/aJ7xFKQJw/C0ZEs1QhZL7QG6AFOYcpnGWNlv3tkF761PFtTyhpNQrR1AFfzml5zG+zWfFbKs6Mw==",
169+
"dependencies": {
170+
"CommunityToolkit.WinUI.Extensions": "8.2.250402",
171+
"Microsoft.WindowsAppSDK": "1.6.250108002"
172+
}
173+
},
174+
"CommunityToolkit.WinUI.Triggers": {
175+
"type": "Transitive",
176+
"resolved": "8.2.250402",
177+
"contentHash": "laHIrBQkwQCurTNSQdGdEXUyoCpqY8QFXSybDM/Q1Ti/23xL+sRX/gHe3pP8uMM59bcwYbYlMRCbIaLnxnrdjw==",
178+
"dependencies": {
179+
"CommunityToolkit.WinUI.Helpers": "8.2.250402",
180+
"Microsoft.WindowsAppSDK": "1.6.250108002"
181+
}
182+
},
155183
"Google.Protobuf": {
156184
"type": "Transitive",
157185
"resolved": "3.29.3",

0 commit comments

Comments
 (0)