From 8ec0d58065377add410562f8c7ae168d05c09e2c Mon Sep 17 00:00:00 2001 From: Aleksandar Pesic Date: Thu, 13 Jun 2019 19:11:54 +0200 Subject: [PATCH] Removing duplcated code from profile view models. (#403) * Minor improvements to remote SSH profiles. Username prefilled, and line ending defaults to LF. * Implementing "Set Default" on SSH Profiles. * Simplifying profile view models. * Fixing null themes issue. * Changing line ending of a sinfle file to CRLF. * Changing file to LF, to avoid false differences. * Converting a file to LF in order to avoid false differences. * Fixining a bug with shortcuts. --- .../Settings/ProfilesPageViewModel.cs | 11 +- .../Settings/SshProfilesPageViewModel.cs | 29 +- .../SettingsViewModel.cs | 2 +- .../ShellProfileViewModel.cs | 471 ++++++++++-------- .../SshProfileViewModel.cs | 464 +++-------------- FluentTerminal.App/App.xaml.cs | 16 +- .../Dialogs/SshInfoDialog.xaml.cs | 12 +- .../Services/SshHelperService.cs | 17 +- .../SettingsPages/ShellProfileSettings.xaml | 39 +- FluentTerminal.Models/ShellProfile.cs | 4 +- FluentTerminal.Models/SshProfile.cs | 26 +- 11 files changed, 432 insertions(+), 659 deletions(-) diff --git a/FluentTerminal.App.ViewModels/Settings/ProfilesPageViewModel.cs b/FluentTerminal.App.ViewModels/Settings/ProfilesPageViewModel.cs index 26ab885..50f666e 100644 --- a/FluentTerminal.App.ViewModels/Settings/ProfilesPageViewModel.cs +++ b/FluentTerminal.App.ViewModels/Settings/ProfilesPageViewModel.cs @@ -98,12 +98,11 @@ namespace FluentTerminal.App.ViewModels.Settings private void Clone(ShellProfileViewModel shellProfile) { - var cloned = new ShellProfile(shellProfile.Model) - { - Id = Guid.NewGuid(), - PreInstalled = false, - Name = $"Copy of {shellProfile.Name}" - }; + var cloned = shellProfile.Model.Clone(); + + cloned.Id = Guid.NewGuid(); + cloned.PreInstalled = false; + cloned.Name = $"Copy of {shellProfile.Name}"; AddShellProfile(cloned); } diff --git a/FluentTerminal.App.ViewModels/Settings/SshProfilesPageViewModel.cs b/FluentTerminal.App.ViewModels/Settings/SshProfilesPageViewModel.cs index a4895a8..c914c99 100644 --- a/FluentTerminal.App.ViewModels/Settings/SshProfilesPageViewModel.cs +++ b/FluentTerminal.App.ViewModels/Settings/SshProfilesPageViewModel.cs @@ -16,16 +16,19 @@ namespace FluentTerminal.App.ViewModels.Settings private readonly IFileSystemService _fileSystemService; private SshProfileViewModel _selectedShellProfile; private readonly IApplicationView _applicationView; + private readonly IDefaultValueProvider _defaultValueProvider; private readonly ITrayProcessCommunicationService _trayProcessCommunicationService; public SshProfilesPageViewModel(ISettingsService settingsService, IDialogService dialogService, IFileSystemService fileSystemService, IApplicationView applicationView, + IDefaultValueProvider defaultValueProvider, ITrayProcessCommunicationService trayProcessCommunicationService) { _settingsService = settingsService; _dialogService = dialogService; _fileSystemService = fileSystemService; _applicationView = applicationView; + _defaultValueProvider = defaultValueProvider; _trayProcessCommunicationService = trayProcessCommunicationService; CreateSshProfileCommand = new RelayCommand(CreateSshProfile); @@ -35,7 +38,7 @@ namespace FluentTerminal.App.ViewModels.Settings foreach (var sshProfile in _settingsService.GetSshProfiles()) { var viewModel = new SshProfileViewModel(sshProfile, settingsService, dialogService, - fileSystemService, applicationView, _trayProcessCommunicationService, false); + fileSystemService, applicationView, defaultValueProvider, _trayProcessCommunicationService, false); viewModel.Deleted += OnSshProfileDeleted; viewModel.SetAsDefault += OnSshProfileSetAsDefault; @@ -49,9 +52,8 @@ namespace FluentTerminal.App.ViewModels.Settings if (SshProfiles.Count == 0) CreateSshProfile(); - SelectedSshProfile = SshProfiles.FirstOrDefault(p => p.IsDefault); - if (SelectedSshProfile == null) - SelectedSshProfile = SshProfiles.First(); + + SelectedSshProfile = SshProfiles.FirstOrDefault(p => p.IsDefault) ?? SshProfiles.First(); } private void OnSshProfileSetAsDefault(object sender, EventArgs e) @@ -105,12 +107,12 @@ namespace FluentTerminal.App.ViewModels.Settings private void Clone(SshProfileViewModel shellProfile) { - var cloned = new SshProfile(shellProfile.Model) - { - Id = Guid.NewGuid(), - PreInstalled = false, - Name = $"Copy of {shellProfile.Name}" - }; + var cloned = (SshProfile) shellProfile.Model.Clone(); + + cloned.Id = Guid.NewGuid(); + cloned.PreInstalled = false; + cloned.Name = $"Copy of {shellProfile.Name}"; + foreach (KeyBinding keyBinding in cloned.KeyBindings) { keyBinding.Command = cloned.Id.ToString(); @@ -120,8 +122,9 @@ namespace FluentTerminal.App.ViewModels.Settings private void AddSshProfile(SshProfile sshProfile) { - var viewModel = new SshProfileViewModel(sshProfile, _settingsService, _dialogService, - _fileSystemService, _applicationView, _trayProcessCommunicationService, true); + var viewModel = new SshProfileViewModel(sshProfile, _settingsService, _dialogService, _fileSystemService, + _applicationView, _defaultValueProvider, _trayProcessCommunicationService, true); + viewModel.EditCommand.Execute(null); viewModel.SetAsDefault += OnSshProfileSetAsDefault; viewModel.Deleted += OnSshProfileDeleted; @@ -137,4 +140,4 @@ namespace FluentTerminal.App.ViewModels.Settings public ObservableCollection SshProfiles { get; } = new ObservableCollection(); } -} \ No newline at end of file +} diff --git a/FluentTerminal.App.ViewModels/SettingsViewModel.cs b/FluentTerminal.App.ViewModels/SettingsViewModel.cs index 2f5d8ce..187df32 100644 --- a/FluentTerminal.App.ViewModels/SettingsViewModel.cs +++ b/FluentTerminal.App.ViewModels/SettingsViewModel.cs @@ -18,7 +18,7 @@ namespace FluentTerminal.App.ViewModels Terminal = new TerminalPageViewModel(settingsService, dialogService, defaultValueProvider, systemFontService); Themes = new ThemesPageViewModel(settingsService, dialogService, defaultValueProvider, themeParserFactory, fileSystemService); Mouse = new MousePageViewModel(settingsService, dialogService, defaultValueProvider); - SshProfiles = new SshProfilesPageViewModel(settingsService, dialogService, fileSystemService, applicationView, trayProcessCommunicationService); + SshProfiles = new SshProfilesPageViewModel(settingsService, dialogService, fileSystemService, applicationView, defaultValueProvider, trayProcessCommunicationService); } public event EventHandler Closed; diff --git a/FluentTerminal.App.ViewModels/ShellProfileViewModel.cs b/FluentTerminal.App.ViewModels/ShellProfileViewModel.cs index c442127..b0dcda3 100644 --- a/FluentTerminal.App.ViewModels/ShellProfileViewModel.cs +++ b/FluentTerminal.App.ViewModels/ShellProfileViewModel.cs @@ -15,36 +15,213 @@ namespace FluentTerminal.App.ViewModels { public class ShellProfileViewModel : ViewModelBase { - private readonly IDialogService _dialogService; - private readonly IFileSystemService _fileSystemService; - private readonly ISettingsService _settingsService; - private string _arguments; - private ShellProfile _fallbackProfile; - private bool _inEditMode; - private bool _isDefault; - private string _location; - private LineEndingStyle _lineEndingStyle; - private string _name; - private bool _isNew; - private TabTheme _selectedTabTheme; - private TerminalTheme _selectedTerminalTheme; - private string _workingDirectory; - private bool _useConPty; - private readonly IApplicationView _applicationView; - private readonly IDefaultValueProvider _defaultValueProvider; + #region Static - public ShellProfileViewModel(ShellProfile shellProfile, ISettingsService settingsService, IDialogService dialogService, IFileSystemService fileSystemService, IApplicationView applicationView, IDefaultValueProvider defaultValueProvider, Boolean isNew) + private static readonly LineEndingStyle[] LineEndingStylesArray = + Enum.GetValues(typeof(LineEndingStyle)).Cast().ToArray(); + + #endregion Static + + #region Fields + + private ShellProfile _fallbackProfile; + + protected readonly IDialogService DialogService; + protected readonly IFileSystemService FileSystemService; + protected readonly ISettingsService SettingsService; + protected readonly IApplicationView ApplicationView; + protected readonly IDefaultValueProvider DefaultValueProvider; + + #endregion Fields + + #region Properties + + protected bool IsNew { get; set; } + + public Guid Id { get; private set; } + + public ShellProfile Model { get; private set; } + + public bool PreInstalled { get; private set; } + + private bool _useConPty; + + public bool UseConPty + { + get => _useConPty; + set => Set(ref _useConPty, value); + } + + private string _arguments; + + public string Arguments + { + get => _arguments; + set => Set(ref _arguments, value); + } + + private bool _inEditMode; + + public bool InEditMode + { + get => _inEditMode; + set => Set(ref _inEditMode, value); + } + + private bool _isDefault; + + public bool IsDefault + { + get => _isDefault; + set => Set(ref _isDefault, value); + } + + private string _location; + + public string Location + { + get => _location; + set => Set(ref _location, value); + } + + private string _name; + + public string Name + { + get => _name; + set => Set(ref _name, value); + } + + private TabTheme _selectedTabTheme; + + public TabTheme SelectedTabTheme + { + get => _selectedTabTheme ?? (_selectedTabTheme = TabThemes.FirstOrDefault(t => t.Id.Equals(_tabThemeId))); + set + { + if (value != null && Set(ref _selectedTabTheme, value)) + { + _tabThemeId = value.Id; + } + } + } + + private int _tabThemeId; + + public int TabThemeId + { + get => _tabThemeId; + set + { + if (Set(ref _tabThemeId, value)) + { + SelectedTabTheme = TabThemes.FirstOrDefault(t => t.Id.Equals(value)); + } + } + } + + private TerminalTheme _selectedTerminalTheme; + + public TerminalTheme SelectedTerminalTheme + { + get => _selectedTerminalTheme ?? + (_selectedTerminalTheme = TerminalThemes.FirstOrDefault(t => t.Id.Equals(_terminalThemeId))); + set + { + if (value != null && Set(ref _selectedTerminalTheme, value)) + { + _terminalThemeId = value.Id; + } + } + } + + private Guid _terminalThemeId; + + public Guid TerminalThemeId + { + get => _terminalThemeId; + set + { + if (Set(ref _terminalThemeId, value)) + { + SelectedTerminalTheme = TerminalThemes.FirstOrDefault(t => t.Id.Equals(value)); + } + } + } + + private string _workingDirectory; + + public string WorkingDirectory + { + get => _workingDirectory; + set => Set(ref _workingDirectory, value); + } + + private LineEndingStyle _lineEndingTranslation; + + public LineEndingStyle LineEndingTranslation + { + get => _lineEndingTranslation; + set => Set(ref _lineEndingTranslation, value); + } + + public ObservableCollection TabThemes { get; } + + public KeyBindingsViewModel KeyBindings { get; } + + public ObservableCollection TerminalThemes { get; } + + public ObservableCollection LineEndingStyles { get; } = + new ObservableCollection(LineEndingStylesArray); + + #endregion Properties + + #region Events + + public event EventHandler Deleted; + + public event EventHandler SetAsDefault; + + #endregion Events + + #region Commands + + public IAsyncCommand BrowseForCustomShellCommand { get; } + + public IAsyncCommand BrowseForWorkingDirectoryCommand { get; } + + public IAsyncCommand CancelEditCommand { get; } + + public IAsyncCommand DeleteCommand { get; } + + public RelayCommand EditCommand { get; } + + public IAsyncCommand SaveChangesCommand { get; } + + public RelayCommand SetDefaultCommand { get; } + + public IAsyncCommand RestoreDefaultsCommand { get; } + + public IAsyncCommand AddKeyboardShortcutCommand { get; } + + #endregion Commands + + #region Constrcutor + + public ShellProfileViewModel(ShellProfile shellProfile, ISettingsService settingsService, + IDialogService dialogService, IFileSystemService fileSystemService, IApplicationView applicationView, + IDefaultValueProvider defaultValueProvider, bool isNew) { Model = shellProfile; - _settingsService = settingsService; - _dialogService = dialogService; - _fileSystemService = fileSystemService; - _applicationView = applicationView; - _defaultValueProvider = defaultValueProvider; - _isNew = isNew; + SettingsService = settingsService; + DialogService = dialogService; + FileSystemService = fileSystemService; + ApplicationView = applicationView; + DefaultValueProvider = defaultValueProvider; + IsNew = isNew; - _settingsService.ThemeAdded += OnThemeAdded; - _settingsService.ThemeDeleted += OnThemeDeleted; + SettingsService.ThemeAdded += OnThemeAdded; + SettingsService.ThemeDeleted += OnThemeDeleted; TabThemes = new ObservableCollection(settingsService.GetTabThemes()); @@ -56,37 +233,42 @@ namespace FluentTerminal.App.ViewModels Name = "Default" } }; - foreach (var theme in _settingsService.GetThemes()) + foreach (var theme in SettingsService.GetThemes()) { TerminalThemes.Add(theme); } - KeyBindings = new KeyBindingsViewModel(shellProfile.Id.ToString(), _dialogService, string.Empty, false); + KeyBindings = new KeyBindingsViewModel(shellProfile.Id.ToString(), DialogService, string.Empty, false); - InitializeViewModelProperties(shellProfile); + InitializeViewModelPropertiesPrivate(shellProfile); SetDefaultCommand = new RelayCommand(SetDefault); DeleteCommand = new AsyncCommand(Delete, CanDelete); EditCommand = new RelayCommand(Edit); CancelEditCommand = new AsyncCommand(CancelEdit); - SaveChangesCommand = new RelayCommand(SaveChanges); + SaveChangesCommand = new AsyncCommand(SaveChangesAsync); AddKeyboardShortcutCommand = new AsyncCommand(AddKeyboardShortcut); BrowseForCustomShellCommand = new AsyncCommand(BrowseForCustomShell); BrowseForWorkingDirectoryCommand = new AsyncCommand(BrowseForWorkingDirectory); RestoreDefaultsCommand = new AsyncCommand(RestoreDefaults); } - private void InitializeViewModelProperties(ShellProfile shellProfile) + #endregion Constrcutor + + #region Methods + + // Loads view model properties from the input shellProfile + private void InitializeViewModelPropertiesPrivate(ShellProfile shellProfile) { - SelectedTerminalTheme = TerminalThemes.FirstOrDefault(t => t.Id == shellProfile.TerminalThemeId); Id = shellProfile.Id; Name = shellProfile.Name; Arguments = shellProfile.Arguments; Location = shellProfile.Location; WorkingDirectory = shellProfile.WorkingDirectory; - SelectedTabTheme = TabThemes.FirstOrDefault(t => t.Id == shellProfile.TabThemeId); + TerminalThemeId = shellProfile.TerminalThemeId; + TabThemeId = shellProfile.TabThemeId; PreInstalled = shellProfile.PreInstalled; - LineEndingStyle = shellProfile.LineEndingTranslation; + LineEndingTranslation = shellProfile.LineEndingTranslation; UseConPty = shellProfile.UseConPty; KeyBindings.Clear(); @@ -96,9 +278,41 @@ namespace FluentTerminal.App.ViewModels } } + // Loads view model properties from the input shellProfile + protected virtual void InitializeViewModelProperties(ShellProfile shellProfile) => + InitializeViewModelPropertiesPrivate(shellProfile); + + // Fills the input profile properties the view model properties. (Inverse of InitializeViewModelProperties()). + protected virtual Task FillProfileAsync(ShellProfile profile) + { + profile.Id = Id; + profile.Name = Name; + profile.Arguments = Arguments; + profile.Location = Location; + profile.WorkingDirectory = WorkingDirectory; + profile.TerminalThemeId = TerminalThemeId; + profile.TabThemeId = TabThemeId; + profile.PreInstalled = PreInstalled; + profile.LineEndingTranslation = LineEndingTranslation; + profile.UseConPty = UseConPty; + profile.KeyBindings = KeyBindings.KeyBindings.Select(x => x.Model).ToList(); + + return Task.CompletedTask; + } + + // Used to "remember" the current state. + protected virtual async Task CreateProfileAsync() + { + var profile = new ShellProfile(); + + await FillProfileAsync(profile); + + return profile; + } + private void OnThemeAdded(object sender, TerminalTheme e) { - _applicationView.RunOnDispatcherThread(() => + ApplicationView.RunOnDispatcherThread(() => { TerminalThemes.Add(e); }); @@ -108,7 +322,7 @@ namespace FluentTerminal.App.ViewModels { if (SelectedTerminalTheme.Id == e) { - _applicationView.RunOnDispatcherThread(() => + ApplicationView.RunOnDispatcherThread(() => { SelectedTerminalTheme = TerminalThemes.FirstOrDefault(x => x.Id == Guid.Empty); Model.TerminalThemeId = Guid.Empty; @@ -120,140 +334,15 @@ namespace FluentTerminal.App.ViewModels } } - public event EventHandler Deleted; - public event EventHandler SetAsDefault; - - public IAsyncCommand BrowseForCustomShellCommand { get; } - public IAsyncCommand BrowseForWorkingDirectoryCommand { get; } - public IAsyncCommand CancelEditCommand { get; } - public IAsyncCommand DeleteCommand { get; } - public RelayCommand EditCommand { get; } - public RelayCommand SaveChangesCommand { get; } - public RelayCommand SetDefaultCommand { get; } - public IAsyncCommand RestoreDefaultsCommand { get; } - public IAsyncCommand AddKeyboardShortcutCommand { get; } - public ObservableCollection TabThemes { get; } - public KeyBindingsViewModel KeyBindings { get; } - - public ObservableCollection TerminalThemes { get; } - public ShellProfile Model { get; private set; } - public bool PreInstalled { get; private set; } - - public bool UseConPty + public virtual async Task SaveChangesAsync() { - get => _useConPty; - set => Set(ref _useConPty, value); - } + await FillProfileAsync(Model); - public string Arguments - { - get => _arguments; - set => Set(ref _arguments, value); - } - - public Guid Id { get; private set; } - - public bool InEditMode - { - get => _inEditMode; - set => Set(ref _inEditMode, value); - } - - public bool IsDefault - { - get => _isDefault; - set => Set(ref _isDefault, value); - } - - public string Location - { - get => _location; - set => Set(ref _location, value); - } - - public string Name - { - get => _name; - set => Set(ref _name, value); - } - - public TabTheme SelectedTabTheme - { - get => _selectedTabTheme; - set - { - if (value != null) - { - Set(ref _selectedTabTheme, value); - } - } - } - - public TerminalTheme SelectedTerminalTheme - { - get => _selectedTerminalTheme; - set - { - if (value != null) - { - Set(ref _selectedTerminalTheme, value); - } - } - } - - public string WorkingDirectory - { - get => _workingDirectory; - set => Set(ref _workingDirectory, value); - } - - public LineEndingStyle LineEndingStyle - { - get => _lineEndingStyle; - set => Set(ref _lineEndingStyle, value); - } - - public bool DoNotModifyIsSelected - { - get => LineEndingStyle == LineEndingStyle.DoNotModify; - set { if (value) { LineEndingStyle = LineEndingStyle.DoNotModify; } - } - } - - public bool ToCRLFIsSelected - { - get => LineEndingStyle == LineEndingStyle.ToCRLF; - set { if (value) LineEndingStyle = LineEndingStyle.ToCRLF; } - } - - public bool ToLFIsSelected - { - get => LineEndingStyle == LineEndingStyle.ToLF; - set { if (value) LineEndingStyle = LineEndingStyle.ToLF; } - } - - public bool ToCRIsSelected - { - get => LineEndingStyle == LineEndingStyle.ToCR; - set { if (value) { LineEndingStyle = LineEndingStyle.ToCR; } } - } - - public void SaveChanges() - { - Model.Arguments = Arguments; - Model.Location = Location; - Model.Name = Name; - Model.WorkingDirectory = WorkingDirectory; - Model.TabThemeId = SelectedTabTheme.Id; - Model.TerminalThemeId = SelectedTerminalTheme.Id; - Model.LineEndingTranslation = LineEndingStyle; - Model.UseConPty = UseConPty; - Model.KeyBindings = KeyBindings.KeyBindings.Select(x => x.Model).ToList(); - _settingsService.SaveShellProfile(Model); + SettingsService.SaveShellProfile(Model); KeyBindings.Editable = false; InEditMode = false; - _isNew = false; + IsNew = false; } private async Task RestoreDefaults() @@ -263,13 +352,14 @@ namespace FluentTerminal.App.ViewModels throw new InvalidOperationException(); } - var result = await _dialogService.ShowMessageDialogAsnyc(I18N.Translate("PleaseConfirm"), I18N.Translate("ConfirmRestoreProfile"), DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true); + var result = await DialogService.ShowMessageDialogAsnyc(I18N.Translate("PleaseConfirm"), + I18N.Translate("ConfirmRestoreProfile"), DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true); if (result == DialogButton.OK) { - Model = _defaultValueProvider.GetPreinstalledShellProfiles().FirstOrDefault(x => x.Id == Model.Id); + Model = DefaultValueProvider.GetPreinstalledShellProfiles().FirstOrDefault(x => x.Id == Model.Id); InitializeViewModelProperties(Model); - _settingsService.SaveShellProfile(Model); + SettingsService.SaveShellProfile(Model); } } @@ -280,7 +370,7 @@ namespace FluentTerminal.App.ViewModels private async Task BrowseForCustomShell() { - var file = await _fileSystemService.OpenFile(new[] { ".exe" }).ConfigureAwait(true); + var file = await FileSystemService.OpenFile(new[] { ".exe" }).ConfigureAwait(true); if (file != null) { Location = file.Path; @@ -289,7 +379,7 @@ namespace FluentTerminal.App.ViewModels private async Task BrowseForWorkingDirectory() { - var directory = await _fileSystemService.BrowseForDirectory().ConfigureAwait(true); + var directory = await FileSystemService.BrowseForDirectory().ConfigureAwait(true); if (directory != null) { WorkingDirectory = directory; @@ -298,47 +388,22 @@ namespace FluentTerminal.App.ViewModels private async Task CancelEdit() { - if (_isNew) + if (IsNew) { await Delete(); } else { - ShellProfile changedProfile = new ShellProfile - { - Id = Model.Id, - PreInstalled = Model.PreInstalled, - Arguments = Arguments, - Location = Location, - Name = Name, - WorkingDirectory = WorkingDirectory, - TabThemeId = SelectedTabTheme.Id, - TerminalThemeId = SelectedTerminalTheme.Id, - LineEndingTranslation = _lineEndingStyle, - UseConPty = UseConPty, - KeyBindings = KeyBindings.KeyBindings.Select(x => x.Model).ToList() - }; + ShellProfile changedProfile = await CreateProfileAsync(); if (!_fallbackProfile.EqualTo(changedProfile)) { - var result = await _dialogService.ShowMessageDialogAsnyc(I18N.Translate("PleaseConfirm"), I18N.Translate("ConfirmDiscardChanges"), DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true); + var result = await DialogService.ShowMessageDialogAsnyc(I18N.Translate("PleaseConfirm"), I18N.Translate("ConfirmDiscardChanges"), DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true); if (result == DialogButton.OK) { - Arguments = _fallbackProfile.Arguments; - Location = _fallbackProfile.Location; - Name = _fallbackProfile.Name; - WorkingDirectory = _fallbackProfile.WorkingDirectory; - LineEndingStyle = _fallbackProfile.LineEndingTranslation; - UseConPty = _fallbackProfile.UseConPty; - SelectedTerminalTheme = TerminalThemes.FirstOrDefault(t => t.Id == _fallbackProfile.TerminalThemeId); - SelectedTabTheme = TabThemes.FirstOrDefault(t => t.Id == _fallbackProfile.TabThemeId); - - KeyBindings.KeyBindings.Clear(); - foreach (var keyBinding in Model.KeyBindings.Select(x => new KeyBinding(x)).ToList()) - { - KeyBindings.Add(keyBinding); - } + // Cancelled, so rollback + InitializeViewModelProperties(_fallbackProfile); KeyBindings.Editable = false; InEditMode = false; @@ -359,7 +424,7 @@ namespace FluentTerminal.App.ViewModels private async Task Delete() { - var result = await _dialogService.ShowMessageDialogAsnyc(I18N.Translate("PleaseConfirm"), I18N.Translate("ConfirmDeleteProfile"), DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true); + var result = await DialogService.ShowMessageDialogAsnyc(I18N.Translate("PleaseConfirm"), I18N.Translate("ConfirmDeleteProfile"), DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true); if (result == DialogButton.OK) { @@ -369,7 +434,7 @@ namespace FluentTerminal.App.ViewModels private void Edit() { - _fallbackProfile = new ShellProfile(Model); + _fallbackProfile = Model.Clone(); KeyBindings.Editable = true; InEditMode = true; @@ -379,5 +444,7 @@ namespace FluentTerminal.App.ViewModels { SetAsDefault?.Invoke(this, EventArgs.Empty); } + + #endregion Methods } } \ No newline at end of file diff --git a/FluentTerminal.App.ViewModels/SshProfileViewModel.cs b/FluentTerminal.App.ViewModels/SshProfileViewModel.cs index 9d409fc..13c79d6 100644 --- a/FluentTerminal.App.ViewModels/SshProfileViewModel.cs +++ b/FluentTerminal.App.ViewModels/SshProfileViewModel.cs @@ -1,133 +1,24 @@ using FluentTerminal.App.Services; using FluentTerminal.App.Services.Utilities; using FluentTerminal.App.ViewModels.Infrastructure; -using FluentTerminal.App.ViewModels.Settings; using FluentTerminal.Models; using FluentTerminal.Models.Enums; -using GalaSoft.MvvmLight; -using GalaSoft.MvvmLight.Command; using System; -using System.Collections.ObjectModel; -using System.Linq; using System.Text; using System.Threading.Tasks; namespace FluentTerminal.App.ViewModels { - public class SshProfileViewModel : ViewModelBase, ISshConnectionInfo + public class SshProfileViewModel : ShellProfileViewModel, ISshConnectionInfo { - #region Constants - - private const string MoshExe = "mosh.exe"; - - #endregion Constants - #region Fields - private readonly IDialogService _dialogService; - private readonly IFileSystemService _fileSystemService; - private readonly ISettingsService _settingsService; - private SshProfile _fallbackProfile; - private readonly IApplicationView _applicationView; private readonly ITrayProcessCommunicationService _trayProcessCommunicationService; - private bool _isNew; #endregion Fields #region Properties - private Guid _id; - - public Guid Id - { - get => _id; - private set => Set(ref _id, value); - } - - public SshProfile Model { get; private set; } - - public KeyBindingsViewModel KeyBindings { get; } - - private bool _inEditMode; - - public bool InEditMode - { - get => _inEditMode; - set => Set(ref _inEditMode, value); - } - - private bool _isDefault; - - public bool IsDefault - { - get => _isDefault; - set => Set(ref _isDefault, value); - } - - private string _name; - - public string Name - { - get => _name; - set => Set(ref _name, value); - } - - private TabTheme _selectedTabTheme; - - public TabTheme SelectedTabTheme - { - get => _selectedTabTheme; - set - { - if (value != null && Set(ref _selectedTabTheme, value)) - { - TabThemeId = value.Id; - } - } - } - - private int _tabThemeId; - - public int TabThemeId - { - get => _tabThemeId; - set - { - if (Set(ref _tabThemeId, value)) - { - SelectedTabTheme = TabThemes.First(t => t.Id.Equals(value)); - } - } - } - - private TerminalTheme _selectedTerminalTheme; - - public TerminalTheme SelectedTerminalTheme - { - get => _selectedTerminalTheme; - set - { - if (value != null && Set(ref _selectedTerminalTheme, value)) - { - TerminalThemeId = value.Id; - } - } - } - - private Guid _terminalThemeId; - - public Guid TerminalThemeId - { - get => _terminalThemeId; - set - { - if (Set(ref _terminalThemeId, value)) - { - SelectedTerminalTheme = TerminalThemes.First(t => t.Id.Equals(value)); - } - } - } - private string _host; public string Host @@ -184,97 +75,95 @@ namespace FluentTerminal.App.ViewModels set => Set(ref _moshPortTo, value); } - private bool _useConPty; - - public bool UseConPty - { - get => _useConPty; - set => Set(ref _useConPty, value); - } - - private LineEndingStyle _lineEndingTranslation; - - public LineEndingStyle LineEndingTranslation - { - get => _lineEndingTranslation; - set => Set(ref _lineEndingTranslation, value); - } - - public ObservableCollection LineEndingStyles { get; } = - new ObservableCollection(Enum.GetValues(typeof(LineEndingStyle)).Cast()); - - public ObservableCollection TabThemes { get; } - - public ObservableCollection TerminalThemes { get; } - #endregion Properties #region Commands - public IAsyncCommand BrowseForIdentityFileCommand { get; } - - public IAsyncCommand CancelEditCommand { get; } - - public IAsyncCommand DeleteCommand { get; } - - public RelayCommand EditCommand { get; } - - public AsyncCommand SaveChangesCommand { get; } - - public RelayCommand SetDefaultCommand { get; } - - //public IAsyncCommand RestoreDefaultsCommand { get; } - - public IAsyncCommand AddKeyboardShortcutCommand { get; } - - public object CloneCommand - { - get { throw new NotImplementedException(); } - } - + public IAsyncCommand BrowseForIdentityFileCommand { get; } + #endregion Commands - - #region Events - - public event EventHandler Deleted; - public event EventHandler SetAsDefault; - - #endregion Events + + #region Constructor public SshProfileViewModel(SshProfile sshProfile, ISettingsService settingsService, IDialogService dialogService, IFileSystemService fileSystemService, IApplicationView applicationView, - ITrayProcessCommunicationService trayProcessCommunicationService, bool isNew) + IDefaultValueProvider defaultValueProvider, + ITrayProcessCommunicationService trayProcessCommunicationService, bool isNew) : base( + sshProfile ?? new SshProfile(), settingsService, dialogService, fileSystemService, applicationView, + defaultValueProvider, isNew) { - Model = sshProfile ?? new SshProfile(); - _settingsService = settingsService; - _dialogService = dialogService; - _fileSystemService = fileSystemService; - _applicationView = applicationView; _trayProcessCommunicationService = trayProcessCommunicationService; - _isNew = isNew; - _settingsService.ThemeAdded += OnThemeAdded; - _settingsService.ThemeDeleted += OnThemeDeleted; + InitializeViewModelPropertiesPrivate(sshProfile ?? new SshProfile()); - TabThemes = new ObservableCollection(settingsService.GetTabThemes()); - - TerminalThemes = new ObservableCollection(_settingsService.GetThemes()); - TerminalThemes.Insert(0, new TerminalTheme {Id = Guid.Empty, Name = "Default"}); - - KeyBindings = new KeyBindingsViewModel(sshProfile.Id.ToString(), _dialogService, string.Empty, false); - - InitializeViewModelProperties(sshProfile); - - SetDefaultCommand = new RelayCommand(SetDefault); - DeleteCommand = new AsyncCommand(Delete, CanDelete); - EditCommand = new RelayCommand(Edit); - CancelEditCommand = new AsyncCommand(CancelEdit); - SaveChangesCommand = new AsyncCommand(SaveChanges); - AddKeyboardShortcutCommand = new AsyncCommand(AddKeyboardShortcut); BrowseForIdentityFileCommand = new AsyncCommand(BrowseForIdentityFile); } + #endregion Constructor + #region Methods + + // Fills the remaining view model properties (those which aren't filled by the base method) from the input sshProfile + private void InitializeViewModelPropertiesPrivate(SshProfile sshProfile) + { + Host = sshProfile.Host; + SshPort = sshProfile.SshPort; + + Username = sshProfile.Username; + + if (string.IsNullOrEmpty(Username)) + { + _trayProcessCommunicationService.GetUserName().ContinueWith(t => + { + if (string.IsNullOrEmpty(Username)) + { + Username = t.Result; + } + }, TaskContinuationOptions.OnlyOnRanToCompletion); + } + + IdentityFile = sshProfile.IdentityFile; + UseMosh = sshProfile.UseMosh; + MoshPortFrom = sshProfile.MoshPortFrom; + MoshPortTo = sshProfile.MoshPortTo; + } + + protected override void InitializeViewModelProperties(ShellProfile sshProfile) + { + base.InitializeViewModelProperties(sshProfile); + + InitializeViewModelPropertiesPrivate((SshProfile)sshProfile); + } + + protected override async Task FillProfileAsync(ShellProfile profile) + { + await base.FillProfileAsync(profile); + + profile.Location = await _trayProcessCommunicationService.GetMoshSshPath(_useMosh); + profile.Arguments = GetArgumentsString(); + profile.WorkingDirectory = null; + + var sshProfile = (SshProfile)profile; + + sshProfile.Host = Host; + sshProfile.SshPort = SshPort; + sshProfile.Username = Username; + sshProfile.IdentityFile = IdentityFile; + sshProfile.UseMosh = UseMosh; + sshProfile.MoshPortFrom = MoshPortFrom; + sshProfile.MoshPortTo = MoshPortTo; + } + + public virtual Task AcceptChangesAsync() => FillProfileAsync(Model); + + protected override async Task CreateProfileAsync() + { + var profile = new SshProfile(); + + await FillProfileAsync(profile); + + return profile; + } private string GetArgumentsString() { @@ -295,63 +184,13 @@ namespace FluentTerminal.App.ViewModels return sb.ToString(); } - private void InitializeViewModelProperties(SshProfile sshProfile) - { - SelectedTerminalTheme = TerminalThemes.FirstOrDefault(t => t.Id == sshProfile.TerminalThemeId); - Id = sshProfile.Id; - Name = sshProfile.Name; - - Host = sshProfile.Host; - SshPort = sshProfile.SshPort; - Username = sshProfile.Username; - IdentityFile = sshProfile.IdentityFile; - UseMosh = sshProfile.UseMosh; - MoshPortFrom = sshProfile.MoshPortFrom; - MoshPortTo = sshProfile.MoshPortTo; - - UseConPty = sshProfile.UseConPty; - - SelectedTabTheme = TabThemes.FirstOrDefault(t => t.Id == sshProfile.TabThemeId); - LineEndingTranslation = sshProfile.LineEndingTranslation; - - KeyBindings.Clear(); - foreach (var keyBinding in sshProfile.KeyBindings.Select(x => new KeyBinding(x)).ToList()) - { - KeyBindings.Add(keyBinding); - } - } - - private void OnThemeAdded(object sender, TerminalTheme e) - { - _applicationView.RunOnDispatcherThread(() => - { - TerminalThemes.Add(e); - }); - } - - private void OnThemeDeleted(object sender, Guid e) - { - if (SelectedTerminalTheme.Id == e) - { - _applicationView.RunOnDispatcherThread(() => - { - SelectedTerminalTheme = TerminalThemes.FirstOrDefault(x => x.Id == Guid.Empty); - Model.TerminalThemeId = Guid.Empty; - if (_fallbackProfile != null) - { - _fallbackProfile.TerminalThemeId = Guid.Empty; - } - }); - } - } - - public async Task SaveChanges() + public override async Task SaveChangesAsync() { var result = Validate(); if (result != SshConnectionInfoValidationResult.Valid) { - await _dialogService.ShowMessageDialogAsnyc(I18N.Translate("InvalidInput"), + await DialogService.ShowMessageDialogAsnyc(I18N.Translate("InvalidInput"), result.GetErrorString(Environment.NewLine), DialogButton.OK); return; @@ -359,167 +198,22 @@ namespace FluentTerminal.App.ViewModels await AcceptChangesAsync(); - _settingsService.SaveSshProfile(Model, _isNew); + SettingsService.SaveSshProfile((SshProfile) Model, IsNew); KeyBindings.Editable = false; InEditMode = false; - _isNew = false; - } - - public async Task AcceptChangesAsync() - { - Model.Location = await _trayProcessCommunicationService.GetMoshSshPath(_useMosh); - Model.Arguments = GetArgumentsString(); - Model.Host = Host; - Model.SshPort = SshPort; - Model.Username = Username; - Model.IdentityFile = IdentityFile; - Model.UseMosh = UseMosh; - Model.MoshPortFrom = MoshPortFrom; - Model.MoshPortTo = MoshPortTo; - - Model.UseConPty = UseConPty; - - Model.Name = Name; - Model.TabThemeId = SelectedTabTheme.Id; - Model.TerminalThemeId = SelectedTerminalTheme.Id; - Model.LineEndingTranslation = LineEndingTranslation; - Model.KeyBindings = KeyBindings.KeyBindings.Select(x => x.Model).ToList(); - } - - public Task AddKeyboardShortcut() - { - return KeyBindings.ShowAddKeyBindingDialog(); + IsNew = false; } private async Task BrowseForIdentityFile() { - var file = await _fileSystemService.OpenFile(new[] { "*" }).ConfigureAwait(true); + var file = await FileSystemService.OpenFile(new[] { "*" }).ConfigureAwait(true); if (file != null) { IdentityFile = file.Path; } } - private async Task CancelEdit() - { - if (_isNew) - { - await Delete(); - } - else - { - SshProfile changedProfile = new SshProfile - { - Id = Id, - Name = Name, - TabThemeId = SelectedTabTheme.Id, - TerminalThemeId = SelectedTerminalTheme.Id, - LineEndingTranslation = LineEndingTranslation, - - Host = Host, - SshPort = SshPort, - Username = Username, - IdentityFile = IdentityFile, - UseMosh = UseMosh, - MoshPortFrom = MoshPortFrom, - MoshPortTo = MoshPortTo, - - UseConPty = UseConPty, - - KeyBindings = KeyBindings.KeyBindings.Select(x => x.Model).ToList() - }; - - if (!_fallbackProfile.EqualTo(changedProfile)) - { - var result = await _dialogService.ShowMessageDialogAsnyc(I18N.Translate("PleaseConfirm"), I18N.Translate("ConfirmDiscardChanges"), DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true); - - if (result == DialogButton.OK) - { - Name = _fallbackProfile.Name; - - Host = _fallbackProfile.Host; - SshPort = _fallbackProfile.SshPort; - Username = _fallbackProfile.Username; - IdentityFile = _fallbackProfile.IdentityFile; - UseMosh = _fallbackProfile.UseMosh; - MoshPortFrom = _fallbackProfile.MoshPortFrom; - MoshPortTo = _fallbackProfile.MoshPortTo; - - UseConPty = _fallbackProfile.UseConPty; - - LineEndingTranslation = _fallbackProfile.LineEndingTranslation; - SelectedTerminalTheme = TerminalThemes.FirstOrDefault(t => t.Id == _fallbackProfile.TerminalThemeId); - SelectedTabTheme = TabThemes.FirstOrDefault(t => t.Id == _fallbackProfile.TabThemeId); - - KeyBindings.KeyBindings.Clear(); - foreach (var keyBinding in _fallbackProfile.KeyBindings.Select(x => new KeyBinding(x)).ToList()) - { - KeyBindings.Add(keyBinding); - } - - KeyBindings.Editable = false; - InEditMode = false; - } - } - else - { - KeyBindings.Editable = false; - InEditMode = false; - } - } - } - - private bool CanDelete() - { - return !Model.PreInstalled; - } - - private async Task Delete() - { - var result = await _dialogService.ShowMessageDialogAsnyc(I18N.Translate("PleaseConfirm"), I18N.Translate("ConfirmDeleteTheme"), DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true); - - if (result == DialogButton.OK) - { - Deleted?.Invoke(this, EventArgs.Empty); - } - } - - private void Edit() - { - _fallbackProfile = new SshProfile - { - Id = Id, - Name = Name, - Host = Host, - SshPort = SshPort, - Username = Username, - IdentityFile = IdentityFile, - UseMosh = UseMosh, - MoshPortFrom = MoshPortFrom, - MoshPortTo = MoshPortTo, - UseConPty = UseConPty, - LineEndingTranslation = LineEndingTranslation, - // ReSharper disable PossibleNullReferenceException - TerminalThemeId = TerminalThemes.FirstOrDefault(t => t.Id == SelectedTerminalTheme.Id).Id, - TabThemeId = TabThemes.FirstOrDefault(t => t.Id == SelectedTabTheme.Id).Id - // ReSharper restore PossibleNullReferenceException - }; - - foreach (var keyBinding in Model.KeyBindings.Select(x => new KeyBinding(x)).ToList()) - { - _fallbackProfile.KeyBindings.Add(keyBinding); - } - - KeyBindings.Editable = true; - InEditMode = true; - } - - private void SetDefault() - { - SetAsDefault?.Invoke(this, EventArgs.Empty); - } - public SshConnectionInfoValidationResult Validate(bool allowNoUser = false) => this.GetValidationResult(allowNoUser); diff --git a/FluentTerminal.App/App.xaml.cs b/FluentTerminal.App/App.xaml.cs index 1ad450d..9cd72e0 100755 --- a/FluentTerminal.App/App.xaml.cs +++ b/FluentTerminal.App/App.xaml.cs @@ -195,11 +195,11 @@ namespace FluentTerminal.App if (isSsh) { - SshProfile connectionInfo; + SshProfileViewModel connectionInfo; try { - connectionInfo = (SshProfile) _sshHelperService.Value.ParseSsh(protocolActivated.Uri); + connectionInfo = (SshProfileViewModel) _sshHelperService.Value.ParseSsh(protocolActivated.Uri); } catch (Exception ex) { @@ -212,11 +212,15 @@ namespace FluentTerminal.App SshConnectionInfoValidationResult result = connectionInfo.Validate(); - if (result != SshConnectionInfoValidationResult.Valid) + if (result == SshConnectionInfoValidationResult.Valid) + { + await connectionInfo.AcceptChangesAsync(); + } + else { // Link is valid, but incomplete (i.e. username missing), so we need to show dialog. connectionInfo = - (SshProfile) await _dialogService.ShowSshConnectionInfoDialogAsync(connectionInfo); + (SshProfileViewModel) await _dialogService.ShowSshConnectionInfoDialogAsync(connectionInfo); if (connectionInfo == null) { @@ -228,9 +232,9 @@ namespace FluentTerminal.App } if (mainViewModel == null) - await CreateTerminal(connectionInfo, _applicationSettings.NewTerminalLocation); + await CreateTerminal(connectionInfo.Model, _applicationSettings.NewTerminalLocation); else - await mainViewModel.AddTerminalAsync(connectionInfo); + await mainViewModel.AddTerminalAsync(connectionInfo.Model); return; } diff --git a/FluentTerminal.App/Dialogs/SshInfoDialog.xaml.cs b/FluentTerminal.App/Dialogs/SshInfoDialog.xaml.cs index e86bc16..30fab49 100644 --- a/FluentTerminal.App/Dialogs/SshInfoDialog.xaml.cs +++ b/FluentTerminal.App/Dialogs/SshInfoDialog.xaml.cs @@ -168,7 +168,17 @@ URL={0} DataContext = input; Focus(FocusState.Programmatic); - return await ShowAsync() == ContentDialogResult.Primary ? (SshProfileViewModel) DataContext : null; + + if (await ShowAsync() != ContentDialogResult.Primary) + { + return null; + } + + var vm = (SshProfileViewModel) DataContext; + + await vm.AcceptChangesAsync(); + + return vm; } } } diff --git a/FluentTerminal.App/Services/SshHelperService.cs b/FluentTerminal.App/Services/SshHelperService.cs index 3135ab0..4a1059d 100644 --- a/FluentTerminal.App/Services/SshHelperService.cs +++ b/FluentTerminal.App/Services/SshHelperService.cs @@ -60,6 +60,7 @@ namespace FluentTerminal.App.Services private readonly IDialogService _dialogService; private readonly IFileSystemService _fileSystemService; private readonly IApplicationView _applicationView; + private readonly IDefaultValueProvider _defaultValueProvider; private readonly ITrayProcessCommunicationService _trayProcessCommunicationService; #endregion Fields @@ -67,12 +68,15 @@ namespace FluentTerminal.App.Services #region Constructor public SshHelperService(ISettingsService settingsService, IDialogService dialogService, - IFileSystemService fileSystemService, IApplicationView applicationView, ITrayProcessCommunicationService trayProcessCommunicationService) + IFileSystemService fileSystemService, IApplicationView applicationView, + IDefaultValueProvider defaultValueProvider, + ITrayProcessCommunicationService trayProcessCommunicationService) { _settingsService = settingsService; _dialogService = dialogService; _fileSystemService = fileSystemService; _applicationView = applicationView; + _defaultValueProvider = defaultValueProvider; _trayProcessCommunicationService = trayProcessCommunicationService; } @@ -87,7 +91,7 @@ namespace FluentTerminal.App.Services public ISshConnectionInfo ParseSsh(Uri uri) { SshProfileViewModel vm = new SshProfileViewModel(null, _settingsService, _dialogService, - _fileSystemService, _applicationView, _trayProcessCommunicationService, true) + _fileSystemService, _applicationView, _defaultValueProvider, _trayProcessCommunicationService, true) { Host = uri.Host, UseMosh = MoshUriScheme.Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase) @@ -176,16 +180,11 @@ namespace FluentTerminal.App.Services public async Task GetSshProfileAsync(SshProfile profile) { SshProfileViewModel vm = new SshProfileViewModel(profile, _settingsService, _dialogService, - _fileSystemService, _applicationView, _trayProcessCommunicationService, true); + _fileSystemService, _applicationView, _defaultValueProvider, _trayProcessCommunicationService, true); vm = (SshProfileViewModel) await _dialogService.ShowSshConnectionInfoDialogAsync(vm); - if (vm != null) - { - await vm.AcceptChangesAsync(); - } - - return vm?.Model; + return (SshProfile) vm?.Model; } public Task GetSavedSshProfileAsync() => diff --git a/FluentTerminal.App/Views/SettingsPages/ShellProfileSettings.xaml b/FluentTerminal.App/Views/SettingsPages/ShellProfileSettings.xaml index ccfe09d..55c1bb8 100644 --- a/FluentTerminal.App/Views/SettingsPages/ShellProfileSettings.xaml +++ b/FluentTerminal.App/Views/SettingsPages/ShellProfileSettings.xaml @@ -8,7 +8,8 @@ xmlns:models="using:FluentTerminal.Models" xmlns:settings="using:FluentTerminal.App.ViewModels.Settings" xmlns:viewmodels="using:FluentTerminal.App.ViewModels" - xmlns:views="using:FluentTerminal.App.Views" + xmlns:views="using:FluentTerminal.App.Views" + xmlns:enums="using:FluentTerminal.Models.Enums" mc:Ignorable="d"> @@ -320,28 +321,18 @@ IsEnabled="{x:Bind InEditMode, Mode=OneWay}" IsOn="{x:Bind UseConPty, Mode=TwoWay}" /> - - - - - - - + + + + + + + diff --git a/FluentTerminal.Models/ShellProfile.cs b/FluentTerminal.Models/ShellProfile.cs index 37d2ccf..24bc1c8 100644 --- a/FluentTerminal.Models/ShellProfile.cs +++ b/FluentTerminal.Models/ShellProfile.cs @@ -18,7 +18,7 @@ namespace FluentTerminal.Models } - public ShellProfile(ShellProfile other) + protected ShellProfile(ShellProfile other) { Id = other.Id; PreInstalled = other.PreInstalled; @@ -89,6 +89,8 @@ namespace FluentTerminal.Models && other.KeyBindings.SequenceEqual(KeyBindings); } + public virtual ShellProfile Clone() => new ShellProfile(this); + /// /// Checks the profile for errors and returns string describing the found errors, if any. /// Returns null if no errors found. diff --git a/FluentTerminal.Models/SshProfile.cs b/FluentTerminal.Models/SshProfile.cs index 01cf2c6..dd1a94d 100644 --- a/FluentTerminal.Models/SshProfile.cs +++ b/FluentTerminal.Models/SshProfile.cs @@ -5,7 +5,6 @@ namespace FluentTerminal.Models { public class SshProfile : ShellProfile, ISshConnectionInfo { - #region Constants public const ushort DefaultSshPort = 22; @@ -34,9 +33,12 @@ namespace FluentTerminal.Models #region Constructors - public SshProfile() { } + public SshProfile() + { + LineEndingTranslation = LineEndingStyle.ToLF; + } - public SshProfile(SshProfile other) : base(other) + protected SshProfile(SshProfile other) : base(other) { Host = other.Host; SshPort = other.SshPort; @@ -57,7 +59,7 @@ namespace FluentTerminal.Models public override bool EqualTo(ShellProfile other) { - if (!(other is SshProfile otherSsh)) + if (!(other is SshProfile otherSsh) || !base.EqualTo(other)) { return false; } @@ -67,16 +69,18 @@ namespace FluentTerminal.Models return true; } - return otherSsh.Id.Equals(Id) && string.Equals(otherSsh.Name, Name) && string.Equals(otherSsh.Host, Host) && - otherSsh.SshPort.Equals(SshPort) && string.Equals(otherSsh.Username, Username) && - (string.IsNullOrEmpty(IdentityFile) + return string.Equals(otherSsh.Host, Host) + && otherSsh.SshPort.Equals(SshPort) + && string.Equals(otherSsh.Username, Username) + && (string.IsNullOrEmpty(IdentityFile) ? string.IsNullOrEmpty(otherSsh.IdentityFile) - : string.Equals(otherSsh.IdentityFile, IdentityFile)) && otherSsh.UseMosh.Equals(UseMosh) && - otherSsh.MoshPortFrom.Equals(MoshPortFrom) && otherSsh.MoshPortTo.Equals(MoshPortTo) && - otherSsh.TabThemeId.Equals(TabThemeId) && otherSsh.TerminalThemeId.Equals(TerminalThemeId) && - otherSsh.LineEndingTranslation == LineEndingTranslation && otherSsh.KeyBindings.SequenceEqual(KeyBindings); + : string.Equals(otherSsh.IdentityFile, IdentityFile)) && otherSsh.UseMosh.Equals(UseMosh) + && otherSsh.MoshPortFrom.Equals(MoshPortFrom) + && otherSsh.MoshPortTo.Equals(MoshPortTo); } + public override ShellProfile Clone() => new SshProfile(this); + public SshConnectionInfoValidationResult Validate(bool allowNoUser = false) => this.GetValidationResult(allowNoUser);