using FluentTerminal.App.Services; 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.Threading.Tasks; using Windows.ApplicationModel.Core; using Windows.UI.Core; using Windows.UI.Core.Preview; namespace FluentTerminal.App.ViewModels { public class MainViewModel : ViewModelBase { private readonly IDialogService _dialogService; private readonly IKeyboardCommandService _keyboardCommandService; private readonly ISettingsService _settingsService; private readonly ITrayProcessCommunicationService _trayProcessCommunicationService; private ApplicationSettings _applicationSettings; private string _background; private double _backgroundOpacity; private CoreDispatcher _dispatcher; private int _nextTerminalId; private TerminalViewModel _selectedTerminal; private string _title; public MainViewModel(ISettingsService settingsService, ITrayProcessCommunicationService trayProcessCommunicationService, IDialogService dialogService, IKeyboardCommandService keyboardCommandService) { _settingsService = settingsService; _settingsService.CurrentThemeChanged += OnCurrentThemeChanged; _settingsService.ApplicationSettingsChanged += OnApplicationSettingsChanged; _trayProcessCommunicationService = trayProcessCommunicationService; _dialogService = dialogService; _keyboardCommandService = keyboardCommandService; _keyboardCommandService.RegisterCommandHandler(Command.NewTab, () => AddTerminal(null)); _keyboardCommandService.RegisterCommandHandler(Command.CloseTab, CloseCurrentTab); _keyboardCommandService.RegisterCommandHandler(Command.NextTab, SelectNextTab); _keyboardCommandService.RegisterCommandHandler(Command.PreviousTab, SelectPreviousTab); _keyboardCommandService.RegisterCommandHandler(Command.NewWindow, async () => await NewWindow()); _keyboardCommandService.RegisterCommandHandler(Command.ShowSettings, async () => await ShowSettings()); var currentTheme = _settingsService.GetCurrentTheme(); Background = currentTheme.Colors.Background; BackgroundOpacity = currentTheme.BackgroundOpacity; _applicationSettings = _settingsService.GetApplicationSettings(); AddTerminalCommand = new RelayCommand(() => AddTerminal(null)); ShowSettingsCommand = new RelayCommand(async () => await ShowSettings()); Terminals.CollectionChanged += OnTerminalsCollectionChanged; Title = "Fluent Terminal"; _dispatcher = CoreApplication.GetCurrentView().Dispatcher; SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += OnCloseRequest; } public RelayCommand AddTerminalCommand { get; } public string Background { get => _background; set => Set(ref _background, value); } public double BackgroundOpacity { get => _backgroundOpacity; set => Set(ref _backgroundOpacity, value); } public TerminalViewModel SelectedTerminal { get => _selectedTerminal; set { if (Set(ref _selectedTerminal, value)) { SelectedTerminal?.FocusTerminal(); } } } public RelayCommand ShowSettingsCommand { get; } public ObservableCollection Terminals { get; } = new ObservableCollection(); public string Title { get => _title; set => Set(ref _title, value); } public Task AddTerminal(string startupDirectory) { return _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var terminal = new TerminalViewModel(GetNextTerminalId(), _settingsService, _trayProcessCommunicationService, _dialogService, _keyboardCommandService, _applicationSettings, startupDirectory); terminal.CloseRequested += OnTerminalCloseRequested; terminal.TitleChanged += OnTitleChanged; Terminals.Add(terminal); SelectedTerminal = terminal; }).AsTask(); } public void CloseAllTerminals() { foreach (var terminal in Terminals) { terminal.CloseView(); } } private void CloseCurrentTab() { SelectedTerminal?.CloseCommand.Execute(null); } private int GetNextTerminalId() { return _nextTerminalId++; } private Task NewWindow() { return App.Instance.CreateNewTerminalWindow(string.Empty); } private async void OnApplicationSettingsChanged(object sender, EventArgs e) { await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => { _applicationSettings = _settingsService.GetApplicationSettings(); }); } private async void OnCloseRequest(object sender, SystemNavigationCloseRequestedPreviewEventArgs e) { var deferral = e.GetDeferral(); if (_applicationSettings.ConfirmClosingWindows) { var result = await _dialogService.ShowDialogAsnyc("Please confirm", "Are you sure you want to close this window?", DialogButton.OK, DialogButton.Cancel); if (result == DialogButton.OK) { CloseAllTerminals(); App.Instance.TerminalWindowClosed(this); } else { e.Handled = true; } } else { CloseAllTerminals(); App.Instance.TerminalWindowClosed(this); } deferral.Complete(); } private async void OnCurrentThemeChanged(object sender, System.EventArgs e) { await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var currentTheme = _settingsService.GetCurrentTheme(); Background = currentTheme.Colors.Background; BackgroundOpacity = currentTheme.BackgroundOpacity; }); } private void OnTerminalCloseRequested(object sender, EventArgs e) { if (Terminals.Count == 1) { return; } if (sender is TerminalViewModel terminal) { terminal.CloseView(); if (SelectedTerminal == terminal) { SelectedTerminal = Terminals.LastOrDefault(t => t != terminal); } Terminals.Remove(terminal); } } private void OnTerminalsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { if (Terminals.Any()) { Title = Terminals.First().Title; } } private void OnTitleChanged(object sender, string e) { if (sender is TerminalViewModel terminal && Terminals.First() == terminal) { Title = e; } } private void SelectNextTab() { var currentIndex = Terminals.IndexOf(SelectedTerminal); var nextIndex = (currentIndex + 1) % Terminals.Count; SelectedTerminal = Terminals[nextIndex]; } private void SelectPreviousTab() { var currentIndex = Terminals.IndexOf(SelectedTerminal); var previousIndex = (currentIndex - 1 + Terminals.Count) % Terminals.Count; SelectedTerminal = Terminals[previousIndex]; } private Task ShowSettings() { return App.Instance.ShowSettings(); } } }