Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Source/GlobalAssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

[assembly: AssemblyVersion("2025.10.18.0")]
[assembly: AssemblyFileVersion("2025.10.18.0")]
[assembly: AssemblyVersion("2025.11.1.0")]
[assembly: AssemblyFileVersion("2025.11.1.0")]
27 changes: 24 additions & 3 deletions Source/NETworkManager.Localization/Resources/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 12 additions & 3 deletions Source/NETworkManager.Localization/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -2367,9 +2367,6 @@ $$hostname$$ --&gt; Hostname</value>
<data name="DeleteProfileFile" xml:space="preserve">
<value>Delete profile file</value>
</data>
<data name="DeleteProfileFileMessage" xml:space="preserve">
<value>Selected profile file will be deleted permanently.</value>
</data>
<data name="ResetProfilesMessage" xml:space="preserve">
<value>All profiles in this profile file will be permanently deleted!</value>
</data>
Expand Down Expand Up @@ -3999,4 +3996,16 @@ Right-click for more options.</value>
<data name="AdminConsoleSession" xml:space="preserve">
<value>Admin (console) session</value>
</data>
<data name="DeleteProfileFileXMessage" xml:space="preserve">
<value>Profile file "{0}" will be deleted permanently.</value>
</data>
<data name="EnableEncryptionQuestion" xml:space="preserve">
<value>Enable encryption?</value>
</data>
<data name="EnableEncryptionForProfileFileMessage" xml:space="preserve">
<value>Do you want to enable profile file encryption to protect sensitive data such as hosts, IP addresses, URLs, and stored credentials?

You can enable or disable encryption later at any time by right-clicking the profile file to manage encryption settings.
If you click Cancel, the profile file will remain unencrypted.</value>
</data>
</root>
4 changes: 2 additions & 2 deletions Source/NETworkManager.Setup/NETworkManager.Setup.wixproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="WixToolset.Sdk/5.0.0">
<Project Sdk="WixToolset.Sdk/6.0.2">
<ItemGroup>
<Content Include="Resources\WixUIBanner.png"/>
<Content Include="Resources\WixUIDialog.png"/>
Expand All @@ -7,7 +7,7 @@
<None Include="Resources\LICENSE.rtf"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="WixToolset.UI.wixext" Version="5.0.0"/>
<PackageReference Include="WixToolset.UI.wixext" Version="6.0.2"/>
<ProjectReference Include="..\NETworkManager\NETworkManager.csproj"/>
</ItemGroup>
</Project>
158 changes: 123 additions & 35 deletions Source/NETworkManager/ViewModels/SettingsProfilesViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ public SettingsProfilesViewModel(IDialogCoordinator instance)
ProfileFiles.SortDescriptions.Add(
new SortDescription(nameof(ProfileFileInfo.Name), ListSortDirection.Ascending));

SelectedProfileFile = ProfileFiles.Cast<ProfileFileInfo>().FirstOrDefault();

LoadSettings();
}

Expand All @@ -101,52 +103,113 @@ private static void OpenLocationAction()
Process.Start("explorer.exe", ProfileManager.GetProfilesFolderLocation());
}

public ICommand AddProfileFileCommand => new RelayCommand(_ => AddProfileFileAction());
public ICommand AddProfileFileCommand => new RelayCommand(async _ => await AddProfileFileAction().ConfigureAwait(false));

private async void AddProfileFileAction()
private async Task AddProfileFileAction()
{
var customDialog = new CustomDialog
{
Title = Strings.AddProfileFile
};
var profileName = string.Empty;

var childWindow = new ProfileFileChildWindow();

var profileFileViewModel = new ProfileFileViewModel(async instance =>
var childWindowViewModel = new ProfileFileViewModel(instance =>
{
await _dialogCoordinator.HideMetroDialogAsync(this, customDialog);
childWindow.IsOpen = false;
ConfigurationManager.Current.IsChildWindowOpen = false;

profileName = instance.Name;

ProfileManager.CreateEmptyProfileFile(instance.Name);
}, async _ => { await _dialogCoordinator.HideMetroDialogAsync(this, customDialog); });
}, _ =>
{
childWindow.IsOpen = false;
ConfigurationManager.Current.IsChildWindowOpen = false;
});

