diff --git a/FluentTerminal.App.Services/Exceptions/SaveTextFileException.cs b/FluentTerminal.App.Services/Exceptions/SaveTextFileException.cs new file mode 100644 index 0000000..92b284c --- /dev/null +++ b/FluentTerminal.App.Services/Exceptions/SaveTextFileException.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace FluentTerminal.App.Services.Exceptions +{ + public class SaveTextFileException : Exception + { + public SaveTextFileException() : base() + { + } + + public SaveTextFileException(string message) : base(message) + { + } + + public SaveTextFileException(string message, Exception innerException) : base(message, innerException) + { + } + + protected SaveTextFileException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) + { + } + } +} diff --git a/FluentTerminal.App.Services/ISettingsService.cs b/FluentTerminal.App.Services/ISettingsService.cs index ad2dd55..183dcba 100644 --- a/FluentTerminal.App.Services/ISettingsService.cs +++ b/FluentTerminal.App.Services/ISettingsService.cs @@ -42,7 +42,7 @@ namespace FluentTerminal.App.Services void SaveDefaultSshProfileId(Guid id); void SaveKeyBindings(string command, ICollection keyBindings); void SaveShellProfile(ShellProfile shellProfile, bool newShell = false); - void SaveSshProfile(SshProfile shellProfile, bool newShell = false); + void SaveSshProfile(SshProfile sshProfile, bool newShell = false); void SaveTerminalOptions(TerminalOptions terminalOptions); void SaveTheme(TerminalTheme theme, bool newTheme = false); ShellProfile GetShellProfile(Guid id); diff --git a/FluentTerminal.App.Services/Implementation/DefaultValueProvider.cs b/FluentTerminal.App.Services/Implementation/DefaultValueProvider.cs index 314e374..5a987ae 100644 --- a/FluentTerminal.App.Services/Implementation/DefaultValueProvider.cs +++ b/FluentTerminal.App.Services/Implementation/DefaultValueProvider.cs @@ -12,14 +12,13 @@ namespace FluentTerminal.App.Services.Implementation { public ApplicationSettings GetDefaultApplicationSettings() { - var logDirectoryPath = String.Empty; + var logDirectoryPath = string.Empty; try { // Accessing ApplicationData.Current during run of unit tests causes // "System.InvalidOperationException : The process has no package identity" exception. logDirectoryPath = ApplicationData.Current.LocalCacheFolder.Path; - } - catch (InvalidOperationException) { } + } catch (InvalidOperationException) { } return new ApplicationSettings { @@ -359,9 +358,9 @@ namespace FluentTerminal.App.Services.Implementation } }; + default: + throw new InvalidOperationException($"Default keybindings for Command '{command}' are missing"); } - - return null; } public Guid GetDefaultShellProfileId() diff --git a/FluentTerminal.App.Services/Implementation/ITermThemeParser.cs b/FluentTerminal.App.Services/Implementation/ITermThemeParser.cs index cb8be61..56aec2d 100644 --- a/FluentTerminal.App.Services/Implementation/ITermThemeParser.cs +++ b/FluentTerminal.App.Services/Implementation/ITermThemeParser.cs @@ -51,7 +51,7 @@ namespace FluentTerminal.App.Services.Implementation public const string RedComponent = "Red Component"; } - public async Task Parse(string fileName, Stream fileContent) + public Task Parse(string fileName, Stream fileContent) { if (string.IsNullOrWhiteSpace(fileName)) { @@ -65,13 +65,13 @@ namespace FluentTerminal.App.Services.Implementation var node = PList.Load(fileContent) as DictionaryNode ?? throw new ParseThemeException("Root node was not a dictionary."); - return new TerminalTheme + return Task.FromResult(new TerminalTheme { Name = Path.GetFileNameWithoutExtension(fileName), Colors = GetColors(node), Id = Guid.NewGuid(), PreInstalled = false - }; + }); } private TerminalColors GetColors(DictionaryNode themeDictionary) @@ -110,8 +110,6 @@ namespace FluentTerminal.App.Services.Implementation var green = dictionaryNode[ITermThemeColorKeys.GreenComponent] as RealNode ?? throw new ParseThemeException("Green node value was not a real number"); var blue = dictionaryNode[ITermThemeColorKeys.BlueComponent] as RealNode ?? throw new ParseThemeException("Blue node value was not a real number"); - var color = $"#{alpha:X2}{GetByteValue(red):X2}{GetByteValue(green):X2}{GetByteValue(blue):X2}"; - if (alpha == byte.MaxValue) { return $"#{GetByteValue(red):X2}{GetByteValue(green):X2}{GetByteValue(blue):X2}"; diff --git a/FluentTerminal.App.Services/Implementation/ThemeParserFactory.cs b/FluentTerminal.App.Services/Implementation/ThemeParserFactory.cs index efea5cd..77db4bf 100644 --- a/FluentTerminal.App.Services/Implementation/ThemeParserFactory.cs +++ b/FluentTerminal.App.Services/Implementation/ThemeParserFactory.cs @@ -5,7 +5,7 @@ namespace FluentTerminal.App.Services.Implementation { public class ThemeParserFactory : IThemeParserFactory { - private IEnumerable _parsers; + private readonly IEnumerable _parsers; public IEnumerable SupportedFileTypes { get; } diff --git a/FluentTerminal.App.Services/Implementation/TrayProcessCommunicationService.cs b/FluentTerminal.App.Services/Implementation/TrayProcessCommunicationService.cs index e618843..37a6949 100644 --- a/FluentTerminal.App.Services/Implementation/TrayProcessCommunicationService.cs +++ b/FluentTerminal.App.Services/Implementation/TrayProcessCommunicationService.cs @@ -1,4 +1,5 @@ -using FluentTerminal.Models; +using FluentTerminal.App.Services.Exceptions; +using FluentTerminal.Models; using FluentTerminal.Models.Enums; using FluentTerminal.Models.Requests; using FluentTerminal.Models.Responses; @@ -82,7 +83,7 @@ namespace FluentTerminal.App.Services.Implementation if (!response.Success) { - throw new Exception(string.IsNullOrEmpty(response.Error) ? "Failed to save the file." : response.Error); + throw new SaveTextFileException(string.IsNullOrEmpty(response.Error) ? "Failed to save the file." : response.Error); } } @@ -233,11 +234,11 @@ namespace FluentTerminal.App.Services.Implementation _terminalOutputHandlers[terminalId] = callback; } - public void UnsubscribeFromTerminalOutput(byte terminalId) + public void UnsubscribeFromTerminalOutput(byte id) { - if (_terminalOutputHandlers.ContainsKey(terminalId)) + if (_terminalOutputHandlers.ContainsKey(id)) { - _terminalOutputHandlers.Remove(terminalId); + _terminalOutputHandlers.Remove(id); } } diff --git a/FluentTerminal.App.Services/Terminal.cs b/FluentTerminal.App.Services/Terminal.cs index c3ff22f..e4af181 100644 --- a/FluentTerminal.App.Services/Terminal.cs +++ b/FluentTerminal.App.Services/Terminal.cs @@ -11,9 +11,9 @@ namespace FluentTerminal.App.Services { private readonly ITrayProcessCommunicationService _trayProcessCommunicationService; private Func> _selectedTextCallback; - private bool _closingFromUI = false; - private bool _exited = false; - private bool _requireShellProcessStart = true; + private bool _closingFromUI; + private bool _exited; + private readonly bool _requireShellProcessStart; public Terminal(ITrayProcessCommunicationService trayProcessCommunicationService, byte? terminalId = null) { @@ -33,7 +33,7 @@ namespace FluentTerminal.App.Services _exited = true; Exited?.Invoke(this, status.ExitCode); - if (_closingFromUI == true || status.ExitCode <= 0) + if (_closingFromUI || status.ExitCode <= 0) { Closed?.Invoke(this, System.EventArgs.Empty); } diff --git a/FluentTerminal.App.ViewModels/Infrastructure/IAsyncCommand.cs b/FluentTerminal.App.ViewModels/Infrastructure/IAsyncCommand.cs index 7a04ec2..1b06675 100644 --- a/FluentTerminal.App.ViewModels/Infrastructure/IAsyncCommand.cs +++ b/FluentTerminal.App.ViewModels/Infrastructure/IAsyncCommand.cs @@ -12,7 +12,7 @@ namespace FluentTerminal.App.ViewModels.Infrastructure bool CanExecute(); } - public interface IAsyncCommand : ICommand + public interface IAsyncCommand : ICommand { Task ExecuteAsync(T parameter); bool CanExecute(T parameter); diff --git a/FluentTerminal.App.ViewModels/Profiles/ProfileProviderViewModelBase.cs b/FluentTerminal.App.ViewModels/Profiles/ProfileProviderViewModelBase.cs index d39aec8..e54a9b9 100644 --- a/FluentTerminal.App.ViewModels/Profiles/ProfileProviderViewModelBase.cs +++ b/FluentTerminal.App.ViewModels/Profiles/ProfileProviderViewModelBase.cs @@ -43,7 +43,7 @@ namespace FluentTerminal.App.ViewModels.Profiles { if (value == null) { - throw new ArgumentNullException(); + throw new ArgumentNullException(nameof(value)); } if (ReferenceEquals(_model, value)) diff --git a/FluentTerminal.App.ViewModels/Settings/AboutPageViewModel.cs b/FluentTerminal.App.ViewModels/Settings/AboutPageViewModel.cs index 8e7fecb..f3b6af3 100644 --- a/FluentTerminal.App.ViewModels/Settings/AboutPageViewModel.cs +++ b/FluentTerminal.App.ViewModels/Settings/AboutPageViewModel.cs @@ -9,14 +9,12 @@ namespace FluentTerminal.App.ViewModels.Settings public class AboutPageViewModel : ViewModelBase { private const string BaseUrl = "https://github.com/felixse/FluentTerminal/releases/tag/"; - private readonly ISettingsService _settingsService; private readonly IUpdateService _updateService; private string _latestVersion; private readonly IApplicationView _applicationView; - public AboutPageViewModel(ISettingsService settingsService, IUpdateService updateService, IApplicationView applicationView) + public AboutPageViewModel(IUpdateService updateService, IApplicationView applicationView) { - _settingsService = settingsService; _updateService = updateService; _applicationView = applicationView; diff --git a/FluentTerminal.App.ViewModels/Settings/GeneralPageViewModel.cs b/FluentTerminal.App.ViewModels/Settings/GeneralPageViewModel.cs index 6351a99..8cd30e7 100644 --- a/FluentTerminal.App.ViewModels/Settings/GeneralPageViewModel.cs +++ b/FluentTerminal.App.ViewModels/Settings/GeneralPageViewModel.cs @@ -1,5 +1,6 @@ using FluentTerminal.App.Services; using FluentTerminal.App.Services.Utilities; +using FluentTerminal.App.ViewModels.Infrastructure; using FluentTerminal.Models; using FluentTerminal.Models.Enums; using GalaSoft.MvvmLight; @@ -23,9 +24,11 @@ namespace FluentTerminal.App.ViewModels.Settings private bool _needsToRestart; private readonly IApplicationLanguageService _applicationLanguageService; private readonly ITrayProcessCommunicationService _trayProcessCommunicationService; + private readonly IFileSystemService _fileSystemService; public GeneralPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider, - IStartupTaskService startupTaskService, IApplicationLanguageService applicationLanguageService, ITrayProcessCommunicationService trayProcessCommunicationService) + IStartupTaskService startupTaskService, IApplicationLanguageService applicationLanguageService, + ITrayProcessCommunicationService trayProcessCommunicationService, IFileSystemService fileSystemService) { _settingsService = settingsService; _dialogService = dialogService; @@ -33,10 +36,12 @@ namespace FluentTerminal.App.ViewModels.Settings _startupTaskService = startupTaskService; _applicationLanguageService = applicationLanguageService; _trayProcessCommunicationService = trayProcessCommunicationService; + _fileSystemService = fileSystemService; _applicationSettings = _settingsService.GetApplicationSettings(); - RestoreDefaultsCommand = new RelayCommand(async () => await RestoreDefaults().ConfigureAwait(false)); + RestoreDefaultsCommand = new AsyncCommand(RestoreDefaults); + BrowseLogDirectoryCommand = new AsyncCommand(BrowseLogDirectory); } public IEnumerable Languages => _applicationLanguageService.Languages; @@ -267,7 +272,9 @@ namespace FluentTerminal.App.ViewModels.Settings } } - public RelayCommand RestoreDefaultsCommand { get; } + public IAsyncCommand RestoreDefaultsCommand { get; } + + public IAsyncCommand BrowseLogDirectoryCommand { get; } public bool StartupTaskEnabled { @@ -430,5 +437,15 @@ namespace FluentTerminal.App.ViewModels.Settings } SetStartupTaskPropertiesForStatus(status); } + + private async Task BrowseLogDirectory() + { + var folder = await _fileSystemService.BrowseForDirectory(); + + if (folder != null) + { + LogDirectoryPath = folder; + } + } } } \ No newline at end of file diff --git a/FluentTerminal.App.ViewModels/Settings/KeyBindingsPageViewModel.cs b/FluentTerminal.App.ViewModels/Settings/KeyBindingsPageViewModel.cs index ec06f73..134b996 100644 --- a/FluentTerminal.App.ViewModels/Settings/KeyBindingsPageViewModel.cs +++ b/FluentTerminal.App.ViewModels/Settings/KeyBindingsPageViewModel.cs @@ -14,17 +14,14 @@ namespace FluentTerminal.App.ViewModels.Settings { public class KeyBindingsPageViewModel : ViewModelBase { - private readonly IDefaultValueProvider _defaultValueProvider; private readonly IDialogService _dialogService; private readonly ISettingsService _settingsService; private readonly ITrayProcessCommunicationService _trayProcessCommunicationService; - private IDictionary> _keyBindings; - public KeyBindingsPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider, ITrayProcessCommunicationService trayProcessCommunicationService) + public KeyBindingsPageViewModel(ISettingsService settingsService, IDialogService dialogService, ITrayProcessCommunicationService trayProcessCommunicationService) { _settingsService = settingsService; _dialogService = dialogService; - _defaultValueProvider = defaultValueProvider; _trayProcessCommunicationService = trayProcessCommunicationService; RestoreDefaultsCommand = new RelayCommand(async () => await RestoreDefaults().ConfigureAwait(false)); AddCommand = new RelayCommand(async command => await Add(command).ConfigureAwait(false)); @@ -54,15 +51,13 @@ namespace FluentTerminal.App.ViewModels.Settings private void Initialize(IDictionary> keyBindings) { - _keyBindings = keyBindings; - ClearKeyBindings(); foreach (var value in Enum.GetValues(typeof(Command))) { var command = (Command)value; var viewModel = new KeyBindingsViewModel(command.ToString(), _dialogService, I18N.Translate($"{nameof(Command)}.{command}"), true); - foreach (var keyBinding in _keyBindings[command.ToString()]) + foreach (var keyBinding in keyBindings[command.ToString()]) { viewModel.Add(keyBinding); } diff --git a/FluentTerminal.App.ViewModels/Settings/TerminalPageViewModel.cs b/FluentTerminal.App.ViewModels/Settings/TerminalPageViewModel.cs index 271d6fe..d6025b8 100644 --- a/FluentTerminal.App.ViewModels/Settings/TerminalPageViewModel.cs +++ b/FluentTerminal.App.ViewModels/Settings/TerminalPageViewModel.cs @@ -114,7 +114,6 @@ namespace FluentTerminal.App.ViewModels.Settings get => _terminalOptions.ScrollBackLimit.ToString(); set { - var oldValue = _terminalOptions.ScrollBackLimit; if (uint.TryParse(value, out uint intValue)) { if (intValue == uint.MinValue) diff --git a/FluentTerminal.App.ViewModels/Settings/ThemesPageViewModel.cs b/FluentTerminal.App.ViewModels/Settings/ThemesPageViewModel.cs index 85cc872..b9f1836 100644 --- a/FluentTerminal.App.ViewModels/Settings/ThemesPageViewModel.cs +++ b/FluentTerminal.App.ViewModels/Settings/ThemesPageViewModel.cs @@ -1,11 +1,13 @@ using FluentTerminal.App.Services; using FluentTerminal.App.Services.Utilities; +using FluentTerminal.App.ViewModels.Infrastructure; using FluentTerminal.Models; using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Command; using System; using System.Collections.ObjectModel; using System.Linq; +using System.Threading.Tasks; namespace FluentTerminal.App.ViewModels.Settings { @@ -31,7 +33,7 @@ namespace FluentTerminal.App.ViewModels.Settings _fileSystemService = fileSystemService; CreateThemeCommand = new RelayCommand(CreateTheme); - ImportThemeCommand = new RelayCommand(ImportTheme); + ImportThemeCommand = new AsyncCommand(ImportTheme); CloneCommand = new RelayCommand(CloneTheme); _settingsService.TerminalOptionsChanged += OnTerminalOptionsChanged; @@ -56,7 +58,7 @@ namespace FluentTerminal.App.ViewModels.Settings } public RelayCommand CreateThemeCommand { get; } - public RelayCommand ImportThemeCommand { get; } + public IAsyncCommand ImportThemeCommand { get; } public RelayCommand CloneCommand { get; set; } public double BackgroundOpacity @@ -110,7 +112,7 @@ namespace FluentTerminal.App.ViewModels.Settings AddTheme(theme); } - private async void ImportTheme() + private async Task ImportTheme() { var file = await _fileSystemService.OpenFile(_themeParserFactory.SupportedFileTypes).ConfigureAwait(true); if (file != null) diff --git a/FluentTerminal.App.ViewModels/SettingsViewModel.cs b/FluentTerminal.App.ViewModels/SettingsViewModel.cs index d71df56..aa6950a 100644 --- a/FluentTerminal.App.ViewModels/SettingsViewModel.cs +++ b/FluentTerminal.App.ViewModels/SettingsViewModel.cs @@ -12,9 +12,9 @@ namespace FluentTerminal.App.ViewModels IFileSystemService fileSystemService, IStartupTaskService startupTaskService, IUpdateService updateService, IApplicationView applicationView, IApplicationLanguageService applicationLanguageService, ApplicationDataContainers containers) { - About = new AboutPageViewModel(settingsService, updateService, applicationView); - KeyBindings = new KeyBindingsPageViewModel(settingsService, dialogService, defaultValueProvider, trayProcessCommunicationService); - General = new GeneralPageViewModel(settingsService, dialogService, defaultValueProvider, startupTaskService, applicationLanguageService, trayProcessCommunicationService); + About = new AboutPageViewModel(updateService, applicationView); + KeyBindings = new KeyBindingsPageViewModel(settingsService, dialogService, trayProcessCommunicationService); + General = new GeneralPageViewModel(settingsService, dialogService, defaultValueProvider, startupTaskService, applicationLanguageService, trayProcessCommunicationService, fileSystemService); Profiles = new ProfilesPageViewModel(settingsService, dialogService, defaultValueProvider, fileSystemService, applicationView); Terminal = new TerminalPageViewModel(settingsService, dialogService, defaultValueProvider, systemFontService); Themes = new ThemesPageViewModel(settingsService, dialogService, defaultValueProvider, themeParserFactory, fileSystemService); diff --git a/FluentTerminal.App.ViewModels/TerminalViewModel.cs b/FluentTerminal.App.ViewModels/TerminalViewModel.cs index 6c71460..da5f577 100644 --- a/FluentTerminal.App.ViewModels/TerminalViewModel.cs +++ b/FluentTerminal.App.ViewModels/TerminalViewModel.cs @@ -407,7 +407,7 @@ namespace FluentTerminal.App.ViewModels private bool CanExecuteCommand() { - return (Initialized == true && _disposalRequested == false); + return Initialized && !_disposalRequested; } private async Task CloseTab() diff --git a/FluentTerminal.App/Adapters/DispatcherTimerAdapter.cs b/FluentTerminal.App/Adapters/DispatcherTimerAdapter.cs index 456bc3e..7f90c46 100644 --- a/FluentTerminal.App/Adapters/DispatcherTimerAdapter.cs +++ b/FluentTerminal.App/Adapters/DispatcherTimerAdapter.cs @@ -15,7 +15,7 @@ namespace FluentTerminal.App.Adapters private void OnDispatcherTimerTick(object sender, object e) { - Tick?.Invoke(this, null); + Tick?.Invoke(this, EventArgs.Empty); } public TimeSpan Interval diff --git a/FluentTerminal.App/Converters/BackgroundToApplicationThemeConverter.cs b/FluentTerminal.App/Converters/BackgroundToApplicationThemeConverter.cs index 4e4ef1f..7992711 100644 --- a/FluentTerminal.App/Converters/BackgroundToApplicationThemeConverter.cs +++ b/FluentTerminal.App/Converters/BackgroundToApplicationThemeConverter.cs @@ -20,12 +20,7 @@ namespace FluentTerminal.App.Converters color = (Color)value; } - if (color != null) - { - return ContrastHelper.GetIdealThemeForBackgroundColor(color); - } - - return null; + return ContrastHelper.GetIdealThemeForBackgroundColor(color); } public object ConvertBack(object value, Type targetType, object parameter, string language) diff --git a/FluentTerminal.App/Dialogs/CustomCommandDialog.xaml b/FluentTerminal.App/Dialogs/CustomCommandDialog.xaml index c9bd234..69839c1 100644 --- a/FluentTerminal.App/Dialogs/CustomCommandDialog.xaml +++ b/FluentTerminal.App/Dialogs/CustomCommandDialog.xaml @@ -13,10 +13,9 @@ Title="Quick Launch" d:DataContext="{d:DesignInstance viewModels:CommandProfileProviderViewModel, IsDesignTimeCreatable=False}" DefaultButton="Primary" - Loading="OnLoading" PrimaryButtonText="Button1" SecondaryButtonText="Button2" - PrimaryButtonClick="ContentDialog_PrimaryButtonClick"> + PrimaryButtonClick="OnPrimaryButtonClick"> @@ -35,14 +34,14 @@ PreviewKeyUp="CommandTextBox_OnPreviewKeyUp" QueryIcon="Find" PlaceholderText="Enter a command (e.g. 'ssh username@host')" - Text="{Binding Command, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" + Text="{x:Bind ViewModel.Command, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" KeyUp="CommandTextBox_OnKeyUp" Margin="0 8 2 0" AutoMaximizeSuggestionArea="True" - ItemsSource="{Binding Commands, Mode=OneWay}" > + ItemsSource="{x:Bind ViewModel.Commands, Mode=OneWay}" > - + @@ -85,8 +84,8 @@ Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Stretch" - ItemsSource="{Binding LineEndingStyles}" - SelectedItem="{Binding LineEndingTranslation, Mode=TwoWay}" + ItemsSource="{x:Bind ViewModel.LineEndingStyles}" + SelectedItem="{x:Bind ViewModel.LineEndingTranslation, Mode=TwoWay}" Margin="0,8,0,0"> @@ -109,8 +108,8 @@ Grid.Column="1" HorizontalAlignment="Stretch" ItemTemplateSelector="{StaticResource TabThemeTemplateSelector}" - ItemsSource="{Binding TabThemes, Mode=OneWay}" - SelectedItem="{Binding SelectedTabTheme, Mode=TwoWay}" + ItemsSource="{x:Bind ViewModel.TabThemes, Mode=OneWay}" + SelectedItem="{x:Bind ViewModel.SelectedTabTheme, Mode=TwoWay}" Margin="0,8,0,0" /> @@ -126,8 +125,8 @@ Grid.Column="1" HorizontalAlignment="Stretch" ItemTemplateSelector="{StaticResource TerminalThemeTemplateSelector}" - ItemsSource="{Binding TerminalThemes, Mode=OneWay}" - SelectedItem="{Binding SelectedTerminalTheme, Mode=TwoWay}" + ItemsSource="{x:Bind ViewModel.TerminalThemes, Mode=OneWay}" + SelectedItem="{x:Bind ViewModel.SelectedTerminalTheme, Mode=TwoWay}" Margin="0,8,0,0" /> @@ -136,7 +135,7 @@ Grid.Column="0" Grid.ColumnSpan="2" Content="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=UseConPty}" - IsChecked="{Binding UseConPty, Mode=TwoWay}" + IsChecked="{x:Bind ViewModel.UseConPty, Mode=TwoWay}" Margin="0,8,0,0" /> @@ -153,7 +152,7 @@ Grid.Column="1" Margin="0,10,4,0" HorizontalAlignment="Stretch" - Click="SaveLink_OnClick" + Command="{x:Bind SaveLinkCommand}" Content="Save Shortcut" /> diff --git a/FluentTerminal.App/Dialogs/CustomCommandDialog.xaml.cs b/FluentTerminal.App/Dialogs/CustomCommandDialog.xaml.cs index b0524cf..211c93c 100644 --- a/FluentTerminal.App/Dialogs/CustomCommandDialog.xaml.cs +++ b/FluentTerminal.App/Dialogs/CustomCommandDialog.xaml.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Windows.Storage; using Windows.Storage.Pickers; using Windows.UI.Popups; using Windows.UI.Xaml; @@ -16,6 +15,7 @@ using System.Linq; using Windows.System; using Windows.UI.Xaml.Input; using FluentTerminal.App.ViewModels; +using FluentTerminal.App.ViewModels.Infrastructure; // The Content Dialog item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 @@ -31,6 +31,10 @@ namespace FluentTerminal.App.Dialogs private ExecutedCommand _lastChosenCommand; + public CommandProfileProviderViewModel ViewModel { get; private set; } + + public IAsyncCommand SaveLinkCommand { get; } + public CustomCommandDialog(ISettingsService settingsService, IApplicationView applicationView, ITrayProcessCommunicationService trayProcessCommunicationService, ApplicationDataContainers containers) { @@ -41,6 +45,8 @@ namespace FluentTerminal.App.Dialogs InitializeComponent(); + SaveLinkCommand = new AsyncCommand(SaveLink); + PrimaryButtonText = I18N.Translate("OK"); SecondaryButtonText = I18N.Translate("Cancel"); @@ -53,18 +59,11 @@ namespace FluentTerminal.App.Dialogs CommandTextBox.Focus(FocusState.Programmatic); } - private void OnLoading(FrameworkElement sender, object args) + private async void OnPrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) { - SetupFocus(); - } - - private async void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) - { - var vm = (CommandProfileProviderViewModel) DataContext; - var deferral = args.GetDeferral(); - var error = await vm.AcceptChangesAsync(); + var error = await ViewModel.AcceptChangesAsync(); if (!string.IsNullOrEmpty(error)) { @@ -78,11 +77,9 @@ namespace FluentTerminal.App.Dialogs deferral.Complete(); } - private async void SaveLink_OnClick(object sender, RoutedEventArgs e) + private async Task SaveLink() { - var vm = (CommandProfileProviderViewModel)DataContext; - - var link = await vm.GetUrlAsync(); + var link = await ViewModel.GetUrlAsync(); if (!link.Item1) { @@ -93,11 +90,11 @@ namespace FluentTerminal.App.Dialogs var content = ProfileProviderViewModelBase.GetShortcutFileContent(link.Item2); - FileSavePicker savePicker = new FileSavePicker { SuggestedStartLocation = PickerLocationId.Desktop }; + var savePicker = new FileSavePicker { SuggestedStartLocation = PickerLocationId.Desktop }; savePicker.FileTypeChoices.Add("Shortcut", new List { ".url" }); - StorageFile file = await savePicker.PickSaveFileAsync(); + var file = await savePicker.PickSaveFileAsync(); if (file == null) { @@ -118,7 +115,7 @@ namespace FluentTerminal.App.Dialogs { if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput) { - ((CommandProfileProviderViewModel)DataContext).SetFilter(sender.Text.Trim()); + ViewModel.SetFilter(sender.Text.Trim()); } } @@ -133,14 +130,14 @@ namespace FluentTerminal.App.Dialogs if (args.ChosenSuggestion is CommandItemViewModel commandItem) { - ExecutedCommand executedCommand = ((CommandProfileProviderViewModel) DataContext).Commands + var executedCommand = ViewModel.Commands .FirstOrDefault(c => c.ExecutedCommand.Value.Equals(commandItem.ExecutedCommand.Value.ToString(), StringComparison.OrdinalIgnoreCase))?.ExecutedCommand; if (executedCommand != null) { - ((CommandProfileProviderViewModel) DataContext).SetProfile(executedCommand.ShellProfile.Clone()); + ViewModel.SetProfile(executedCommand.ShellProfile.Clone()); } } } @@ -149,11 +146,9 @@ namespace FluentTerminal.App.Dialogs { var command = _lastChosenCommand; - if (e.Key == VirtualKey.Delete && - !((CommandProfileProviderViewModel) DataContext).IsProfileCommand(command)) + if (e.Key == VirtualKey.Delete && !ViewModel.IsProfileCommand(command)) { - ((CommandProfileProviderViewModel) DataContext).RemoveCommand(command); - + ViewModel.RemoveCommand(command); e.Handled = true; } else @@ -213,21 +208,19 @@ namespace FluentTerminal.App.Dialogs public async Task GetCustomCommandAsync(ShellProfile input = null) { - var vm = new CommandProfileProviderViewModel(_settingsService, _applicationView, + ViewModel = new CommandProfileProviderViewModel(_settingsService, _applicationView, _trayProcessCommunicationService, _historyContainer, input); - DataContext = vm; + SetupFocus(); if (await ShowAsync() != ContentDialogResult.Primary) { return null; } - vm = (CommandProfileProviderViewModel)DataContext; + ViewModel.Model.Tag = new DelayedHistorySaver(ViewModel); - vm.Model.Tag = new DelayedHistorySaver(vm); - - return vm.Model; + return ViewModel.Model; } } } diff --git a/FluentTerminal.App/Dialogs/SshInfoDialog.xaml b/FluentTerminal.App/Dialogs/SshInfoDialog.xaml index 293be58..4272883 100644 --- a/FluentTerminal.App/Dialogs/SshInfoDialog.xaml +++ b/FluentTerminal.App/Dialogs/SshInfoDialog.xaml @@ -6,15 +6,14 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:enums="using:FluentTerminal.Models.Enums" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:views="using:FluentTerminal.App.Views" xmlns:profiles="using:FluentTerminal.App.ViewModels.Profiles" + xmlns:views="using:FluentTerminal.App.Views" x:Uid="SshInfoDialog" Title="SSH Info" d:DataContext="{d:DesignInstance profiles:SshConnectViewModel, IsDesignTimeCreatable=False}" DefaultButton="Primary" - Loading="OnLoading" - PrimaryButtonClick="SshInfoDialog_OnPrimaryButtonClick" + PrimaryButtonClick="OnPrimaryButtonClick" mc:Ignorable="d"> @@ -26,10 +25,9 @@ - + - + @@ -45,7 +43,7 @@ - + + Text="{x:Bind ViewModel.Username, Mode=TwoWay}" /> + Text="{x:Bind ViewModel.Host, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> + Text="{x:Bind ViewModel.SshPort, Mode=TwoWay}" /> - + + Text="{x:Bind ViewModel.IdentityFile, Mode=TwoWay}" />