using System; using System.Collections.Generic; using System.Threading.Tasks; using Windows.Storage.Pickers; using Windows.UI.Popups; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using FluentTerminal.App.Services; using FluentTerminal.App.Services.Dialogs; using FluentTerminal.App.Services.Utilities; using FluentTerminal.App.Utilities; using FluentTerminal.App.ViewModels.Profiles; using FluentTerminal.Models; using System.Linq; using Windows.Foundation; 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 namespace FluentTerminal.App.Dialogs { // ReSharper disable once RedundantExtendsListEntry public sealed partial class CustomCommandDialog : ContentDialog, ICustomCommandDialog { private readonly ISettingsService _settingsService; private readonly IApplicationView _applicationView; private readonly ITrayProcessCommunicationService _trayProcessCommunicationService; private readonly ICommandHistoryService _historyService; private IAsyncOperation _showDialogOperation; private ContentDialogResult _dialogResult = ContentDialogResult.None; private ExecutedCommand _lastChosenCommand; // TODO: The following field is for hacking strange behavior that deletes command text after Tab selection. Consider finding a better fix. private string _tabSelectedCommand; public CommandProfileProviderViewModel ViewModel { get; private set; } public IAsyncCommand SaveLinkCommand { get; } public CustomCommandDialog(ISettingsService settingsService, IApplicationView applicationView, ITrayProcessCommunicationService trayProcessCommunicationService, ICommandHistoryService historyService) { _settingsService = settingsService; _applicationView = applicationView; _trayProcessCommunicationService = trayProcessCommunicationService; _historyService = historyService; InitializeComponent(); SaveLinkCommand = new AsyncCommand(SaveLink); PrimaryButtonText = I18N.Translate("OK"); SecondaryButtonText = I18N.Translate("Cancel"); var currentTheme = settingsService.GetCurrentTheme(); RequestedTheme = ContrastHelper.GetIdealThemeForBackgroundColor(currentTheme.Colors.Background); } private void SetupFocus() { CommandTextBox.Focus(FocusState.Programmatic); } private async void OnPrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) { var deferral = args.GetDeferral(); var error = await ViewModel.AcceptChangesAsync(); if (string.IsNullOrEmpty(error)) { _dialogResult = ContentDialogResult.Primary; } else { args.Cancel = true; await new MessageDialog(error, I18N.Translate("InvalidInput")).ShowAsync(); SetupFocus(); } deferral.Complete(); } private void OnSecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) { _dialogResult = ContentDialogResult.Secondary; } private async Task SaveLink() { var link = await ViewModel.GetUrlAsync(); if (!link.Item1) { await new MessageDialog(link.Item2, I18N.Translate("InvalidInput")).ShowAsync(); return; } var content = ProfileProviderViewModelBase.GetShortcutFileContent(link.Item2); var savePicker = new FileSavePicker { SuggestedStartLocation = PickerLocationId.Desktop }; savePicker.FileTypeChoices.Add("Shortcut", new List { ".url" }); var file = await savePicker.PickSaveFileAsync(); if (file == null) { return; } try { await _trayProcessCommunicationService.SaveTextFileAsync(file.Path, content); } catch (Exception ex) { await new MessageDialog(ex.Message, I18N.Translate("Error")).ShowAsync(); } } private void CommandTextBox_OnTextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args) { if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput) { ViewModel.SetFilter(sender.Text.Trim()); } // TODO: Else branch added for Tab-selection hack mentioned above. else if (!string.IsNullOrEmpty(_tabSelectedCommand)) { ViewModel.Command = _tabSelectedCommand; _tabSelectedCommand = null; } } private void CommandTextBox_OnSuggestionChosen(AutoSuggestBox sender, AutoSuggestBoxSuggestionChosenEventArgs args) { _lastChosenCommand = (args.SelectedItem as CommandItemViewModel)?.ExecutedCommand; } private void CommandTextBox_OnQuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) { _lastChosenCommand = null; if (args.ChosenSuggestion is CommandItemViewModel commandItem) { var executedCommand = ViewModel.Commands.FirstOrDefault(c => c.ExecutedCommand.Value.Equals(commandItem.ExecutedCommand.Value, StringComparison.OrdinalIgnoreCase))?.ExecutedCommand; if (executedCommand != null) { ViewModel.SetProfile(executedCommand.ShellProfile.Clone()); } } } private void CommandTextBox_OnPreviewKeyUp(object sender, KeyRoutedEventArgs e) { var command = _lastChosenCommand; if (e.Key == VirtualKey.Delete && !ViewModel.IsProfileCommand(command)) { ViewModel.RemoveCommand(command); e.Handled = true; } else { e.Handled = false; } } private async void CommandTextBox_OnKeyUp(object sender, KeyRoutedEventArgs e) { switch (e.Key) { case VirtualKey.Down: case VirtualKey.Up: if (!CommandTextBox.IsSuggestionListOpen) { CommandTextBox.IsSuggestionListOpen = true; } return; case VirtualKey.Enter: if (string.IsNullOrWhiteSpace(CommandTextBox.Text) && !CommandTextBox.IsSuggestionListOpen) { CommandTextBox.IsSuggestionListOpen = true; } else { var error = await ViewModel.AcceptChangesAsync(); if (string.IsNullOrEmpty(error)) { _dialogResult = ContentDialogResult.Primary; _showDialogOperation.Cancel(); } else { await new MessageDialog(error, I18N.Translate("InvalidInput")).ShowAsync(); } } return; } } private void CommandTextBox_OnKeyDown(object sender, KeyRoutedEventArgs e) { if (e.Key == VirtualKey.Tab) { if (_lastChosenCommand != null) { ViewModel.Command = _lastChosenCommand.Value; _tabSelectedCommand = _lastChosenCommand.Value; } e.Handled = false; } else { _tabSelectedCommand = null; } } public async Task GetCustomCommandAsync(ShellProfile input = null) { ViewModel = new CommandProfileProviderViewModel(_settingsService, _applicationView, _trayProcessCommunicationService, _historyService, input); SetupFocus(); _showDialogOperation = ShowAsync(); var result = await _showDialogOperation.AsTask().ContinueWith(t => _dialogResult); return result != ContentDialogResult.Primary ? null : ViewModel.Model; } } }