childWindow.Title = Strings.AddProfileFile;

childWindow.DataContext = childWindowViewModel;

ConfigurationManager.Current.IsChildWindowOpen = true;

await (Application.Current.MainWindow as MainWindow).ShowChildWindowAsync(childWindow);

if (string.IsNullOrEmpty(profileName))
return;

SelectedProfileFile = ProfileFiles.Cast<ProfileFileInfo>()
.FirstOrDefault(p => p.Name.Equals(profileName, StringComparison.OrdinalIgnoreCase));

customDialog.Content = new ProfileFileDialog
// Ask to enable encryption for the new profile file
if (await ShowEnableEncryptionMessage())
EnableEncryptionAction();
}

private async Task<bool> ShowEnableEncryptionMessage()
{
var result = false;

var childWindow = new OKCancelInfoMessageChildWindow();

var childWindowViewModel = new OKCancelInfoMessageViewModel(_ =>
{
DataContext = profileFileViewModel
};
childWindow.IsOpen = false;
ConfigurationManager.Current.IsChildWindowOpen = false;

await _dialogCoordinator.ShowMetroDialogAsync(this, customDialog);
result = true;
}, _ =>
{
childWindow.IsOpen = false;
ConfigurationManager.Current.IsChildWindowOpen = false;
},
Strings.EnableEncryptionForProfileFileMessage
);

childWindow.Title = Strings.EnableEncryptionQuestion;

childWindow.DataContext = childWindowViewModel;

ConfigurationManager.Current.IsChildWindowOpen = true;

await (Application.Current.MainWindow as MainWindow).ShowChildWindowAsync(childWindow);

return result;
}

public ICommand EditProfileFileCommand => new RelayCommand(_ => EditProfileFileAction());
public ICommand EditProfileFileCommand => new RelayCommand(async _ => await EditProfileFileAction().ConfigureAwait(false));

private async void EditProfileFileAction()
private async Task EditProfileFileAction()
{
var customDialog = new CustomDialog
{
Title = Strings.EditProfileFile
};
var profileName = string.Empty;

var childWindow = new ProfileFileChildWindow();

var profileFileViewModel = new ProfileFileViewModel(async instance =>
var childWindowViewModel = new ProfileFileViewModel(instance =>
{
await _dialogCoordinator.HideMetroDialogAsync(this, customDialog);
childWindow.IsOpen = false;
ConfigurationManager.Current.IsChildWindowOpen = false;

ProfileManager.RenameProfileFile(SelectedProfileFile, instance.Name);
}, async _ => { await _dialogCoordinator.HideMetroDialogAsync(this, customDialog); }, SelectedProfileFile);
profileName = instance.Name;

customDialog.Content = new ProfileFileDialog
ProfileManager.RenameProfileFile(SelectedProfileFile, instance.Name);
}, _ =>
{
DataContext = profileFileViewModel
};
childWindow.IsOpen = false;
ConfigurationManager.Current.IsChildWindowOpen = false;
}, SelectedProfileFile);

await _dialogCoordinator.ShowMetroDialogAsync(this, customDialog);
childWindow.Title = Strings.EditProfileFile;

childWindow.DataContext = childWindowViewModel;

ConfigurationManager.Current.IsChildWindowOpen = true;

await (Application.Current.MainWindow as MainWindow).ShowChildWindowAsync(childWindow);

if (string.IsNullOrEmpty(profileName))
return;

SelectedProfileFile = ProfileFiles.Cast<ProfileFileInfo>()
.FirstOrDefault(p => p.Name.Equals(profileName, StringComparison.OrdinalIgnoreCase));
}

public ICommand DeleteProfileFileCommand =>
Expand All @@ -172,7 +235,7 @@ private Task DeleteProfileFileAction()
childWindow.IsOpen = false;
ConfigurationManager.Current.IsChildWindowOpen = false;
},
Strings.DeleteProfileFileMessage, Strings.Delete);
string.Format(Strings.DeleteProfileFileXMessage, SelectedProfileFile.Name), Strings.Delete);

