Compare commits

...
10 Commits
56 changed files with 2517 additions and 789 deletions

No files matched your search

+1 -2
View File
@@ -1,6 +1,6 @@
# Project specific
FluentTerminal.App/Win32
FluentTerminal.SystemTray/Client
FluentTerminal.App/Client/
FluentTerminal.Client/dist
## Ignore Visual Studio temporary files, build results, and
@@ -291,4 +291,3 @@ __pycache__/
*.btm.cs
*.odx.cs
*.xsd.cs
FluentTerminal.Client/dist/bundle.js
+21 -1
View File
@@ -1,12 +1,32 @@
<Application
x:Class="FluentTerminal.App.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:FluentTerminal.App.Converters">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles\Custom.xaml" />
</ResourceDictionary.MergedDictionaries>
<converters:IntToVisibilityConverter
x:Key="OneToVisibleConverter"
Else="Collapsed"
If="1"
Then="Visible" />
<converters:IntToVisibilityConverter
x:Key="OneToCollapsedConverter"
Else="Visible"
If="1"
Then="Collapsed" />
<converters:NegateConverter x:Key="NegateConverter" />
<converters:FalseToVisibleConverter x:Key="FalseToVisibleConverter" />
<converters:TrueToVisibleConverter x:Key="TrueToVisibleConverter" />
<converters:IntToVisibilityConverter
x:Key="ZeroToCollapsedConverter"
Else="Visible"
If="0"
Then="Collapsed" />
<converters:IntToExtendedVirtualKeyConverter x:Key="IntToExtendedVirtualKeyConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>
+56 -23
View File
@@ -3,8 +3,12 @@ using FluentTerminal.App.Services;
using FluentTerminal.App.Services.Implementation;
using FluentTerminal.App.ViewModels;
using FluentTerminal.App.Views;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
@@ -26,31 +30,44 @@ namespace FluentTerminal.App
public static App Instance;
private bool _alreadyLaunched;
private IContainer _container;
private int _openTerminalWindows;
private int? _settingsWindowId;
private readonly ISettingsService _settingsService;
private ApplicationSettings _applicationSettings;
private List<MainViewModel> _mainViewModels;
public App()
{
_mainViewModels = new List<MainViewModel>();
InitializeComponent();
Instance = this;
var builder = new ContainerBuilder();
builder.RegisterType<SettingsService>().As<ISettingsService>().SingleInstance();
builder.RegisterType<DefaultValueProvider>().As<IDefaultValueProvider>().SingleInstance();
builder.RegisterType<TerminalService>().As<ITerminalService>().SingleInstance();
builder.RegisterType<TrayProcessCommunicationService>().As<ITrayProcessCommunicationService>().SingleInstance();
builder.RegisterType<DialogService>().As<IDialogService>().SingleInstance();
builder.RegisterType<KeyboardCommandService>().As<IKeyboardCommandService>().InstancePerDependency();
builder.RegisterType<MainViewModel>().InstancePerDependency();
builder.RegisterType<SettingsViewModel>().InstancePerDependency();
_container = builder.Build();
_settingsService = _container.Resolve<ISettingsService>();
_settingsService.ApplicationSettingsChanged += OnApplicationSettingsChanged;
_applicationSettings = _settingsService.GetApplicationSettings();
}
private void OnApplicationSettingsChanged(object sender, EventArgs e)
{
_applicationSettings = _settingsService.GetApplicationSettings();
}
public async Task CreateNewTerminalWindow(string startupDirectory)
{
var viewModel = _container.Resolve<MainViewModel>();
viewModel.AddTerminal(startupDirectory);
var id = await CreateSecondaryView(typeof(MainPage), viewModel, true);
var id = await CreateSecondaryView<MainViewModel>(typeof(MainPage), true, startupDirectory);
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(id);
}
@@ -63,15 +80,14 @@ namespace FluentTerminal.App
{
if (_settingsWindowId == null)
{
var viewModel = _container.Resolve<SettingsViewModel>();
_settingsWindowId = await CreateSecondaryView(typeof(SettingsPage), viewModel, true);
_settingsWindowId = await CreateSecondaryView<SettingsViewModel>(typeof(SettingsPage), true, null);
}
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(_settingsWindowId.Value);
}
public void TerminalWindowClosed()
public void TerminalWindowClosed(MainViewModel viewModel)
{
_openTerminalWindows--;
_mainViewModels.Remove(viewModel);
}
protected override async void OnActivated(IActivatedEventArgs args)
@@ -95,7 +111,15 @@ namespace FluentTerminal.App
}
else if (command == "new")
{
await CreateNewTerminalWindow(parameter);
if (_applicationSettings.NewTerminalLocation == NewTerminalLocation.Tab && _mainViewModels.Any())
{
await _mainViewModels.Last().AddTerminal(parameter);
}
else
{
await CreateNewTerminalWindow(parameter);
}
}
}
else
@@ -107,9 +131,16 @@ namespace FluentTerminal.App
}
else if (command == "new")
{
var viewModel = _container.Resolve<MainViewModel>();
viewModel.AddTerminal(parameter);
await CreateMainView(typeof(MainPage), viewModel, true);
if (_applicationSettings.NewTerminalLocation == NewTerminalLocation.Tab && _mainViewModels.Any())
{
await _mainViewModels.Last().AddTerminal(parameter);
}
else
{
var viewModel = _container.Resolve<MainViewModel>();
await viewModel.AddTerminal(parameter);
await CreateMainView(typeof(MainPage), viewModel, true);
}
}
}
}
@@ -132,15 +163,13 @@ namespace FluentTerminal.App
if (!_alreadyLaunched)
{
var viewModel = _container.Resolve<MainViewModel>();
viewModel.AddTerminal(null);
await viewModel.AddTerminal(null);
await CreateMainView(typeof(MainPage), viewModel, true);
Window.Current.Activate();
}
else if (_openTerminalWindows == 0)
else if (_mainViewModels.Any() == false)
{
var viewModel = _container.Resolve<MainViewModel>();
viewModel.AddTerminal(null);
await CreateSecondaryView(typeof(MainPage), viewModel, true);
await CreateSecondaryView<MainViewModel>(typeof(MainPage), true, string.Empty);
}
}
@@ -161,9 +190,9 @@ namespace FluentTerminal.App
{
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = extendViewIntoTitleBar;
if (pageType == typeof(MainPage))
if (viewModel is MainViewModel mainViewModel)
{
_openTerminalWindows++;
_mainViewModels.Add(mainViewModel);
}
rootFrame.Navigate(pageType, viewModel);
@@ -172,11 +201,14 @@ namespace FluentTerminal.App
Window.Current.Activate();
}
private async Task<int> CreateSecondaryView(Type pageType, INotifyPropertyChanged viewModel, bool ExtendViewIntoTitleBar)
private async Task<int> CreateSecondaryView<TViewModel>(Type pageType, bool ExtendViewIntoTitleBar, object parameter)
{
int windowId = 0;
TViewModel viewModel = default;
await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
viewModel = _container.Resolve<TViewModel>();
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = ExtendViewIntoTitleBar;
var frame = new Frame();
frame.Navigate(pageType, viewModel);
@@ -186,9 +218,10 @@ namespace FluentTerminal.App
windowId = ApplicationView.GetForCurrentView().Id;
});
if (pageType == typeof(MainPage))
if (viewModel is MainViewModel mainViewModel && parameter is string directory)
{
_openTerminalWindows++;
_mainViewModels.Add(mainViewModel);
await mainViewModel.AddTerminal(directory);
}
return windowId;
@@ -0,0 +1,23 @@
using FluentTerminal.Models.Enums;
using System;
using Windows.UI.Xaml.Data;
namespace FluentTerminal.App.Converters
{
public class IntToExtendedVirtualKeyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is int intValue)
{
return ((ExtendedVirtualKey)intValue).ToString();
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}
+89 -62
View File
@@ -45,6 +45,7 @@
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
<LangVersion>7.1</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols>
@@ -79,6 +80,7 @@
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<LangVersion>7.1</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
@@ -91,6 +93,7 @@
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
<LangVersion>7.1</LangVersion>
</PropertyGroup>
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
@@ -101,6 +104,7 @@
</Compile>
<Compile Include="Behaviors\MiddleClickBehavior.cs" />
<Compile Include="Converters\FalseToVisibleConverter.cs" />
<Compile Include="Converters\IntToExtendedVirtualKeyConverter.cs" />
<Compile Include="Converters\IntToVisibilityConverter.cs" />
<Compile Include="Converters\NegateConverter.cs" />
<Compile Include="Converters\TerminalViewModelToViewConverter.cs" />
@@ -113,22 +117,35 @@
<Compile Include="Services\IDefaultValueProvider.cs" />
<Compile Include="Services\Implementation\DefaultValueProvider.cs" />
<Compile Include="Services\Implementation\SettingsService.cs" />
<Compile Include="Services\Implementation\TerminalService.cs" />
<Compile Include="Services\Implementation\TrayProcessCommunicationService.cs" />
<Compile Include="Services\ISettingsService.cs" />
<Compile Include="Services\ITerminalService.cs" />
<Compile Include="Services\ITrayProcessCommunicationService.cs" />
<Compile Include="Utilities\ColorExtensions.cs" />
<Compile Include="Utilities\HttpJsonContent.cs" />
<Compile Include="Utilities\IHttpContentExtensions.cs" />
<Compile Include="ViewModels\MainViewModel.cs" />
<Compile Include="ViewModels\SettingsViewModel.cs" />
<Compile Include="ViewModels\Settings\GeneralPageViewModel.cs" />
<Compile Include="ViewModels\Settings\KeyBindingsPageViewModel.cs" />
<Compile Include="ViewModels\Settings\KeyBindingsViewModel.cs" />
<Compile Include="ViewModels\Settings\KeyBindingViewModel.cs" />
<Compile Include="ViewModels\Settings\ShellPageViewModel.cs" />
<Compile Include="ViewModels\Settings\TerminalPageViewModel.cs" />
<Compile Include="ViewModels\Settings\ThemesPageViewModel.cs" />
<Compile Include="ViewModels\ThemeViewModel.cs" />
<Compile Include="ViewModels\TerminalViewModel.cs" />
<Compile Include="Views\BindableColorsTitleBar.cs" />
<Compile Include="Views\ITerminalView.cs" />
<Compile Include="Views\KeyBindingsView.xaml.cs">
<DependentUpon>KeyBindingsView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\MainPage.xaml.cs">
<DependentUpon>MainPage.xaml</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Views\CreateKeyBindingDialog.xaml.cs">
<DependentUpon>CreateKeyBindingDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Views\SettingsPage.xaml.cs">
<DependentUpon>SettingsPage.xaml</DependentUpon>
</Compile>
@@ -159,75 +176,17 @@
<SubType>Designer</SubType>
</AppxManifest>
<Content Include="Assets\settingsicons.ttf" />
<None Include="FluentTerminal.App_StoreKey.pfx" />
<None Include="FluentTerminal.App_TemporaryKey.pfx" />
<Content Include="Win32\FluentTerminal.Models.dll" />
<Content Include="Win32\FluentTerminal.Models.pdb" />
<Content Include="Win32\FluentTerminal.SystemTray.exe.config" />
</ItemGroup>
<ItemGroup>
<Content Include="Assets\AppIcons\LargeTile.scale-100.png" />
<Content Include="Assets\AppIcons\LargeTile.scale-125.png" />
<Content Include="Assets\AppIcons\LargeTile.scale-150.png" />
<Content Include="Assets\AppIcons\LargeTile.scale-200.png" />
<Content Include="Assets\AppIcons\LargeTile.scale-400.png" />
<Content Include="Assets\AppIcons\SmallTile.scale-100.png" />
<Content Include="Assets\AppIcons\SmallTile.scale-125.png" />
<Content Include="Assets\AppIcons\SmallTile.scale-150.png" />
<Content Include="Assets\AppIcons\SmallTile.scale-200.png" />
<Content Include="Assets\AppIcons\SmallTile.scale-400.png" />
<Content Include="Assets\AppIcons\SplashScreen.scale-100.png" />
<Content Include="Assets\AppIcons\SplashScreen.scale-125.png" />
<Content Include="Assets\AppIcons\SplashScreen.scale-150.png" />
<Content Include="Assets\AppIcons\SplashScreen.scale-200.png" />
<Content Include="Assets\AppIcons\SplashScreen.scale-400.png" />
<Content Include="Assets\AppIcons\Square150x150Logo.scale-100.png" />
<Content Include="Assets\AppIcons\Square150x150Logo.scale-125.png" />
<Content Include="Assets\AppIcons\Square150x150Logo.scale-150.png" />
<Content Include="Assets\AppIcons\Square150x150Logo.scale-200.png" />
<Content Include="Assets\AppIcons\Square150x150Logo.scale-400.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.altform-unplated_targetsize-16.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.altform-unplated_targetsize-24.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.altform-unplated_targetsize-256.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.altform-unplated_targetsize-32.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.altform-unplated_targetsize-48.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.scale-100.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.scale-125.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.scale-150.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.scale-200.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.scale-400.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.targetsize-16.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.targetsize-24.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.targetsize-256.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.targetsize-32.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.targetsize-48.png" />
<Content Include="Assets\AppIcons\StoreLogo.scale-100.png" />
<Content Include="Assets\AppIcons\StoreLogo.scale-125.png" />
<Content Include="Assets\AppIcons\StoreLogo.scale-150.png" />
<Content Include="Assets\AppIcons\StoreLogo.scale-200.png" />
<Content Include="Assets\AppIcons\StoreLogo.scale-400.png" />
<Content Include="Assets\AppIcons\Wide310x150Logo.scale-100.png" />
<Content Include="Assets\AppIcons\Wide310x150Logo.scale-125.png" />
<Content Include="Assets\AppIcons\Wide310x150Logo.scale-150.png" />
<Content Include="Assets\AppIcons\Wide310x150Logo.scale-200.png" />
<Content Include="Assets\AppIcons\Wide310x150Logo.scale-400.png" />
<None Include="Package.StoreAssociation.xml" />
<Content Include="Properties\Default.rd.xml" />
<Content Include="Win32\Client\bundle.js" />
<Content Include="Win32\Client\index.html" />
<Content Include="Win32\Client\style.css" />
<Content Include="Win32\Client\xterm.css" />
<Content Include="Win32\CommonServiceLocator.dll" />
<Content Include="Win32\CommonServiceLocator.pdb" />
<Content Include="Win32\Fleck.dll" />
<Content Include="Win32\FluentTerminal.Models.dll" />
<Content Include="Win32\FluentTerminal.Models.pdb" />
<Content Include="Win32\FluentTerminal.SystemTray.exe" />
<Content Include="Win32\FluentTerminal.SystemTray.pdb" />
<Content Include="Win32\GlobalHotKey.dll" />
<Content Include="Win32\Microsoft.Owin.dll" />
<Content Include="Win32\Microsoft.Owin.FileSystems.dll" />
<Content Include="Win32\Microsoft.Owin.Host.HttpListener.dll" />
<Content Include="Win32\Microsoft.Owin.Hosting.dll" />
<Content Include="Win32\Microsoft.Owin.StaticFiles.dll" />
<Content Include="Win32\Microsoft.Win32.Primitives.dll" />
<Content Include="Win32\netstandard.dll" />
<Content Include="Win32\Newtonsoft.Json.dll" />
@@ -348,12 +307,72 @@
<Content Include="Win32\winpty-debugserver.exe" />
<Content Include="Win32\winpty.dll" />
<Content Include="Win32\winpty.NET.dll" />
<None Include="FluentTerminal.App_StoreKey.pfx" />
<None Include="FluentTerminal.App_TemporaryKey.pfx" />
<Content Include="Client\bundle.js" />
<Content Include="Client\index.html" />
<Content Include="Client\style.css" />
<Content Include="Client\xterm.css" />
<Content Include="Win32\FluentTerminal.SystemTray.exe.config" />
</ItemGroup>
<ItemGroup>
<Content Include="Assets\AppIcons\LargeTile.scale-100.png" />
<Content Include="Assets\AppIcons\LargeTile.scale-125.png" />
<Content Include="Assets\AppIcons\LargeTile.scale-150.png" />
<Content Include="Assets\AppIcons\LargeTile.scale-200.png" />
<Content Include="Assets\AppIcons\LargeTile.scale-400.png" />
<Content Include="Assets\AppIcons\SmallTile.scale-100.png" />
<Content Include="Assets\AppIcons\SmallTile.scale-125.png" />
<Content Include="Assets\AppIcons\SmallTile.scale-150.png" />
<Content Include="Assets\AppIcons\SmallTile.scale-200.png" />
<Content Include="Assets\AppIcons\SmallTile.scale-400.png" />
<Content Include="Assets\AppIcons\SplashScreen.scale-100.png" />
<Content Include="Assets\AppIcons\SplashScreen.scale-125.png" />
<Content Include="Assets\AppIcons\SplashScreen.scale-150.png" />
<Content Include="Assets\AppIcons\SplashScreen.scale-200.png" />
<Content Include="Assets\AppIcons\SplashScreen.scale-400.png" />
<Content Include="Assets\AppIcons\Square150x150Logo.scale-100.png" />
<Content Include="Assets\AppIcons\Square150x150Logo.scale-125.png" />
<Content Include="Assets\AppIcons\Square150x150Logo.scale-150.png" />
<Content Include="Assets\AppIcons\Square150x150Logo.scale-200.png" />
<Content Include="Assets\AppIcons\Square150x150Logo.scale-400.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.altform-unplated_targetsize-16.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.altform-unplated_targetsize-24.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.altform-unplated_targetsize-256.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.altform-unplated_targetsize-32.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.altform-unplated_targetsize-48.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.scale-100.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.scale-125.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.scale-150.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.scale-200.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.scale-400.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.targetsize-16.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.targetsize-24.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.targetsize-256.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.targetsize-32.png" />
<Content Include="Assets\AppIcons\Square44x44Logo.targetsize-48.png" />
<Content Include="Assets\AppIcons\StoreLogo.scale-100.png" />
<Content Include="Assets\AppIcons\StoreLogo.scale-125.png" />
<Content Include="Assets\AppIcons\StoreLogo.scale-150.png" />
<Content Include="Assets\AppIcons\StoreLogo.scale-200.png" />
<Content Include="Assets\AppIcons\StoreLogo.scale-400.png" />
<Content Include="Assets\AppIcons\Wide310x150Logo.scale-100.png" />
<Content Include="Assets\AppIcons\Wide310x150Logo.scale-125.png" />
<Content Include="Assets\AppIcons\Wide310x150Logo.scale-150.png" />
<Content Include="Assets\AppIcons\Wide310x150Logo.scale-200.png" />
<Content Include="Assets\AppIcons\Wide310x150Logo.scale-400.png" />
<None Include="Package.StoreAssociation.xml" />
<Content Include="Properties\Default.rd.xml" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="Views\KeyBindingsView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\MainPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -363,6 +382,10 @@
<Generator>MSBuild:Compile</Generator>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Page>
<Page Include="Views\CreateKeyBindingDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\SettingsPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -437,6 +460,7 @@
<Name>FluentTerminal.RuntimeComponent</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
@@ -445,6 +469,9 @@
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PreBuildEvent>xcopy /y "$(SolutionDir)FluentTerminal.Client\dist" "$(ProjectDir)Client"</PreBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" IgnorableNamespaces="uap mp desktop rescap">
<Identity Name="53621FSApps.FluentTerminal" Publisher="CN=BDC72197-B634-438A-B863-16DCB7D90C85" Version="0.1.6.0" />
<Identity Name="53621FSApps.FluentTerminal" Publisher="CN=BDC72197-B634-438A-B863-16DCB7D90C85" Version="0.1.7.0" />
<mp:PhoneIdentity PhoneProductId="f7225014-f405-4342-ad2e-ebf6ac60ea2c" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>Fluent Terminal</DisplayName>
@@ -8,7 +8,7 @@ namespace FluentTerminal.App.Services
{
ShellConfiguration GetDefaultShellConfiguration();
TerminalOptions GetDefaultTerminalOptions();
IEnumerable<KeyBinding> GetDefaultKeyBindings();
KeyBindings GetDefaultKeyBindings();
ApplicationSettings GetDefaultApplicationSettings();
Guid GetDefaultThemeId();
IEnumerable<TerminalTheme> GetPreInstalledThemes();
@@ -9,6 +9,7 @@ namespace FluentTerminal.App.Services
event EventHandler CurrentThemeChanged;
event EventHandler TerminalOptionsChanged;
event EventHandler ApplicationSettingsChanged;
event EventHandler KeyBindingsChanged;
ShellConfiguration GetShellConfiguration();
void SaveShellConfiguration(ShellConfiguration shellConfiguration);
@@ -19,7 +20,8 @@ namespace FluentTerminal.App.Services
ApplicationSettings GetApplicationSettings();
void SaveApplicationSettings(ApplicationSettings applicationSettings);
IEnumerable<KeyBinding> GetKeyBindings();
KeyBindings GetKeyBindings();
void SaveKeyBindings(KeyBindings keyBindings);
TerminalTheme GetCurrentTheme();
Guid GetCurrentThemeId();
@@ -3,9 +3,10 @@ using System.Threading.Tasks;
namespace FluentTerminal.App.Services
{
public interface ITerminalService
public interface ITrayProcessCommunicationService
{
Task<CreateTerminalResponse> CreateTerminal(TerminalSize size, ShellConfiguration shellConfiguration);
Task ResizeTerminal(int id, TerminalSize size);
Task UpdateToggleWindowKeyBindings();
}
}
@@ -8,6 +8,114 @@ namespace FluentTerminal.App.Services.Implementation
{
internal class DefaultValueProvider : IDefaultValueProvider
{
public ApplicationSettings GetDefaultApplicationSettings()
{
return new ApplicationSettings
{
ConfirmClosingTabs = false,
ConfirmClosingWindows = false,
NewTerminalLocation = NewTerminalLocation.Tab
};
}
public KeyBindings GetDefaultKeyBindings()
{
return new KeyBindings
{
NewTab = new[]
{
new KeyBinding
{
Command = Command.NewTab,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.T
}
},
CloseTab = new[] {
new KeyBinding
{
Command = Command.CloseTab,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.W
}
},
NextTab = new[] {
new KeyBinding
{
Command = Command.NextTab,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.Tab
}
},
PreviousTab = new[] {
new KeyBinding
{
Command = Command.PreviousTab,
Ctrl = true,
Alt = false,
Shift = true,
Key = (int)VirtualKey.Tab
}
},
NewWindow = new[] {
new KeyBinding
{
Command = Command.NewWindow,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.N
}
},
ShowSettings = new[] {
new KeyBinding
{
Command = Command.ShowSettings,
Ctrl = true,
Alt = false,
Shift = false,
Key = 188 // comma
}
},
Copy = new[] {
new KeyBinding
{
Command = Command.Copy,
Ctrl = true,
Alt = false,
Shift = true,
Key = (int)VirtualKey.C
}
},
Paste = new[] {
new KeyBinding
{
Command = Command.Paste,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.V
}
},
ToggleWindow = new[] {
new KeyBinding
{
Command = Command.ToggleWindow,
Ctrl = false,
Alt = false,
Shift = false,
Key = (int)VirtualKey.Scroll
}
}
};
}
public ShellConfiguration GetDefaultShellConfiguration()
{
return new ShellConfiguration
@@ -106,93 +214,5 @@ namespace FluentTerminal.App.Services.Implementation
return new[] { defaultXterm, powerShell };
}
public IEnumerable<KeyBinding> GetDefaultKeyBindings()
{
return new[]
{
new KeyBinding
{
Command = Command.NewTab,
Ctrl = true,
Alt = false,
Meta = false,
Shift = false,
Key = (int)VirtualKey.T
},
new KeyBinding
{
Command = Command.CloseTab,
Ctrl = true,
Alt = false,
Meta = false,
Shift = false,
Key = (int)VirtualKey.W
},
new KeyBinding
{
Command = Command.NextTab,
Ctrl = true,
Alt = false,
Meta = false,
Shift = false,
Key = (int)VirtualKey.Tab
},
new KeyBinding
{
Command = Command.PreviousTab,
Ctrl = true,
Alt = false,
Meta = false,
Shift = true,
Key = (int)VirtualKey.Tab
},
new KeyBinding
{
Command = Command.NewWindow,
Ctrl = true,
Alt = false,
Meta = false,
Shift = false,
Key = (int)VirtualKey.N
},
new KeyBinding
{
Command = Command.ShowSettings,
Ctrl = true,
Alt = false,
Meta = false,
Shift = false,
Key = 188 // comma
},
new KeyBinding
{
Command = Command.Copy,
Ctrl = true,
Alt = false,
Meta = false,
Shift = true,
Key = (int)VirtualKey.C
},
new KeyBinding
{
Command = Command.Paste,
Ctrl = true,
Alt = false,
Meta = false,
Shift = false,
Key = (int)VirtualKey.V
}
};
}
public ApplicationSettings GetDefaultApplicationSettings()
{
return new ApplicationSettings
{
ConfirmClosingTabs = false,
ConfirmClosingWindows = false
};
}
}
}
}
@@ -18,6 +18,7 @@ namespace FluentTerminal.App.Services.Implementation
public event EventHandler CurrentThemeChanged;
public event EventHandler TerminalOptionsChanged;
public event EventHandler ApplicationSettingsChanged;
public event EventHandler KeyBindingsChanged;
public SettingsService(IDefaultValueProvider defaultValueProvider)
{
@@ -119,9 +120,15 @@ namespace FluentTerminal.App.Services.Implementation
ApplicationSettingsChanged?.Invoke(this, EventArgs.Empty);
}
public IEnumerable<KeyBinding> GetKeyBindings()
public KeyBindings GetKeyBindings()
{
return _roamingSettings.ReadValueFromJson("KeyBindings", _defaultValueProvider.GetDefaultKeyBindings());
return _roamingSettings.ReadValueFromJson(nameof(KeyBindings), _defaultValueProvider.GetDefaultKeyBindings());
}
public void SaveKeyBindings(KeyBindings keyBindings)
{
_roamingSettings.WriteValueAsJson(nameof(KeyBindings), keyBindings);
KeyBindingsChanged?.Invoke(this, EventArgs.Empty);
}
}
}
@@ -6,13 +6,23 @@ using Windows.Web.Http;
namespace FluentTerminal.App.Services.Implementation
{
internal class TerminalService : ITerminalService
internal class TrayProcessCommunicationService : ITrayProcessCommunicationService
{
private readonly HttpClient _httpClient;
private readonly ISettingsService _settingsService;
public TerminalService()
public TrayProcessCommunicationService(ISettingsService settingsService)
{
_httpClient = new HttpClient();
_settingsService = settingsService;
UpdateToggleWindowKeyBindings();
}
public Task UpdateToggleWindowKeyBindings()
{
var keyBindings = _settingsService.GetKeyBindings().ToggleWindow;
return _httpClient.PostAsync(new Uri($"http://localhost:9000/keybindings/togglewindow"), HttpJsonContent.From(keyBindings)).AsTask();
}
public async Task<CreateTerminalResponse> CreateTerminal(TerminalSize size, ShellConfiguration shellConfiguration)
+42 -11
View File
@@ -18,20 +18,21 @@ namespace FluentTerminal.App.ViewModels
private readonly IDialogService _dialogService;
private readonly IKeyboardCommandService _keyboardCommandService;
private readonly ISettingsService _settingsService;
private readonly ITerminalService _terminalService;
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, ITerminalService terminalService, IDialogService dialogService, IKeyboardCommandService keyboardCommandService)
public MainViewModel(ISettingsService settingsService, ITrayProcessCommunicationService trayProcessCommunicationService, IDialogService dialogService, IKeyboardCommandService keyboardCommandService)
{
_settingsService = settingsService;
_settingsService.CurrentThemeChanged += OnCurrentThemeChanged;
_settingsService.ApplicationSettingsChanged += OnApplicationSettingsChanged;
_terminalService = terminalService;
_trayProcessCommunicationService = trayProcessCommunicationService;
_dialogService = dialogService;
_keyboardCommandService = keyboardCommandService;
_keyboardCommandService.RegisterCommandHandler(Command.NewTab, () => AddTerminal(null));
@@ -48,6 +49,10 @@ namespace FluentTerminal.App.ViewModels
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;
}
@@ -82,13 +87,23 @@ namespace FluentTerminal.App.ViewModels
public ObservableCollection<TerminalViewModel> Terminals { get; } = new ObservableCollection<TerminalViewModel>();
public void AddTerminal(string startupDirectory)
public string Title
{
var terminal = new TerminalViewModel(GetNextTerminalId(), _settingsService, _terminalService, _dialogService, _keyboardCommandService, _applicationSettings, startupDirectory);
terminal.CloseRequested += OnTerminalCloseRequested;
Terminals.Add(terminal);
get => _title;
set => Set(ref _title, value);
}
SelectedTerminal = terminal;
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()
@@ -111,7 +126,7 @@ namespace FluentTerminal.App.ViewModels
private Task NewWindow()
{
return App.Instance.CreateNewTerminalWindow(null);
return App.Instance.CreateNewTerminalWindow(string.Empty);
}
private async void OnApplicationSettingsChanged(object sender, EventArgs e)
@@ -133,7 +148,7 @@ namespace FluentTerminal.App.ViewModels
if (result == DialogButton.OK)
{
CloseAllTerminals();
App.Instance.TerminalWindowClosed();
App.Instance.TerminalWindowClosed(this);
}
else
{
@@ -143,7 +158,7 @@ namespace FluentTerminal.App.ViewModels
else
{
CloseAllTerminals();
App.Instance.TerminalWindowClosed();
App.Instance.TerminalWindowClosed(this);
}
deferral.Complete();
}
@@ -176,6 +191,22 @@ namespace FluentTerminal.App.ViewModels
}
}
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);
@@ -0,0 +1,101 @@
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Threading.Tasks;
namespace FluentTerminal.App.ViewModels.Settings
{
public class GeneralPageViewModel : ViewModelBase
{
private readonly IDefaultValueProvider _defaultValueProvider;
private readonly IDialogService _dialogService;
private readonly ISettingsService _settingsService;
private ApplicationSettings _applicationSettings;
private bool _editingNewTerminalLocation;
public GeneralPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider)
{
_settingsService = settingsService;
_dialogService = dialogService;
_defaultValueProvider = defaultValueProvider;
_applicationSettings = _settingsService.GetApplicationSettings();
RestoreDefaultsCommand = new RelayCommand(async () => await RestoreDefaults());
}
public bool ConfirmClosingTabs
{
get => _applicationSettings.ConfirmClosingTabs;
set
{
if (_applicationSettings.ConfirmClosingTabs != value)
{
_applicationSettings.ConfirmClosingTabs = value;
_settingsService.SaveApplicationSettings(_applicationSettings);
RaisePropertyChanged();
}
}
}
public bool ConfirmClosingWindows
{
get => _applicationSettings.ConfirmClosingWindows;
set
{
if (_applicationSettings.ConfirmClosingWindows != value)
{
_applicationSettings.ConfirmClosingWindows = value;
_settingsService.SaveApplicationSettings(_applicationSettings);
RaisePropertyChanged();
}
}
}
public NewTerminalLocation NewTerminalLocation
{
get => _applicationSettings.NewTerminalLocation;
set
{
if (_applicationSettings.NewTerminalLocation != value && !_editingNewTerminalLocation)
{
_editingNewTerminalLocation = true;
_applicationSettings.NewTerminalLocation = value;
_settingsService.SaveApplicationSettings(_applicationSettings);
RaisePropertyChanged();
RaisePropertyChanged(nameof(WindowIsSelected));
RaisePropertyChanged(nameof(TabIsSelected));
_editingNewTerminalLocation = false;
}
}
}
public RelayCommand RestoreDefaultsCommand { get; }
public bool TabIsSelected
{
get => NewTerminalLocation == NewTerminalLocation.Tab;
set => NewTerminalLocation = NewTerminalLocation.Tab;
}
public bool WindowIsSelected
{
get => NewTerminalLocation == NewTerminalLocation.Window;
set => NewTerminalLocation = NewTerminalLocation.Window;
}
private async Task RestoreDefaults()
{
var result = await _dialogService.ShowDialogAsnyc("Please confirm", "Are you sure you want to restore the general settings?", DialogButton.OK, DialogButton.Cancel);
if (result == DialogButton.OK)
{
var defaults = _defaultValueProvider.GetDefaultApplicationSettings();
ConfirmClosingWindows = defaults.ConfirmClosingWindows;
ConfirmClosingTabs = defaults.ConfirmClosingTabs;
NewTerminalLocation = defaults.NewTerminalLocation;
}
}
}
}
@@ -0,0 +1,115 @@
using FluentTerminal.App.Services;
using FluentTerminal.App.Views;
using FluentTerminal.Models;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
namespace FluentTerminal.App.ViewModels.Settings
{
public class KeyBindingViewModel : ViewModelBase
{
private readonly IDialogService _dialogService;
public KeyBindingViewModel(KeyBinding keyBinding, IDialogService dialogService)
{
Model = keyBinding;
_dialogService = dialogService;
EditCommand = new RelayCommand(async () => await Edit());
DeleteCommand = new RelayCommand(async () => await Delete());
}
public event EventHandler Deleted;
public event EventHandler Edited;
public bool Alt
{
get => Model.Alt;
set
{
if (Model.Alt != value)
{
Model.Alt = value;
RaisePropertyChanged();
}
}
}
public bool Ctrl
{
get => Model.Ctrl;
set
{
if (Model.Ctrl != value)
{
Model.Ctrl = value;
RaisePropertyChanged();
}
}
}
public RelayCommand DeleteCommand { get; }
public RelayCommand EditCommand { get; }
public int Key
{
get => Model.Key;
set
{
if (Model.Key != value)
{
Model.Key = value;
RaisePropertyChanged();
}
}
}
public KeyBinding Model { get; }
public bool Shift
{
get => Model.Shift;
set
{
if (Model.Shift != value)
{
Model.Shift = value;
RaisePropertyChanged();
}
}
}
public async Task<bool> Edit()
{
var dialog = new CreateKeyBindingDialog(_dialogService);
var result = await dialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
Alt = dialog.KeyBinding.Alt;
Ctrl = dialog.KeyBinding.Ctrl;
Shift = dialog.KeyBinding.Shift;
Key = dialog.KeyBinding.Key;
Edited?.Invoke(this, EventArgs.Empty);
return true;
}
return false;
}
private async Task Delete()
{
var result = await _dialogService.ShowDialogAsnyc("Please confirm", "Are you sure you want to delete this keybinding?", DialogButton.OK, DialogButton.Cancel);
if (result == DialogButton.OK)
{
Deleted?.Invoke(this, EventArgs.Empty);
}
}
}
}
@@ -0,0 +1,123 @@
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace FluentTerminal.App.ViewModels.Settings
{
public class KeyBindingsPageViewModel : ViewModelBase
{
private KeyBindings _keyBindings;
private readonly ISettingsService _settingsService;
private readonly IDialogService _dialogService;
private readonly IDefaultValueProvider _defaultValueProvider;
private readonly ITrayProcessCommunicationService _trayProcessCommunicationService;
public KeyBindingsPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider, ITrayProcessCommunicationService trayProcessCommunicationService)
{
_settingsService = settingsService;
_dialogService = dialogService;
_defaultValueProvider = defaultValueProvider;
_trayProcessCommunicationService = trayProcessCommunicationService;
RestoreDefaultsCommand = new RelayCommand(async () => await RestoreDefaults());
AddCommand = new RelayCommand<Command>(async command => await Add(command));
Initialize(_settingsService.GetKeyBindings());
}
private void Initialize(KeyBindings keyBindings)
{
_keyBindings = keyBindings;
_keyBindings.NewTab = new List<KeyBinding>(_keyBindings.NewTab);
NewTab = CreateViewModel(Command.NewTab, _keyBindings.NewTab);
ToggleWindow = CreateViewModel(Command.ToggleWindow, _keyBindings.ToggleWindow);
NextTab = CreateViewModel(Command.NextTab, _keyBindings.NextTab);
PreviousTab = CreateViewModel(Command.PreviousTab, _keyBindings.PreviousTab);
CloseTab = CreateViewModel(Command.CloseTab, _keyBindings.CloseTab);
NewWindow = CreateViewModel(Command.NewWindow, _keyBindings.NewWindow);
ShowSettings = CreateViewModel(Command.ShowSettings, _keyBindings.ShowSettings);
Copy = CreateViewModel(Command.Copy, _keyBindings.Copy);
Paste = CreateViewModel(Command.Paste, _keyBindings.Paste);
RaisePropertyChanged(nameof(NewTab));
RaisePropertyChanged(nameof(ToggleWindow));
RaisePropertyChanged(nameof(NextTab));
RaisePropertyChanged(nameof(PreviousTab));
RaisePropertyChanged(nameof(CloseTab));
RaisePropertyChanged(nameof(NewWindow));
RaisePropertyChanged(nameof(ShowSettings));
RaisePropertyChanged(nameof(Copy));
RaisePropertyChanged(nameof(Paste));
}
public KeyBindingsViewModel NewTab { get; private set; }
public KeyBindingsViewModel ToggleWindow { get; private set; }
public KeyBindingsViewModel NextTab { get; private set; }
public KeyBindingsViewModel PreviousTab { get; private set; }
public KeyBindingsViewModel CloseTab { get; private set; }
public KeyBindingsViewModel NewWindow { get; private set; }
public KeyBindingsViewModel ShowSettings { get; private set; }
public KeyBindingsViewModel Copy { get; private set; }
public KeyBindingsViewModel Paste { get; private set; }
public RelayCommand RestoreDefaultsCommand { get; }
public RelayCommand<Command> AddCommand { get; }
private Task Add(Command command)
{
switch (command)
{
case Command.ToggleWindow:
return ToggleWindow.Add();
case Command.NextTab:
return NextTab.Add();
case Command.PreviousTab:
return PreviousTab.Add();
case Command.NewTab:
return NewTab.Add();
case Command.CloseTab:
return CloseTab.Add();
case Command.NewWindow:
return NewWindow.Add();
case Command.ShowSettings:
return ShowSettings.Add();
case Command.Copy:
return Copy.Add();
case Command.Paste:
return Paste.Add();
}
return Task.CompletedTask;
}
private async Task RestoreDefaults()
{
var result = await _dialogService.ShowDialogAsnyc("Please confirm", "Are you sure you want to restore the default keybindings?", DialogButton.OK, DialogButton.Cancel);
if (result == DialogButton.OK)
{
Initialize(_defaultValueProvider.GetDefaultKeyBindings());
_settingsService.SaveKeyBindings(_keyBindings);
}
}
private KeyBindingsViewModel CreateViewModel(Command command, ICollection<KeyBinding> keyBindings)
{
var viewModel = new KeyBindingsViewModel(command, keyBindings, _dialogService);
viewModel.Edited += OnEdited;
return viewModel;
}
private void OnEdited(object sender, System.EventArgs e)
{
_settingsService.SaveKeyBindings(_keyBindings);
_trayProcessCommunicationService.UpdateToggleWindowKeyBindings();
}
}
}
@@ -0,0 +1,67 @@
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
namespace FluentTerminal.App.ViewModels.Settings
{
public class KeyBindingsViewModel : ViewModelBase
{
private readonly Command _command;
private readonly IDialogService _dialogService;
private ICollection<KeyBinding> _keyBindings;
public KeyBindingsViewModel(Command command, ICollection<KeyBinding> keyBindings, IDialogService dialogService)
{
_command = command;
_keyBindings = keyBindings;
_dialogService = dialogService;
foreach (var binding in keyBindings)
{
var viewModel = new KeyBindingViewModel(binding, _dialogService);
viewModel.Deleted += ViewModel_Deleted;
viewModel.Edited += ViewModel_Edited;
KeyBindings.Add(viewModel);
}
}
public event EventHandler Edited;
public ObservableCollection<KeyBindingViewModel> KeyBindings { get; } = new ObservableCollection<KeyBindingViewModel>();
public async Task Add()
{
var newKeyBinding = new KeyBindingViewModel(new KeyBinding { Command = _command }, _dialogService);
if (await newKeyBinding.Edit())
{
newKeyBinding.Deleted += ViewModel_Deleted;
newKeyBinding.Edited += ViewModel_Edited;
KeyBindings.Add(newKeyBinding);
_keyBindings.Add(newKeyBinding.Model);
Edited?.Invoke(this, EventArgs.Empty);
}
}
private void ViewModel_Deleted(object sender, EventArgs e)
{
if (sender is KeyBindingViewModel keyBinding)
{
_keyBindings.Remove(keyBinding.Model);
KeyBindings.Remove(keyBinding);
Edited?.Invoke(this, EventArgs.Empty);
}
}
private void ViewModel_Edited(object sender, EventArgs e)
{
Edited?.Invoke(this, EventArgs.Empty);
}
}
}
@@ -0,0 +1,158 @@
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Threading.Tasks;
using Windows.Storage.Pickers;
namespace FluentTerminal.App.ViewModels.Settings
{
public class ShellPageViewModel : ViewModelBase
{
private readonly IDefaultValueProvider _defaultValueProvider;
private readonly IDialogService _dialogService;
private readonly ISettingsService _settingsService;
private ShellConfiguration _shellConfiguration;
private bool _editingShellType;
public ShellPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider)
{
_settingsService = settingsService;
_dialogService = dialogService;
_defaultValueProvider = defaultValueProvider;
RestoreDefaultsCommand = new RelayCommand(async () => await RestoreDefaults());
BrowseForCustomShellCommand = new RelayCommand(async () => await BrowseForCustomShell());
BrowseForWorkingDirectoryCommand = new RelayCommand(async () => await BrowseForWorkingDirectory());
_shellConfiguration = _settingsService.GetShellConfiguration();
}
public string Arguments
{
get => _shellConfiguration.Arguments;
set
{
if (_shellConfiguration.Arguments != value)
{
_shellConfiguration.Arguments = value;
_settingsService.SaveShellConfiguration(_shellConfiguration);
RaisePropertyChanged();
}
}
}
public RelayCommand BrowseForCustomShellCommand { get; }
public RelayCommand BrowseForWorkingDirectoryCommand { get; }
public bool CMDIsSelected
{
get => ShellType == ShellType.CMD;
set => ShellType = ShellType.CMD;
}
public bool CustomShellIsSelected
{
get => ShellType == ShellType.Custom;
set => ShellType = ShellType.Custom;
}
public string CustomShellLocation
{
get => _shellConfiguration.CustomShellLocation;
set
{
if (_shellConfiguration.CustomShellLocation != value)
{
_shellConfiguration.CustomShellLocation = value;
_settingsService.SaveShellConfiguration(_shellConfiguration);
RaisePropertyChanged();
}
}
}
public bool PoweShellIsSelected
{
get => ShellType == ShellType.PowerShell;
set => ShellType = ShellType.PowerShell;
}
public RelayCommand RestoreDefaultsCommand { get; }
public ShellType ShellType
{
get => _shellConfiguration.Shell;
set
{
if (_shellConfiguration.Shell != value && !_editingShellType)
{
_editingShellType = true;
_shellConfiguration.Shell = value;
_settingsService.SaveShellConfiguration(_shellConfiguration);
RaisePropertyChanged();
RaisePropertyChanged(nameof(CustomShellIsSelected));
RaisePropertyChanged(nameof(PoweShellIsSelected));
RaisePropertyChanged(nameof(CMDIsSelected));
_editingShellType = false;
}
}
}
public string WorkingDirectory
{
get => _shellConfiguration.WorkingDirectory;
set
{
if (_shellConfiguration.WorkingDirectory != value)
{
_shellConfiguration.WorkingDirectory = value;
_settingsService.SaveShellConfiguration(_shellConfiguration);
RaisePropertyChanged();
}
}
}
private async Task BrowseForCustomShell()
{
var picker = new FileOpenPicker();
picker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
picker.FileTypeFilter.Add(".exe");
var file = await picker.PickSingleFileAsync().AsTask();
if (file != null)
{
CustomShellLocation = file.Path;
}
}
private async Task BrowseForWorkingDirectory()
{
var picker = new FolderPicker();
picker.FileTypeFilter.Add(".whatever"); // else a ComException is thrown
picker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
var folder = await picker.PickSingleFolderAsync();
if (folder != null)
{
WorkingDirectory = folder.Path;
}
}
private async Task RestoreDefaults()
{
var result = await _dialogService.ShowDialogAsnyc("Please confirm", "Are you sure you want to restore the default shell configuration?", DialogButton.OK, DialogButton.Cancel);
if (result == DialogButton.OK)
{
var defaults = _defaultValueProvider.GetDefaultShellConfiguration();
ShellType = defaults.Shell;
CustomShellLocation = defaults.CustomShellLocation;
WorkingDirectory = defaults.WorkingDirectory;
Arguments = defaults.Arguments;
}
}
}
}
@@ -0,0 +1,134 @@
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using Microsoft.Graphics.Canvas.Text;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FluentTerminal.App.ViewModels.Settings
{
public class TerminalPageViewModel : ViewModelBase
{
private TerminalOptions _terminalOptions;
private readonly ISettingsService _settingsService;
private readonly IDialogService _dialogService;
private readonly IDefaultValueProvider _defaultValueProvider;
private bool _isEditingCursorStyle;
public bool BarIsSelected
{
get => CursorStyle == CursorStyle.Bar;
set => CursorStyle = CursorStyle.Bar;
}
public bool BlockIsSelected
{
get => CursorStyle == CursorStyle.Block;
set => CursorStyle = CursorStyle.Block;
}
public bool CursorBlink
{
get => _terminalOptions.CursorBlink;
set
{
if (_terminalOptions.CursorBlink != value)
{
_terminalOptions.CursorBlink = value;
_settingsService.SaveTerminalOptions(_terminalOptions);
RaisePropertyChanged();
}
}
}
public string FontFamily
{
get => _terminalOptions.FontFamily;
set
{
if (_terminalOptions.FontFamily != value)
{
_terminalOptions.FontFamily = value;
_settingsService.SaveTerminalOptions(_terminalOptions);
RaisePropertyChanged();
}
}
}
public IEnumerable<string> Fonts { get; }
public int FontSize
{
get => _terminalOptions.FontSize;
set
{
if (_terminalOptions.FontSize != value)
{
_terminalOptions.FontSize = value;
_settingsService.SaveTerminalOptions(_terminalOptions);
RaisePropertyChanged();
}
}
}
public IEnumerable<int> Sizes { get; }
public bool UnderlineIsSelected
{
get => CursorStyle == CursorStyle.Underline;
set => CursorStyle = CursorStyle.Underline;
}
public RelayCommand RestoreDefaultsCommand { get; }
private CursorStyle CursorStyle
{
get => _terminalOptions.CursorStyle;
set
{
if (_terminalOptions.CursorStyle != value && !_isEditingCursorStyle)
{
_isEditingCursorStyle = true;
_terminalOptions.CursorStyle = value;
_settingsService.SaveTerminalOptions(_terminalOptions);
RaisePropertyChanged();
RaisePropertyChanged(nameof(BlockIsSelected));
RaisePropertyChanged(nameof(BarIsSelected));
RaisePropertyChanged(nameof(UnderlineIsSelected));
_isEditingCursorStyle = false;
}
}
}
private async Task RestoreDefaults()
{
var result = await _dialogService.ShowDialogAsnyc("Please confirm", "Are you sure you want to restore the default terminal options?", DialogButton.OK, DialogButton.Cancel);
if (result == DialogButton.OK)
{
var defaults = _defaultValueProvider.GetDefaultTerminalOptions();
CursorBlink = defaults.CursorBlink;
CursorStyle = defaults.CursorStyle;
FontFamily = defaults.FontFamily;
FontSize = defaults.FontSize;
}
}
public TerminalPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider)
{
_settingsService = settingsService;
_dialogService = dialogService;
_defaultValueProvider = defaultValueProvider;
RestoreDefaultsCommand = new RelayCommand(async () => await RestoreDefaults());
Fonts = CanvasTextFormat.GetSystemFontFamilies().OrderBy(s => s);
Sizes = Enumerable.Range(1, 72);
_terminalOptions = _settingsService.GetTerminalOptions();
}
}
}
@@ -0,0 +1,106 @@
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.ObjectModel;
using System.Linq;
namespace FluentTerminal.App.ViewModels.Settings
{
public class ThemesPageViewModel : ViewModelBase
{
private readonly IDefaultValueProvider _defaultValueProvider;
private readonly IDialogService _dialogService;
private readonly ISettingsService _settingsService;
private ThemeViewModel _selectedTheme;
public ThemesPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider)
{
_settingsService = settingsService;
_dialogService = dialogService;
_defaultValueProvider = defaultValueProvider;
CreateThemeCommand = new RelayCommand(CreateTheme);
var activeThemeId = _settingsService.GetCurrentThemeId();
foreach (var theme in _settingsService.GetThemes())
{
var viewModel = new ThemeViewModel(theme, _settingsService, _dialogService);
viewModel.Activated += OnThemeActivated;
viewModel.Deleted += OnThemeDeleted;
if (theme.Id == activeThemeId)
{
viewModel.IsActive = true;
}
Themes.Add(viewModel);
}
SelectedTheme = Themes.First(t => t.IsActive);
}
public RelayCommand CreateThemeCommand { get; set; }
public ThemeViewModel SelectedTheme
{
get => _selectedTheme;
set => Set(ref _selectedTheme, value);
}
public ObservableCollection<ThemeViewModel> Themes { get; } = new ObservableCollection<ThemeViewModel>();
private void CreateTheme()
{
var defaultTheme = _settingsService.GetTheme(_defaultValueProvider.GetDefaultThemeId());
var theme = new TerminalTheme
{
Id = Guid.NewGuid(),
PreInstalled = false,
Name = "New Theme",
BackgroundOpacity = defaultTheme.BackgroundOpacity,
Colors = new TerminalColors(defaultTheme.Colors)
};
_settingsService.SaveTheme(theme);
var viewModel = new ThemeViewModel(theme, _settingsService, _dialogService);
viewModel.Activated += OnThemeActivated;
viewModel.Deleted += OnThemeDeleted;
Themes.Add(viewModel);
SelectedTheme = viewModel;
}
private void OnThemeActivated(object sender, EventArgs e)
{
if (sender is ThemeViewModel activatedTheme)
{
_settingsService.SaveCurrentThemeId(activatedTheme.Id);
foreach (var theme in Themes)
{
theme.IsActive = theme.Id == activatedTheme.Id;
}
}
}
private void OnThemeDeleted(object sender, EventArgs e)
{
if (sender is ThemeViewModel theme)
{
if (SelectedTheme == theme)
{
SelectedTheme = Themes.First();
}
Themes.Remove(theme);
if (theme.IsActive)
{
Themes.First().IsActive = true;
_settingsService.SaveCurrentThemeId(Themes.First().Id);
}
_settingsService.DeleteTheme(theme.Id);
}
}
}
}
@@ -1,371 +1,24 @@
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using FluentTerminal.App.ViewModels.Settings;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using Microsoft.Graphics.Canvas.Text;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using Windows.Storage.Pickers;
namespace FluentTerminal.App.ViewModels
{
public class SettingsViewModel : ViewModelBase
{
private readonly IDefaultValueProvider _defaultValueProvider;
private readonly IDialogService _dialogService;
private readonly ISettingsService _settingsService;
private ApplicationSettings _applicationSettings;
private ThemeViewModel _selectedTheme;
private ShellConfiguration _shellConfiguration;
private TerminalOptions _terminalOptions;
public SettingsViewModel(ISettingsService settingsService, IDefaultValueProvider defaultValueProvider, IDialogService dialogService)
public SettingsViewModel(ISettingsService settingsService, IDefaultValueProvider defaultValueProvider, IDialogService dialogService, ITrayProcessCommunicationService trayProcessCommunicationService)
{
_settingsService = settingsService;
_defaultValueProvider = defaultValueProvider;
_dialogService = dialogService;
BrowseForCustomShellCommand = new RelayCommand(async () => await BrowseForCustomShell());
BrowseForWorkingDirectoryCommand = new RelayCommand(async () => await BrowseForWorkingDirectory());
RestoreDefaultsCommand = new RelayCommand<string>(async (area) => await RestoreDefaults(area));
CreateThemeCommand = new RelayCommand(CreateTheme);
_shellConfiguration = _settingsService.GetShellConfiguration();
_terminalOptions = _settingsService.GetTerminalOptions();
_applicationSettings = _settingsService.GetApplicationSettings();
ShellType = _shellConfiguration.Shell;
var activeThemeId = _settingsService.GetCurrentThemeId();
foreach (var theme in _settingsService.GetThemes())
{
var viewModel = new ThemeViewModel(theme, _settingsService, _dialogService);
viewModel.Activated += OnThemeActivated;
viewModel.Deleted += OnThemeDeleted;
if (theme.Id == activeThemeId)
{
viewModel.IsActive = true;
}
Themes.Add(viewModel);
}
SelectedTheme = Themes.First();
Fonts = CanvasTextFormat.GetSystemFontFamilies().OrderBy(s => s);
Sizes = Enumerable.Range(1, 72);
KeyBindings = new KeyBindingsPageViewModel(settingsService, dialogService, defaultValueProvider, trayProcessCommunicationService);
General = new GeneralPageViewModel(settingsService, dialogService, defaultValueProvider);
Shell = new ShellPageViewModel(settingsService, dialogService, defaultValueProvider);
Terminal = new TerminalPageViewModel(settingsService, dialogService, defaultValueProvider);
Themes = new ThemesPageViewModel(settingsService, dialogService, defaultValueProvider);
}
public string Arguments
{
get => _shellConfiguration.Arguments;
set
{
if (_shellConfiguration.Arguments != value)
{
_shellConfiguration.Arguments = value;
_settingsService.SaveShellConfiguration(_shellConfiguration);
RaisePropertyChanged();
}
}
}
public bool BarIsSelected
{
get => CursorStyle == CursorStyle.Bar;
set => CursorStyle = CursorStyle.Bar;
}
public bool BlockIsSelected
{
get => CursorStyle == CursorStyle.Block;
set => CursorStyle = CursorStyle.Block;
}
public RelayCommand BrowseForCustomShellCommand { get; }
public RelayCommand BrowseForWorkingDirectoryCommand { get; }
public bool CMDIsSelected
{
get => ShellType == ShellType.CMD;
set => ShellType = ShellType.CMD;
}
public bool ConfirmClosingTabs
{
get => _applicationSettings.ConfirmClosingTabs;
set
{
if (_applicationSettings.ConfirmClosingTabs != value)
{
_applicationSettings.ConfirmClosingTabs = value;
_settingsService.SaveApplicationSettings(_applicationSettings);
RaisePropertyChanged();
}
}
}
public bool ConfirmClosingWindows
{
get => _applicationSettings.ConfirmClosingWindows;
set
{
if (_applicationSettings.ConfirmClosingWindows != value)
{
_applicationSettings.ConfirmClosingWindows = value;
_settingsService.SaveApplicationSettings(_applicationSettings);
RaisePropertyChanged();
}
}
}
public RelayCommand CreateThemeCommand { get; set; }
public bool CursorBlink
{
get => _terminalOptions.CursorBlink;
set
{
if (_terminalOptions.CursorBlink != value)
{
_terminalOptions.CursorBlink = value;
_settingsService.SaveTerminalOptions(_terminalOptions);
RaisePropertyChanged();
}
}
}
public bool CustomShellIsSelected
{
get => ShellType == ShellType.Custom;
set => ShellType = ShellType.Custom;
}
public string CustomShellLocation
{
get => _shellConfiguration.CustomShellLocation;
set
{
if (_shellConfiguration.CustomShellLocation != value)
{
_shellConfiguration.CustomShellLocation = value;
_settingsService.SaveShellConfiguration(_shellConfiguration);
RaisePropertyChanged();
}
}
}
public string FontFamily
{
get => _terminalOptions.FontFamily;
set
{
if (_terminalOptions.FontFamily != value)
{
_terminalOptions.FontFamily = value;
_settingsService.SaveTerminalOptions(_terminalOptions);
RaisePropertyChanged();
}
}
}
public IEnumerable<string> Fonts { get; }
public int FontSize
{
get => _terminalOptions.FontSize;
set
{
if (_terminalOptions.FontSize != value)
{
_terminalOptions.FontSize = value;
_settingsService.SaveTerminalOptions(_terminalOptions);
RaisePropertyChanged();
}
}
}
public bool PoweShellIsSelected
{
get => ShellType == ShellType.PowerShell;
set => ShellType = ShellType.PowerShell;
}
public RelayCommand<string> RestoreDefaultsCommand { get; }
public ThemeViewModel SelectedTheme
{
get => _selectedTheme;
set => Set(ref _selectedTheme, value);
}
public ShellType ShellType
{
get => _shellConfiguration.Shell;
set
{
if (_shellConfiguration.Shell != value)
{
_shellConfiguration.Shell = value;
_settingsService.SaveShellConfiguration(_shellConfiguration);
RaisePropertyChanged();
RaisePropertyChanged(nameof(CustomShellIsSelected));
RaisePropertyChanged(nameof(PoweShellIsSelected));
RaisePropertyChanged(nameof(CMDIsSelected));
}
}
}
public IEnumerable<int> Sizes { get; }
public ObservableCollection<ThemeViewModel> Themes { get; } = new ObservableCollection<ThemeViewModel>();
public bool UnderlineIsSelected
{
get => CursorStyle == CursorStyle.Underline;
set => CursorStyle = CursorStyle.Underline;
}
public string WorkingDirectory
{
get => _shellConfiguration.WorkingDirectory;
set
{
if (_shellConfiguration.WorkingDirectory != value)
{
_shellConfiguration.WorkingDirectory = value;
_settingsService.SaveShellConfiguration(_shellConfiguration);
RaisePropertyChanged();
}
}
}
private CursorStyle CursorStyle
{
get => _terminalOptions.CursorStyle;
set
{
if (_terminalOptions.CursorStyle != value)
{
_terminalOptions.CursorStyle = value;
_settingsService.SaveTerminalOptions(_terminalOptions);
RaisePropertyChanged();
RaisePropertyChanged(nameof(BlockIsSelected));
RaisePropertyChanged(nameof(BarIsSelected));
RaisePropertyChanged(nameof(UnderlineIsSelected));
}
}
}
private async Task BrowseForCustomShell()
{
var picker = new FileOpenPicker();
picker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
picker.FileTypeFilter.Add(".exe");
var file = await picker.PickSingleFileAsync().AsTask();
if (file != null)
{
CustomShellLocation = file.Path;
}
}
private async Task BrowseForWorkingDirectory()
{
var picker = new FolderPicker();
picker.FileTypeFilter.Add(".whatever"); // else a ComException is thrown
picker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
var folder = await picker.PickSingleFolderAsync();
if (folder != null)
{
WorkingDirectory = folder.Path;
}
}
private void CreateTheme()
{
var defaultTheme = _settingsService.GetTheme(_defaultValueProvider.GetDefaultThemeId());
var theme = new TerminalTheme
{
Id = Guid.NewGuid(),
PreInstalled = false,
Name = "New Theme",
BackgroundOpacity = defaultTheme.BackgroundOpacity,
Colors = new TerminalColors(defaultTheme.Colors)
};
_settingsService.SaveTheme(theme);
var viewModel = new ThemeViewModel(theme, _settingsService, _dialogService);
viewModel.Activated += OnThemeActivated;
viewModel.Deleted += OnThemeDeleted;
Themes.Add(viewModel);
SelectedTheme = viewModel;
}
private void OnThemeActivated(object sender, EventArgs e)
{
if (sender is ThemeViewModel activatedTheme)
{
_settingsService.SaveCurrentThemeId(activatedTheme.Id);
foreach (var theme in Themes)
{
theme.IsActive = theme.Id == activatedTheme.Id;
}
}
}
private void OnThemeDeleted(object sender, EventArgs e)
{
if (sender is ThemeViewModel theme)
{
if (SelectedTheme == theme)
{
SelectedTheme = Themes.First();
}
Themes.Remove(theme);
if (theme.IsActive)
{
Themes.First().IsActive = true;
_settingsService.SaveCurrentThemeId(Themes.First().Id);
}
_settingsService.DeleteTheme(theme.Id);
}
}
private async Task RestoreDefaults(string area)
{
var result = await _dialogService.ShowDialogAsnyc("Please confirm", "Are you sure you want to restore default values for this page?", DialogButton.OK, DialogButton.Cancel);
if (result == DialogButton.OK && area == "shell")
{
var defaults = _defaultValueProvider.GetDefaultShellConfiguration();
ShellType = defaults.Shell;
CustomShellLocation = defaults.CustomShellLocation;
WorkingDirectory = defaults.WorkingDirectory;
Arguments = defaults.Arguments;
}
else if (result == DialogButton.OK && area == "terminal")
{
var defaults = _defaultValueProvider.GetDefaultTerminalOptions();
CursorBlink = defaults.CursorBlink;
CursorStyle = defaults.CursorStyle;
FontFamily = defaults.FontFamily;
FontSize = defaults.FontSize;
}
else if (result == DialogButton.OK && area == "general")
{
var defaults = _defaultValueProvider.GetDefaultApplicationSettings();
ConfirmClosingWindows = defaults.ConfirmClosingWindows;
ConfirmClosingTabs = defaults.ConfirmClosingTabs;
}
}
public GeneralPageViewModel General { get; }
public KeyBindingsPageViewModel KeyBindings { get; }
public TerminalPageViewModel Terminal { get; }
public ShellPageViewModel Shell { get; }
public ThemesPageViewModel Themes { get; }
}
}
@@ -5,6 +5,7 @@ using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.ApplicationModel.DataTransfer;
@@ -18,7 +19,7 @@ namespace FluentTerminal.App.ViewModels
private readonly IDialogService _dialogService;
private readonly IKeyboardCommandService _keyboardCommandService;
private readonly ISettingsService _settingsService;
private readonly ITerminalService _terminalService;
private readonly ITrayProcessCommunicationService _trayProcessCommunicationService;
private ApplicationSettings _applicationSettings;
private CoreDispatcher _dispatcher;
private string _resizeOverlayContent;
@@ -29,7 +30,7 @@ namespace FluentTerminal.App.ViewModels
private ITerminalView _terminalView;
private string _title;
public TerminalViewModel(int id, ISettingsService settingsService, ITerminalService terminalService, IDialogService dialogService, IKeyboardCommandService keyboardCommandService, ApplicationSettings applicationSettings, string startupDirectory)
public TerminalViewModel(int id, ISettingsService settingsService, ITrayProcessCommunicationService trayProcessCommunicationService, IDialogService dialogService, IKeyboardCommandService keyboardCommandService, ApplicationSettings applicationSettings, string startupDirectory)
{
Id = id;
Title = DefaultTitle;
@@ -38,7 +39,8 @@ namespace FluentTerminal.App.ViewModels
_settingsService.CurrentThemeChanged += OnCurrentThemeChanged;
_settingsService.TerminalOptionsChanged += OnTerminalOptionsChanged;
_settingsService.ApplicationSettingsChanged += OnApplicationSettingsChanged;
_terminalService = terminalService;
_settingsService.KeyBindingsChanged += OnKeyBindingsChanged;
_trayProcessCommunicationService = trayProcessCommunicationService;
_dialogService = dialogService;
_keyboardCommandService = keyboardCommandService;
_applicationSettings = applicationSettings;
@@ -52,6 +54,15 @@ namespace FluentTerminal.App.ViewModels
_dispatcher = CoreApplication.GetCurrentView().Dispatcher;
}
private async void OnKeyBindingsChanged(object sender, EventArgs e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
var keyBindings = _settingsService.GetKeyBindings();
await _terminalView.ChangeKeyBindings(GetKeyBindingsCollection(keyBindings));
});
}
public event EventHandler CloseRequested;
public event EventHandler<string> TitleChanged;
@@ -119,7 +130,7 @@ namespace FluentTerminal.App.ViewModels
var theme = _settingsService.GetCurrentTheme();
var keyBindings = _settingsService.GetKeyBindings();
var size = await _terminalView.CreateTerminal(options, theme.Colors, keyBindings);
var size = await _terminalView.CreateTerminal(options, theme.Colors, GetKeyBindingsCollection(keyBindings));
var configuration = _settingsService.GetShellConfiguration();
if (!string.IsNullOrWhiteSpace(_startupDirectory))
@@ -127,7 +138,7 @@ namespace FluentTerminal.App.ViewModels
configuration.WorkingDirectory = _startupDirectory;
}
var response = await _terminalService.CreateTerminal(size, configuration);
var response = await _trayProcessCommunicationService.CreateTerminal(size, configuration);
if (response.Success)
{
@@ -167,7 +178,7 @@ namespace FluentTerminal.App.ViewModels
private async void OnApplicationSettingsChanged(object sender, EventArgs e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
_applicationSettings = _settingsService.GetApplicationSettings();
});
@@ -229,12 +240,27 @@ namespace FluentTerminal.App.ViewModels
}
ResizeOverlayContent = $"{e.Columns} x {e.Rows}";
ShowResizeOverlay = true;
await _terminalService.ResizeTerminal(_terminalId, e);
await _trayProcessCommunicationService.ResizeTerminal(_terminalId, e);
}
private void OnTerminalTitleChanged(object sender, string e)
{
Title = e;
}
private IEnumerable<KeyBinding> GetKeyBindingsCollection(KeyBindings keyBindings)
{
var list = new List<KeyBinding>();
list.AddRange(keyBindings.CloseTab);
list.AddRange(keyBindings.Copy);
list.AddRange(keyBindings.NewTab);
list.AddRange(keyBindings.NewWindow);
list.AddRange(keyBindings.NextTab);
list.AddRange(keyBindings.Paste);
list.AddRange(keyBindings.PreviousTab);
list.AddRange(keyBindings.ShowSettings);
return list;
}
}
}
@@ -1,13 +1,19 @@
using Windows.UI;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using System;
namespace FluentTerminal.App.Views
{
public sealed class BindableColorsTitleBar : Control
{
private ApplicationViewTitleBar _titleBar;
private readonly ApplicationViewTitleBar _titleBar;
private readonly UISettings _uiSettings;
private readonly CoreDispatcher _dispatcher;
private bool _customValues;
private Color? _buttonForeground;
private Color? _buttonHoverBackground;
@@ -18,12 +24,32 @@ namespace FluentTerminal.App.Views
public BindableColorsTitleBar()
{
DefaultStyleKey = typeof(BindableColorsTitleBar);
_uiSettings = new UISettings();
_uiSettings.ColorValuesChanged += OnColorValuesChanged;
_titleBar = ApplicationView.GetForCurrentView().TitleBar;
_titleBar = ApplicationView.GetForCurrentView().TitleBar;
_titleBar.ButtonBackgroundColor = Colors.Transparent;
_titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
_titleBar.ButtonForegroundColor = (Color)this.Resources["SystemBaseHighColor"];
_dispatcher = Window.Current.Dispatcher;
_buttonHoverBackground = _titleBar.ButtonHoverBackgroundColor = Color.FromArgb(24, 255, 255, 255);
_buttonPressedBackground = _titleBar.ButtonPressedBackgroundColor = Color.FromArgb(48, 255, 255, 255);
}
private async void OnColorValuesChanged(UISettings sender, object args)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
if (!_customValues)
{
_titleBar.ButtonForegroundColor = (Color)this.Resources["SystemBaseHighColor"];
}
});
}
public Color TitleBarForeground
{
get { return (Color)GetValue(TitleBarForegroundProperty); }
@@ -55,6 +81,8 @@ namespace FluentTerminal.App.Views
_titleBar.ButtonPressedForegroundColor = _buttonPressedForeground;
_titleBar.ButtonHoverForegroundColor = _buttonHoverForeground;
_titleBar.InactiveForegroundColor = _inactiveForeground;
_customValues = true;
}
public void ResetTitleBar()
@@ -65,6 +93,8 @@ namespace FluentTerminal.App.Views
_titleBar.ButtonPressedForegroundColor = null;
_titleBar.ButtonHoverForegroundColor = null;
_titleBar.InactiveForegroundColor = null;
_customValues = false;
}
}
}
@@ -0,0 +1,67 @@
<ContentDialog
x:Class="FluentTerminal.App.Views.CreateKeyBindingDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="400"
PrimaryButtonText="OK"
SecondaryButtonText="Cancel"
mc:Ignorable="d">
<StackPanel>
<TextBlock Margin="0,0,0,24" Text="Enter your keybinding now" />
<StackPanel x:Name="Root" Orientation="Horizontal">
<Grid
Width="48"
Height="32"
Margin="0,0,6,0"
Background="{ThemeResource SystemControlBackgroundBaseLowBrush}"
Visibility="{x:Bind KeyBinding.Ctrl, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="Ctrl" />
</Grid>
<Grid
Width="48"
Height="32"
Margin="0,0,6,0"
Background="{ThemeResource SystemControlBackgroundBaseLowBrush}"
Visibility="{x:Bind KeyBinding.Alt, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="Alt" />
</Grid>
<Grid
Width="48"
Height="32"
Margin="0,0,6,0"
Background="{ThemeResource SystemControlBackgroundBaseLowBrush}"
Visibility="{x:Bind KeyBinding.Shift, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="Shift" />
</Grid>
<Grid
Width="48"
Height="32"
Margin="0,0,6,0"
Background="{ThemeResource SystemControlBackgroundBaseLowBrush}"
Visibility="{x:Bind KeyBinding.Key, Mode=OneWay, Converter={StaticResource ZeroToCollapsedConverter}}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{x:Bind KeyBinding.Key, Mode=OneWay, Converter={StaticResource IntToExtendedVirtualKeyConverter}}" />
</Grid>
<HyperlinkButton
x:Name="ResetButton"
Margin="24,0,0,0"
Command="{x:Bind ResetCommand}"
Content="Reset"
PreviewKeyDown="OnResetButtonPreviewKeyDown" />
</StackPanel>
</StackPanel>
</ContentDialog>
@@ -0,0 +1,69 @@
using FluentTerminal.App.Services;
using FluentTerminal.App.ViewModels.Settings;
using FluentTerminal.Models;
using GalaSoft.MvvmLight.Command;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace FluentTerminal.App.Views
{
public sealed partial class CreateKeyBindingDialog : ContentDialog
{
public static readonly DependencyProperty KeyBindingProperty =
DependencyProperty.Register(nameof(KeyBinding), typeof(KeyBindingViewModel), typeof(CreateKeyBindingDialog), new PropertyMetadata(null));
private readonly IDialogService _dialogService;
public CreateKeyBindingDialog(IDialogService dialogService)
{
_dialogService = dialogService;
InitializeComponent();
ResetCommand = new RelayCommand(Reset);
PreviewKeyDown += RegisterKeyBindingDialog_PreviewKeyDown;
Reset();
}
public KeyBindingViewModel KeyBinding
{
get { return (KeyBindingViewModel)GetValue(KeyBindingProperty); }
set { SetValue(KeyBindingProperty, value); }
}
public RelayCommand ResetCommand { get; }
private void OnResetButtonPreviewKeyDown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
{
e.Handled = true;
}
private void RegisterKeyBindingDialog_PreviewKeyDown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
{
switch (e.Key)
{
case VirtualKey.Control:
KeyBinding.Ctrl = true;
break;
case VirtualKey.Shift:
KeyBinding.Shift = true;
break;
case VirtualKey.Menu:
KeyBinding.Alt = true;
break;
default:
KeyBinding.Key = (int)e.Key;
break;
}
ResetButton.Visibility = Visibility.Visible;
}
private void Reset()
{
KeyBinding = new KeyBindingViewModel(new KeyBinding(), _dialogService);
ResetButton.Visibility = Visibility.Collapsed;
}
}
}
@@ -14,6 +14,7 @@ namespace FluentTerminal.App.Views
Task ChangeTheme(TerminalColors theme);
Task ChangeOptions(TerminalOptions options);
Task ChangeKeyBindings(IEnumerable<KeyBinding> keyBindings);
Task<TerminalSize> CreateTerminal(TerminalOptions options, TerminalColors theme, IEnumerable<KeyBinding> keyBindings);
Task ConnectToSocket(string url);
void Close();
@@ -0,0 +1,79 @@
<UserControl
x:Class="FluentTerminal.App.Views.KeyBindingsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:settings="using:FluentTerminal.App.ViewModels.Settings"
d:DesignHeight="300"
d:DesignWidth="400"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ItemsControl Grid.Row="0" ItemsSource="{x:Bind ViewModel.KeyBindings, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="settings:KeyBindingViewModel">
<StackPanel
x:Name="Root"
Margin="0,0,0,6"
Orientation="Horizontal">
<Grid
Width="48"
Height="32"
Margin="0,0,6,0"
Background="{ThemeResource SystemControlBackgroundBaseLowBrush}"
Visibility="{x:Bind Ctrl, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="Ctrl" />
</Grid>
<Grid
Width="48"
Height="32"
Margin="0,0,6,0"
Background="{ThemeResource SystemControlBackgroundBaseLowBrush}"
Visibility="{x:Bind Alt, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="Alt" />
</Grid>
<Grid
Width="48"
Height="32"
Margin="0,0,6,0"
Background="{ThemeResource SystemControlBackgroundBaseLowBrush}"
Visibility="{x:Bind Shift, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="Shift" />
</Grid>
<Grid
Width="64"
Height="32"
Margin="0,0,6,0"
Background="{ThemeResource SystemControlBackgroundBaseLowBrush}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{x:Bind Key, Mode=OneWay, Converter={StaticResource IntToExtendedVirtualKeyConverter}}" />
</Grid>
<HyperlinkButton
Margin="12,0,0,0"
Command="{x:Bind EditCommand}"
Content="Edit" />
<HyperlinkButton
Margin="12,0,0,0"
Command="{x:Bind DeleteCommand}"
Content="Delete" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
@@ -0,0 +1,23 @@
using FluentTerminal.App.ViewModels.Settings;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace FluentTerminal.App.Views
{
public sealed partial class KeyBindingsView : UserControl
{
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register(nameof(ViewModel), typeof(KeyBindingsViewModel), typeof(KeyBindingsView), new PropertyMetadata(null));
public KeyBindingsView()
{
InitializeComponent();
}
public KeyBindingsViewModel ViewModel
{
get { return (KeyBindingsViewModel)GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
}
}
+1 -11
View File
@@ -13,16 +13,6 @@
mc:Ignorable="d">
<Page.Resources>
<converters:TerminalViewModelToViewConverter x:Key="TerminalViewModelToViewConverter" />
<converters:IntToVisibilityConverter
x:Key="OneToVisibleConverter"
Else="Collapsed"
If="1"
Then="Visible" />
<converters:IntToVisibilityConverter
x:Key="OneToCollapsedConverter"
Else="Visible"
If="1"
Then="Collapsed" />
</Page.Resources>
<Grid x:Name="Root">
<Grid.Background>
@@ -51,7 +41,7 @@
Grid.Column="0"
IsHitTestVisible="False"
Style="{StaticResource WindowTitleTextBlockStyle}"
Text="{x:Bind ViewModel.Terminals[0].Title, Mode=OneWay}"
Text="{x:Bind ViewModel.Title, Mode=OneWay}"
Visibility="{x:Bind ViewModel.Terminals.Count, Mode=OneWay, Converter={StaticResource OneToVisibleConverter}}" />
<ListView
x:Name="Tabs"
+2 -7
View File
@@ -2,15 +2,10 @@
x:Class="FluentTerminal.App.Views.SettingsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:FluentTerminal.App.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<converters:TrueToVisibleConverter x:Key="TrueToVisibleConverter" />
<converters:FalseToVisibleConverter x:Key="FalseToVisibleConverter" />
</Page.Resources>
<Grid x:Name="Root" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="Root">
<TextBlock
x:Name="AppTitle"
Canvas.ZIndex="1"
@@ -70,7 +65,7 @@
</NavigationViewItem.Icon>
</NavigationViewItem>
</NavigationView.MenuItems>
<Grid>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Frame x:Name="ContentFrame" />
<TextBlock
Margin="12,8,0,0"
+24 -28
View File
@@ -2,7 +2,6 @@
using FluentTerminal.App.Views.SettingsPages;
using System.Linq;
using Windows.ApplicationModel.Core;
using Windows.UI;
using Windows.UI.Core.Preview;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
@@ -13,25 +12,15 @@ namespace FluentTerminal.App.Views
{
public sealed partial class SettingsPage : Page
{
public double CoreTitleBarHeight { get; }
public SettingsViewModel ViewModel { get; private set; }
public SettingsPage()
{
InitializeComponent();
Root.DataContext = this;
ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar;
titleBar.ButtonBackgroundColor = Colors.Transparent;
titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
titleBar.ButtonForegroundColor = (Color)this.Resources["SystemBaseHighColor"];
ApplicationView.PreferredLaunchViewSize = new Windows.Foundation.Size(1024, 768);
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize;
ApplicationView.GetForCurrentView().Title = "Settings";
CoreApplicationViewTitleBar coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
coreTitleBar.LayoutMetricsChanged += TitleBar_LayoutMetricsChanged;
@@ -40,6 +29,9 @@ namespace FluentTerminal.App.Views
SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += SettingsPage_CloseRequested;
}
public double CoreTitleBarHeight { get; }
public SettingsViewModel ViewModel { get; private set; }
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is SettingsViewModel viewModel)
@@ -48,16 +40,6 @@ namespace FluentTerminal.App.Views
}
}
private void SettingsPage_CloseRequested(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
{
App.Instance.SettingsWindowClosed();
}
private void TitleBar_LayoutMetricsChanged(CoreApplicationViewTitleBar sender, object args)
{
AppTitle.Margin = new Thickness(CoreApplication.GetCurrentView().TitleBar.SystemOverlayLeftInset + 12, 8, 0, 0);
}
private void NavigationView_Loaded(object sender, RoutedEventArgs e)
{
NavigationView.SelectedItem = NavigationView.MenuItems.Cast<NavigationViewItemBase>().FirstOrDefault(m => m.Tag.ToString() == "general");
@@ -70,22 +52,36 @@ namespace FluentTerminal.App.Views
switch (item.Tag)
{
case "general":
ContentFrame.Navigate(typeof(GeneralSettings), ViewModel);
ContentFrame.Navigate(typeof(GeneralSettings), ViewModel.General);
break;
case "shell":
ContentFrame.Navigate(typeof(ShellSettings), ViewModel);
ContentFrame.Navigate(typeof(ShellSettings), ViewModel.Shell);
break;
case "themes":
ContentFrame.Navigate(typeof(ThemeSettings), ViewModel);
ContentFrame.Navigate(typeof(ThemeSettings), ViewModel.Themes);
break;
case "terminal":
ContentFrame.Navigate(typeof(TerminalSettings), ViewModel);
ContentFrame.Navigate(typeof(TerminalSettings), ViewModel.Terminal);
break;
case "keyBindings":
ContentFrame.Navigate(typeof(KeyBindingSettings), ViewModel);
ContentFrame.Navigate(typeof(KeyBindingSettings), ViewModel.KeyBindings);
break;
}
}
}
}
private void SettingsPage_CloseRequested(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
{
App.Instance.SettingsWindowClosed();
}
private void TitleBar_LayoutMetricsChanged(CoreApplicationViewTitleBar sender, object args)
{
AppTitle.Margin = new Thickness(CoreApplication.GetCurrentView().TitleBar.SystemOverlayLeftInset + 12, 8, 0, 0);
}
}
}
}
@@ -4,7 +4,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
NavigationCacheMode="Required"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
@@ -30,14 +29,18 @@
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
DefaultLabelPosition="Right">
<AppBarButton
Command="{Binding ViewModel.RestoreDefaultsCommand}"
CommandParameter="general"
Command="{x:Bind ViewModel.RestoreDefaultsCommand}"
Icon="Undo"
Label="Restore Defaults" />
</CommandBar>
</Grid>
<StackPanel Grid.Row="2" Margin="24,0,0,0">
<TextBlock Margin="0,0,0,8" Text="Open new terminals as" />
<RadioButton Content="Tabs" IsChecked="{x:Bind ViewModel.TabIsSelected, Mode=TwoWay}" />
<RadioButton
Margin="0,0,0,24"
Content="Windows"
IsChecked="{x:Bind ViewModel.WindowIsSelected, Mode=TwoWay}" />
<ToggleSwitch
Margin="0,0,0,24"
Header="Ask before closing windows"
@@ -1,4 +1,4 @@
using FluentTerminal.App.ViewModels;
using FluentTerminal.App.ViewModels.Settings;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
@@ -6,7 +6,7 @@ namespace FluentTerminal.App.Views.SettingsPages
{
public sealed partial class GeneralSettings : Page
{
public SettingsViewModel ViewModel { get; private set; }
public GeneralPageViewModel ViewModel { get; private set; }
public GeneralSettings()
{
@@ -15,7 +15,7 @@ namespace FluentTerminal.App.Views.SettingsPages
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is SettingsViewModel viewModel)
if (e.Parameter is GeneralPageViewModel viewModel)
{
ViewModel = viewModel;
}
@@ -3,9 +3,208 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:FluentTerminal.App.Views.SettingsPages"
xmlns:enums="using:FluentTerminal.Models.Enums"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="using:FluentTerminal.App.Views"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="32" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="1" Margin="24,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock
Margin="0,10,0,0"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
Text="Keybindings" />
<CommandBar
Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
DefaultLabelPosition="Right">
<AppBarButton Icon="Add" Label="Add">
<AppBarButton.Flyout>
<MenuFlyout>
<MenuFlyoutItem Command="{x:Bind ViewModel.AddCommand}" Text="New tab">
<MenuFlyoutItem.CommandParameter>
<enums:Command>NewTab</enums:Command>
</MenuFlyoutItem.CommandParameter>
</MenuFlyoutItem>
<MenuFlyoutItem Command="{x:Bind ViewModel.AddCommand}" Text="Close tab">
<MenuFlyoutItem.CommandParameter>
<enums:Command>CloseTab</enums:Command>
</MenuFlyoutItem.CommandParameter>
</MenuFlyoutItem>
<MenuFlyoutItem Command="{x:Bind ViewModel.AddCommand}" Text="Next tab">
<MenuFlyoutItem.CommandParameter>
<enums:Command>NextTab</enums:Command>
</MenuFlyoutItem.CommandParameter>
</MenuFlyoutItem>
<MenuFlyoutItem Command="{x:Bind ViewModel.AddCommand}" Text="Previous tab">
<MenuFlyoutItem.CommandParameter>
<enums:Command>PreviousTab</enums:Command>
</MenuFlyoutItem.CommandParameter>
</MenuFlyoutItem>
<MenuFlyoutItem Command="{x:Bind ViewModel.AddCommand}" Text="New window">
<MenuFlyoutItem.CommandParameter>
<enums:Command>NewWindow</enums:Command>
</MenuFlyoutItem.CommandParameter>
</MenuFlyoutItem>
<MenuFlyoutItem Command="{x:Bind ViewModel.AddCommand}" Text="Show settings">
<MenuFlyoutItem.CommandParameter>
<enums:Command>ShowSettings</enums:Command>
</MenuFlyoutItem.CommandParameter>
</MenuFlyoutItem>
<MenuFlyoutItem Command="{x:Bind ViewModel.AddCommand}" Text="Toggle window">
<MenuFlyoutItem.CommandParameter>
<enums:Command>ToggleWindow</enums:Command>
</MenuFlyoutItem.CommandParameter>
</MenuFlyoutItem>
<MenuFlyoutItem Command="{x:Bind ViewModel.AddCommand}" Text="Copy">
<MenuFlyoutItem.CommandParameter>
<enums:Command>Copy</enums:Command>
</MenuFlyoutItem.CommandParameter>
</MenuFlyoutItem>
<MenuFlyoutItem Command="{x:Bind ViewModel.AddCommand}" Text="Paste">
<MenuFlyoutItem.CommandParameter>
<enums:Command>Paste</enums:Command>
</MenuFlyoutItem.CommandParameter>
</MenuFlyoutItem>
</MenuFlyout>
</AppBarButton.Flyout>
</AppBarButton>
<AppBarButton
Command="{x:Bind ViewModel.RestoreDefaultsCommand}"
CommandParameter="keyBindings"
Icon="Undo"
Label="Restore Defaults" />
</CommandBar>
</Grid>
<ScrollViewer Grid.Row="2" Margin="24,24,0,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" />
<TextBlock
Grid.Row="0"
Grid.Column="0"
Margin="0,6,24,0"
Text="New tab" />
<views:KeyBindingsView
Grid.Row="0"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.NewTab, Mode=OneWay}" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="0,6,24,0"
Text="Close tab" />
<views:KeyBindingsView
Grid.Row="1"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.CloseTab, Mode=OneWay}" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="0,6,24,0"
Text="Next tab" />
<views:KeyBindingsView
Grid.Row="2"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.NextTab, Mode=OneWay}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="0,6,24,0"
Text="Previous tab" />
<views:KeyBindingsView
Grid.Row="3"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.PreviousTab, Mode=OneWay}" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Margin="0,6,24,0"
Text="New window" />
<views:KeyBindingsView
Grid.Row="4"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.NewWindow, Mode=OneWay}" />
<TextBlock
Grid.Row="5"
Grid.Column="0"
Margin="0,6,24,0"
Text="Show settings" />
<views:KeyBindingsView
Grid.Row="5"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.ShowSettings, Mode=OneWay}" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
Margin="0,6,24,0"
Text="Toggle window" />
<views:KeyBindingsView
Grid.Row="6"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.ToggleWindow, Mode=OneWay}" />
<TextBlock
Grid.Row="7"
Grid.Column="0"
Margin="0,6,24,0"
Text="Copy" />
<views:KeyBindingsView
Grid.Row="7"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.Copy, Mode=OneWay}" />
<TextBlock
Grid.Row="8"
Grid.Column="0"
Margin="0,6,24,0"
Text="Paste" />
<views:KeyBindingsView
Grid.Row="8"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.Paste, Mode=OneWay}" />
</Grid>
</ScrollViewer>
</Grid>
</Page>
@@ -1,30 +1,30 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using FluentTerminal.App.ViewModels;
using FluentTerminal.App.ViewModels.Settings;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// Die Elementvorlage "Leere Seite" wird unter https://go.microsoft.com/fwlink/?LinkId=234238 dokumentiert.
namespace FluentTerminal.App.Views.SettingsPages
{
/// <summary>
/// Eine leere Seite, die eigenständig verwendet oder zu der innerhalb eines Rahmens navigiert werden kann.
/// </summary>
public sealed partial class KeyBindingSettings : Page
{
public KeyBindingsPageViewModel ViewModel { get; private set; }
public KeyBindingSettings()
{
this.InitializeComponent();
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is KeyBindingsPageViewModel viewModel)
{
ViewModel = viewModel;
}
}
private void KeyBindingView_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
}
}
}
@@ -4,7 +4,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
NavigationCacheMode="Required"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
@@ -30,8 +29,7 @@
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
DefaultLabelPosition="Right">
<AppBarButton
Command="{Binding ViewModel.RestoreDefaultsCommand}"
CommandParameter="shell"
Command="{x:Bind ViewModel.RestoreDefaultsCommand}"
Icon="Undo"
Label="Restore Defaults" />
</CommandBar>
@@ -39,9 +37,9 @@
<StackPanel Grid.Row="2" Margin="24,0,0,0">
<TextBlock Margin="0,0,0,8" Text="Type" />
<RadioButton Content="PowerShell" IsChecked="{Binding ViewModel.PoweShellIsSelected, Mode=TwoWay}" />
<RadioButton Content="CMD" IsChecked="{Binding ViewModel.CMDIsSelected, Mode=TwoWay}" />
<RadioButton Content="Custom" IsChecked="{Binding ViewModel.CustomShellIsSelected, Mode=TwoWay}" />
<RadioButton Content="PowerShell" IsChecked="{x:Bind ViewModel.PoweShellIsSelected, Mode=TwoWay}" />
<RadioButton Content="CMD" IsChecked="{x:Bind ViewModel.CMDIsSelected, Mode=TwoWay}" />
<RadioButton Content="Custom" IsChecked="{x:Bind ViewModel.CustomShellIsSelected, Mode=TwoWay}" />
<StackPanel Margin="0,24,0,0" Orientation="Horizontal">
<TextBox
@@ -1,4 +1,4 @@
using FluentTerminal.App.ViewModels;
using FluentTerminal.App.ViewModels.Settings;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
@@ -6,7 +6,7 @@ namespace FluentTerminal.App.Views.SettingsPages
{
public sealed partial class ShellSettings : Page
{
public SettingsViewModel ViewModel { get; private set; }
public ShellPageViewModel ViewModel { get; private set; }
public ShellSettings()
{
@@ -15,7 +15,7 @@ namespace FluentTerminal.App.Views.SettingsPages
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is SettingsViewModel viewModel)
if (e.Parameter is ShellPageViewModel viewModel)
{
ViewModel = viewModel;
}
@@ -4,7 +4,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
NavigationCacheMode="Required"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
@@ -30,8 +29,7 @@
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
DefaultLabelPosition="Right">
<AppBarButton
Command="{Binding ViewModel.RestoreDefaultsCommand}"
CommandParameter="terminal"
Command="{x:Bind ViewModel.RestoreDefaultsCommand}"
Icon="Undo"
Label="Restore Defaults" />
</CommandBar>
@@ -54,9 +52,9 @@
Header="Blinking Cursor"
IsOn="{x:Bind ViewModel.CursorBlink, Mode=TwoWay}" />
<TextBlock Margin="0,0,0,8" Text="Cursor Style" />
<RadioButton Content="Block" IsChecked="{Binding ViewModel.BlockIsSelected, Mode=TwoWay}" />
<RadioButton Content="Underline" IsChecked="{Binding ViewModel.UnderlineIsSelected, Mode=TwoWay}" />
<RadioButton Content="Bar" IsChecked="{Binding ViewModel.BarIsSelected, Mode=TwoWay}" />
<RadioButton Content="Block" IsChecked="{x:Bind ViewModel.BlockIsSelected, Mode=TwoWay}" />
<RadioButton Content="Underline" IsChecked="{x:Bind ViewModel.UnderlineIsSelected, Mode=TwoWay}" />
<RadioButton Content="Bar" IsChecked="{x:Bind ViewModel.BarIsSelected, Mode=TwoWay}" />
</StackPanel>
</Grid>
</Page>
@@ -1,4 +1,4 @@
using FluentTerminal.App.ViewModels;
using FluentTerminal.App.ViewModels.Settings;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
@@ -11,11 +11,11 @@ namespace FluentTerminal.App.Views.SettingsPages
InitializeComponent();
}
public SettingsViewModel ViewModel { get; private set; }
public TerminalPageViewModel ViewModel { get; private set; }
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is SettingsViewModel viewModel)
if (e.Parameter is TerminalPageViewModel viewModel)
{
ViewModel = viewModel;
}
@@ -2,18 +2,11 @@
x:Class="FluentTerminal.App.Views.SettingsPages.ThemeSettings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:FluentTerminal.App.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewmodels="using:FluentTerminal.App.ViewModels"
xmlns:views="using:FluentTerminal.App.Views"
NavigationCacheMode="Required"
mc:Ignorable="d">
<Page.Resources>
<converters:NegateConverter x:Key="NegateConverter" />
<converters:FalseToVisibleConverter x:Key="FalseToVisibleConverter" />
<converters:TrueToVisibleConverter x:Key="TrueToVisibleConverter" />
</Page.Resources>
<Grid x:Name="Root">
<Grid.Background>
<AcrylicBrush
@@ -1,4 +1,4 @@
using FluentTerminal.App.ViewModels;
using FluentTerminal.App.ViewModels.Settings;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
@@ -6,7 +6,7 @@ namespace FluentTerminal.App.Views.SettingsPages
{
public sealed partial class ThemeSettings : Page
{
public SettingsViewModel ViewModel { get; private set; }
public ThemesPageViewModel ViewModel { get; private set; }
public ThemeSettings()
{
@@ -16,7 +16,7 @@ namespace FluentTerminal.App.Views.SettingsPages
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is SettingsViewModel viewModel)
if (e.Parameter is ThemesPageViewModel viewModel)
{
ViewModel = viewModel;
}
@@ -27,6 +27,5 @@ namespace FluentTerminal.App.Views.SettingsPages
{
TitleBar.ResetTitleBar();
}
}
}
@@ -2,16 +2,11 @@
x:Class="FluentTerminal.App.Views.TerminalView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:FluentTerminal.App.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:FluentTerminal.App.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="400"
mc:Ignorable="d">
<UserControl.Resources>
<converters:TrueToVisibleConverter x:Key="TrueToVisibleConverter" />
</UserControl.Resources>
<Grid>
<Grid x:Name="WebViewContainer" Margin="12" />
<Grid
@@ -70,6 +70,12 @@ namespace FluentTerminal.App.Views
return ExecuteScriptAsync($"changeTheme('{serialized}')");
}
public Task ChangeKeyBindings(IEnumerable<KeyBinding> keyBindings)
{
var serialized = JsonConvert.SerializeObject(keyBindings);
return ExecuteScriptAsync($"changeKeyBindings('{serialized}')");
}
public void Close()
{
_webView?.Navigate(new Uri("about:blank"));
@@ -190,7 +196,7 @@ namespace FluentTerminal.App.Views
Items = { _copyMenuItem, _pasteMenuItem }
};
_webView.Navigate(new Uri("http://localhost:9000/Client/index.html"));
_webView.Navigate(new Uri("ms-appx-web:///Client/index.html"));
await _loaded.WaitAsync();
+6 -1
View File
@@ -67,7 +67,6 @@ function createTerminal(options, theme, keyBindings) {
var keyBinding = window.keyBindings[i];
if (keyBinding.ctrl == e.ctrlKey
&& keyBinding.alt == e.altKey
&& keyBinding.meta == e.metaKey
&& keyBinding.shift == e.shiftKey
&& keyBinding.key == e.keyCode) {
if (document.visibilityState == 'visible') {
@@ -113,6 +112,11 @@ function changeOptions(options) {
term.setOption('fontSize', options.fontSize);
}
function changeKeyBindings(keyBindings) {
keyBindings = JSON.parse(keyBindings);
window.keyBindings = keyBindings;
}
function paste(content) {
content = b64DecodeUnicode(content);
term.send(content);
@@ -132,4 +136,5 @@ window.createTerminal = createTerminal;
window.connectToWebSocket = connectToWebSocket;
window.changeTheme = changeTheme;
window.changeOptions = changeOptions;
window.changeKeyBindings = changeKeyBindings;
window.paste = paste;
+4 -1
View File
@@ -1,8 +1,11 @@
namespace FluentTerminal.Models
using FluentTerminal.Models.Enums;
namespace FluentTerminal.Models
{
public class ApplicationSettings
{
public bool ConfirmClosingTabs { get; set; }
public bool ConfirmClosingWindows { get; set; }
public NewTerminalLocation NewTerminalLocation { get; set; }
}
}
@@ -0,0 +1,187 @@
namespace FluentTerminal.Models.Enums
{
public enum ExtendedVirtualKey
{
None = 0,
LeftButton = 1,
RightButton = 2,
Cancel = 3,
MiddleButton = 4,
XButton1 = 5,
XButton2 = 6,
Back = 8,
Tab = 9,
Clear = 12,
Enter = 13,
Shift = 16,
Control = 17,
Menu = 18,
Pause = 19,
CapitalLock = 20,
Kana = 21,
Hangul = 21,
Junja = 23,
Final = 24,
Hanja = 25,
Kanji = 25,
Escape = 27,
Convert = 28,
NonConvert = 29,
Accept = 30,
ModeChange = 31,
Space = 32,
PageUp = 33,
PageDown = 34,
End = 35,
Home = 36,
Left = 37,
Up = 38,
Right = 39,
Down = 40,
Select = 41,
Print = 42,
Execute = 43,
Snapshot = 44,
Insert = 45,
Delete = 46,
Help = 47,
Number0 = 48,
Number1 = 49,
Number2 = 50,
Number3 = 51,
Number4 = 52,
Number5 = 53,
Number6 = 54,
Number7 = 55,
Number8 = 56,
Number9 = 57,
A = 65,
B = 66,
C = 67,
D = 68,
E = 69,
F = 70,
G = 71,
H = 72,
I = 73,
J = 74,
K = 75,
L = 76,
M = 77,
N = 78,
O = 79,
P = 80,
Q = 81,
R = 82,
S = 83,
T = 84,
U = 85,
V = 86,
W = 87,
X = 88,
Y = 89,
Z = 90,
LeftWindows = 91,
RightWindows = 92,
Application = 93,
Sleep = 95,
NumberPad0 = 96,
NumberPad1 = 97,
NumberPad2 = 98,
NumberPad3 = 99,
NumberPad4 = 100,
NumberPad5 = 101,
NumberPad6 = 102,
NumberPad7 = 103,
NumberPad8 = 104,
NumberPad9 = 105,
Multiply = 106,
Add = 107,
Separator = 108,
Subtract = 109,
Decimal = 110,
Divide = 111,
F1 = 112,
F2 = 113,
F3 = 114,
F4 = 115,
F5 = 116,
F6 = 117,
F7 = 118,
F8 = 119,
F9 = 120,
F10 = 121,
F11 = 122,
F12 = 123,
F13 = 124,
F14 = 125,
F15 = 126,
F16 = 127,
F17 = 128,
F18 = 129,
F19 = 130,
F20 = 131,
F21 = 132,
F22 = 133,
F23 = 134,
F24 = 135,
NavigationView = 136,
NavigationMenu = 137,
NavigationUp = 138,
NavigationDown = 139,
NavigationLeft = 140,
NavigationRight = 141,
NavigationAccept = 142,
NavigationCancel = 143,
NumberKeyLock = 144,
Scroll = 145,
LeftShift = 160,
RightShift = 161,
LeftControl = 162,
RightControl = 163,
LeftMenu = 164,
RightMenu = 165,
GoBack = 166,
GoForward = 167,
Refresh = 168,
Stop = 169,
Search = 170,
Favorites = 171,
GoHome = 172,
VolumeMute = 173,
VolumeDown = 174,
VolumeUp = 175,
MediaNext = 176,
MediaPrevious = 177,
MediaStop = 178,
MediaPlayPause = 179,
Plus = 187,
Comma = 188,
Minus = 189,
Period = 190,
GamepadA = 195,
GamepadB = 196,
GamepadX = 197,
GamepadY = 198,
GamepadRightShoulder = 199,
GamepadLeftShoulder = 200,
GamepadLeftTrigger = 201,
GamepadRightTrigger = 202,
GamepadDPadUp = 203,
GamepadDPadDown = 204,
GamepadDPadLeft = 205,
GamepadDPadRight = 206,
GamepadMenu = 207,
GamepadView = 208,
GamepadLeftThumbstickButton = 209,
GamepadRightThumbstickButton = 210,
GamepadLeftThumbstickUp = 211,
GamepadLeftThumbstickDown = 212,
GamepadLeftThumbstickRight = 213,
GamepadLeftThumbstickLeft = 214,
GamepadRightThumbstickUp = 215,
GamepadRightThumbstickDown = 216,
GamepadRightThumbstickRight = 217,
GamepadRightThumbstickLeft = 218
}
}
@@ -0,0 +1,8 @@
namespace FluentTerminal.Models.Enums
{
public enum NewTerminalLocation
{
Tab,
Window
}
}
-1
View File
@@ -9,7 +9,6 @@ namespace FluentTerminal.Models
public int Key { get; set; }
public bool Ctrl { get; set; }
public bool Alt { get; set; }
public bool Meta { get; set; }
public bool Shift { get; set; }
}
}
+17
View File
@@ -0,0 +1,17 @@
using System.Collections.Generic;
namespace FluentTerminal.Models
{
public class KeyBindings
{
public ICollection<KeyBinding> ToggleWindow { get; set; }
public ICollection<KeyBinding> NextTab { get; set; }
public ICollection<KeyBinding> PreviousTab { get; set; }
public ICollection<KeyBinding> NewTab { get; set; }
public ICollection<KeyBinding> CloseTab { get; set; }
public ICollection<KeyBinding> NewWindow { get; set; }
public ICollection<KeyBinding> ShowSettings { get; set; }
public ICollection<KeyBinding> Copy { get; set; }
public ICollection<KeyBinding> Paste { get; set; }
}
}
@@ -0,0 +1,24 @@
using FluentTerminal.Models;
using FluentTerminal.SystemTray.Services;
using System.Collections.Generic;
using System.Web.Http;
namespace FluentTerminal.SystemTray.Controllers
{
public class KeyBindingsController : ApiController
{
private readonly ToggleWindowService _toggleWindowService;
public KeyBindingsController(ToggleWindowService toggleWindowService)
{
_toggleWindowService = toggleWindowService;
}
[HttpPost]
[Route("keybindings/togglewindow")]
public void PostToggleWindowKeyBindings([FromBody]IEnumerable<KeyBinding> keyBindings)
{
_toggleWindowService.SetHotKeys(keyBindings);
}
}
}
@@ -112,10 +112,13 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Controllers\KeyBindingsController.cs" />
<Compile Include="Controllers\TerminalsController.cs" />
<Compile Include="LoopbackEnabler.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\ToggleWindowService.cs" />
<Compile Include="Services\NotificationService.cs" />
<Compile Include="Services\TerminalSession.cs" />
<Compile Include="Services\TerminalsManager.cs" />
<Compile Include="Startup.cs" />
@@ -156,10 +159,7 @@
<Version>1.1.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.AspNet.WebApi.OwinSelfHost">
<Version>5.2.3</Version>
</PackageReference>
<PackageReference Include="Microsoft.Owin.StaticFiles">
<Version>3.1.0</Version>
<Version>5.2.4</Version>
</PackageReference>
<PackageReference Include="Unity.WebAPI">
<Version>5.3.0</Version>
@@ -175,18 +175,6 @@
<Content Include="BinaryDependencies\x86\winpty-agent.exe" />
<Content Include="BinaryDependencies\x86\winpty-debugserver.exe" />
<Content Include="BinaryDependencies\x86\winpty.dll" />
<Content Include="Client\bundle.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Client\index.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Client\style.css">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Client\xterm.css">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FluentTerminal.Models\FluentTerminal.Models.csproj">
@@ -201,6 +189,7 @@ xcopy /y /s "$(ProjectDir)bin\$(PlatformName)\$(ConfigurationName)" "$(SolutionD
</PostBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PreBuildEvent>xcopy /y "$(SolutionDir)FluentTerminal.Client\dist" "$(ProjectDir)Client"</PreBuildEvent>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
</Project>
@@ -0,0 +1,26 @@
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;
namespace FluentTerminal.SystemTray.Services
{
public class NotificationService
{
public void ShowNotification(string title, string content)
{
string xml = $@"<toast>
<visual>
<binding template='ToastGeneric'>
<text>{title}</text>
<text>{content}</text>
</binding>
</visual>
</toast>";
var doc = new XmlDocument();
doc.LoadXml(xml);
var toast = new ToastNotification(doc);
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
}
}
@@ -0,0 +1,154 @@
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GlobalHotKey;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Threading;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Core;
namespace FluentTerminal.SystemTray.Services
{
public class ToggleWindowService : IDisposable
{
private readonly HotKeyManager _hotKeyManager;
private readonly NotificationService _notificationService;
private Dispatcher _dispatcher;
private bool _disposedValue;
private List<HotKey> _hotKeys;
public ToggleWindowService(Dispatcher dispatcher, HotKeyManager hotKeyManager, NotificationService notificationService)
{
_dispatcher = dispatcher;
_notificationService = notificationService;
_hotKeyManager = hotKeyManager;
_hotKeys = new List<HotKey>();
_hotKeyManager.KeyPressed += OnKeyPressed;
}
public void Dispose()
{
Dispose(true);
}
public void SetHotKeys(IEnumerable<KeyBinding> keyBindings)
{
foreach (var hotKey in _hotKeys)
{
_dispatcher.Invoke(() =>
{
_hotKeyManager.Unregister(hotKey);
});
}
_hotKeys.Clear();
foreach (var keyBinding in keyBindings)
{
try
{
var key = Utilities.ExtendVirtualKeyToInputKey((ExtendedVirtualKey)keyBinding.Key);
var modifiers = ModifierKeys.None;
if (keyBinding.Alt)
{
modifiers |= ModifierKeys.Alt;
}
if (keyBinding.Ctrl)
{
modifiers |= ModifierKeys.Control;
}
if (keyBinding.Shift)
{
modifiers |= ModifierKeys.Shift;
}
var hotKey = new HotKey(key, modifiers);
_dispatcher.Invoke(() =>
{
_hotKeyManager.Register(hotKey);
});
_hotKeys.Add(hotKey);
}
catch (Exception)
{
_notificationService.ShowNotification("Error", "Failed to register the following hotkey: " + GetKeyBindingRepresentation(keyBinding));
}
}
}
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
_hotKeyManager?.Dispose();
}
_disposedValue = true;
}
}
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
private static string GetKeyBindingRepresentation(KeyBinding keyBinding)
{
var keys = new List<string>();
if (keyBinding.Ctrl)
{
keys.Add("Ctrl");
}
if (keyBinding.Alt)
{
keys.Add("Alt");
}
if (keyBinding.Shift)
{
keys.Add("Shift");
}
keys.Add(((ExtendedVirtualKey)keyBinding.Key).ToString());
return string.Join(" + ", keys);
}
[DllImport("user32.dll")]
private static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint ProcessId);
private string GetActiveProcessFileName()
{
try
{
var hwnd = GetForegroundWindow();
GetWindowThreadProcessId(hwnd, out uint pid);
var process = Process.GetProcessById((int)pid);
return process.MainWindowTitle;
}
catch (Exception)
{
return null;
}
}
private async void OnKeyPressed(object sender, KeyPressedEventArgs e)
{
if (GetActiveProcessFileName() == "Fluent Terminal")
{
SendKeys.Send("%{Tab}");
}
else
{
IEnumerable<AppListEntry> appListEntries = await Package.Current.GetAppListEntriesAsync();
await appListEntries.First().LaunchAsync();
}
}
}
}
+6 -1
View File
@@ -1,6 +1,8 @@
using FluentTerminal.SystemTray.Services;
using GlobalHotKey;
using Owin;
using System.Web.Http;
using System.Windows.Threading;
using Unity;
using Unity.Lifetime;
@@ -15,10 +17,13 @@ namespace FluentTerminal.SystemTray
var container = new UnityContainer();
container.RegisterType<TerminalsManager>(new ContainerControlledLifetimeManager());
container.RegisterType<NotificationService>(new ContainerControlledLifetimeManager());
container.RegisterType<ToggleWindowService>(new ContainerControlledLifetimeManager());
container.RegisterInstance(new HotKeyManager(), new ContainerControlledLifetimeManager());
container.RegisterInstance(Dispatcher.CurrentDispatcher, new ContainerControlledLifetimeManager());
config.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
appBuilder.UseStaticFiles("/Client");
appBuilder.UseWebApi(config);
}
}
@@ -1,72 +1,43 @@
using GlobalHotKey;
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;
using Windows.ApplicationModel;
using Windows.ApplicationModel.AppService;
using Windows.ApplicationModel.Core;
using Windows.Data.Xml.Dom;
using Windows.Foundation.Collections;
using Windows.UI.Notifications;
namespace FluentTerminal.SystemTray
{
public class SystemTrayApplicationContext : ApplicationContext
{
private AppServiceConnection connection = null;
private HotKeyManager hotKeyManager = null;
private NotifyIcon notifyIcon = null;
private AppServiceConnection _connection;
private readonly NotifyIcon _notifyIcon;
public SystemTrayApplicationContext()
{
var openMenuItem = new MenuItem("Show", new EventHandler(OpenApp));
var newWindowItem = new MenuItem("New Window", new EventHandler(NewWindow));
var settingsMenuItem = new MenuItem("Show Settings", new EventHandler(ShowSettings));
var newWindowItem = new MenuItem("New window", new EventHandler(NewWindow));
var settingsMenuItem = new MenuItem("Show settings", new EventHandler(ShowSettings));
var exitMenuItem = new MenuItem("Exit", new EventHandler(Exit));
openMenuItem.DefaultItem = true;
notifyIcon = new NotifyIcon();
notifyIcon.DoubleClick += OpenApp;
notifyIcon.Text = "Fluent Terminal";
notifyIcon.Icon = Properties.Resources.Square44x44Logo_scale_100;
notifyIcon.ContextMenu = new ContextMenu(new MenuItem[] { openMenuItem, newWindowItem, settingsMenuItem, exitMenuItem });
notifyIcon.Visible = true;
hotKeyManager = new HotKeyManager();
try
{
hotKeyManager.Register(Key.Scroll, ModifierKeys.None);
hotKeyManager.KeyPressed += HotkeyManager_KeyPressed;
}
catch (Exception)
{
ShowNotification("Fluent Terminal", "Unable to register hotkey for toggle window command");
}
_notifyIcon = new NotifyIcon();
_notifyIcon.DoubleClick += OpenApp;
_notifyIcon.Text = "Fluent Terminal";
_notifyIcon.Icon = Properties.Resources.Square44x44Logo_scale_100;
_notifyIcon.ContextMenu = new ContextMenu(new MenuItem[] { openMenuItem, newWindowItem, settingsMenuItem, exitMenuItem });
_notifyIcon.Visible = true;
}
[DllImport("user32.dll")]
public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint ProcessId);
protected override void Dispose(bool disposing)
{
hotKeyManager.Dispose();
base.Dispose(disposing);
}
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
private void Connection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
{
connection.ServiceClosed -= Connection_ServiceClosed;
connection = null;
_connection.ServiceClosed -= Connection_ServiceClosed;
_connection = null;
}
private async void Exit(object sender, EventArgs e)
@@ -79,36 +50,6 @@ namespace FluentTerminal.SystemTray
Application.Exit();
}
private string GetActiveProcessFileName()
{
try
{
IntPtr hwnd = GetForegroundWindow();
GetWindowThreadProcessId(hwnd, out uint pid);
Process p = Process.GetProcessById((int)pid);
return p.MainWindowTitle;
}
catch (Exception e)
{
return null;
}
}
private void HotkeyManager_KeyPressed(object sender, KeyPressedEventArgs e)
{
if (e.HotKey.Key == Key.Scroll)
{
if (GetActiveProcessFileName() == "Fluent Terminal")
{
SendKeys.Send("%{Tab}");
}
else
{
OpenApp(this, EventArgs.Empty);
}
}
}
private void NewWindow(object sender, EventArgs e)
{
Process.Start("flute.exe", "new");
@@ -123,15 +64,15 @@ namespace FluentTerminal.SystemTray
private async Task SendMessage(ValueSet message)
{
if (connection == null)
if (_connection == null)
{
connection = new AppServiceConnection
_connection = new AppServiceConnection
{
PackageFamilyName = Package.Current.Id.FamilyName,
AppServiceName = "FluentTerminalAppService"
};
connection.ServiceClosed += Connection_ServiceClosed;
AppServiceConnectionStatus connectionStatus = await connection.OpenAsync();
_connection.ServiceClosed += Connection_ServiceClosed;
AppServiceConnectionStatus connectionStatus = await _connection.OpenAsync();
if (connectionStatus != AppServiceConnectionStatus.Success)
{
@@ -139,25 +80,7 @@ namespace FluentTerminal.SystemTray
return;
}
}
await connection.SendMessageAsync(message);
}
private void ShowNotification(string title, string content)
{
string xml = $@"<toast>
<visual>
<binding template='ToastGeneric'>
<text>{title}</text>
<text>{content}</text>
</binding>
</visual>
</toast>";
var doc = new XmlDocument();
doc.LoadXml(xml);
var toast = new ToastNotification(doc);
ToastNotificationManager.CreateToastNotifier().Show(toast);
await _connection.SendMessageAsync(message);
}
private void ShowSettings(object sender, EventArgs e)
+292 -1
View File
@@ -1,7 +1,9 @@
using System;
using FluentTerminal.Models.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Windows.Input;
namespace FluentTerminal.SystemTray
{
@@ -33,5 +35,294 @@ namespace FluentTerminal.SystemTray
}
return null;
}
public static Key ExtendVirtualKeyToInputKey(ExtendedVirtualKey key)
{
switch (key)
{
case ExtendedVirtualKey.Cancel:
return Key.Cancel;
case ExtendedVirtualKey.Back:
return Key.Back;
case ExtendedVirtualKey.Tab:
return Key.Tab;
case ExtendedVirtualKey.Clear:
return Key.Clear;
case ExtendedVirtualKey.Enter:
return Key.Enter;
case ExtendedVirtualKey.Shift:
return Key.LeftShift;
case ExtendedVirtualKey.Menu:
return Key.LeftAlt;
case ExtendedVirtualKey.Pause:
return Key.Pause;
case ExtendedVirtualKey.CapitalLock:
return Key.CapsLock;
case ExtendedVirtualKey.Kana:
return Key.KanaMode;
case ExtendedVirtualKey.Junja:
return Key.JunjaMode;
case ExtendedVirtualKey.Final:
return Key.FinalMode;
case ExtendedVirtualKey.Kanji:
return Key.KanjiMode;
case ExtendedVirtualKey.Escape:
return Key.Escape;
case ExtendedVirtualKey.Convert:
return Key.ImeConvert;
case ExtendedVirtualKey.NonConvert:
return Key.ImeNonConvert;
case ExtendedVirtualKey.Accept:
return Key.ImeAccept;
case ExtendedVirtualKey.ModeChange:
return Key.ImeModeChange;
case ExtendedVirtualKey.Space:
return Key.Space;
case ExtendedVirtualKey.PageUp:
return Key.PageUp;
case ExtendedVirtualKey.PageDown:
return Key.PageDown;
case ExtendedVirtualKey.End:
return Key.End;
case ExtendedVirtualKey.Home:
return Key.Home;
case ExtendedVirtualKey.Left:
return Key.Left;
case ExtendedVirtualKey.Up:
return Key.Up;
case ExtendedVirtualKey.Right:
return Key.Right;
case ExtendedVirtualKey.Down:
return Key.Down;
case ExtendedVirtualKey.Select:
return Key.Select;
case ExtendedVirtualKey.Print:
return Key.Print;
case ExtendedVirtualKey.Execute:
return Key.Execute;
case ExtendedVirtualKey.Snapshot:
return Key.Snapshot;
case ExtendedVirtualKey.Insert:
return Key.Insert;
case ExtendedVirtualKey.Delete:
return Key.Delete;
case ExtendedVirtualKey.Help:
return Key.Help;
case ExtendedVirtualKey.Number0:
return Key.D0;
case ExtendedVirtualKey.Number1:
return Key.D1;
case ExtendedVirtualKey.Number2:
return Key.D2;
case ExtendedVirtualKey.Number3:
return Key.D3;
case ExtendedVirtualKey.Number4:
return Key.D4;
case ExtendedVirtualKey.Number5:
return Key.D5;
case ExtendedVirtualKey.Number6:
return Key.D6;
case ExtendedVirtualKey.Number7:
return Key.D7;
case ExtendedVirtualKey.Number8:
return Key.D8;
case ExtendedVirtualKey.Number9:
return Key.D9;
case ExtendedVirtualKey.A:
return Key.A;
case ExtendedVirtualKey.B:
return Key.B;
case ExtendedVirtualKey.C:
return Key.C;
case ExtendedVirtualKey.D:
return Key.D;
case ExtendedVirtualKey.E:
return Key.E;
case ExtendedVirtualKey.F:
return Key.F;
case ExtendedVirtualKey.G:
return Key.G;
case ExtendedVirtualKey.H:
return Key.H;
case ExtendedVirtualKey.I:
return Key.I;
case ExtendedVirtualKey.J:
return Key.J;
case ExtendedVirtualKey.K:
return Key.K;
case ExtendedVirtualKey.L:
return Key.L;
case ExtendedVirtualKey.M:
return Key.M;
case ExtendedVirtualKey.N:
return Key.N;
case ExtendedVirtualKey.O:
return Key.O;
case ExtendedVirtualKey.P:
return Key.P;
case ExtendedVirtualKey.Q:
return Key.Q;
case ExtendedVirtualKey.R:
return Key.R;
case ExtendedVirtualKey.S:
return Key.S;
case ExtendedVirtualKey.T:
return Key.T;
case ExtendedVirtualKey.U:
return Key.U;
case ExtendedVirtualKey.V:
return Key.V;
case ExtendedVirtualKey.W:
return Key.W;
case ExtendedVirtualKey.X:
return Key.X;
case ExtendedVirtualKey.Y:
return Key.Y;
case ExtendedVirtualKey.Z:
return Key.Z;
case ExtendedVirtualKey.LeftWindows:
return Key.LWin;
case ExtendedVirtualKey.RightWindows:
return Key.RWin;
case ExtendedVirtualKey.Application:
return Key.Apps;
case ExtendedVirtualKey.Sleep:
return Key.Sleep;
case ExtendedVirtualKey.NumberPad0:
return Key.NumPad0;
case ExtendedVirtualKey.NumberPad1:
return Key.NumPad1;
case ExtendedVirtualKey.NumberPad2:
return Key.NumPad2;
case ExtendedVirtualKey.NumberPad3:
return Key.NumPad3;
case ExtendedVirtualKey.NumberPad4:
return Key.NumPad4;
case ExtendedVirtualKey.NumberPad5:
return Key.NumPad5;
case ExtendedVirtualKey.NumberPad6:
return Key.NumPad6;
case ExtendedVirtualKey.NumberPad7:
return Key.NumPad7;
case ExtendedVirtualKey.NumberPad8:
return Key.NumPad8;
case ExtendedVirtualKey.NumberPad9:
return Key.NumPad9;
case ExtendedVirtualKey.Multiply:
return Key.Multiply;
case ExtendedVirtualKey.Add:
return Key.Add;
case ExtendedVirtualKey.Separator:
return Key.Separator;
case ExtendedVirtualKey.Subtract:
return Key.Subtract;
case ExtendedVirtualKey.Decimal:
return Key.Decimal;
case ExtendedVirtualKey.Divide:
return Key.Divide;
case ExtendedVirtualKey.F1:
return Key.F1;
case ExtendedVirtualKey.F2:
return Key.F2;
case ExtendedVirtualKey.F3:
return Key.F3;
case ExtendedVirtualKey.F4:
return Key.F4;
case ExtendedVirtualKey.F5:
return Key.F5;
case ExtendedVirtualKey.F6:
return Key.F6;
case ExtendedVirtualKey.F7:
return Key.F7;
case ExtendedVirtualKey.F8:
return Key.F8;
case ExtendedVirtualKey.F9:
return Key.F9;
case ExtendedVirtualKey.F10:
return Key.F10;
case ExtendedVirtualKey.F11:
return Key.F11;
case ExtendedVirtualKey.F12:
return Key.F12;
case ExtendedVirtualKey.F13:
return Key.F13;
case ExtendedVirtualKey.F14:
return Key.F14;
case ExtendedVirtualKey.F15:
return Key.F15;
case ExtendedVirtualKey.F16:
return Key.F16;
case ExtendedVirtualKey.F17:
return Key.F17;
case ExtendedVirtualKey.F18:
return Key.F18;
case ExtendedVirtualKey.F19:
return Key.F19;
case ExtendedVirtualKey.F20:
return Key.F20;
case ExtendedVirtualKey.F21:
return Key.F21;
case ExtendedVirtualKey.F22:
return Key.F22;
case ExtendedVirtualKey.F23:
return Key.F23;
case ExtendedVirtualKey.F24:
return Key.F24;
case ExtendedVirtualKey.NumberKeyLock:
return Key.NumLock;
case ExtendedVirtualKey.Scroll:
return Key.Scroll;
case ExtendedVirtualKey.LeftShift:
return Key.LeftShift;
case ExtendedVirtualKey.RightShift:
return Key.RightShift;
case ExtendedVirtualKey.LeftControl:
return Key.LeftCtrl;
case ExtendedVirtualKey.RightControl:
return Key.RightCtrl;
case ExtendedVirtualKey.LeftMenu:
return Key.LeftAlt;
case ExtendedVirtualKey.RightMenu:
return Key.RightAlt;
case ExtendedVirtualKey.GoBack:
return Key.BrowserBack;
case ExtendedVirtualKey.GoForward:
return Key.BrowserForward;
case ExtendedVirtualKey.Refresh:
return Key.BrowserRefresh;
case ExtendedVirtualKey.Stop:
return Key.BrowserStop;
case ExtendedVirtualKey.Search:
return Key.BrowserSearch;
case ExtendedVirtualKey.Favorites:
return Key.BrowserFavorites;
case ExtendedVirtualKey.GoHome:
return Key.BrowserHome;
case ExtendedVirtualKey.VolumeMute:
return Key.VolumeMute;
case ExtendedVirtualKey.VolumeDown:
return Key.VolumeDown;
case ExtendedVirtualKey.VolumeUp:
return Key.VolumeUp;
case ExtendedVirtualKey.MediaNext:
return Key.MediaNextTrack;
case ExtendedVirtualKey.MediaPrevious:
return Key.MediaPreviousTrack;
case ExtendedVirtualKey.MediaStop:
return Key.MediaStop;
case ExtendedVirtualKey.MediaPlayPause:
return Key.MediaPlayPause;
case ExtendedVirtualKey.Plus:
return Key.OemPlus;
case ExtendedVirtualKey.Comma:
return Key.OemComma;
case ExtendedVirtualKey.Minus:
return Key.OemMinus;
case ExtendedVirtualKey.Period:
return Key.OemPeriod;
default:
return Key.None;
}
}
}
}