Files
FluentTerminal/FluentTerminal.App/Dialogs/CustomCommandDialog.xaml.cs
T
Aleksandar Pesic e88fb78e9d Quick command implementation (#472)
* Separating "SSH Info" and "Quick Launch", and updating translations.

* Adding "Quick Launch" to menu.

* Auto-complete, initial version.

* Builds, but not finished.

* Improved, but there are still some bugs...

* Minor changes.

* Refactroing request/response identifiers.

* Improving command history.

* Minor refactoring.

* Deleting history by using "Del" key.

* Handling mosh special case in quick commands.

* SSH command handled as any other command in the path.

* New resource strings.

* Fixing quick command links.

* Fixing after-merging bugs.

* Improving filtering.

* Finishing filtering.

* Changing placeholder text.

* Minor refactoring.

* Updating resources.

* Renaming NewRemoteTab back to NewSshTab.
2019-08-08 08:02:09 +02:00

219 lines
7.4 KiB
C#

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;
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.System;
using Windows.UI.Xaml.Input;
using FluentTerminal.App.ViewModels;
// 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 IApplicationDataContainer _historyContainer;
private ExecutedCommand _lastChosenCommand;
public CustomCommandDialog(ISettingsService settingsService, IApplicationView applicationView,
ITrayProcessCommunicationService trayProcessCommunicationService, ApplicationDataContainers containers)
{
_settingsService = settingsService;
_applicationView = applicationView;
_trayProcessCommunicationService = trayProcessCommunicationService;
_historyContainer = containers.HistoryContainer;
InitializeComponent();
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 void OnLoading(FrameworkElement sender, object args)
{
SetupFocus();
}
private async void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
var vm = (CommandProfileProviderViewModel) DataContext;
var deferral = args.GetDeferral();
var error = await vm.AcceptChangesAsync();
if (!string.IsNullOrEmpty(error))
{
args.Cancel = true;
await new MessageDialog(error, I18N.Translate("InvalidInput")).ShowAsync();
SetupFocus();
}
deferral.Complete();
}
private async void SaveLink_OnClick(object sender, RoutedEventArgs e)
{
var vm = (CommandProfileProviderViewModel)DataContext;
var link = await vm.GetUrlAsync();
if (!link.Item1)
{
await new MessageDialog(link.Item2, I18N.Translate("InvalidInput")).ShowAsync();
return;
}
var content = ProfileProviderViewModelBase.GetShortcutFileContent(link.Item2);
FileSavePicker savePicker = new FileSavePicker { SuggestedStartLocation = PickerLocationId.Desktop };
savePicker.FileTypeChoices.Add("Shortcut", new List<string> { ".url" });
StorageFile 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();
}
}
public async Task<ShellProfile> GetCustomCommandAsync(ShellProfile input = null)
{
var vm = new CommandProfileProviderViewModel(_settingsService, _applicationView,
_trayProcessCommunicationService, _historyContainer, input);
DataContext = vm;
if (await ShowAsync() != ContentDialogResult.Primary)
{
return null;
}
vm = (CommandProfileProviderViewModel) DataContext;
vm.SaveToHistory();
return vm.Model;
}
private void CommandTextBox_OnTextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
{
((CommandProfileProviderViewModel)DataContext).SetFilter(sender.Text.Trim());
}
}
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)
{
ExecutedCommand executedCommand = ((CommandProfileProviderViewModel) DataContext).Commands
.FirstOrDefault(c =>
c.ExecutedCommand.Value.Equals(commandItem.ExecutedCommand.Value.ToString(),
StringComparison.OrdinalIgnoreCase))?.ExecutedCommand;
if (executedCommand != null)
{
((CommandProfileProviderViewModel) DataContext).SetProfile(executedCommand.ShellProfile.Clone());
}
}
}
private void CommandTextBox_OnPreviewKeyUp(object sender, KeyRoutedEventArgs e)
{
var command = _lastChosenCommand;
if (e.Key == VirtualKey.Delete && command != null)
{
((CommandProfileProviderViewModel)DataContext).RemoveCommand(command);
e.Handled = true;
}
else
{
e.Handled = false;
}
}
private void CommandTextBox_OnKeyUp(object sender, KeyRoutedEventArgs e)
{
if (e.Key != VirtualKey.Enter)
return;
if (string.IsNullOrWhiteSpace(CommandTextBox.Text))
{
CommandTextBox.IsSuggestionListOpen = true;
}
else
{
// TODO: Try to find a better way to handle [Enter] on auto-complete field.
// Weird way to move the focus to the primary button...
if (!(FocusManager.FindLastFocusableElement(this) is Control secondaryButton) ||
!secondaryButton.Name.Equals("SecondaryButton"))
{
return;
}
secondaryButton.Focus(FocusState.Programmatic);
var options = new FindNextElementOptions
{
SearchRoot = this,
XYFocusNavigationStrategyOverride = XYFocusNavigationStrategyOverride.Projection
};
if (FocusManager.FindNextElement(FocusNavigationDirection.Left, options) is Control primaryButton)
{
primaryButton.Focus(FocusState.Programmatic);
}
}
}
}
}