childWindow.Title = Strings.DeleteProfileFile;

Expand All @@ -187,13 +250,7 @@ private Task DeleteProfileFileAction()

private async void EnableEncryptionAction()
{
var settings = AppearanceManager.MetroDialog;

settings.AffirmativeButtonText = Strings.OK;
settings.NegativeButtonText = Strings.Cancel;
settings.DefaultButtonFocus = MessageDialogResult.Affirmative;

if (await _dialogCoordinator.ShowMessageAsync(this, Strings.Disclaimer, Strings.ProfileEncryptionDisclaimer, MessageDialogStyle.AffirmativeAndNegative, settings) != MessageDialogResult.Affirmative)
if (!await ShowEncryptionDisclaimerAsync())
return;

var customDialog = new CustomDialog
Expand Down Expand Up @@ -228,6 +285,37 @@ await _dialogCoordinator.ShowMessageAsync(this, Strings.EncryptionError,
await _dialogCoordinator.ShowMetroDialogAsync(this, customDialog);
}

private async Task<bool> ShowEncryptionDisclaimerAsync()
{
var result = false;

var childWindow = new OKCancelInfoMessageChildWindow();

var childWindowViewModel = new OKCancelInfoMessageViewModel(_ =>
{
childWindow.IsOpen = false;
ConfigurationManager.Current.IsChildWindowOpen = false;

result = true;
}, _ =>
{
childWindow.IsOpen = false;
ConfigurationManager.Current.IsChildWindowOpen = false;
},
Strings.ProfileEncryptionDisclaimer
);

childWindow.Title = Strings.Disclaimer;

childWindow.DataContext = childWindowViewModel;

ConfigurationManager.Current.IsChildWindowOpen = true;

await (Application.Current.MainWindow as MainWindow).ShowChildWindowAsync(childWindow);

return result;
}

public ICommand ChangeMasterPasswordCommand => new RelayCommand(_ => ChangeMasterPasswordAction());

private async void ChangeMasterPasswordAction()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
xmlns:simpleChildWindow="clr-namespace:MahApps.Metro.SimpleChildWindow;assembly=MahApps.Metro.SimpleChildWindow"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:converters="clr-namespace:NETworkManager.Converters;assembly=NETworkManager.Converters"
Loaded="ChildWindow_Loaded"
Loaded="ChildWindow_OnLoaded"
Style="{StaticResource DefaultChildWindow}"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:OKCancelInfoMessageViewModel}">
<simpleChildWindow:ChildWindow.Resources>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public OKCancelInfoMessageChildWindow()
InitializeComponent();
}

private void ChildWindow_Loaded(object sender, System.Windows.RoutedEventArgs e)
private void ChildWindow_OnLoaded(object sender, System.Windows.RoutedEventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(delegate
{
Expand Down
5 changes: 2 additions & 3 deletions Source/NETworkManager/Views/OKMessageChildWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
xmlns:simpleChildWindow="clr-namespace:MahApps.Metro.SimpleChildWindow;assembly=MahApps.Metro.SimpleChildWindow"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:converters="clr-namespace:NETworkManager.Converters;assembly=NETworkManager.Converters"
Loaded="ChildWindow_Loaded"
Loaded="ChildWindow_OnLoaded"
Style="{StaticResource DefaultChildWindow}"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:OKMessageViewModel}">
<simpleChildWindow:ChildWindow.Resources>
<converters:ChildWindowIconToRectangleStyleConverter x:Key="ChildWindowIconToRectangleStyleConverter" />
</simpleChildWindow:ChildWindow.Resources>
<Grid Margin="10">

<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="20" />
Expand Down
2 changes: 1 addition & 1 deletion Source/NETworkManager/Views/OKMessageChildWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public OKMessageChildWindow()
InitializeComponent();
}

private void ChildWindow_Loaded(object sender, System.Windows.RoutedEventArgs e)
private void ChildWindow_OnLoaded(object sender, System.Windows.RoutedEventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(delegate
{
Expand Down
Loading