Compare commits

...
84 Commits
Author SHA1 Message Date
FelixSe dcdf8d1854 Added search function 2018-05-27 20:22:21 +02:00
FelixSe fb717b3750 Fix crashes on delete or restore keybindings 2018-05-27 13:49:53 +02:00
FelixSe aff7b636f1 Add option to select shell profile while creating a new tab (ctrl+shift+t by default) 2018-05-27 13:35:02 +02:00
FelixSe 99a7de25d3 Close tab/window when shell process has exited 2018-05-26 22:32:15 +02:00
FelixSe 28d950ed9a Support multiple shell profiles 2018-05-26 22:05:49 +02:00
Felix 1490470e91 Merge pull request #22 from skipmeister123/master
Added "Homebrew" theme
2018-05-24 21:52:38 +02:00
Hans Kokx 236e0ff2e1 Added "Homebrew" theme 2018-05-24 15:43:24 -04:00
Felix 5cb9158077 Update README.md 2018-05-23 21:47:16 +02:00
FelixSe 941c7c1948 update to xterm 3.4.0 and use dynamic charAtlas 2018-05-20 12:16:03 +02:00
Felix 45e096c033 Update README.md 2018-05-06 19:49:08 +02:00
FelixSe d37da0ef31 fixed last ambiguous xcopy 2018-05-06 18:52:29 +02:00
FelixSe 49abf56ec6 fixed another ambiguous xcopy 2018-05-02 22:42:22 +02:00
FelixSe 618a2485e1 fix postbuild event when target directory is not yet created 2018-05-02 22:27:02 +02:00
felixse cdeeeb6fa8 Make hintpath in Models.csproj use a variable for program files (x86) 2018-05-02 11:02:00 +02:00
felixse be833cc174 Make hintpaths in SystemTray.csproj use a variable for program files (x86) 2018-05-02 10:40:22 +02:00
FelixSe 39955bcb3e Started writing some unit tests 2018-05-01 21:22:34 +02:00
FelixSe e9b76a6867 Code cleanup 2018-05-01 13:10:47 +02:00
FelixSe 89bce37dbd Fix bug while adding secondary keybindings 2018-05-01 13:10:41 +02:00
FelixSe 82a195c2f2 Use AppService instead of WebAPI for inter process communication 2018-04-29 15:52:57 +02:00
FelixSe c48889cbbc Execute copy only when selection is not empty, this allows for ctrl + c to be used as the default copy keybinding 2018-04-22 13:12:50 +02:00
FelixSe dd9d5d2e72 Extend key enum, improve displaying 2018-04-22 12:45:56 +02:00
FelixSe 7f7f15ea03 Support meta key for keybindings 2018-04-22 12:45:30 +02:00
FelixSe f502303426 Update xterm to 3.3.0 2018-04-15 16:23:24 +02:00
FelixSe 2f2ed06d58 Refactored App startup 2018-04-15 16:13:20 +02:00
FelixSe 809167a872 removed unnecessary quotes in context menu integration script 2018-04-15 16:11:26 +02:00
FelixSe 5d3fd25098 remove unused field 2018-04-15 16:10:41 +02:00
FelixSe 6674fd0ad9 Fix for open Fluent Terminal here failing if no other terminal window open 2018-03-18 14:07:34 +01:00
FelixSe f874cb070d Fix race condition while retrieving the systemtrays API port 2018-03-18 13:37:20 +01:00
FelixSe 40230bfce8 Rename tray command to 'new terminal' since it does not necessarily create a new window 2018-03-14 22:20:04 +01:00
FelixSe 3afa2b5f25 Remove App.Instance singleton 2018-03-11 00:26:23 +01:00
FelixSe 94ba1b8324 Update xterm.js to 3.2.0 2018-03-10 23:33:41 +01:00
FelixSe 6dfacdfebd Remove almost unused AppService in favor of using flute.exe 2018-03-10 00:06:25 +01:00
FelixSe 1ca7371103 No longer depending on a static port for communication with Tray process 2018-03-06 21:45:24 +01:00
Felix 1cb388d4af Update README.md 2018-03-05 21:16:56 +01:00
FelixSe 3bdd96c388 Screenshots look better without cursors.. 2018-03-05 21:02:10 +01:00
FelixSe 5bc5bf224f Add Screenshots 2018-03-05 20:56:45 +01:00
FelixSe 01815db1fe Fix typo, set correct c# version in csproj, increase version 2018-03-05 19:26:33 +01:00
FelixSe 80cf43d3bf Store client in app data instead of serving it 2018-03-04 22:26:30 +01:00
FelixSe 050f162c08 Split SettingsPageViewModel into one per page, fix buggy radio buttons 2018-03-04 14:40:05 +01:00
FelixSe f5e03c9856 Register converters only once 2018-03-04 13:22:27 +01:00
FelixSe f763798683 Added option to create new terminals (e.g from context menu) as tabs instead of windows 2018-03-04 13:07:32 +01:00
FelixSe 46120e3431 Make toggle window hotkey configurable 2018-03-03 11:44:46 +01:00
FelixSe 829077883b Improved layout for keybindings settings page 2018-02-26 22:00:58 +01:00
FelixSe 8c928faa09 Some cosmetic changes 2018-02-25 22:31:52 +01:00
FelixSe 1654e9f1f5 Propagate changed keyBindings immediately 2018-02-25 21:52:17 +01:00
FelixSe f542331192 Editable keybindings 2018-02-25 15:40:36 +01:00
FelixSe 6830adb788 Increase version, add generated files to .gitignore 2018-02-22 22:33:18 +01:00
FelixSe 02e015371c Supress webview native context menu 2018-02-22 22:07:21 +01:00
FelixSe 80bdfa012c Show notification if registering hotkey for toggle window fails 2018-02-20 22:04:23 +01:00
FelixSe 70326e9585 Add missing whitespace in product name 2018-02-20 22:04:20 +01:00
FelixSe c0e1415b6e Use shell executable name as tab title 2018-02-20 21:56:51 +01:00
FelixSe 13a3402b58 Improve error message for failed shell startup 2018-02-20 18:41:34 +01:00
FelixSe 73703412f8 Fix for shells no longer getting cleaned up on window close 2018-02-20 18:18:45 +01:00
FelixSe ab226d95d4 Added option to confirm before closing tab/window 2018-02-19 23:34:22 +01:00
FelixSe de7a76bb3b Add icons to settings pages 2018-02-19 21:01:09 +01:00
FelixSe 379f58b4b8 Rename open to show in tray icon 2018-02-19 20:38:37 +01:00
FelixSe 3a04cd3db2 Close tabs with middle click 2018-02-19 20:37:25 +01:00
FelixSe df0d3f080b Use non acrylic accent color for resize overlay 2018-02-19 19:34:54 +01:00
FelixSe 04131d271a Improve size of titlebar button icons 2018-02-19 19:31:31 +01:00
FelixSe d66fe26634 Global hotkey for show/hide window 2018-02-18 23:10:05 +01:00
FelixSe 8870f0621c Keyboard shortcuts 2018-02-18 21:08:22 +01:00
FelixSe e5250a7ae8 Reorderable tabs for windows 2018-02-17 17:32:48 +01:00
FelixSe b2b6cedf2c Increase version to 0.1.5.0 2018-02-16 17:37:54 +01:00
Felix e777c2c5ac Update README.md 2018-02-16 17:31:46 +01:00
FelixSe 7dcd8e1fbb Make background opacity configurable 2018-02-15 23:00:30 +01:00
FelixSe 37518cf88b Terminal Settings 2018-02-15 22:26:55 +01:00
FelixSe ca0e22b8d0 Reenable settings window title bar when navigation view is collapsed 2018-02-15 16:50:06 +01:00
FelixSe 074f5f9c7e Wrap dialogs in service 2018-02-14 18:00:00 +01:00
FelixSe 0b40963c82 change theme also on existing windows 2018-02-14 11:56:52 +01:00
FelixSe 0b6b8a9968 Fix selection color for xterm.js theme 2018-02-14 10:04:20 +01:00
FelixSe 47613454c7 Switch to official xterm.js 2018-02-14 10:04:05 +01:00
FelixSe 96d063b4fd Theme settings 2018-02-13 23:36:23 +01:00
FelixSe fec44fb0b5 fix context menu integrations for directories that contain whitespaces 2018-02-06 19:12:39 +01:00
FelixSe 58e7de5271 fix explorer integration path for installations where HomeDrive is not C: 2018-02-06 19:09:20 +01:00
FelixSe 466b7a7503 Display default window title again when terminal is resetting its title 2018-02-05 23:30:04 +01:00
FelixSe 50f9c84420 Support specifying the startup directory via command line and provide basic Explorer context menu integration 2018-02-05 23:23:03 +01:00
FelixSe f07dae98ee Escape shell executable path in commandLine 2018-02-04 00:12:44 +01:00
FelixSe 1cc74f79b4 Fix shell arguments 2018-02-03 23:34:07 +01:00
FelixSe 60c4f0518d Recover missing Client files 2018-02-03 23:20:53 +01:00
FelixSe f9fb05b194 Removed generated files from repository and added to .gitignore 2018-02-03 22:45:17 +01:00
FelixSe d933f60b8b Merge branch 'master' of https://github.com/felixse/FluentTerminal 2018-02-03 22:40:33 +01:00
FelixSe 45bba6e2eb Use hyper.js xterm fork for now instead of including it in this repository 2018-02-03 22:39:32 +01:00
FelixSe 210aeedc25 Update winpty to 0.4.3 2018-02-03 22:04:22 +01:00
Felix acfb8e8883 Update README.md 2018-02-03 21:46:00 +01:00
413 changed files with 6990 additions and 50170 deletions

No files matched your search

+2
View File
@@ -1,5 +1,7 @@
# Project specific
FluentTerminal.App/Win32
FluentTerminal.App/Client/
FluentTerminal.Client/dist
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
@@ -0,0 +1,3 @@
reg add "HKCU\Software\Classes\Directory\shell\Open Fluent Terminal here\command" /d "\"%LOCALAPPDATA%\Microsoft\WindowsApps\flute.exe\" new %%1" /f
reg add "HKCU\Software\Classes\Directory\Background\shell\Open Fluent Terminal here\command" /d "\"%LOCALAPPDATA%\Microsoft\WindowsApps\flute.exe\" new %%V" /f
reg add "HKCU\Software\Classes\LibraryFolder\Background\shell\Open Fluent Terminal here\command" /d "\"%LOCALAPPDATA%\Microsoft\WindowsApps\flute.exe\" new %%V" /f
@@ -0,0 +1,3 @@
reg delete "HKCU\Software\Classes\Directory\shell\Open Fluent Terminal here" /f
reg delete "HKCU\Software\Classes\Directory\Background\shell\Open Fluent Terminal here" /f
reg delete "HKCU\Software\Classes\LibraryFolder\Background\shell\Open Fluent Terminal here" /f
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

@@ -0,0 +1,171 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}</ProjectGuid>
<OutputType>AppContainerExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FluentTerminal.App.Test</RootNamespace>
<AssemblyName>FluentTerminal.App.Test</AssemblyName>
<DefaultLanguage>de-DE</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PackageCertificateKeyFile>FluentTerminal.App.Test_TemporaryKey.pfx</PackageCertificateKeyFile>
<UnitTestPlatformVersion Condition="'$(UnitTestPlatformVersion)' == ''">$(VisualStudioVersion)</UnitTestPlatformVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<OutputPath>bin\ARM\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<ItemGroup>
<SDKReference Include="TestPlatform.Universal, Version=$(UnitTestPlatformVersion)" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\DialogServiceTests.cs" />
<Compile Include="Services\KeyboardCommandServiceTests.cs" />
<Compile Include="UnitTestApp.xaml.cs">
<DependentUpon>UnitTestApp.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="UnitTestApp.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
<None Include="FluentTerminal.App.Test_TemporaryKey.pfx" />
</ItemGroup>
<ItemGroup>
<Content Include="Properties\UnitTestApp.rd.xml" />
<Content Include="Assets\LockScreenLogo.scale-200.png" />
<Content Include="Assets\SplashScreen.scale-200.png" />
<Content Include="Assets\Square150x150Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Assets\StoreLogo.png" />
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AutoFixture">
<Version>4.2.1</Version>
</PackageReference>
<PackageReference Include="FluentAssertions">
<Version>5.3.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.1.2</Version>
</PackageReference>
<PackageReference Include="Moq">
<Version>4.8.2</Version>
</PackageReference>
<PackageReference Include="MSTest.TestAdapter">
<Version>1.2.1</Version>
</PackageReference>
<PackageReference Include="MSTest.TestFramework">
<Version>1.2.1</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FluentTerminal.App\FluentTerminal.App.csproj">
<Project>{41020100-3414-4e0a-9a8e-92d3c4179df8}</Project>
<Name>FluentTerminal.App</Name>
</ProjectReference>
<ProjectReference Include="..\FluentTerminal.Models\FluentTerminal.Models.csproj">
<Project>{5EA40453-A0AA-449E-8406-D6EA51D7E70E}</Project>
<Name>FluentTerminal.Models</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- 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">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
@@ -0,0 +1,45 @@
<?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"
IgnorableNamespaces="uap mp">
<Identity Name="63c2a56f-7075-408a-a37d-24bb7fb21665"
Publisher="CN=Felix"
Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="63c2a56f-7075-408a-a37d-24bb7fb21665" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>FluentTerminal.App.Test</DisplayName>
<PublisherDisplayName>Felix</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="vstest.executionengine.universal.App"
Executable="$targetnametoken$.exe"
EntryPoint="FluentTerminal.App.Test.App">
<uap:VisualElements
DisplayName="FluentTerminal.App.Test"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png"
Description="FluentTerminal.App.Test"
BackgroundColor="transparent">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png"/>
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClientServer" />
</Capabilities>
</Package>
@@ -0,0 +1,18 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("FluentTerminal.App.Test")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FluentTerminal.App.Test")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyMetadata("TargetPlatform","UAP")]
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: ComVisible(false)]
@@ -0,0 +1,29 @@
<!--
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
developers. However, you can modify these parameters to modify the behavior of the .NET Native
optimizer.
Runtime Directives are documented at http://go.microsoft.com/fwlink/?LinkID=391919
To fully enable reflection for App1.MyClass and all of its public/private members
<Type Name="App1.MyClass" Dynamic="Required All"/>
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
<Namespace Name="DataClasses.ViewModels" Seralize="All" />
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Application>
<!--
An Assembly element with Name="*Application*" applies to all assemblies in
the application package. The asterisks are not wildcards.
-->
<Assembly Name="*Application*" Dynamic="Required All" />
<!-- Add your application specific runtime directives here. -->
</Application>
</Directives>
@@ -0,0 +1,62 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using AutoFixture;
using FluentAssertions;
using FluentTerminal.App.Services;
using FluentTerminal.App.Services.Implementation;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace FluentTerminal.App.Test.Services
{
[TestClass]
public class DialogServiceTests
{
private Fixture _fixture;
[TestInitialize]
public void TestInitialize()
{
_fixture = new Fixture();
}
[TestMethod]
public void ShowDialogAsync_TitleIsEmpty_ThrowsArgumentNullException()
{
var title = string.Empty;
var content = _fixture.Create<string>();
var buttons = _fixture.CreateMany<DialogButton>(2);
var dialogService = new DialogService(Mock.Of<ISettingsService>());
Func<Task<DialogButton>> invoke = () => dialogService.ShowMessageDialogAsnyc(title, content, buttons.ElementAt(0), buttons.ElementAt(1));
invoke.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("title");
}
[TestMethod]
public void ShowDialogAsync_ContentIsEmpty_ThrowsArgumentNullException()
{
var title = _fixture.Create<string>();
var content = string.Empty;
var buttons = _fixture.CreateMany<DialogButton>(2);
var dialogService = new DialogService(Mock.Of<ISettingsService>());
Func<Task<DialogButton>> invoke = () => dialogService.ShowMessageDialogAsnyc(title, content, buttons.ElementAt(0), buttons.ElementAt(1));
invoke.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("content");
}
[TestMethod]
public void ShowDialogAsync_NoButtonsPassed_ThrowsArgumentException()
{
var title = _fixture.Create<string>();
var content = _fixture.Create<string>();
var dialogService = new DialogService(Mock.Of<ISettingsService>());
Func<Task<DialogButton>> invoke = () => dialogService.ShowMessageDialogAsnyc(title, content);
invoke.Should().Throw<ArgumentException>().And.ParamName.Should().Be("buttons");
}
}
}
@@ -0,0 +1,71 @@
using AutoFixture;
using FluentAssertions;
using FluentTerminal.App.Services.Implementation;
using FluentTerminal.Models.Enums;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
namespace FluentTerminal.App.Test.Services
{
[TestClass]
public class KeyboardCommandServiceTests
{
private Fixture _fixture;
[TestInitialize]
public void TestInitialize()
{
_fixture = new Fixture();
}
[TestMethod]
public void RegisterCommandHandler_HandlerIsNull_ThrowsArgumentNullException()
{
var command = _fixture.Create<Command>();
Action handler = null;
var keyboardCommandService = new KeyboardCommandService();
Action invoke = () => keyboardCommandService.RegisterCommandHandler(command, handler);
invoke.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("handler");
}
[TestMethod]
public void RegisterCommandHandler_CommandAlreadyRegisted_ThrowsInvalidOperationException()
{
var command = _fixture.Create<Command>();
var handler = _fixture.Create<Action>();
var keyboardCommandService = new KeyboardCommandService();
keyboardCommandService.RegisterCommandHandler(command, handler);
Action invoke = () => keyboardCommandService.RegisterCommandHandler(command, handler);
invoke.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public void SendCommand_CommandIsRegistered_HandlerGetsInvoked()
{
var command = _fixture.Create<Command>();
var handlerCalled = false;
var keyboardCommandService = new KeyboardCommandService();
keyboardCommandService.RegisterCommandHandler(command, () => handlerCalled = true);
keyboardCommandService.SendCommand(command);
handlerCalled.Should().BeTrue();
}
[TestMethod]
public void SendCommand_CommandIsNotRegisted_KeyNotFoundExceptionIsThrown()
{
var command = _fixture.Create<Command>();
var keyboardCommandService = new KeyboardCommandService();
Action invoke = () => keyboardCommandService.SendCommand(command);
invoke.Should().Throw<KeyNotFoundException>();
}
}
}
+8
View File
@@ -0,0 +1,8 @@
<Application
x:Class="FluentTerminal.App.Test.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:FluentTerminal.App.Test"
RequestedTheme="Light">
</Application>
+102
View File
@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
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;
namespace FluentTerminal.App.Test
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
sealed partial class App : Application
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
this.DebugSettings.EnableFrameRateCounter = true;
}
#endif
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.CreateDefaultUI();
// Ensure the current window is active
Window.Current.Activate();
Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.Run(e.Arguments);
}
/// <summary>
/// Invoked when Navigation to a certain page fails
/// </summary>
/// <param name="sender">The Frame which failed navigation</param>
/// <param name="e">Details about the navigation failure</param>
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
/// <summary>
/// Invoked when application execution is being suspended. Application state is saved
/// without knowing whether the application will be terminated or resumed with the contents
/// of memory still intact.
/// </summary>
/// <param name="sender">The source of the suspend request.</param>
/// <param name="e">Details about the suspend request.</param>
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: Save application state and stop any background activity
deferral.Complete();
}
}
}
+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>
+154 -81
View File
@@ -3,7 +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;
@@ -14,120 +19,143 @@ using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using IContainer = Autofac.IContainer;
namespace FluentTerminal.App
{
sealed partial class App : Application
public sealed partial class App : Application
{
public static BackgroundTaskDeferral AppServiceDeferral = null;
public static AppServiceConnection Connection = null;
public static App Instance;
public TaskCompletionSource<int> _trayReady = new TaskCompletionSource<int>();
private readonly ISettingsService _settingsService;
private readonly ITrayProcessCommunicationService _trayProcessCommunicationService;
private bool _alreadyLaunched;
private IContainer _container;
private int _openTerminalWindows;
private ApplicationSettings _applicationSettings;
private readonly IContainer _container;
private readonly List<MainViewModel> _mainViewModels;
private SettingsViewModel _settingsViewModel;
private int? _settingsWindowId;
private AppServiceConnection _appServiceConnection;
private BackgroundTaskDeferral _appServiceDeferral;
public App()
{
_mainViewModels = new List<MainViewModel>();
InitializeComponent();
Instance = this;
var builder = new ContainerBuilder();
builder.RegisterType<SettingsService>().As<ISettingsService>().InstancePerDependency();
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();
}
public async Task CreateNewTerminalWindow()
{
var id = await CreateSecondaryView(typeof(MainPage), true);
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(id);
}
_settingsService = _container.Resolve<ISettingsService>();
_settingsService.ApplicationSettingsChanged += OnApplicationSettingsChanged;
public void SettingsWindowClosed()
{
_settingsWindowId = null;
}
_trayProcessCommunicationService = _container.Resolve<ITrayProcessCommunicationService>();
public async Task ShowSettings()
{
if (_settingsWindowId == null)
{
_settingsWindowId = await CreateSecondaryView(typeof(SettingsPage), true);
}
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(_settingsWindowId.Value);
}
public void TerminalWindowClosed()
{
_openTerminalWindows--;
_applicationSettings = _settingsService.GetApplicationSettings();
}
protected override async void OnActivated(IActivatedEventArgs args)
{
if (args is CommandLineActivatedEventArgs commandLineActivated)
{
var argument = commandLineActivated.Operation.Arguments.Trim();
if (string.IsNullOrWhiteSpace(commandLineActivated.Operation.Arguments))
{
return;
}
var arguments = commandLineActivated.Operation.Arguments.Split(' ', 2);
var command = arguments[0];
var parameter = arguments.Length > 1 ? arguments[1] : string.Empty;
if (_alreadyLaunched)
{
if (argument == "settings")
if (command == "settings")
{
await ShowSettings();
await ShowSettings().ConfigureAwait(true);
}
else if (argument == "new")
else if (command == "new")
{
await CreateNewTerminalWindow();
if (_applicationSettings.NewTerminalLocation == NewTerminalLocation.Tab && _mainViewModels.Count > 0)
{
await _mainViewModels.Last().AddTerminal(parameter, false).ConfigureAwait(true);
}
else
{
await CreateNewTerminalWindow(parameter).ConfigureAwait(true);
}
}
}
else
{
if (argument == "settings")
if (command == "settings")
{
CreateMainView(typeof(SettingsPage), true);
var viewModel = _container.Resolve<SettingsViewModel>();
await CreateMainView(typeof(SettingsPage), viewModel, true).ConfigureAwait(true);
}
else if (argument == "new")
else if (command == "new")
{
CreateMainView(typeof(MainPage), true);
var viewModel = _container.Resolve<MainViewModel>();
await viewModel.AddTerminal(parameter, false).ConfigureAwait(true);
await CreateMainView(typeof(MainPage), viewModel, true).ConfigureAwait(true);
}
}
}
}
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
if (!_alreadyLaunched)
{
var viewModel = _container.Resolve<MainViewModel>();
await viewModel.AddTerminal(null, false).ConfigureAwait(true);
await CreateMainView(typeof(MainPage), viewModel, true).ConfigureAwait(true);
Window.Current.Activate();
}
else if (_mainViewModels.Count == 0)
{
await CreateSecondaryView<MainViewModel>(typeof(MainPage), true, string.Empty).ConfigureAwait(true);
}
}
protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
base.OnBackgroundActivated(args);
if (args.TaskInstance.TriggerDetails is AppServiceTriggerDetails details)
{
AppServiceDeferral = args.TaskInstance.GetDeferral();
args.TaskInstance.Canceled += OnTaskCanceled;
Connection = details.AppServiceConnection;
Connection.RequestReceived += OnRequestReceived;
if (details.CallerPackageFamilyName == Package.Current.Id.FamilyName)
{
_appServiceDeferral = args.TaskInstance.GetDeferral();
args.TaskInstance.Canceled += OnTaskCanceled;
_appServiceConnection = details.AppServiceConnection;
_trayReady.SetResult(0);
}
}
}
protected override async void OnLaunched(LaunchActivatedEventArgs e)
private void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
var launch = FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync().AsTask();
var clearCache = WebView.ClearTemporaryWebDataAsync().AsTask();
await Task.WhenAll(launch, clearCache);
_appServiceDeferral?.Complete();
_appServiceDeferral = null;
_appServiceConnection = null;
if (!_alreadyLaunched)
{
CreateMainView(typeof(MainPage), true);
Window.Current.Activate();
}
else if (_openTerminalWindows == 0)
{
await CreateSecondaryView(typeof(MainPage), true);
}
Application.Current.Exit();
}
private void CreateMainView(Type pageType, bool extendViewIntoTitleBar)
private async Task CreateMainView(Type pageType, INotifyPropertyChanged viewModel, bool extendViewIntoTitleBar)
{
await StartSystemTray().ConfigureAwait(true);
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
{
@@ -138,66 +166,111 @@ namespace FluentTerminal.App
if (rootFrame.Content == null)
{
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = extendViewIntoTitleBar;
rootFrame.Navigate(pageType, GetViewModelForPageType(pageType));
if (pageType == typeof(MainPage))
if (viewModel is MainViewModel mainViewModel)
{
_openTerminalWindows++;
mainViewModel.Closed += OnMainViewModelClosed;
mainViewModel.NewWindowRequested += OnNewWindowRequested;
mainViewModel.ShowSettingsRequested += OnShowSettingsRequested;
_mainViewModels.Add(mainViewModel);
}
rootFrame.Navigate(pageType, viewModel);
}
_alreadyLaunched = true;
Window.Current.Activate();
}
private async Task<int> CreateSecondaryView(Type pageType, bool ExtendViewIntoTitleBar)
private async Task CreateNewTerminalWindow(string startupDirectory)
{
var id = await CreateSecondaryView<MainViewModel>(typeof(MainPage), true, startupDirectory).ConfigureAwait(true);
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(id);
}
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, GetViewModelForPageType(pageType));
frame.Navigate(pageType, viewModel);
Window.Current.Content = frame;
Window.Current.Activate();
windowId = ApplicationView.GetForCurrentView().Id;
});
if (pageType == typeof(MainPage))
if (viewModel is MainViewModel mainViewModel && parameter is string directory)
{
_openTerminalWindows++;
mainViewModel.Closed += OnMainViewModelClosed;
mainViewModel.NewWindowRequested += OnNewWindowRequested;
mainViewModel.ShowSettingsRequested += OnShowSettingsRequested;
_mainViewModels.Add(mainViewModel);
await mainViewModel.AddTerminal(directory, false).ConfigureAwait(true);
}
if (viewModel is SettingsViewModel settingsViewModel)
{
_settingsViewModel = settingsViewModel;
_settingsViewModel.Closed += OnSettingsClosed;
}
return windowId;
}
private object GetViewModelForPageType(Type pageType)
private void OnApplicationSettingsChanged(object sender, EventArgs e)
{
if (pageType == typeof(MainPage))
{
return _container.Resolve<MainViewModel>();
}
else if (pageType == typeof(SettingsPage))
{
return _container.Resolve<SettingsViewModel>();
}
throw new Exception("No ViewModel defined for Page: " + pageType.Name);
_applicationSettings = _settingsService.GetApplicationSettings();
}
private void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
private void OnMainViewModelClosed(object sender, EventArgs e)
{
if (args.Request.Message.ContainsKey("exit"))
if (sender is MainViewModel viewModel)
{
App.Current.Exit();
viewModel.Closed -= OnMainViewModelClosed;
viewModel.NewWindowRequested -= OnNewWindowRequested;
viewModel.ShowSettingsRequested -= OnShowSettingsRequested;
_mainViewModels.Remove(viewModel);
}
}
private void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
private async void OnNewWindowRequested(object sender, EventArgs e)
{
if (AppServiceDeferral != null)
await CreateNewTerminalWindow(string.Empty).ConfigureAwait(true);
}
private void OnSettingsClosed(object sender, EventArgs e)
{
_settingsViewModel.Closed -= OnSettingsClosed;
_settingsViewModel = null;
_settingsWindowId = null;
}
private async void OnShowSettingsRequested(object sender, EventArgs e)
{
await ShowSettings().ConfigureAwait(true);
}
private async Task ShowSettings()
{
if (_settingsViewModel == null)
{
AppServiceDeferral.Complete();
_settingsWindowId = await CreateSecondaryView<SettingsViewModel>(typeof(SettingsPage), true, null).ConfigureAwait(true);
}
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(_settingsWindowId.Value);
}
private async Task StartSystemTray()
{
var launch = FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync().AsTask();
var clearCache = WebView.ClearTemporaryWebDataAsync().AsTask();
await Task.WhenAll(launch, clearCache, _trayReady.Task).ConfigureAwait(true);
await _trayProcessCommunicationService.Initialize(_appServiceConnection).ConfigureAwait(true);
}
}
}
Binary file not shown.
@@ -0,0 +1,40 @@
using Microsoft.Xaml.Interactivity;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Input;
namespace FluentTerminal.App.Behaviors
{
public class MiddleClickBehavior : Trigger<UIElement>
{
private bool _middleButtonPressed;
protected override void OnAttached()
{
AssociatedObject.PointerPressed += OnPointerPressed;
AssociatedObject.PointerReleased += OnPointerReleased;
}
protected override void OnDetaching()
{
AssociatedObject.PointerPressed -= OnPointerPressed;
AssociatedObject.PointerReleased -= OnPointerReleased;
}
private void OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
var point = e.GetCurrentPoint(AssociatedObject);
_middleButtonPressed = point.Properties.IsMiddleButtonPressed;
}
private void OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
var point = e.GetCurrentPoint(AssociatedObject);
var middleButtonStillPressed = point.Properties.IsMiddleButtonPressed;
if (_middleButtonPressed && !middleButtonStillPressed)
{
Interaction.ExecuteActions(AssociatedObject, Actions, null);
}
}
}
}
@@ -0,0 +1,43 @@
using FluentTerminal.Models.Enums;
using System;
using System.ComponentModel;
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 GetEnumDescription((ExtendedVirtualKey)intValue);
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
private static string GetEnumDescription(Enum value)
{
var fieldInfo = value.GetType().GetField(value.ToString());
if (fieldInfo == null)
{
return value.ToString();
}
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes?.Length > 0)
{
return attributes[0].Description;
}
return value.ToString();
}
}
}
@@ -0,0 +1,50 @@
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
namespace FluentTerminal.App.Converters
{
public class IntToVisibilityConverter : DependencyObject, IValueConverter
{
public static readonly DependencyProperty ElseProperty =
DependencyProperty.Register(nameof(Else), typeof(Visibility), typeof(IntToVisibilityConverter), new PropertyMetadata(Visibility.Collapsed));
public static readonly DependencyProperty IfProperty =
DependencyProperty.Register(nameof(If), typeof(int), typeof(IntToVisibilityConverter), new PropertyMetadata(0));
public static readonly DependencyProperty ThenProperty =
DependencyProperty.Register(nameof(Then), typeof(Visibility), typeof(IntToVisibilityConverter), new PropertyMetadata(Visibility.Visible));
public Visibility Else
{
get { return (Visibility)GetValue(ElseProperty); }
set { SetValue(ElseProperty, value); }
}
public int If
{
get { return (int)GetValue(IfProperty); }
set { SetValue(IfProperty, value); }
}
public Visibility Then
{
get { return (Visibility)GetValue(ThenProperty); }
set { SetValue(ThenProperty, value); }
}
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is int count)
{
return count == If ? Then : Else;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,22 @@
using System;
using Windows.UI.Xaml.Data;
namespace FluentTerminal.App.Converters
{
public class NegateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is bool boolean)
{
return !boolean;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}
@@ -8,7 +8,7 @@ namespace FluentTerminal.App.Converters
{
internal class TerminalViewModelToViewConverter : IValueConverter
{
private Dictionary<int, TerminalView> _viewDictionary;
private readonly Dictionary<int, TerminalView> _viewDictionary;
public TerminalViewModelToViewConverter()
{
@@ -0,0 +1,18 @@
<ContentDialog
x:Class="FluentTerminal.App.Dialogs.ShellProfileSelectionDialog"
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"
Title="Select Profile"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
CloseButtonText="Cancel"
PrimaryButtonText="Start"
RequestedTheme="Dark"
mc:Ignorable="d">
<ComboBox
HorizontalAlignment="Stretch"
DisplayMemberPath="Name"
ItemsSource="{x:Bind Profiles}"
SelectedItem="{x:Bind SelectedProfile, Mode=TwoWay}" />
</ContentDialog>
@@ -0,0 +1,22 @@
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using System.Collections.Generic;
using System.Linq;
using Windows.UI.Xaml.Controls;
namespace FluentTerminal.App.Dialogs
{
public sealed partial class ShellProfileSelectionDialog : ContentDialog
{
public IEnumerable<ShellProfile> Profiles { get; }
public ShellProfile SelectedProfile { get; private set; }
public ShellProfileSelectionDialog(ISettingsService settingsService)
{
Profiles = settingsService.GetShellProfiles();
SelectedProfile = Profiles.First();
this.InitializeComponent();
}
}
}
+108 -151
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>
@@ -99,34 +102,60 @@
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</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" />
<Compile Include="Converters\TrueToVisibleConverter.cs" />
<Compile Include="Dialogs\ShellProfileSelectionDialog.xaml.cs">
<DependentUpon>ShellProfileSelectionDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Services\IDialogService.cs" />
<Compile Include="Services\Implementation\DialogService.cs" />
<Compile Include="Services\Implementation\KeyboardCommandService.cs" />
<Compile Include="Services\IKeyboardCommandService.cs" />
<Compile Include="Utilities\ApplicationDataContainerExtensions.cs" />
<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="Utilities\HttpJsonContent.cs" />
<Compile Include="Utilities\IHttpContentExtensions.cs" />
<Compile Include="Services\ITrayProcessCommunicationService.cs" />
<Compile Include="Utilities\ColorExtensions.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\ProfilesPageViewModel.cs" />
<Compile Include="ViewModels\Settings\TerminalPageViewModel.cs" />
<Compile Include="ViewModels\Settings\ThemesPageViewModel.cs" />
<Compile Include="ViewModels\ShellProfileViewModel.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>
<Compile Include="Views\SettingsPages\ColorSettings.xaml.cs">
<DependentUpon>ColorSettings.xaml</DependentUpon>
<Compile Include="Views\SettingsPages\ThemeSettings.xaml.cs">
<DependentUpon>ThemeSettings.xaml</DependentUpon>
</Compile>
<Compile Include="Views\SettingsPages\FontSettings.xaml.cs">
<DependentUpon>FontSettings.xaml</DependentUpon>
<Compile Include="Views\SettingsPages\TerminalSettings.xaml.cs">
<DependentUpon>TerminalSettings.xaml</DependentUpon>
</Compile>
<Compile Include="Views\SettingsPages\GeneralSettings.xaml.cs">
<DependentUpon>GeneralSettings.xaml</DependentUpon>
@@ -134,8 +163,11 @@
<Compile Include="Views\SettingsPages\KeyBindingSettings.xaml.cs">
<DependentUpon>KeyBindingSettings.xaml</DependentUpon>
</Compile>
<Compile Include="Views\SettingsPages\ShellSettings.xaml.cs">
<DependentUpon>ShellSettings.xaml</DependentUpon>
<Compile Include="Views\SettingsPages\ShellProfileSettings.xaml.cs">
<DependentUpon>ShellProfileSettings.xaml</DependentUpon>
</Compile>
<Compile Include="Views\TerminalColorPicker.xaml.cs">
<DependentUpon>TerminalColorPicker.xaml</DependentUpon>
</Compile>
<Compile Include="Views\TerminalView.xaml.cs">
<DependentUpon>TerminalView.xaml</DependentUpon>
@@ -145,10 +177,37 @@
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
<None Include="FluentTerminal.App_StoreKey.pfx" />
<None Include="FluentTerminal.App_TemporaryKey.pfx" />
<Content Include="Assets\settingsicons.ttf" />
<Content Include="Win32\Autofac.dll" />
<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\Newtonsoft.Json.dll" />
<Content Include="Win32\System.Data.Common.dll" />
<Content Include="Win32\System.Diagnostics.StackTrace.dll" />
<Content Include="Win32\System.Diagnostics.Tracing.dll" />
<Content Include="Win32\System.Globalization.Extensions.dll" />
<Content Include="Win32\System.IO.Compression.dll" />
<Content Include="Win32\System.Net.Http.dll" />
<Content Include="Win32\System.Net.Sockets.dll" />
<Content Include="Win32\System.Runtime.Serialization.Primitives.dll" />
<Content Include="Win32\System.Security.Cryptography.Algorithms.dll" />
<Content Include="Win32\System.Security.SecureString.dll" />
<Content Include="Win32\System.Threading.Overlapped.dll" />
<Content Include="Win32\System.Xml.XPath.XDocument.dll" />
<Content Include="Win32\winpty-agent.exe" />
<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>
@@ -199,146 +258,20 @@
<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.SystemTray.exe" />
<Content Include="Win32\FluentTerminal.SystemTray.pdb" />
<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" />
<Content Include="Win32\Owin.dll" />
<Content Include="Win32\System.AppContext.dll" />
<Content Include="Win32\System.Collections.Concurrent.dll" />
<Content Include="Win32\System.Collections.dll" />
<Content Include="Win32\System.Collections.NonGeneric.dll" />
<Content Include="Win32\System.Collections.Specialized.dll" />
<Content Include="Win32\System.ComponentModel.dll" />
<Content Include="Win32\System.ComponentModel.EventBasedAsync.dll" />
<Content Include="Win32\System.ComponentModel.Primitives.dll" />
<Content Include="Win32\System.ComponentModel.TypeConverter.dll" />
<Content Include="Win32\System.Console.dll" />
<Content Include="Win32\System.Data.Common.dll" />
<Content Include="Win32\System.Diagnostics.Contracts.dll" />
<Content Include="Win32\System.Diagnostics.Debug.dll" />
<Content Include="Win32\System.Diagnostics.FileVersionInfo.dll" />
<Content Include="Win32\System.Diagnostics.Process.dll" />
<Content Include="Win32\System.Diagnostics.StackTrace.dll" />
<Content Include="Win32\System.Diagnostics.TextWriterTraceListener.dll" />
<Content Include="Win32\System.Diagnostics.Tools.dll" />
<Content Include="Win32\System.Diagnostics.TraceSource.dll" />
<Content Include="Win32\System.Diagnostics.Tracing.dll" />
<Content Include="Win32\System.Drawing.Primitives.dll" />
<Content Include="Win32\System.Dynamic.Runtime.dll" />
<Content Include="Win32\System.Globalization.Calendars.dll" />
<Content Include="Win32\System.Globalization.dll" />
<Content Include="Win32\System.Globalization.Extensions.dll" />
<Content Include="Win32\System.IO.Compression.dll" />
<Content Include="Win32\System.IO.Compression.ZipFile.dll" />
<Content Include="Win32\System.IO.dll" />
<Content Include="Win32\System.IO.FileSystem.dll" />
<Content Include="Win32\System.IO.FileSystem.DriveInfo.dll" />
<Content Include="Win32\System.IO.FileSystem.Primitives.dll" />
<Content Include="Win32\System.IO.FileSystem.Watcher.dll" />
<Content Include="Win32\System.IO.IsolatedStorage.dll" />
<Content Include="Win32\System.IO.MemoryMappedFiles.dll" />
<Content Include="Win32\System.IO.Pipes.dll" />
<Content Include="Win32\System.IO.UnmanagedMemoryStream.dll" />
<Content Include="Win32\System.Linq.dll" />
<Content Include="Win32\System.Linq.Expressions.dll" />
<Content Include="Win32\System.Linq.Parallel.dll" />
<Content Include="Win32\System.Linq.Queryable.dll" />
<Content Include="Win32\System.Net.Http.dll" />
<Content Include="Win32\System.Net.Http.Formatting.dll" />
<Content Include="Win32\System.Net.NameResolution.dll" />
<Content Include="Win32\System.Net.NetworkInformation.dll" />
<Content Include="Win32\System.Net.Ping.dll" />
<Content Include="Win32\System.Net.Primitives.dll" />
<Content Include="Win32\System.Net.Requests.dll" />
<Content Include="Win32\System.Net.Security.dll" />
<Content Include="Win32\System.Net.Sockets.dll" />
<Content Include="Win32\System.Net.WebHeaderCollection.dll" />
<Content Include="Win32\System.Net.WebSockets.Client.dll" />
<Content Include="Win32\System.Net.WebSockets.dll" />
<Content Include="Win32\System.ObjectModel.dll" />
<Content Include="Win32\System.Reflection.dll" />
<Content Include="Win32\System.Reflection.Extensions.dll" />
<Content Include="Win32\System.Reflection.Primitives.dll" />
<Content Include="Win32\System.Resources.Reader.dll" />
<Content Include="Win32\System.Resources.ResourceManager.dll" />
<Content Include="Win32\System.Resources.Writer.dll" />
<Content Include="Win32\System.Runtime.CompilerServices.VisualC.dll" />
<Content Include="Win32\System.Runtime.dll" />
<Content Include="Win32\System.Runtime.Extensions.dll" />
<Content Include="Win32\System.Runtime.Handles.dll" />
<Content Include="Win32\System.Runtime.InteropServices.dll" />
<Content Include="Win32\System.Runtime.InteropServices.RuntimeInformation.dll" />
<Content Include="Win32\System.Runtime.Numerics.dll" />
<Content Include="Win32\System.Runtime.Serialization.Formatters.dll" />
<Content Include="Win32\System.Runtime.Serialization.Json.dll" />
<Content Include="Win32\System.Runtime.Serialization.Primitives.dll" />
<Content Include="Win32\System.Runtime.Serialization.Xml.dll" />
<Content Include="Win32\System.Security.Claims.dll" />
<Content Include="Win32\System.Security.Cryptography.Algorithms.dll" />
<Content Include="Win32\System.Security.Cryptography.Csp.dll" />
<Content Include="Win32\System.Security.Cryptography.Encoding.dll" />
<Content Include="Win32\System.Security.Cryptography.Primitives.dll" />
<Content Include="Win32\System.Security.Cryptography.X509Certificates.dll" />
<Content Include="Win32\System.Security.Principal.dll" />
<Content Include="Win32\System.Security.SecureString.dll" />
<Content Include="Win32\System.Text.Encoding.dll" />
<Content Include="Win32\System.Text.Encoding.Extensions.dll" />
<Content Include="Win32\System.Text.RegularExpressions.dll" />
<Content Include="Win32\System.Threading.dll" />
<Content Include="Win32\System.Threading.Overlapped.dll" />
<Content Include="Win32\System.Threading.Tasks.dll" />
<Content Include="Win32\System.Threading.Tasks.Parallel.dll" />
<Content Include="Win32\System.Threading.Thread.dll" />
<Content Include="Win32\System.Threading.ThreadPool.dll" />
<Content Include="Win32\System.Threading.Timer.dll" />
<Content Include="Win32\System.ValueTuple.dll" />
<Content Include="Win32\System.Web.Http.dll" />
<Content Include="Win32\System.Web.Http.Owin.dll" />
<Content Include="Win32\System.Xml.ReaderWriter.dll" />
<Content Include="Win32\System.Xml.XDocument.dll" />
<Content Include="Win32\System.Xml.XmlDocument.dll" />
<Content Include="Win32\System.Xml.XmlSerializer.dll" />
<Content Include="Win32\System.Xml.XPath.dll" />
<Content Include="Win32\System.Xml.XPath.XDocument.dll" />
<Content Include="Win32\Unity.Abstractions.dll" />
<Content Include="Win32\Unity.Abstractions.pdb" />
<Content Include="Win32\Unity.Configuration.dll" />
<Content Include="Win32\Unity.Configuration.pdb" />
<Content Include="Win32\Unity.Container.dll" />
<Content Include="Win32\Unity.Container.pdb" />
<Content Include="Win32\Unity.Interception.Configuration.dll" />
<Content Include="Win32\Unity.Interception.Configuration.pdb" />
<Content Include="Win32\Unity.Interception.dll" />
<Content Include="Win32\Unity.Interception.pdb" />
<Content Include="Win32\Unity.RegistrationByConvention.dll" />
<Content Include="Win32\Unity.RegistrationByConvention.pdb" />
<Content Include="Win32\Unity.ServiceLocation.dll" />
<Content Include="Win32\Unity.ServiceLocation.pdb" />
<Content Include="Win32\Unity.WebApi.dll" />
<Content Include="Win32\winpty-agent.exe" />
<Content Include="Win32\winpty-debugserver.exe" />
<Content Include="Win32\winpty.dll" />
<Content Include="Win32\winpty.NET.dll" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="Dialogs\ShellProfileSelectionDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<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>
@@ -348,15 +281,19 @@
<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>
</Page>
<Page Include="Views\SettingsPages\ColorSettings.xaml">
<Page Include="Views\SettingsPages\ThemeSettings.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\SettingsPages\FontSettings.xaml">
<Page Include="Views\SettingsPages\TerminalSettings.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
@@ -368,7 +305,11 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\SettingsPages\ShellSettings.xaml">
<Page Include="Views\SettingsPages\ShellProfileSettings.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\TerminalColorPicker.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
@@ -379,16 +320,28 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac">
<Version>4.6.2</Version>
<Version>4.8.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.0.6</Version>
</PackageReference>
<PackageReference Include="Microsoft.Toolkit.Uwp.UI">
<Version>2.1.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls">
<Version>2.1.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.Xaml.Behaviors.Uwp.Managed">
<Version>2.0.0</Version>
</PackageReference>
<PackageReference Include="MvvmLightLibs">
<Version>5.3.0</Version>
</PackageReference>
<PackageReference Include="Newtonsoft.Json">
<Version>10.0.3</Version>
<Version>11.0.2</Version>
</PackageReference>
<PackageReference Include="Win2D.uwp">
<Version>1.21.0</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
@@ -406,6 +359,7 @@
<Name>FluentTerminal.RuntimeComponent</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
@@ -414,6 +368,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.4.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>
@@ -1,9 +1,17 @@
using FluentTerminal.Models;
using System;
using System.Collections.Generic;
namespace FluentTerminal.App.Services
{
public interface IDefaultValueProvider
{
ShellConfiguration GetDefaultShellConfiguration();
IEnumerable<ShellProfile> GetPreinstalledShellProfiles();
Guid GetDefaultShellProfileId();
TerminalOptions GetDefaultTerminalOptions();
KeyBindings GetDefaultKeyBindings();
ApplicationSettings GetDefaultApplicationSettings();
Guid GetDefaultThemeId();
IEnumerable<TerminalTheme> GetPreInstalledThemes();
}
}
@@ -0,0 +1,18 @@
using FluentTerminal.Models;
using System.Threading.Tasks;
namespace FluentTerminal.App.Services
{
public enum DialogButton
{
OK,
Cancel
}
public interface IDialogService
{
Task<DialogButton> ShowMessageDialogAsnyc(string title, string content, params DialogButton[] buttons);
Task<ShellProfile> ShowProfileSelectionDialogAsync();
}
}
@@ -0,0 +1,11 @@
using FluentTerminal.Models.Enums;
using System;
namespace FluentTerminal.App.Services
{
public interface IKeyboardCommandService
{
void RegisterCommandHandler(Command command, Action handler);
void SendCommand(Command command);
}
}
@@ -1,10 +1,40 @@
using FluentTerminal.Models;
using System;
using System.Collections.Generic;
namespace FluentTerminal.App.Services
{
public interface ISettingsService
{
ShellConfiguration GetShellConfiguration();
void SaveShellConfiguration(ShellConfiguration spawnConfiguration);
event EventHandler CurrentThemeChanged;
event EventHandler TerminalOptionsChanged;
event EventHandler ApplicationSettingsChanged;
event EventHandler KeyBindingsChanged;
Guid GetDefaultShellProfileId();
ShellProfile GetDefaultShellProfile();
void SaveDefaultShellProfileId(Guid id);
IEnumerable<ShellProfile> GetShellProfiles();
void SaveShellProfile(ShellProfile shellProfile);
void DeleteShellProfile(Guid id);
TerminalOptions GetTerminalOptions();
void SaveTerminalOptions(TerminalOptions terminalOptions);
ApplicationSettings GetApplicationSettings();
void SaveApplicationSettings(ApplicationSettings applicationSettings);
KeyBindings GetKeyBindings();
void SaveKeyBindings(KeyBindings keyBindings);
TerminalTheme GetCurrentTheme();
Guid GetCurrentThemeId();
TerminalTheme GetTheme(Guid id);
void SaveCurrentThemeId(Guid id);
IEnumerable<TerminalTheme> GetThemes();
void SaveTheme(TerminalTheme theme);
void DeleteTheme(Guid id);
}
}
@@ -1,11 +0,0 @@
using FluentTerminal.Models;
using System.Threading.Tasks;
namespace FluentTerminal.App.Services
{
public interface ITerminalService
{
Task<CreateTerminalResponse> CreateTerminal(TerminalSize size, ShellConfiguration shellConfiguration);
Task ResizeTerminal(int id, TerminalSize size);
}
}
@@ -0,0 +1,15 @@
using FluentTerminal.Models;
using FluentTerminal.Models.Responses;
using System.Threading.Tasks;
using Windows.ApplicationModel.AppService;
namespace FluentTerminal.App.Services
{
public interface ITrayProcessCommunicationService
{
Task Initialize(AppServiceConnection appServiceConnection);
Task<CreateTerminalResponse> CreateTerminal(TerminalSize size, ShellProfile shellProfile);
Task ResizeTerminal(int id, TerminalSize size);
Task UpdateToggleWindowKeyBindings();
}
}
@@ -1,19 +1,300 @@
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using System;
using System.Collections.Generic;
using Windows.System;
namespace FluentTerminal.App.Services.Implementation
{
internal class DefaultValueProvider : IDefaultValueProvider
{
public ShellConfiguration GetDefaultShellConfiguration()
public ApplicationSettings GetDefaultApplicationSettings()
{
return new ShellConfiguration
return new ApplicationSettings
{
Shell = ShellType.PowerShell,
CustomShellLocation = string.Empty,
WorkingDirectory = string.Empty,
Arguments = string.Empty
ConfirmClosingTabs = false,
ConfirmClosingWindows = false,
NewTerminalLocation = NewTerminalLocation.Tab
};
}
public KeyBindings GetDefaultKeyBindings()
{
return new KeyBindings
{
NewTab = new List<KeyBinding>
{
new KeyBinding
{
Command = Command.NewTab,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.T
}
},
ConfigurableNewTab = new List<KeyBinding>
{
new KeyBinding
{
Command = Command.ConfigurableNewTab,
Ctrl = true,
Alt = false,
Shift = true,
Key = (int)VirtualKey.T
}
},
CloseTab = new List<KeyBinding>
{
new KeyBinding
{
Command = Command.CloseTab,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.W
}
},
NextTab = new List<KeyBinding>
{
new KeyBinding
{
Command = Command.NextTab,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.Tab
}
},
PreviousTab = new List<KeyBinding>
{
new KeyBinding
{
Command = Command.PreviousTab,
Ctrl = true,
Alt = false,
Shift = true,
Key = (int)VirtualKey.Tab
}
},
NewWindow = new List<KeyBinding>
{
new KeyBinding
{
Command = Command.NewWindow,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.N
}
},
ShowSettings = new List<KeyBinding>
{
new KeyBinding
{
Command = Command.ShowSettings,
Ctrl = true,
Alt = false,
Shift = false,
Key = 188 // comma
}
},
Copy = new List<KeyBinding>
{
new KeyBinding
{
Command = Command.Copy,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.C
}
},
Paste = new List<KeyBinding>
{
new KeyBinding
{
Command = Command.Paste,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.V
}
},
ToggleWindow = new List<KeyBinding>
{
new KeyBinding
{
Command = Command.ToggleWindow,
Ctrl = false,
Alt = false,
Shift = false,
Key = (int)VirtualKey.Scroll
}
},
Search = new List<KeyBinding>
{
new KeyBinding
{
Command = Command.Search,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.F
}
}
};
}
public Guid GetDefaultShellProfileId()
{
return Guid.Parse("813f2298-210a-481a-bdbf-c17bc637a3e2");
}
public TerminalOptions GetDefaultTerminalOptions()
{
return new TerminalOptions
{
BellStyle = BellStyle.None,
CursorBlink = true,
CursorStyle = CursorStyle.Block,
FontFamily = "Consolas",
FontSize = 13
};
}
public Guid GetDefaultThemeId()
{
return Guid.Parse("281e4352-bb50-47b7-a691-2b13830df95e");
}
public IEnumerable<ShellProfile> GetPreinstalledShellProfiles()
{
return new[]
{
new ShellProfile
{
Id = GetDefaultShellProfileId(),
Name = "Powershell",
Arguments = string.Empty,
Location = @"C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe",
PreInstalled = true,
WorkingDirectory = string.Empty
},
new ShellProfile
{
Id = Guid.Parse("ab942a61-7673-4755-9bd8-765aff91d9a3"),
Name = "CMD",
Arguments = string.Empty,
Location = @"C:\Windows\System32\cmd.exe",
PreInstalled = true,
WorkingDirectory = string.Empty
}
};
}
public IEnumerable<TerminalTheme> GetPreInstalledThemes()
{
var defaultXterm = new TerminalTheme
{
Id = GetDefaultThemeId(),
Author = "xterm.js",
Name = "Xterm.js Default",
PreInstalled = true,
BackgroundOpacity = 0.8,
Colors = new TerminalColors
{
Black = "#2e3436",
Red = "#cc0000",
Green = "#4e9a06",
Yellow = "#c4a000",
Blue = "#3465a4",
Magenta = "#75507b",
Cyan = "#06989a",
White = "#d3d7cf",
BrightBlack = "#555753",
BrightRed = "#ef2929",
BrightGreen = "#8ae234",
BrightYellow = "#fce94f",
BrightBlue = "#729fcf",
BrightMagenta = "#ad7fa8",
BrightCyan = "#34e2e2",
BrightWhite = "#eeeeec",
Foreground = "#ffffff",
Background = "#000000",
Cursor = "#ffffff",
CursorAccent = "#000000",
Selection = "rgba(255, 255, 255, 0.3)"
}
};
var powerShell = new TerminalTheme
{
Id = Guid.Parse("3571ce1b-31ce-4cf7-ae15-e0bff70c3eea"),
Author = "Microsoft",
Name = "PowerShell",
PreInstalled = true,
BackgroundOpacity = 0.8,
Colors = new TerminalColors
{
Black = "#000000",
Red = "#800000",
Green = "#008000",
Yellow = "#EEEDF0",
Blue = "#000080",
Magenta = "#012456",
Cyan = "#008080",
White = "#c0c0c0",
BrightBlack = "#808080",
BrightRed = "#ff0000",
BrightGreen = "#00ff00",
BrightYellow = "#ffff00",
BrightBlue = "#0000ff",
BrightMagenta = "#ff00ff",
BrightCyan = "#00ffff",
BrightWhite = "#ffffff",
Foreground = "#ffffff",
Background = "#012456",
Cursor = "#fedba9",
CursorAccent = "#000000",
Selection = "#fedba9"
}
};
var homebrew = new TerminalTheme
{
Id = Guid.Parse("5f034210-067b-40e2-b9c9-6a25eb6fb8e6"),
Author = "Hans Kokx",
Name = "Homebrew",
PreInstalled = true,
BackgroundOpacity = 0.8,
Colors = new TerminalColors
{
Black = "#000000",
Red = "#A0160B",
Green = "#00AF21",
Yellow = "#A1A222",
Blue = "#192AB7",
Magenta = "#AA2FAE",
Cyan = "#12B1BC",
White = "#BBB5AF",
BrightBlack = "#747876",
BrightRed = "#E52213",
BrightGreen = "#00D92B",
BrightYellow = "#E6E435",
BrightBlue = "#283EF9",
BrightMagenta = "#EB43E6",
BrightCyan = "#15E7E8",
BrightWhite = "#E9E9E9",
Foreground = "#00D92B",
Background = "#000000",
Cursor = "#00D92B",
CursorAccent = "#000000",
Selection = "#4CFFFFFF"
}
};
return new[] { defaultXterm, powerShell, homebrew };
}
}
}
}
@@ -0,0 +1,61 @@
using System;
using System.Threading.Tasks;
using FluentTerminal.App.Dialogs;
using FluentTerminal.Models;
using Windows.UI.Popups;
using Windows.UI.Xaml.Controls;
namespace FluentTerminal.App.Services.Implementation
{
public class DialogService : IDialogService
{
private readonly ISettingsService _settingsService;
public DialogService(ISettingsService settingsService)
{
_settingsService = settingsService;
}
public async Task<DialogButton> ShowMessageDialogAsnyc(string title, string content, params DialogButton[] buttons)
{
if (string.IsNullOrWhiteSpace(title))
{
throw new ArgumentNullException(nameof(title));
}
if (string.IsNullOrWhiteSpace(content))
{
throw new ArgumentNullException(nameof(content));
}
if (buttons.Length == 0)
{
throw new ArgumentException("Must not be empty", nameof(buttons));
}
var dialog = new MessageDialog(content, title);
foreach (var button in buttons)
{
dialog.Commands.Add(new UICommand(button.ToString()));
}
var result = await dialog.ShowAsync();
return Enum.Parse<DialogButton>(result.Label);
}
public async Task<ShellProfile> ShowProfileSelectionDialogAsync()
{
var dialog = new ShellProfileSelectionDialog(_settingsService);
var result = await dialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
return dialog.SelectedProfile;
}
return null;
}
}
}
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using FluentTerminal.Models.Enums;
namespace FluentTerminal.App.Services.Implementation
{
public class KeyboardCommandService : IKeyboardCommandService
{
private readonly Dictionary<Command, Action> _commandHandlers = new Dictionary<Command, Action>();
public void RegisterCommandHandler(Command command, Action handler)
{
if (_commandHandlers.ContainsKey(command))
{
throw new InvalidOperationException("command already registered");
}
_commandHandlers[command] = handler ?? throw new ArgumentNullException(nameof(handler));
}
public void SendCommand(Command command)
{
if (_commandHandlers.TryGetValue(command, out Action handler))
{
handler.Invoke();
return;
}
throw new KeyNotFoundException($"No handler registered for command: {command}");
}
}
}
@@ -1,38 +1,177 @@
using FluentTerminal.App.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using FluentTerminal.App.Utilities;
using FluentTerminal.Models;
using Newtonsoft.Json;
using Windows.Storage;
namespace FluentTerminal.App.Services.Implementation
{
internal class SettingsService : ISettingsService
{
public const string ThemesContainerName = "Themes";
public const string ShellProfilesContainerName = "ShellProfiles";
public const string CurrentThemeKey = "CurrentTheme";
public const string DefaultShellProfileKey = "DefaultShellProfile";
private readonly IDefaultValueProvider _defaultValueProvider;
private ApplicationDataContainer _localSettings;
private ApplicationDataContainer _roamingSettings;
private readonly ApplicationDataContainer _localSettings;
private readonly ApplicationDataContainer _themes;
private readonly ApplicationDataContainer _shellProfiles;
private readonly ApplicationDataContainer _roamingSettings;
public event EventHandler CurrentThemeChanged;
public event EventHandler TerminalOptionsChanged;
public event EventHandler ApplicationSettingsChanged;
public event EventHandler KeyBindingsChanged;
public SettingsService(IDefaultValueProvider defaultValueProvider)
{
_defaultValueProvider = defaultValueProvider;
_localSettings = ApplicationData.Current.LocalSettings;
_roamingSettings = ApplicationData.Current.RoamingSettings;
ApplicationData.Current.DataChanged += OnDataChanged;
_themes = _roamingSettings.CreateContainer(ThemesContainerName, ApplicationDataCreateDisposition.Always);
_shellProfiles = _roamingSettings.CreateContainer(ShellProfilesContainerName, ApplicationDataCreateDisposition.Always);
foreach (var theme in _defaultValueProvider.GetPreInstalledThemes())
{
_themes.WriteValueAsJson(theme.Id.ToString(), theme);
}
foreach (var shellProfile in _defaultValueProvider.GetPreinstalledShellProfiles())
{
_shellProfiles.WriteValueAsJson(shellProfile.Id.ToString(), shellProfile);
}
}
private void OnDataChanged(ApplicationData sender, object args)
public TerminalTheme GetCurrentTheme()
{
//todo handle data changed for roaming settings
var id = GetCurrentThemeId();
return GetTheme(id);
}
public ShellConfiguration GetShellConfiguration()
public Guid GetCurrentThemeId()
{
return _localSettings.ReadValueFromJson(nameof(ShellConfiguration), _defaultValueProvider.GetDefaultShellConfiguration());
if (_roamingSettings.Values.TryGetValue(CurrentThemeKey, out object value))
{
return (Guid)value;
}
return _defaultValueProvider.GetDefaultThemeId();
}
public void SaveShellConfiguration(ShellConfiguration spawnConfiguration)
public void SaveCurrentThemeId(Guid id)
{
_localSettings.WriteValueAsJson(nameof(ShellConfiguration), spawnConfiguration);
_roamingSettings.Values[CurrentThemeKey] = id;
CurrentThemeChanged?.Invoke(this, EventArgs.Empty);
}
public void SaveTheme(TerminalTheme theme)
{
_themes.WriteValueAsJson(theme.Id.ToString(), theme);
if (theme.Id == GetCurrentThemeId())
{
CurrentThemeChanged?.Invoke(this, EventArgs.Empty);
}
}
public void DeleteTheme(Guid id)
{
_themes.Values.Remove(id.ToString());
}
public IEnumerable<TerminalTheme> GetThemes()
{
return _themes.Values.Select(x => JsonConvert.DeserializeObject<TerminalTheme>((string)x.Value)).ToList();
}
public TerminalTheme GetTheme(Guid id)
{
return _themes.ReadValueFromJson(id.ToString(), default(TerminalTheme));
}
public TerminalOptions GetTerminalOptions()
{
return _roamingSettings.ReadValueFromJson(nameof(TerminalOptions), _defaultValueProvider.GetDefaultTerminalOptions());
}
public void SaveTerminalOptions(TerminalOptions terminalOptions)
{
_roamingSettings.WriteValueAsJson(nameof(TerminalOptions), terminalOptions);
TerminalOptionsChanged?.Invoke(this, EventArgs.Empty);
}
public ApplicationSettings GetApplicationSettings()
{
return _roamingSettings.ReadValueFromJson(nameof(ApplicationSettings), _defaultValueProvider.GetDefaultApplicationSettings());
}
public void SaveApplicationSettings(ApplicationSettings applicationSettings)
{
_roamingSettings.WriteValueAsJson(nameof(ApplicationSettings), applicationSettings);
ApplicationSettingsChanged?.Invoke(this, EventArgs.Empty);
}
public KeyBindings GetKeyBindings()
{
var defaults = _defaultValueProvider.GetDefaultKeyBindings();
var keyBindings = _roamingSettings.ReadValueFromJson<KeyBindings>(nameof(KeyBindings), null);
if (keyBindings.ConfigurableNewTab == null)
{
keyBindings.ConfigurableNewTab = defaults.ConfigurableNewTab;
}
if (keyBindings.Search == null)
{
keyBindings.Search = defaults.Search;
}
return keyBindings ?? _defaultValueProvider.GetDefaultKeyBindings();
}
public void SaveKeyBindings(KeyBindings keyBindings)
{
_roamingSettings.WriteValueAsJson(nameof(KeyBindings), keyBindings);
KeyBindingsChanged?.Invoke(this, EventArgs.Empty);
}
public Guid GetDefaultShellProfileId()
{
if (_roamingSettings.Values.TryGetValue(DefaultShellProfileKey, out object value))
{
return (Guid)value;
}
return _defaultValueProvider.GetDefaultShellProfileId();
}
public ShellProfile GetDefaultShellProfile()
{
var id = GetDefaultShellProfileId();
return _shellProfiles.ReadValueFromJson(id.ToString(), default(ShellProfile));
}
public void SaveDefaultShellProfileId(Guid id)
{
_roamingSettings.Values[DefaultShellProfileKey] = id;
}
public IEnumerable<ShellProfile> GetShellProfiles()
{
return _shellProfiles.Values.Select(x => JsonConvert.DeserializeObject<ShellProfile>((string)x.Value)).ToList();
}
public void SaveShellProfile(ShellProfile shellProfile)
{
_shellProfiles.WriteValueAsJson(shellProfile.Id.ToString(), shellProfile);
}
public void DeleteShellProfile(Guid id)
{
_shellProfiles.Values.Remove(id.ToString());
}
}
}
}
@@ -1,37 +0,0 @@
using System;
using System.Threading.Tasks;
using FluentTerminal.App.Utilities;
using FluentTerminal.Models;
using Windows.Web.Http;
namespace FluentTerminal.App.Services.Implementation
{
internal class TerminalService : ITerminalService
{
private readonly HttpClient _httpClient;
public TerminalService()
{
_httpClient = new HttpClient();
}
public async Task<CreateTerminalResponse> CreateTerminal(TerminalSize size, ShellConfiguration shellConfiguration)
{
var request = new CreateTerminalRequest
{
Size = size,
Configuration = shellConfiguration
};
var response = await _httpClient.PostAsync(new Uri($"http://localhost:9000/terminals"), HttpJsonContent.From(request));
var createTerminalResponse = await response.Content.ReadAs<CreateTerminalResponse>();
return createTerminalResponse;
}
public Task ResizeTerminal(int id, TerminalSize size)
{
return _httpClient.PostAsync(new Uri($"http://localhost:9000/terminals/{id}/resize"), HttpJsonContent.From(size)).AsTask();
}
}
}
@@ -0,0 +1,82 @@
using System;
using System.Threading.Tasks;
using FluentTerminal.Models;
using FluentTerminal.Models.Requests;
using FluentTerminal.Models.Responses;
using Newtonsoft.Json;
using Windows.ApplicationModel.AppService;
using Windows.Foundation.Collections;
namespace FluentTerminal.App.Services.Implementation
{
internal class TrayProcessCommunicationService : ITrayProcessCommunicationService
{
private readonly ISettingsService _settingsService;
private AppServiceConnection _appServiceConnection;
public TrayProcessCommunicationService(ISettingsService settingsService)
{
_settingsService = settingsService;
}
public async Task<CreateTerminalResponse> CreateTerminal(TerminalSize size, ShellProfile shellProfile)
{
var request = new CreateTerminalRequest
{
Size = size,
Profile = shellProfile
};
var message = new ValueSet
{
{ MessageKeys.Type, MessageTypes.CreateTerminalRequest },
{ MessageKeys.Content, JsonConvert.SerializeObject(request) }
};
var responseMessage = await _appServiceConnection.SendMessageAsync(message);
return JsonConvert.DeserializeObject<CreateTerminalResponse>((string)responseMessage.Message[MessageKeys.Content]);
}
public Task Initialize(AppServiceConnection appServiceConnection)
{
_appServiceConnection = appServiceConnection;
return UpdateToggleWindowKeyBindings();
}
public Task ResizeTerminal(int id, TerminalSize size)
{
var request = new ResizeTerminalRequest
{
TerminalId = id,
NewSize = size
};
var message = new ValueSet
{
{ MessageKeys.Type, MessageTypes.ResizeTerminalRequest },
{ MessageKeys.Content, JsonConvert.SerializeObject(request) }
};
return _appServiceConnection.SendMessageAsync(message).AsTask();
}
public Task UpdateToggleWindowKeyBindings()
{
var keyBindings = _settingsService.GetKeyBindings().ToggleWindow;
var request = new SetToggleWindowKeyBindingsRequest
{
KeyBindings = keyBindings
};
var message = new ValueSet
{
{ MessageKeys.Type, MessageTypes.SetToggleWindowKeyBindingsRequest },
{ MessageKeys.Content, JsonConvert.SerializeObject(request) }
};
return _appServiceConnection.SendMessageAsync(message).AsTask();
}
}
}
+276
View File
@@ -11,6 +11,7 @@
<SolidColorBrush x:Key="TitleBarHoverBackgroundColor" Color="#18FFFFFF" />
<SolidColorBrush x:Key="TitleBarPressedBackgroundColor" Color="#30FFFFFF" />
<SolidColorBrush x:Key="DisabledForegroundColor" Color="#80FFFFFF" />
<Style x:Key="TitleBarButtonStyle" TargetType="Button">
<Setter Property="Background" Value="Transparent" />
@@ -68,4 +69,279 @@
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ColorPreviewButtonStyle" TargetType="Button">
<Setter Property="Width" Value="24" />
<Setter Property="Height" Value="24" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
<ContentPresenter
x:Name="ContentPresenter"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ThemeAppBarButtonStyle" TargetType="AppBarButton">
<Setter Property="BorderBrush" Value="{ThemeResource AppBarButtonBorderBrush}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="Width" Value="68" />
<Setter Property="UseSystemFocusVisuals" Value="True" />
<Setter Property="AllowFocusOnInteraction" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="AppBarButton">
<Grid
x:Name="Root"
MinWidth="{TemplateBinding MinWidth}"
MaxWidth="{TemplateBinding MaxWidth}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid x:Name="ContentRoot" MinHeight="{ThemeResource AppBarThemeMinHeight}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Viewbox
x:Name="ContentViewbox"
Height="20"
Margin="0,14,0,4"
HorizontalAlignment="Stretch"
AutomationProperties.AccessibilityView="Raw">
<ContentPresenter
x:Name="Content"
Height="20"
Content="{TemplateBinding Icon}"
Foreground="{TemplateBinding Foreground}" />
</Viewbox>
<TextBlock
x:Name="TextLabel"
Grid.Row="1"
Margin="2,0,2,6"
AutomationProperties.AccessibilityView="Raw"
FontFamily="{TemplateBinding FontFamily}"
FontSize="12"
Foreground="{TemplateBinding Foreground}"
Text="{TemplateBinding Label}"
TextAlignment="Center"
TextWrapping="Wrap" />
<TextBlock
x:Name="OverflowTextLabel"
Margin="12,0,12,0"
Padding="0,5,0,7"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
AutomationProperties.AccessibilityView="Raw"
FontFamily="{TemplateBinding FontFamily}"
FontSize="15"
Foreground="{TemplateBinding Foreground}"
Text="{TemplateBinding Label}"
TextAlignment="Left"
TextTrimming="Clip"
TextWrapping="NoWrap"
Visibility="Collapsed" />
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ApplicationViewStates">
<VisualState x:Name="FullSize" />
<VisualState x:Name="Compact">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="LabelOnRight">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentViewbox" Storyboard.TargetProperty="Margin">
<DiscreteObjectKeyFrame KeyTime="0" Value="12,14,0,14" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentRoot" Storyboard.TargetProperty="MinHeight">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource AppBarThemeCompactHeight}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="(Grid.Row)">
<DiscreteObjectKeyFrame KeyTime="0" Value="0" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="(Grid.Column)">
<DiscreteObjectKeyFrame KeyTime="0" Value="1" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="TextAlignment">
<DiscreteObjectKeyFrame KeyTime="0" Value="Left" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="Margin">
<DiscreteObjectKeyFrame KeyTime="0" Value="8,15,12,17" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="LabelCollapsed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentRoot" Storyboard.TargetProperty="MinHeight">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource AppBarThemeCompactHeight}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Overflow">
<VisualState.Setters>
<Setter Target="ContentRoot.MinHeight" Value="0" />
<Setter Target="ContentViewbox.Visibility" Value="Collapsed" />
<Setter Target="TextLabel.Visibility" Value="Collapsed" />
<Setter Target="OverflowTextLabel.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="OverflowWithToggleButtons">
<VisualState.Setters>
<Setter Target="ContentRoot.MinHeight" Value="0" />
<Setter Target="ContentViewbox.Visibility" Value="Collapsed" />
<Setter Target="TextLabel.Visibility" Value="Collapsed" />
<Setter Target="OverflowTextLabel.Visibility" Value="Visible" />
<Setter Target="OverflowTextLabel.Margin" Value="38,0,12,0" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="OverflowWithMenuIcons">
<VisualState.Setters>
<Setter Target="ContentRoot.MinHeight" Value="0" />
<Setter Target="ContentViewbox.HorizontalAlignment" Value="Left" />
<Setter Target="ContentViewbox.VerticalAlignment" Value="Center" />
<Setter Target="ContentViewbox.Width" Value="16" />
<Setter Target="ContentViewbox.Height" Value="16" />
<Setter Target="ContentViewbox.Margin" Value="12,0,12,0" />
<Setter Target="TextLabel.Visibility" Value="Collapsed" />
<Setter Target="OverflowTextLabel.Visibility" Value="Visible" />
<Setter Target="OverflowTextLabel.Margin" Value="38,0,12,0" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="OverflowWithToggleButtonsAndMenuIcons">
<VisualState.Setters>
<Setter Target="ContentRoot.MinHeight" Value="0" />
<Setter Target="ContentViewbox.HorizontalAlignment" Value="Left" />
<Setter Target="ContentViewbox.VerticalAlignment" Value="Center" />
<Setter Target="ContentViewbox.Width" Value="16" />
<Setter Target="ContentViewbox.Height" Value="16" />
<Setter Target="ContentViewbox.Margin" Value="38,0,12,0" />
<Setter Target="TextLabel.Visibility" Value="Collapsed" />
<Setter Target="OverflowTextLabel.Visibility" Value="Visible" />
<Setter Target="OverflowTextLabel.Margin" Value="76,0,12,0" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="OverflowTextLabel" />
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="Root.Background" Value="{StaticResource TitleBarHoverBackgroundColor}" />
<Setter Target="Root.BorderBrush" Value="{ThemeResource AppBarButtonBorderBrushPointerOver}" />
</VisualState.Setters>
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="OverflowTextLabel" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Target="Root.Background" Value="{StaticResource TitleBarPressedBackgroundColor}" />
<Setter Target="Root.BorderBrush" Value="{ThemeResource AppBarButtonBorderBrushPressed}" />
</VisualState.Setters>
<Storyboard>
<PointerDownThemeAnimation Storyboard.TargetName="OverflowTextLabel" />
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="Root.Background" Value="Transparent" />
<Setter Target="Root.BorderBrush" Value="{ThemeResource AppBarButtonBorderBrushDisabled}" />
<Setter Target="Content.Foreground" Value="{StaticResource DisabledForegroundColor}" />
<Setter Target="TextLabel.Foreground" Value="{StaticResource DisabledForegroundColor}" />
<Setter Target="OverflowTextLabel.Foreground" Value="{StaticResource DisabledForegroundColor}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="OverflowNormal">
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="ContentRoot" />
</Storyboard>
</VisualState>
<VisualState x:Name="OverflowPointerOver">
<VisualState.Setters>
<Setter Target="Root.Background" Value="{StaticResource TitleBarHoverBackgroundColor}" />
<Setter Target="Root.BorderBrush" Value="{ThemeResource AppBarButtonBorderBrushPointerOver}" />
</VisualState.Setters>
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="ContentRoot" />
</Storyboard>
</VisualState>
<VisualState x:Name="OverflowPressed">
<VisualState.Setters>
<Setter Target="Root.Background" Value="{StaticResource TitleBarPressedBackgroundColor}" />
<Setter Target="Root.BorderBrush" Value="{ThemeResource AppBarButtonBorderBrushPressed}" />
</VisualState.Setters>
<Storyboard>
<PointerDownThemeAnimation Storyboard.TargetName="ContentRoot" />
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="InputModeStates">
<VisualState x:Name="InputModeDefault" />
<VisualState x:Name="TouchInputMode">
<VisualState.Setters>
<Setter Target="OverflowTextLabel.Padding" Value="0,11,0,13" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="GameControllerInputMode">
<VisualState.Setters>
<Setter Target="OverflowTextLabel.Padding" Value="0,11,0,13" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
@@ -1,4 +1,6 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using Windows.Storage;
namespace FluentTerminal.App.Utilities
@@ -9,6 +11,11 @@ namespace FluentTerminal.App.Utilities
{
if (container.Values.TryGetValue(name, out object value))
{
if (EqualityComparer<T>.Default.Equals(fallbackValue, default))
{
fallbackValue = Activator.CreateInstance<T>();
}
JsonConvert.PopulateObject((string)value, fallbackValue);
}
return fallbackValue;
@@ -16,8 +23,7 @@ namespace FluentTerminal.App.Utilities
public static void WriteValueAsJson<T>(this ApplicationDataContainer container, string name, T value)
{
var serialized = JsonConvert.SerializeObject(value);
container.Values[name] = serialized;
container.Values[name] = JsonConvert.SerializeObject(value);
}
}
}
@@ -0,0 +1,49 @@
using Microsoft.Toolkit.Uwp.Helpers;
using System.Globalization;
using Windows.UI;
namespace FluentTerminal.App.Utilities
{
public static class ColorExtensions
{
public static string ToColorString(this Color color, bool allowTransparency)
{
if (allowTransparency)
{
return $"rgba({color.R:G}, {color.G:G}, {color.B:G}, {ToDoubleString(color.A)})";
}
else
{
return $"#{color.R:X2}{color.G:X2}{color.B:X2}";
}
}
private static string ToDoubleString(byte alpha)
{
return (alpha / 256.0).ToString(CultureInfo.InvariantCulture);
}
public static Color FromString(this string colorString)
{
if (colorString.Contains("rgba("))
{
colorString = colorString.Replace("rgba(", string.Empty);
colorString = colorString.Replace(")", string.Empty);
var parts = colorString.Split(", ");
return new Color
{
A = (byte)(int)(double.Parse(parts[3]) * 256.0),
R = byte.Parse(parts[0]),
G = byte.Parse(parts[1]),
B = byte.Parse(parts[2])
};
}
else
{
return colorString.ToColor();
}
}
}
}
@@ -1,14 +0,0 @@
using Newtonsoft.Json;
using Windows.Web.Http;
namespace FluentTerminal.App.Utilities
{
public static class HttpJsonContent
{
public static HttpStringContent From(object content)
{
var serialized = JsonConvert.SerializeObject(content);
return new HttpStringContent(serialized, Windows.Storage.Streams.UnicodeEncoding.Utf8, "application/json");
}
}
}
@@ -1,16 +0,0 @@
using Newtonsoft.Json;
using System;
using System.Threading.Tasks;
using Windows.Web.Http;
namespace FluentTerminal.App.Utilities
{
public static class IHttpContentExtensions
{
public static async Task<T> ReadAs<T>(this IHttpContent content)
{
var contentBody = await content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(contentBody);
}
}
}
+205 -21
View File
@@ -1,39 +1,97 @@
using FluentTerminal.App.Services;
using FluentTerminal.App.Dialogs;
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.UI.Core;
using Windows.UI.Core.Preview;
using Windows.UI.ViewManagement;
namespace FluentTerminal.App.ViewModels
{
public class MainViewModel : ViewModelBase
{
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 readonly CoreDispatcher _dispatcher;
private int _nextTerminalId;
private TerminalViewModel _selectedTerminal;
private string _title;
public MainViewModel(ISettingsService settingsService, ITerminalService terminalService)
public event EventHandler Closed;
public event EventHandler NewWindowRequested;
public event EventHandler ShowSettingsRequested;
public MainViewModel(ISettingsService settingsService, ITrayProcessCommunicationService trayProcessCommunicationService, IDialogService dialogService, IKeyboardCommandService keyboardCommandService)
{
_settingsService = settingsService;
_terminalService = terminalService;
_settingsService.CurrentThemeChanged += OnCurrentThemeChanged;
_settingsService.ApplicationSettingsChanged += OnApplicationSettingsChanged;
_trayProcessCommunicationService = trayProcessCommunicationService;
_dialogService = dialogService;
_keyboardCommandService = keyboardCommandService;
_keyboardCommandService.RegisterCommandHandler(Command.NewTab, () => AddTerminal(null, false));
_keyboardCommandService.RegisterCommandHandler(Command.ConfigurableNewTab, () => AddTerminal(null, true));
_keyboardCommandService.RegisterCommandHandler(Command.CloseTab, CloseCurrentTab);
_keyboardCommandService.RegisterCommandHandler(Command.NextTab, SelectNextTab);
_keyboardCommandService.RegisterCommandHandler(Command.PreviousTab, SelectPreviousTab);
_keyboardCommandService.RegisterCommandHandler(Command.NewWindow, NewWindow);
_keyboardCommandService.RegisterCommandHandler(Command.ShowSettings, ShowSettings);
var currentTheme = _settingsService.GetCurrentTheme();
Background = currentTheme.Colors.Background;
BackgroundOpacity = currentTheme.BackgroundOpacity;
_applicationSettings = _settingsService.GetApplicationSettings();
AddTerminalCommand = new RelayCommand(() => AddTerminal(null, false));
ShowSettingsCommand = new RelayCommand(ShowSettings);
Terminals.CollectionChanged += OnTerminalsCollectionChanged;
Title = "Fluent Terminal";
AddTerminalCommand = new RelayCommand(AddTerminal);
ShowSettingsCommand = new RelayCommand(async () => await ShowSettings());
AddTerminal();
_dispatcher = CoreApplication.GetCurrentView().Dispatcher;
SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += OnCloseRequest;
}
public RelayCommand AddTerminalCommand { get; }
public RelayCommand ShowSettingsCommand { get; }
public string Background
{
get => _background;
set => Set(ref _background, value);
}
public double BackgroundOpacity
{
get => _backgroundOpacity;
set => Set(ref _backgroundOpacity, value);
}
public TerminalViewModel SelectedTerminal
{
get => _selectedTerminal;
set => Set(ref _selectedTerminal, value);
set
{
if (Set(ref _selectedTerminal, value))
{
SelectedTerminal?.FocusTerminal();
}
}
}
public RelayCommand ShowSettingsCommand { get; }
public ObservableCollection<TerminalViewModel> Terminals { get; } = new ObservableCollection<TerminalViewModel>();
public string Title
@@ -42,24 +100,150 @@ namespace FluentTerminal.App.ViewModels
set => Set(ref _title, value);
}
private void AddTerminal()
public Task AddTerminal(string startupDirectory, bool showProfileSelection)
{
var terminal = new TerminalViewModel(_settingsService, _terminalService);
terminal.PropertyChanged += (s, e) =>
return _dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
if (e.PropertyName == nameof(TerminalViewModel.Title) && Terminals.Count == 1)
ShellProfile profile = null;
if (showProfileSelection)
{
Title = terminal.Title;
}
};
Terminals.Add(terminal);
profile = await _dialogService.ShowProfileSelectionDialogAsync();
SelectedTerminal = terminal;
if (profile == null)
{
return;
}
}
else
{
profile = _settingsService.GetDefaultShellProfile();
}
var terminal = new TerminalViewModel(GetNextTerminalId(), _settingsService, _trayProcessCommunicationService, _dialogService, _keyboardCommandService, _applicationSettings, startupDirectory, profile);
terminal.CloseRequested += OnTerminalCloseRequested;
terminal.TitleChanged += OnTitleChanged;
Terminals.Add(terminal);
SelectedTerminal = terminal;
}).AsTask();
}
private Task ShowSettings()
public void CloseAllTerminals()
{
return App.Instance.ShowSettings();
foreach (var terminal in Terminals)
{
terminal.CloseView();
}
}
private void CloseCurrentTab()
{
SelectedTerminal?.CloseCommand.Execute(null);
}
private int GetNextTerminalId()
{
return _nextTerminalId++;
}
private void NewWindow()
{
NewWindowRequested?.Invoke(this, EventArgs.Empty);
}
private async void OnApplicationSettingsChanged(object sender, EventArgs e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => _applicationSettings = _settingsService.GetApplicationSettings());
}
private async void OnCloseRequest(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
{
var deferral = e.GetDeferral();
if (_applicationSettings.ConfirmClosingWindows)
{
var result = await _dialogService.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to close this window?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(false);
if (result == DialogButton.OK)
{
CloseAllTerminals();
Closed?.Invoke(this, EventArgs.Empty);
}
else
{
e.Handled = true;
}
}
else
{
CloseAllTerminals();
Closed?.Invoke(this, EventArgs.Empty);
}
deferral.Complete();
}
private async void OnCurrentThemeChanged(object sender, System.EventArgs e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var currentTheme = _settingsService.GetCurrentTheme();
Background = currentTheme.Colors.Background;
BackgroundOpacity = currentTheme.BackgroundOpacity;
});
}
private void OnTerminalCloseRequested(object sender, EventArgs e)
{
if (sender is TerminalViewModel terminal)
{
terminal.CloseView();
if (SelectedTerminal == terminal)
{
SelectedTerminal = Terminals.LastOrDefault(t => t != terminal);
}
Terminals.Remove(terminal);
if (Terminals.Count == 0)
{
Closed?.Invoke(this, EventArgs.Empty);
ApplicationView.GetForCurrentView().TryConsolidateAsync();
}
}
}
private void OnTerminalsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (Terminals.Any())
{
Title = Terminals.First().Title;
}
}
private void OnTitleChanged(object sender, string e)
{
if (sender is TerminalViewModel terminal && Terminals.First() == terminal)
{
Title = e;
}
}
private void SelectNextTab()
{
var currentIndex = Terminals.IndexOf(SelectedTerminal);
var nextIndex = (currentIndex + 1) % Terminals.Count;
SelectedTerminal = Terminals[nextIndex];
}
private void SelectPreviousTab()
{
var currentIndex = Terminals.IndexOf(SelectedTerminal);
var previousIndex = (currentIndex - 1 + Terminals.Count) % Terminals.Count;
SelectedTerminal = Terminals[previousIndex];
}
private void ShowSettings()
{
ShowSettingsRequested?.Invoke(this, EventArgs.Empty);
}
}
}
@@ -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 readonly 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().ConfigureAwait(false));
}
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.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to restore the general settings?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(false);
if (result == DialogButton.OK)
{
var defaults = _defaultValueProvider.GetDefaultApplicationSettings();
ConfirmClosingWindows = defaults.ConfirmClosingWindows;
ConfirmClosingTabs = defaults.ConfirmClosingTabs;
NewTerminalLocation = defaults.NewTerminalLocation;
}
}
}
}
@@ -0,0 +1,129 @@
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().ConfigureAwait(false));
DeleteCommand = new RelayCommand(async () => await Delete().ConfigureAwait(false));
}
public event EventHandler Deleted;
public event EventHandler Edited;
public bool Meta
{
get => Model.Meta;
set
{
if (Model.Meta != value)
{
Model.Meta = value;
RaisePropertyChanged();
}
}
}
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;
Meta = dialog.KeyBinding.Meta;
Key = dialog.KeyBinding.Key;
Edited?.Invoke(this, EventArgs.Empty);
return true;
}
return false;
}
private async Task Delete()
{
var result = await _dialogService.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to delete this keybinding?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true);
if (result == DialogButton.OK)
{
Deleted?.Invoke(this, EventArgs.Empty);
}
}
}
}
@@ -0,0 +1,131 @@
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().ConfigureAwait(false));
AddCommand = new RelayCommand<Command>(async command => await Add(command).ConfigureAwait(false));
Initialize(_settingsService.GetKeyBindings());
}
private void Initialize(KeyBindings keyBindings)
{
_keyBindings = keyBindings;
NewTab = CreateViewModel(Command.NewTab, _keyBindings.NewTab);
ConfigurableNewTab = CreateViewModel(Command.ConfigurableNewTab, _keyBindings.ConfigurableNewTab);
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);
Search = CreateViewModel(Command.Search, _keyBindings.Search);
RaisePropertyChanged(nameof(NewTab));
RaisePropertyChanged(nameof(ConfigurableNewTab));
RaisePropertyChanged(nameof(ToggleWindow));
RaisePropertyChanged(nameof(NextTab));
RaisePropertyChanged(nameof(PreviousTab));
RaisePropertyChanged(nameof(CloseTab));
RaisePropertyChanged(nameof(NewWindow));
RaisePropertyChanged(nameof(ShowSettings));
RaisePropertyChanged(nameof(Copy));
RaisePropertyChanged(nameof(Paste));
RaisePropertyChanged(nameof(Search));
}
public KeyBindingsViewModel NewTab { get; private set; }
public KeyBindingsViewModel ConfigurableNewTab { 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 KeyBindingsViewModel Search { 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.ConfigurableNewTab:
return ConfigurableNewTab.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();
case Command.Search:
return Search.Add();
}
return Task.CompletedTask;
}
private async Task RestoreDefaults()
{
var result = await _dialogService.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to restore the default keybindings?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true);
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,66 @@
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
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 readonly 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().ConfigureAwait(true))
{
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,104 @@
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 ProfilesPageViewModel : ViewModelBase
{
private readonly IDefaultValueProvider _defaultValueProvider;
private readonly IDialogService _dialogService;
private readonly ISettingsService _settingsService;
private ShellProfileViewModel _selectedShellProfile;
public ProfilesPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider)
{
_settingsService = settingsService;
_dialogService = dialogService;
_defaultValueProvider = defaultValueProvider;
CreateShellProfileCommand = new RelayCommand(CreateShellProfile);
var defaultShellProfileId = _settingsService.GetDefaultShellProfileId();
foreach (var shellProfile in _settingsService.GetShellProfiles())
{
var viewModel = new ShellProfileViewModel(shellProfile, settingsService, dialogService);
viewModel.Deleted += OnShellProfileDeleted;
viewModel.SetAsDefault += OnShellProfileSetAsDefault;
if (shellProfile.Id == defaultShellProfileId)
{
viewModel.IsDefault = true;
}
ShellProfiles.Add(viewModel);
}
SelectedShellProfile = ShellProfiles.First(p => p.IsDefault);
}
private void OnShellProfileSetAsDefault(object sender, EventArgs e)
{
if (sender is ShellProfileViewModel defaultShellProfile)
{
_settingsService.SaveDefaultShellProfileId(defaultShellProfile.Id);
foreach (var shellProfile in ShellProfiles)
{
shellProfile.IsDefault = shellProfile.Id == defaultShellProfile.Id;
}
}
}
private void OnShellProfileDeleted(object sender, EventArgs e)
{
if (sender is ShellProfileViewModel shellProfile)
{
if (SelectedShellProfile == shellProfile)
{
SelectedShellProfile = ShellProfiles.First();
}
ShellProfiles.Remove(shellProfile);
if (shellProfile.IsDefault)
{
ShellProfiles.First().IsDefault = true;
_settingsService.SaveDefaultShellProfileId(ShellProfiles.First().Id);
}
_settingsService.DeleteShellProfile(shellProfile.Id);
}
}
public RelayCommand CreateShellProfileCommand { get; }
private void CreateShellProfile()
{
var shellProfile = new ShellProfile
{
Id = Guid.NewGuid(),
PreInstalled = false,
Name = "New profile"
};
_settingsService.SaveShellProfile(shellProfile);
var viewModel = new ShellProfileViewModel(shellProfile, _settingsService, _dialogService);
viewModel.EditCommand.Execute(null);
viewModel.SetAsDefault += OnShellProfileSetAsDefault;
viewModel.Deleted += OnShellProfileDeleted;
ShellProfiles.Add(viewModel);
SelectedShellProfile = viewModel;
}
public ShellProfileViewModel SelectedShellProfile
{
get => _selectedShellProfile;
set => Set(ref _selectedShellProfile, value);
}
public ObservableCollection<ShellProfileViewModel> ShellProfiles { get; } = new ObservableCollection<ShellProfileViewModel>();
}
}
@@ -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 readonly 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.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to restore the default terminal options?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(false);
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().ConfigureAwait(false));
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; }
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,157 +1,32 @@
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using FluentTerminal.App.ViewModels.Settings;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Threading.Tasks;
using Windows.Storage.Pickers;
using Windows.UI.Popups;
namespace FluentTerminal.App.ViewModels
{
public class SettingsViewModel : ViewModelBase
{
private readonly ISettingsService _settingsService;
private readonly IDefaultValueProvider _defaultValueProvider;
private ShellConfiguration _shellConfiguration;
public SettingsViewModel(ISettingsService settingsService, IDefaultValueProvider defaultValueProvider)
public SettingsViewModel(ISettingsService settingsService, IDefaultValueProvider defaultValueProvider, IDialogService dialogService, ITrayProcessCommunicationService trayProcessCommunicationService)
{
_settingsService = settingsService;
_defaultValueProvider = defaultValueProvider;
BrowseForCustomShellCommand = new RelayCommand(async () => await BrowseForCustomShell());
BrowseForWorkingDirectoryCommand = new RelayCommand(async () => await BrowseForWorkingDirectory());
RestoreDefaultsCommand = new RelayCommand<string>(async (area) => await RestoreDefaults(area));
_shellConfiguration = _settingsService.GetShellConfiguration();
ShellType = _shellConfiguration.Shell;
KeyBindings = new KeyBindingsPageViewModel(settingsService, dialogService, defaultValueProvider, trayProcessCommunicationService);
General = new GeneralPageViewModel(settingsService, dialogService, defaultValueProvider);
Shell = new ProfilesPageViewModel(settingsService, dialogService, defaultValueProvider);
Terminal = new TerminalPageViewModel(settingsService, dialogService, defaultValueProvider);
Themes = new ThemesPageViewModel(settingsService, dialogService, defaultValueProvider);
}
public RelayCommand BrowseForCustomShellCommand { get; }
public RelayCommand BrowseForWorkingDirectoryCommand { get; }
public RelayCommand<string> RestoreDefaultsCommand { get; }
public event EventHandler Closed;
public bool CMDIsSelected
public GeneralPageViewModel General { get; }
public KeyBindingsPageViewModel KeyBindings { get; }
public ProfilesPageViewModel Shell { get; }
public TerminalPageViewModel Terminal { get; }
public ThemesPageViewModel Themes { get; }
public void Close()
{
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 string WorkingDirectory
{
get => _shellConfiguration.WorkingDirectory;
set
{
if (_shellConfiguration.WorkingDirectory != value)
{
_shellConfiguration.WorkingDirectory = value;
_settingsService.SaveShellConfiguration(_shellConfiguration);
RaisePropertyChanged();
}
}
}
public string Arguments
{
get => _shellConfiguration.Arguments;
set
{
if (_shellConfiguration.Arguments != value)
{
_shellConfiguration.Arguments = value;
_settingsService.SaveShellConfiguration(_shellConfiguration);
RaisePropertyChanged();
}
}
}
public bool PoweShellIsSelected
{
get => ShellType == ShellType.PowerShell;
set => ShellType = ShellType.PowerShell;
}
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));
}
}
}
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(string area)
{
var dialog = new MessageDialog("Are you sure you want to restore default values for this page?", "Please confirm");
dialog.Commands.Add(new UICommand("OK"));
dialog.Commands.Add(new UICommand("Cancel"));
var result = await dialog.ShowAsync();
if (result.Label == "OK" && area == "shell")
{
var defaults = _defaultValueProvider.GetDefaultShellConfiguration();
ShellType = defaults.Shell;
CustomShellLocation = defaults.CustomShellLocation;
WorkingDirectory = defaults.WorkingDirectory;
Arguments = defaults.Arguments;
}
Closed?.Invoke(this, EventArgs.Empty);
}
}
}
@@ -0,0 +1,186 @@
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Threading.Tasks;
using Windows.Storage.Pickers;
namespace FluentTerminal.App.ViewModels
{
public class ShellProfileViewModel : ViewModelBase
{
private readonly ShellProfile _shellProfile;
private string _name;
private string _arguments;
private string _location;
private string _workingDirectory;
private string _fallbackName;
private string _fallbackArguments;
private string _fallbackLocation;
private string _fallbackWorkingDirectory;
private bool _isDefault;
private bool _inEditMode;
private readonly ISettingsService _settingsService;
private readonly IDialogService _dialogService;
public ShellProfileViewModel(ShellProfile shellProfile, ISettingsService settingsService, IDialogService dialogService)
{
_shellProfile = shellProfile;
_settingsService = settingsService;
_dialogService = dialogService;
Id = shellProfile.Id;
Name = shellProfile.Name;
Arguments = shellProfile.Arguments;
Location = shellProfile.Location;
WorkingDirectory = shellProfile.WorkingDirectory;
SetDefaultCommand = new RelayCommand(SetDefault);
DeleteCommand = new RelayCommand(async () => await Delete().ConfigureAwait(false), CanDelete);
EditCommand = new RelayCommand(Edit, CanEdit);
CancelEditCommand = new RelayCommand(async () => await CancelEdit().ConfigureAwait(false));
SaveChangesCommand = new RelayCommand(SaveChanges);
BrowseForCustomShellCommand = new RelayCommand(async () => await BrowseForCustomShell().ConfigureAwait(false));
BrowseForWorkingDirectoryCommand = new RelayCommand(async () => await BrowseForWorkingDirectory().ConfigureAwait(false));
}
public event EventHandler Deleted;
public event EventHandler SetAsDefault;
public RelayCommand DeleteCommand { get; }
public RelayCommand EditCommand { get; }
public RelayCommand SaveChangesCommand { get; }
public RelayCommand CancelEditCommand { get; }
public RelayCommand SetDefaultCommand { get; }
public RelayCommand BrowseForCustomShellCommand { get; }
public RelayCommand BrowseForWorkingDirectoryCommand { get; }
public Guid Id { get; }
public string Name
{
get => _name;
set => Set(ref _name, value);
}
public string Arguments
{
get => _arguments;
set => Set(ref _arguments, value);
}
public string Location
{
get => _location;
set => Set(ref _location, value);
}
public string WorkingDirectory
{
get => _workingDirectory;
set => Set(ref _workingDirectory, value);
}
public bool IsDefault
{
get => _isDefault;
set => Set(ref _isDefault, value);
}
public bool InEditMode
{
get => _inEditMode;
set => Set(ref _inEditMode, value);
}
public void SaveChanges()
{
_shellProfile.Arguments = Arguments;
_shellProfile.Location = Location;
_shellProfile.Name = Name;
_shellProfile.WorkingDirectory = WorkingDirectory;
_settingsService.SaveShellProfile(_shellProfile);
InEditMode = false;
}
private async Task CancelEdit()
{
var result = await _dialogService.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to discard all changes?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true);
if (result == DialogButton.OK)
{
Arguments = _fallbackArguments;
Location = _fallbackLocation;
Name = _fallbackName;
WorkingDirectory = _fallbackWorkingDirectory;
InEditMode = false;
}
}
private void Edit()
{
_fallbackArguments = Arguments;
_fallbackLocation = Location;
_fallbackName = Name;
_fallbackWorkingDirectory = WorkingDirectory;
InEditMode = true;
}
private bool CanDelete()
{
return !_shellProfile.PreInstalled;
}
private bool CanEdit()
{
return !_shellProfile.PreInstalled;
}
private async Task Delete()
{
var result = await _dialogService.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to delete this theme?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true);
if (result == DialogButton.OK)
{
Deleted?.Invoke(this, EventArgs.Empty);
}
}
private void SetDefault()
{
SetAsDefault?.Invoke(this, EventArgs.Empty);
}
private async Task BrowseForCustomShell()
{
var picker = new FileOpenPicker
{
SuggestedStartLocation = PickerLocationId.ComputerFolder
};
picker.FileTypeFilter.Add(".exe");
var file = await picker.PickSingleFileAsync();
if (file != null)
{
Location = 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;
}
}
}
}
@@ -1,33 +1,110 @@
using FluentTerminal.App.Services;
using FluentTerminal.App.Views;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.UI.Popups;
using Windows.ApplicationModel.Core;
using Windows.ApplicationModel.DataTransfer;
using Windows.UI.Core;
using Windows.UI.Xaml;
namespace FluentTerminal.App.ViewModels
{
public class TerminalViewModel : ViewModelBase
{
private readonly IDialogService _dialogService;
private readonly IKeyboardCommandService _keyboardCommandService;
private readonly ISettingsService _settingsService;
private readonly ITrayProcessCommunicationService _trayProcessCommunicationService;
private ApplicationSettings _applicationSettings;
private readonly CoreDispatcher _dispatcher;
private string _resizeOverlayContent;
private readonly DispatcherTimer _resizeOverlayTimer;
private bool _showResizeOverlay;
private readonly string _startupDirectory;
private int _terminalId;
private ITerminalView _terminalView;
private string _title;
private string _resizeOverlayContent;
private bool _showResizeOverlay;
private DispatcherTimer _resizeOverlayTimer;
private readonly ISettingsService _settingsService;
private readonly ITerminalService _terminalService;
private int _terminalId;
private readonly ShellProfile _shellProfile;
private bool _showSearchPanel;
private string _searchText;
public int Id { get; private set; }
public TerminalViewModel(int id, ISettingsService settingsService, ITrayProcessCommunicationService trayProcessCommunicationService, IDialogService dialogService,
IKeyboardCommandService keyboardCommandService, ApplicationSettings applicationSettings, string startupDirectory, ShellProfile shellProfile)
{
Id = id;
Title = DefaultTitle;
_settingsService = settingsService;
_settingsService.CurrentThemeChanged += OnCurrentThemeChanged;
_settingsService.TerminalOptionsChanged += OnTerminalOptionsChanged;
_settingsService.ApplicationSettingsChanged += OnApplicationSettingsChanged;
_settingsService.KeyBindingsChanged += OnKeyBindingsChanged;
_trayProcessCommunicationService = trayProcessCommunicationService;
_dialogService = dialogService;
_keyboardCommandService = keyboardCommandService;
_applicationSettings = applicationSettings;
_startupDirectory = startupDirectory;
_shellProfile = shellProfile;
_resizeOverlayTimer = new DispatcherTimer
{
Interval = new TimeSpan(0, 0, 2)
};
_resizeOverlayTimer.Tick += OnResizeOverlayTimerFinished;
CloseCommand = new RelayCommand(async () => await InvokeCloseRequested().ConfigureAwait(false));
FindNextCommand = new RelayCommand(async () => await FindNext().ConfigureAwait(false));
FindPreviousCommand = new RelayCommand(async () => await FindPrevious().ConfigureAwait(false));
CloseSearchPanelCommand = new RelayCommand(CloseSearchPanel);
_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)).ConfigureAwait(false);
});
}
public event EventHandler CloseRequested;
public event EventHandler<string> TitleChanged;
public RelayCommand CloseCommand { get; }
public RelayCommand FindPreviousCommand { get; }
public RelayCommand FindNextCommand { get; }
public RelayCommand CloseSearchPanelCommand { get; }
public int Id { get; }
public bool Initialized { get; private set; }
public string Title
public string DefaultTitle { get; private set; } = "Fluent Terminal";
public string SearchText
{
get => _title;
set => Set(ref _title, value);
get => _searchText;
set => Set(ref _searchText, value);
}
public bool ShowSearchPanel
{
get => _showSearchPanel;
set => Set(ref _showSearchPanel, value);
}
public string ResizeOverlayContent
{
get => _resizeOverlayContent;
set => Set(ref _resizeOverlayContent, value);
}
public bool ShowResizeOverlay
@@ -47,19 +124,127 @@ namespace FluentTerminal.App.ViewModels
}
}
public string ResizeOverlayContent
public string Title
{
get => _resizeOverlayContent;
set => Set(ref _resizeOverlayContent, value);
get => _title;
set
{
value = string.IsNullOrWhiteSpace(value) ? DefaultTitle: value;
if (Set(ref _title, value))
{
TitleChanged?.Invoke(this, Title);
}
}
}
public TerminalViewModel(ISettingsService settingsService, ITerminalService terminalService)
public void CloseView()
{
_settingsService = settingsService;
_terminalService = terminalService;
_resizeOverlayTimer = new DispatcherTimer();
_resizeOverlayTimer.Interval = new TimeSpan(0, 0, 2);
_resizeOverlayTimer.Tick += OnResizeOverlayTimerFinished;
_terminalView.Close();
}
public Task FocusTerminal()
{
return _terminalView?.FocusTerminal();
}
public async Task OnViewIsReady(ITerminalView terminalView)
{
_terminalView = terminalView;
var options = _settingsService.GetTerminalOptions();
var theme = _settingsService.GetCurrentTheme();
var keyBindings = _settingsService.GetKeyBindings();
var size = await _terminalView.CreateTerminal(options, theme.Colors, GetKeyBindingsCollection(keyBindings)).ConfigureAwait(true);
if (!string.IsNullOrWhiteSpace(_startupDirectory))
{
_shellProfile.WorkingDirectory = _startupDirectory;
}
var response = await _trayProcessCommunicationService.CreateTerminal(size, _shellProfile).ConfigureAwait(true);
if (response.Success)
{
_terminalId = response.Id;
_terminalView.TerminalSizeChanged += OnTerminalSizeChanged;
_terminalView.TerminalTitleChanged += OnTerminalTitleChanged;
_terminalView.KeyboardCommandReceived += OnKeyboardCommandReceived;
DefaultTitle = response.ShellExecutableName;
Title = DefaultTitle;
await _terminalView.ConnectToSocket(response.WebSocketUrl).ConfigureAwait(true);
Initialized = true;
}
else
{
await _dialogService.ShowMessageDialogAsnyc("Error", response.Error, DialogButton.OK).ConfigureAwait(true);
}
await FocusTerminal().ConfigureAwait(true);
}
private async Task InvokeCloseRequested()
{
if (_applicationSettings.ConfirmClosingTabs)
{
var result = await _dialogService.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to close this tab?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true);
if (result == DialogButton.Cancel)
{
return;
}
}
CloseRequested?.Invoke(this, EventArgs.Empty);
}
private async void OnApplicationSettingsChanged(object sender, EventArgs e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => _applicationSettings = _settingsService.GetApplicationSettings());
}
private async void OnCurrentThemeChanged(object sender, EventArgs e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
var currentTheme = _settingsService.GetCurrentTheme();
await _terminalView.ChangeTheme(currentTheme.Colors).ConfigureAwait(true);
});
}
private async void OnKeyboardCommandReceived(object sender, Command e)
{
if (e == Command.Copy)
{
var selection = await _terminalView.GetSelection().ConfigureAwait(true);
var dataPackage = new DataPackage();
dataPackage.SetText(selection);
Clipboard.SetContent(dataPackage);
}
else if (e == Command.Paste)
{
var content = Clipboard.GetContent();
if (content.Contains(StandardDataFormats.Text))
{
var text = await content.GetTextAsync();
await _terminalView.Write(text).ConfigureAwait(true);
}
}
else if (e == Command.Search)
{
ShowSearchPanel = !ShowSearchPanel;
if (ShowSearchPanel)
{
_terminalView.FocusSearchTextBox();
}
}
else
{
_keyboardCommandService.SendCommand(e);
}
}
private void OnResizeOverlayTimerFinished(object sender, object e)
@@ -68,34 +253,13 @@ namespace FluentTerminal.App.ViewModels
ShowResizeOverlay = false;
}
public async Task OnViewIsReady(ITerminalView terminalView)
private async void OnTerminalOptionsChanged(object sender, EventArgs e)
{
_terminalView = terminalView;
var size = await _terminalView.CreateTerminal();
var configuration = _settingsService.GetShellConfiguration();
var response = await _terminalService.CreateTerminal(size, configuration);
if (response.Success)
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
_terminalId = response.Id;
_terminalView.TerminalSizeChanged += OnTerminalSizeChanged;
_terminalView.TerminalTitleChanged += OnTerminalTitleChanged;
await _terminalView.ConnectToSocket(response.WebSocketUrl);
Initialized = true;
}
else
{
var dialog = new MessageDialog(response.Error, "Error");
await dialog.ShowAsync();
}
}
private void OnTerminalTitleChanged(object sender, string e)
{
Title = e;
var options = _settingsService.GetTerminalOptions();
await _terminalView.ChangeOptions(options).ConfigureAwait(true);
});
}
private async void OnTerminalSizeChanged(object sender, TerminalSize e)
@@ -106,7 +270,46 @@ namespace FluentTerminal.App.ViewModels
}
ResizeOverlayContent = $"{e.Columns} x {e.Rows}";
ShowResizeOverlay = true;
await _terminalService.ResizeTerminal(_terminalId, e);
await _trayProcessCommunicationService.ResizeTerminal(_terminalId, e).ConfigureAwait(true);
}
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.ConfigurableNewTab);
list.AddRange(keyBindings.NewWindow);
list.AddRange(keyBindings.NextTab);
list.AddRange(keyBindings.Paste);
list.AddRange(keyBindings.PreviousTab);
list.AddRange(keyBindings.ShowSettings);
list.AddRange(keyBindings.Search);
return list;
}
private Task FindNext()
{
return _terminalView.FindNext(SearchText);
}
private Task FindPrevious()
{
return _terminalView.FindPrevious(SearchText);
}
private void CloseSearchPanel()
{
SearchText = string.Empty;
ShowSearchPanel = false;
_terminalView.FocusTerminal();
}
}
}
}
@@ -0,0 +1,369 @@
using FluentTerminal.App.Services;
using FluentTerminal.App.Utilities;
using FluentTerminal.Models;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using Microsoft.Toolkit.Uwp.Helpers;
using System;
using System.Threading.Tasks;
using Windows.UI;
namespace FluentTerminal.App.ViewModels
{
public class ThemeViewModel : ViewModelBase
{
private readonly IDialogService _dialogService;
private readonly ISettingsService _settingsService;
private string _author;
private Color _background;
private double _backgroundOpacity;
private Color _black;
private Color _blue;
private Color _brightBlack;
private Color _brightBlue;
private Color _brightCyan;
private Color _brightGreen;
private Color _brightMagenta;
private Color _brightRed;
private Color _brightWhite;
private Color _brightYellow;
private Color _cursor;
private Color _cursorAccent;
private Color _cyan;
private string _fallBackAuthor;
private double _fallBackBackgroundOpacity;
private TerminalColors _fallBackColors;
private string _fallBackName;
private Color _foreground;
private Color _green;
private bool _inEditMode;
private bool _isActive;
private Color _magenta;
private string _name;
private Color _red;
private Color _selection;
private readonly TerminalTheme _theme;
private Color _white;
private Color _yellow;
public ThemeViewModel(TerminalTheme theme, ISettingsService settingsService, IDialogService dialogService)
{
_theme = theme;
_settingsService = settingsService;
_dialogService = dialogService;
Name = _theme.Name;
Author = _theme.Author;
Id = _theme.Id;
BackgroundOpacity = _theme.BackgroundOpacity;
Black = _theme.Colors.Black.ToColor();
Red = _theme.Colors.Red.ToColor();
Green = _theme.Colors.Green.ToColor();
Yellow = _theme.Colors.Yellow.ToColor();
Blue = _theme.Colors.Blue.ToColor();
Magenta = _theme.Colors.Magenta.ToColor();
Cyan = _theme.Colors.Cyan.ToColor();
White = _theme.Colors.White.ToColor();
BrightBlack = _theme.Colors.BrightBlack.ToColor();
BrightRed = _theme.Colors.BrightRed.ToColor();
BrightGreen = _theme.Colors.BrightGreen.ToColor();
BrightYellow = _theme.Colors.BrightYellow.ToColor();
BrightBlue = _theme.Colors.BrightBlue.ToColor();
BrightMagenta = _theme.Colors.BrightMagenta.ToColor();
BrightCyan = _theme.Colors.BrightCyan.ToColor();
BrightWhite = _theme.Colors.BrightWhite.ToColor();
Background = _theme.Colors.Background.ToColor();
Foreground = _theme.Colors.Foreground.ToColor();
Cursor = _theme.Colors.Cursor.ToColor();
CursorAccent = _theme.Colors.CursorAccent.ToColor();
Selection = _theme.Colors.Selection.FromString();
SetActiveCommand = new RelayCommand(SetActive);
DeleteCommand = new RelayCommand(async () => await Delete().ConfigureAwait(false), CanDelete);
EditCommand = new RelayCommand(Edit, CanEdit);
CancelEditCommand = new RelayCommand(async () => await CancelEdit().ConfigureAwait(false));
SaveChangesCommand = new RelayCommand(SaveChanges);
}
public event EventHandler Activated;
public event EventHandler Deleted;
public string Author
{
get => _author;
set => Set(ref _author, value);
}
public Color Background
{
get => _background;
set => Set(ref _background, value);
}
public double BackgroundOpacity
{
get => _backgroundOpacity;
set => Set(ref _backgroundOpacity, value);
}
public Color Black
{
get => _black;
set => Set(ref _black, value);
}
public Color Blue
{
get => _blue;
set => Set(ref _blue, value);
}
public Color BrightBlack
{
get => _brightBlack;
set => Set(ref _brightBlack, value);
}
public Color BrightBlue
{
get => _brightBlue;
set => Set(ref _brightBlue, value);
}
public Color BrightCyan
{
get => _brightCyan;
set => Set(ref _brightCyan, value);
}
public Color BrightGreen
{
get => _brightGreen;
set => Set(ref _brightGreen, value);
}
public Color BrightMagenta
{
get => _brightMagenta;
set => Set(ref _brightMagenta, value);
}
public Color BrightRed
{
get => _brightRed;
set => Set(ref _brightRed, value);
}
public Color BrightWhite
{
get => _brightWhite;
set => Set(ref _brightWhite, value);
}
public Color BrightYellow
{
get => _brightYellow;
set => Set(ref _brightYellow, value);
}
public RelayCommand CancelEditCommand { get; }
public Color Cursor
{
get => _cursor;
set => Set(ref _cursor, value);
}
public Color CursorAccent
{
get => _cursorAccent;
set => Set(ref _cursorAccent, value);
}
public Color Cyan
{
get => _cyan;
set => Set(ref _cyan, value);
}
public RelayCommand DeleteCommand { get; }
public RelayCommand EditCommand { get; }
public Color Foreground
{
get => _foreground;
set => Set(ref _foreground, value);
}
public Color Green
{
get => _green;
set => Set(ref _green, value);
}
public Guid Id { get; }
public bool InEditMode
{
get => _inEditMode;
set => Set(ref _inEditMode, value);
}
public bool IsActive
{
get => _isActive;
set => Set(ref _isActive, value);
}
public Color Magenta
{
get => _magenta;
set => Set(ref _magenta, value);
}
public string Name
{
get => _name;
set => Set(ref _name, value);
}
public Color Red
{
get => _red;
set => Set(ref _red, value);
}
public RelayCommand SaveChangesCommand { get; }
public Color Selection
{
get => _selection;
set => Set(ref _selection, value);
}
public RelayCommand SetActiveCommand { get; }
public Color White
{
get => _white;
set => Set(ref _white, value);
}
public Color Yellow
{
get => _yellow;
set => Set(ref _yellow, value);
}
public void SaveChanges()
{
_theme.Name = Name;
_theme.Author = Author;
_theme.BackgroundOpacity = BackgroundOpacity;
_theme.Colors.Black = Black.ToColorString(false);
_theme.Colors.Red = Red.ToColorString(false);
_theme.Colors.Green = Green.ToColorString(false);
_theme.Colors.Yellow = Yellow.ToColorString(false);
_theme.Colors.Blue = Blue.ToColorString(false);
_theme.Colors.Magenta = Magenta.ToColorString(false);
_theme.Colors.Cyan = Cyan.ToColorString(false);
_theme.Colors.White = White.ToColorString(false);
_theme.Colors.BrightBlack = BrightBlack.ToColorString(false);
_theme.Colors.BrightRed = BrightRed.ToColorString(false);
_theme.Colors.BrightGreen = BrightGreen.ToColorString(false);
_theme.Colors.BrightYellow = BrightYellow.ToColorString(false);
_theme.Colors.BrightBlue = BrightBlue.ToColorString(false);
_theme.Colors.BrightMagenta = BrightMagenta.ToColorString(false);
_theme.Colors.BrightCyan = BrightCyan.ToColorString(false);
_theme.Colors.BrightWhite = BrightWhite.ToColorString(false);
_theme.Colors.Background = Background.ToColorString(false);
_theme.Colors.Foreground = Foreground.ToColorString(false);
_theme.Colors.Cursor = Cursor.ToColorString(false);
_theme.Colors.CursorAccent = CursorAccent.ToColorString(false);
_theme.Colors.Selection = Selection.ToColorString(true);
_settingsService.SaveTheme(_theme);
InEditMode = false;
}
private async Task CancelEdit()
{
var result = await _dialogService.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to discard all changes?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true);
if (result == DialogButton.OK)
{
Black = _fallBackColors.Black.ToColor();
Red = _fallBackColors.Red.ToColor();
Green = _fallBackColors.Green.ToColor();
Yellow = _fallBackColors.Yellow.ToColor();
Blue = _fallBackColors.Blue.ToColor();
Magenta = _fallBackColors.Magenta.ToColor();
Cyan = _fallBackColors.Cyan.ToColor();
White = _fallBackColors.White.ToColor();
BrightBlack = _fallBackColors.BrightBlack.ToColor();
BrightRed = _fallBackColors.BrightRed.ToColor();
BrightGreen = _fallBackColors.BrightGreen.ToColor();
BrightYellow = _fallBackColors.BrightYellow.ToColor();
BrightBlue = _fallBackColors.BrightBlue.ToColor();
BrightMagenta = _fallBackColors.BrightMagenta.ToColor();
BrightCyan = _fallBackColors.BrightCyan.ToColor();
BrightWhite = _fallBackColors.BrightWhite.ToColor();
Background = _fallBackColors.Background.ToColor();
Foreground = _fallBackColors.Foreground.ToColor();
Cursor = _fallBackColors.Cursor.ToColor();
CursorAccent = _fallBackColors.CursorAccent.ToColor();
Selection = _fallBackColors.Selection.FromString();
Name = _fallBackName;
Author = _fallBackAuthor;
BackgroundOpacity = _fallBackBackgroundOpacity;
InEditMode = false;
}
}
private bool CanDelete()
{
return !_theme.PreInstalled;
}
private bool CanEdit()
{
return !_theme.PreInstalled;
}
private async Task Delete()
{
var result = await _dialogService.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to delete this theme?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true);
if (result == DialogButton.OK)
{
Deleted?.Invoke(this, EventArgs.Empty);
}
}
private void Edit()
{
_fallBackColors = new TerminalColors(_theme.Colors);
_fallBackName = Name;
_fallBackAuthor = Author;
_fallBackBackgroundOpacity = BackgroundOpacity;
InEditMode = true;
}
private void SetActive()
{
Activated?.Invoke(this, EventArgs.Empty);
}
}
}
@@ -0,0 +1,100 @@
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 readonly ApplicationViewTitleBar _titleBar;
private readonly UISettings _uiSettings;
private readonly CoreDispatcher _dispatcher;
private bool _customValues;
private Color? _buttonForeground;
private Color? _buttonHoverBackground;
private Color? _buttonPressedBackground;
private Color? _buttonHoverForeground;
private Color? _buttonPressedForeground;
private Color? _inactiveForeground;
public 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)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)Resources["SystemBaseHighColor"];
}
});
}
public Color TitleBarForeground
{
get { return (Color)GetValue(TitleBarForegroundProperty); }
set { SetValue(TitleBarForegroundProperty, value); }
}
public static readonly DependencyProperty TitleBarForegroundProperty =
DependencyProperty.Register(nameof(TitleBarForeground), typeof(Color), typeof(BindableColorsTitleBar), new PropertyMetadata(Colors.Transparent, TitleBarForegroundChanged));
private static void TitleBarForegroundChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
if (dependencyObject is BindableColorsTitleBar titleBarControl)
{
var color = (Color)args.NewValue;
titleBarControl._buttonForeground = titleBarControl._titleBar.ButtonForegroundColor = color;
titleBarControl._buttonPressedForeground = titleBarControl._titleBar.ButtonPressedForegroundColor = color;
titleBarControl._buttonHoverForeground = titleBarControl._titleBar.ButtonHoverForegroundColor = color;
titleBarControl._inactiveForeground = titleBarControl._titleBar.InactiveForegroundColor = Color.FromArgb(128, color.R, color.G, color.B);
}
}
public void RestoreColors()
{
_titleBar.ButtonForegroundColor = _buttonForeground;
_titleBar.ButtonHoverBackgroundColor = _buttonHoverBackground;
_titleBar.ButtonPressedBackgroundColor = _buttonPressedBackground;
_titleBar.ButtonPressedForegroundColor = _buttonPressedForeground;
_titleBar.ButtonHoverForegroundColor = _buttonHoverForeground;
_titleBar.InactiveForegroundColor = _inactiveForeground;
_customValues = true;
}
public void ResetTitleBar()
{
_titleBar.ButtonForegroundColor = (Color)Resources["SystemBaseHighColor"];
_titleBar.ButtonHoverBackgroundColor = null;
_titleBar.ButtonPressedBackgroundColor = null;
_titleBar.ButtonPressedForegroundColor = null;
_titleBar.ButtonHoverForegroundColor = null;
_titleBar.InactiveForegroundColor = null;
_customValues = false;
}
}
}
@@ -0,0 +1,79 @@
<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.Meta, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<FontIcon
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="f" />
</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,72 @@
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;
case VirtualKey.LeftWindows:
case VirtualKey.RightWindows:
KeyBinding.Meta = true;
break;
default:
KeyBinding.Key = (int)e.Key;
break;
}
ResetButton.Visibility = Visibility.Visible;
e.Handled = true;
}
private void Reset()
{
KeyBinding = new KeyBindingViewModel(new KeyBinding(), _dialogService);
ResetButton.Visibility = Visibility.Collapsed;
}
}
}
+14 -1
View File
@@ -1,5 +1,7 @@
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace FluentTerminal.App.Views
@@ -8,8 +10,19 @@ namespace FluentTerminal.App.Views
{
event EventHandler<TerminalSize> TerminalSizeChanged;
event EventHandler<string> TerminalTitleChanged;
event EventHandler<Command> KeyboardCommandReceived;
Task<TerminalSize> CreateTerminal();
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();
Task FocusTerminal();
Task<string> GetSelection();
Task Write(string text);
Task FindNext(string searchText);
Task FindPrevious(string searchText);
void FocusSearchTextBox();
}
}
@@ -0,0 +1,91 @@
<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 Meta, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<FontIcon
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="f" />
</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); }
}
}
}
+108 -26
View File
@@ -2,48 +2,130 @@
x:Class="FluentTerminal.App.Views.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:behaviors="using:FluentTerminal.App.Behaviors"
xmlns:converters="using:FluentTerminal.App.Converters"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="{ThemeResource SystemControlAcrylicWindowBrush}"
xmlns:viewmodels="using:FluentTerminal.App.ViewModels"
RequestedTheme="Dark"
mc:Ignorable="d">
<Page.Resources>
<converters:TerminalViewModelToViewConverter x:Key="TerminalViewModelToViewConverter" />
</Page.Resources>
<Grid x:Name="Root">
<Grid.Background>
<AcrylicBrush
BackgroundSource="HostBackdrop"
FallbackColor="{x:Bind ViewModel.Background, Mode=OneWay}"
TintColor="{x:Bind ViewModel.Background, Mode=OneWay}"
TintOpacity="{x:Bind ViewModel.BackgroundOpacity, Mode=OneWay}" />
</Grid.Background>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Rectangle x:Name="TitleBar" Fill="Transparent" />
<Grid
Grid.Row="0"
Height="{Binding CoreTitleBarHeight, Mode=OneWay}"
Canvas.ZIndex="3">
<Rectangle x:Name="TitleBar" Fill="Transparent" />
<Grid Padding="{Binding CoreTitleBarPadding, Mode=OneWay}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Canvas.ZIndex="9"
IsHitTestVisible="False"
Style="{StaticResource WindowTitleTextBlockStyle}"
Text="{x:Bind ViewModel.Title, Mode=OneWay}" />
<Button
Grid.Column="2"
Command="{x:Bind ViewModel.ShowSettingsCommand}"
Style="{StaticResource TitleBarButtonStyle}">
<Viewbox Width="16" Height="16">
<SymbolIcon Symbol="Setting" />
</Viewbox>
</Button>
</Grid>
</Grid>
Margin="{Binding CoreTitleBarPadding, Mode=OneWay}"
SizeChanged="Grid_SizeChanged">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
IsHitTestVisible="False"
Style="{StaticResource WindowTitleTextBlockStyle}"
Text="{x:Bind ViewModel.Title, Mode=OneWay}"
Visibility="{x:Bind ViewModel.Terminals.Count, Mode=OneWay, Converter={StaticResource OneToVisibleConverter}}" />
<ListView
x:Name="Tabs"
Grid.Column="0"
AllowDrop="True"
CanDragItems="True"
CanReorderItems="True"
ItemsSource="{x:Bind ViewModel.Terminals}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollMode="Auto"
SelectedItem="{x:Bind ViewModel.SelectedTerminal, Mode=TwoWay}"
Visibility="{x:Bind ViewModel.Terminals.Count, Mode=OneWay, Converter={StaticResource OneToCollapsedConverter}}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="viewmodels:TerminalViewModel">
<Grid
Height="32"
Margin="0"
VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Interactivity:Interaction.Behaviors>
<behaviors:MiddleClickBehavior>
<behaviors:MiddleClickBehavior.Actions>
<core:InvokeCommandAction Command="{x:Bind CloseCommand}" />
</behaviors:MiddleClickBehavior.Actions>
</behaviors:MiddleClickBehavior>
</Interactivity:Interaction.Behaviors>
<TextBlock
Grid.Column="0"
Margin="12,8,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Title, Mode=OneWay}" />
<Button
Grid.Column="2"
Width="32"
Command="{x:Bind CloseCommand}"
Style="{StaticResource TitleBarButtonStyle}"
ToolTipService.ToolTip="Close">
<Viewbox Width="12" Height="12">
<SymbolIcon Symbol="Cancel" />
</Viewbox>
</Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="MinWidth" Value="24" />
<Setter Property="MinHeight" Value="32" />
<Setter Property="Padding" Value="0" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
<StackPanel
x:Name="TitleBarButtons"
Grid.Column="2"
Orientation="Horizontal">
<Button
Command="{x:Bind ViewModel.AddTerminalCommand}"
Style="{StaticResource TitleBarButtonStyle}"
ToolTipService.ToolTip="New Tab">
<Viewbox Width="12" Height="12">
<SymbolIcon Symbol="Add" />
</Viewbox>
</Button>
<Button
HorizontalAlignment="Right"
Command="{x:Bind ViewModel.ShowSettingsCommand}"
Style="{StaticResource TitleBarButtonStyle}"
ToolTipService.ToolTip="Settings">
<Viewbox Width="12" Height="12">
<SymbolIcon Symbol="Setting" />
</Viewbox>
</Button>
</StackPanel>
</Grid>
<ContentControl
x:Name="TerminalContainer"
+12 -8
View File
@@ -3,7 +3,6 @@ using System.ComponentModel;
using Windows.ApplicationModel.Core;
using Windows.UI;
using Windows.UI.Core;
using Windows.UI.Core.Preview;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
@@ -45,7 +44,9 @@ namespace FluentTerminal.App.Views
Loaded += OnLoaded;
Unloaded += OnUnloaded;
Window.Current.Activated += OnWindowActivated;
SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += OnCloseRequest;
ApplicationView.PreferredLaunchViewSize = new Windows.Foundation.Size(800, 600);
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
@@ -56,16 +57,11 @@ namespace FluentTerminal.App.Views
}
}
private void OnCloseRequest(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
{
App.Instance.TerminalWindowClosed();
}
private async void OnWindowActivated(object sender, WindowActivatedEventArgs e)
{
if (e.WindowActivationState != CoreWindowActivationState.Deactivated && TerminalContainer.Content is TerminalView terminal)
{
await terminal.FocusWebView();
await terminal.FocusWebView().ConfigureAwait(true);
}
}
@@ -106,5 +102,13 @@ namespace FluentTerminal.App.Views
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CoreTitleBarPadding)));
}
}
private void Grid_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (sender is Grid grid)
{
Tabs.MaxWidth = grid.ActualWidth - grid.ColumnDefinitions[2].ActualWidth;
}
}
}
}
+52 -69
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"
@@ -20,77 +15,65 @@
Visibility="{Binding IsPaneOpen, ElementName=NavigationView, Converter={StaticResource TrueToVisibleConverter}}" />
<NavigationView
x:Name="NavigationView"
AlwaysShowHeader="False"
Canvas.ZIndex="0"
CompactModeThresholdWidth="560"
ExpandedModeThresholdWidth="560"
IsSettingsVisible="False"
Loaded="NavigationView_Loaded"
OpenPaneLength="280"
OpenPaneLength="200"
SelectionChanged="NavigationView_SelectionChanged">
<NavigationView.MenuItems>
<NavigationViewItem
Content="General"
Icon="Setting"
Tag="general" />
<NavigationViewItem
Content="Key Bindings"
Icon="Setting"
Tag="keyBindings" />
<NavigationViewItem
Content="Shell"
Icon="Setting"
Tag="shell" />
<NavigationViewItem
Content="Font"
Icon="Setting"
Tag="font" />
<NavigationViewItem
Content="Colors"
Icon="Setting"
Tag="colors" />
<NavigationViewItem Content="General" Tag="general">
<NavigationViewItem.Icon>
<FontIcon
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="e"
ToolTipService.ToolTip="General" />
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem Content="Terminal" Tag="terminal">
<NavigationViewItem.Icon>
<FontIcon
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="d"
ToolTipService.ToolTip="Terminal" />
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem Content="Profiles" Tag="profiles">
<NavigationViewItem.Icon>
<FontIcon
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="a"
ToolTipService.ToolTip="Shell" />
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem Content="Keybindings" Tag="keyBindings">
<NavigationViewItem.Icon>
<FontIcon
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="b"
ToolTipService.ToolTip="Keybindings" />
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem Content="Themes" Tag="themes">
<NavigationViewItem.Icon>
<FontIcon
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="c"
ToolTipService.ToolTip="Themes" />
</NavigationViewItem.Icon>
</NavigationViewItem>
</NavigationView.MenuItems>
<NavigationView.HeaderTemplate>
<DataTemplate>
<Grid Margin="24,10,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="{Binding CoreTitleBarHeight}" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Margin="0,-2,0,0"
IsHitTestVisible="False"
Style="{StaticResource CaptionTextBlockStyle}"
Text="Settings"
Visibility="{Binding IsPaneOpen, ElementName=NavigationView, Converter={StaticResource FalseToVisibleConverter}}" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
Text="{Binding SelectedItem.Content, ElementName=NavigationView}" />
<CommandBar
Grid.Row="1"
Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
DefaultLabelPosition="Right">
<AppBarButton
Command="{Binding ViewModel.RestoreDefaultsCommand}"
CommandParameter="{Binding SelectedItem.Tag, ElementName=NavigationView}"
Icon="Undo"
Label="Restore Defaults" />
</CommandBar>
</Grid>
</DataTemplate>
</NavigationView.HeaderTemplate>
<Frame x:Name="ContentFrame" Margin="24" />
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Frame x:Name="ContentFrame" />
<TextBlock
Margin="12,8,0,0"
IsHitTestVisible="False"
Style="{StaticResource CaptionTextBlockStyle}"
Text="Settings"
Visibility="{Binding IsPaneOpen, ElementName=NavigationView, Converter={StaticResource FalseToVisibleConverter}}" />
</Grid>
</NavigationView>
</Grid>
</Page>
+31 -30
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,19 +12,13 @@ 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";
@@ -36,6 +29,10 @@ 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)
@@ -44,19 +41,9 @@ 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() == "shell");
NavigationView.SelectedItem = NavigationView.MenuItems.Cast<NavigationViewItemBase>().FirstOrDefault(m => m.Tag.ToString() == "general");
}
private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
@@ -66,22 +53,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);
case "profiles":
ContentFrame.Navigate(typeof(ShellProfileSettings), ViewModel.Shell);
break;
case "colors":
ContentFrame.Navigate(typeof(ColorSettings), ViewModel);
case "themes":
ContentFrame.Navigate(typeof(ThemeSettings), ViewModel.Themes);
break;
case "font":
ContentFrame.Navigate(typeof(FontSettings), ViewModel);
case "terminal":
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)
{
ViewModel.Close();
}
private void TitleBar_LayoutMetricsChanged(CoreApplicationViewTitleBar sender, object args)
{
AppTitle.Margin = new Thickness(CoreApplication.GetCurrentView().TitleBar.SystemOverlayLeftInset + 12, 8, 0, 0);
}
}
}
}
@@ -1,11 +0,0 @@
<Page
x:Class="FluentTerminal.App.Views.SettingsPages.ColorSettings"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" />
</Page>
@@ -1,30 +0,0 @@
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 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 ColorSettings : Page
{
public ColorSettings()
{
this.InitializeComponent();
}
}
}
@@ -1,11 +0,0 @@
<Page
x:Class="FluentTerminal.App.Views.SettingsPages.FontSettings"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" />
</Page>
@@ -1,30 +0,0 @@
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 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 FontSettings : Page
{
public FontSettings()
{
this.InitializeComponent();
}
}
}
@@ -4,7 +4,49 @@
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 Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="32" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="1" Margin="24,00,0,24">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock
Margin="0,10,0,0"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
Text="General" />
<CommandBar
Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
DefaultLabelPosition="Right">
<AppBarButton
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"
IsOn="{x:Bind ViewModel.ConfirmClosingWindows, Mode=TwoWay}" />
<ToggleSwitch Header="Ask before closing tabs" IsOn="{x:Bind ViewModel.ConfirmClosingTabs, Mode=TwoWay}" />
</StackPanel>
</Grid>
</Page>
@@ -1,12 +1,24 @@
using Windows.UI.Xaml.Controls;
using FluentTerminal.App.ViewModels.Settings;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace FluentTerminal.App.Views.SettingsPages
{
public sealed partial class GeneralSettings : Page
{
public GeneralPageViewModel ViewModel { get; private set; }
public GeneralSettings()
{
this.InitializeComponent();
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is GeneralPageViewModel viewModel)
{
ViewModel = viewModel;
}
}
}
}
@@ -3,9 +3,242 @@
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="New configurable tab">
<MenuFlyoutItem.CommandParameter>
<enums:Command>ConfigurableNewTab</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="Search">
<MenuFlyoutItem.CommandParameter>
<enums:Command>Search</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" />
<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="New configurable tab" />
<views:KeyBindingsView
Grid.Row="1"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.ConfigurableNewTab, Mode=OneWay}" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="0,6,24,0"
Text="Close tab" />
<views:KeyBindingsView
Grid.Row="2"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.CloseTab, Mode=OneWay}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="0,6,24,0"
Text="Next tab" />
<views:KeyBindingsView
Grid.Row="3"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.NextTab, Mode=OneWay}" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Margin="0,6,24,0"
Text="Previous tab" />
<views:KeyBindingsView
Grid.Row="4"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.PreviousTab, Mode=OneWay}" />
<TextBlock
Grid.Row="5"
Grid.Column="0"
Margin="0,6,24,0"
Text="New window" />
<views:KeyBindingsView
Grid.Row="5"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.NewWindow, Mode=OneWay}" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
Margin="0,6,24,0"
Text="Search" />
<views:KeyBindingsView
Grid.Row="6"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.Search, Mode=OneWay}" />
<TextBlock
Grid.Row="7"
Grid.Column="0"
Margin="0,6,24,0"
Text="Show settings" />
<views:KeyBindingsView
Grid.Row="7"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.ShowSettings, Mode=OneWay}" />
<TextBlock
Grid.Row="8"
Grid.Column="0"
Margin="0,6,24,0"
Text="Toggle window" />
<views:KeyBindingsView
Grid.Row="8"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.ToggleWindow, Mode=OneWay}" />
<TextBlock
Grid.Row="9"
Grid.Column="0"
Margin="0,6,24,0"
Text="Copy" />
<views:KeyBindingsView
Grid.Row="9"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.Copy, Mode=OneWay}" />
<TextBlock
Grid.Row="10"
Grid.Column="0"
Margin="0,6,24,0"
Text="Paste" />
<views:KeyBindingsView
Grid.Row="10"
Grid.Column="1"
Margin="0,0,0,24"
ViewModel="{x:Bind ViewModel.Paste, Mode=OneWay}" />
</Grid>
</ScrollViewer>
</Grid>
</Page>
@@ -1,30 +1,24 @@
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.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;
}
}
}
}
@@ -0,0 +1,201 @@
<Page
x:Class="FluentTerminal.App.Views.SettingsPages.ShellProfileSettings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewmodels="using:FluentTerminal.App.ViewModels"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="32" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border
Grid.RowSpan="3"
Grid.Column="0"
Background="{ThemeResource SystemControlAcrylicWindowBrush}" />
<Grid
Grid.Row="1"
Grid.ColumnSpan="2"
Margin="0,0,0,24">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Margin="24,10,0,0"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
Text="Profiles" />
<CommandBar
Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="Transparent"
DefaultLabelPosition="Right"
Visibility="{x:Bind ViewModel.SelectedShellProfile.InEditMode, Mode=OneWay, Converter={StaticResource FalseToVisibleConverter}}">
<AppBarButton
Command="{x:Bind ViewModel.SelectedShellProfile.SetDefaultCommand, Mode=OneWay}"
Icon="Accept"
IsEnabled="{x:Bind ViewModel.SelectedShellProfile.IsDefault, Mode=OneWay, Converter={StaticResource NegateConverter}}"
Label="Set Default" />
<AppBarButton
Command="{x:Bind ViewModel.SelectedShellProfile.EditCommand, Mode=OneWay}"
Icon="Edit"
Label="Edit" />
<AppBarButton
Command="{x:Bind ViewModel.SelectedShellProfile.DeleteCommand, Mode=OneWay}"
Icon="Delete"
Label="Delete" />
</CommandBar>
<CommandBar
Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="Transparent"
DefaultLabelPosition="Right"
Visibility="{x:Bind ViewModel.SelectedShellProfile.InEditMode, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<AppBarButton
Command="{x:Bind ViewModel.SelectedShellProfile.SaveChangesCommand, Mode=OneWay}"
Icon="Save"
Label="Save" />
<AppBarButton
Command="{x:Bind ViewModel.SelectedShellProfile.CancelEditCommand, Mode=OneWay}"
Icon="Cancel"
Label="Cancel" />
</CommandBar>
</Grid>
<StackPanel Grid.Row="2" Grid.Column="0">
<ListView ItemsSource="{x:Bind ViewModel.ShellProfiles}" SelectedItem="{x:Bind ViewModel.SelectedShellProfile, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="viewmodels:ShellProfileViewModel">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{x:Bind Name, Mode=OneWay}" />
<Viewbox
Grid.Column="1"
Width="16"
Height="16"
HorizontalAlignment="Right">
<SymbolIcon Symbol="Accept" Visibility="{x:Bind IsDefault, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}" />
</Viewbox>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
<Button
Height="48"
Margin="0,12,0,0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left"
Background="Transparent"
Command="{x:Bind ViewModel.CreateShellProfileCommand}"
Style="{StaticResource ButtonRevealStyle}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<Viewbox
Width="12"
Height="12"
Margin="0,0,6,0">
<SymbolIcon Symbol="Add" />
</Viewbox>
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" Text="Create new" />
</StackPanel>
</Button.Content>
</Button>
</StackPanel>
<ContentControl
Grid.Row="2"
Grid.Column="1"
Margin="24,0,0,0"
Content="{x:Bind ViewModel.SelectedShellProfile, Mode=TwoWay}">
<ContentControl.ContentTemplate>
<DataTemplate x:DataType="viewmodels:ShellProfileViewModel">
<Grid>
<StackPanel Visibility="{x:Bind InEditMode, Converter={StaticResource TrueToVisibleConverter}, Mode=OneWay}">
<TextBox
Width="300"
HorizontalAlignment="Left"
Header="Name"
IsEnabled="{x:Bind InEditMode, Mode=OneWay}"
IsSpellCheckEnabled="False"
Text="{x:Bind Arguments, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<StackPanel Margin="0,24,0,0" Orientation="Horizontal">
<TextBox
Width="300"
Header="Shell executable location"
IsEnabled="{x:Bind InEditMode, Mode=OneWay}"
IsSpellCheckEnabled="False"
Text="{x:Bind Location, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Button
Margin="6,0,0,0"
VerticalAlignment="Bottom"
Command="{x:Bind BrowseForCustomShellCommand}"
Content="..."
Style="{StaticResource ButtonRevealStyle}" />
</StackPanel>
<StackPanel Margin="0,24,0,0" Orientation="Horizontal">
<TextBox
Width="300"
Header="Working directory"
IsEnabled="{x:Bind InEditMode, Mode=OneWay}"
IsSpellCheckEnabled="False"
Text="{x:Bind WorkingDirectory, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Button
Margin="6,0,0,0"
VerticalAlignment="Bottom"
Command="{x:Bind BrowseForWorkingDirectoryCommand}"
Content="..."
Style="{StaticResource ButtonRevealStyle}" />
</StackPanel>
<TextBox
Width="300"
Margin="0,24,0,0"
HorizontalAlignment="Left"
Header="Arguments"
IsEnabled="{x:Bind InEditMode, Mode=OneWay}"
IsSpellCheckEnabled="False"
Text="{x:Bind Arguments, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
<StackPanel Visibility="{x:Bind InEditMode, Mode=OneWay, Converter={StaticResource FalseToVisibleConverter}}">
<TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{x:Bind Name, Mode=OneWay}" />
<controls:HeaderedTextBlock
Margin="0,58,0,0"
Header="Shell executable location"
Text="{x:Bind Location, Mode=OneWay}" />
<controls:HeaderedTextBlock
Margin="0,36,0,0"
Header="Working directory"
Text="{x:Bind WorkingDirectory, Mode=OneWay}" />
<controls:HeaderedTextBlock
Margin="0,36,0,0"
Header="Arguments"
Text="{x:Bind Arguments, Mode=OneWay}" />
</StackPanel>
</Grid>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Grid>
</Page>
@@ -0,0 +1,24 @@
using FluentTerminal.App.ViewModels.Settings;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace FluentTerminal.App.Views.SettingsPages
{
public sealed partial class ShellProfileSettings : Page
{
public ProfilesPageViewModel ViewModel { get; private set; }
public ShellProfileSettings()
{
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is ProfilesPageViewModel viewModel)
{
ViewModel = viewModel;
}
}
}
}
@@ -1,52 +0,0 @@
<Page
x:Class="FluentTerminal.App.Views.SettingsPages.ShellSettings"
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"
NavigationCacheMode="Required"
mc:Ignorable="d">
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Margin="0,0,0,8" Text="Shell 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}" />
<StackPanel Margin="0,24,0,0" Orientation="Horizontal">
<TextBox
Width="400"
Header="Custom Shell Location"
IsEnabled="{x:Bind ViewModel.CustomShellIsSelected, Mode=OneWay}"
Text="{x:Bind ViewModel.CustomShellLocation, Mode=TwoWay}" />
<Button
Margin="6,0,0,0"
VerticalAlignment="Bottom"
Command="{x:Bind ViewModel.BrowseForCustomShellCommand}"
Content="..."
IsEnabled="{x:Bind ViewModel.CustomShellIsSelected, Mode=OneWay}"
Style="{StaticResource ButtonRevealStyle}" />
</StackPanel>
<StackPanel Margin="0,24,0,0" Orientation="Horizontal">
<TextBox
Width="400"
Header="Working Directory"
Text="{x:Bind ViewModel.WorkingDirectory, Mode=TwoWay}" />
<Button
Margin="6,0,0,0"
VerticalAlignment="Bottom"
Command="{x:Bind ViewModel.BrowseForWorkingDirectoryCommand}"
Content="..."
Style="{StaticResource ButtonRevealStyle}" />
</StackPanel>
<TextBox
Width="400"
Margin="0,24,0,0"
HorizontalAlignment="Left"
Header="Arguments"
Text="{x:Bind ViewModel.Arguments, Mode=TwoWay}" />
</StackPanel>
</Page>
@@ -0,0 +1,60 @@
<Page
x:Class="FluentTerminal.App.Views.SettingsPages.TerminalSettings"
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"
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,00,0,24">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock
Margin="0,10,0,0"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
Text="Terminal" />
<CommandBar
Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
DefaultLabelPosition="Right">
<AppBarButton
Command="{x:Bind ViewModel.RestoreDefaultsCommand}"
Icon="Undo"
Label="Restore Defaults" />
</CommandBar>
</Grid>
<StackPanel Grid.Row="2" Margin="24,0,0,0">
<ComboBox
Width="200"
Margin="0,0,0,24"
Header="Font Family"
ItemsSource="{x:Bind ViewModel.Fonts}"
SelectedValue="{x:Bind ViewModel.FontFamily, Mode=TwoWay}" />
<ComboBox
Width="200"
Margin="0,0,0,24"
Header="Font Size"
ItemsSource="{x:Bind ViewModel.Sizes}"
SelectedValue="{x:Bind ViewModel.FontSize, Mode=TwoWay}" />
<ToggleSwitch
Margin="0,0,0,24"
Header="Blinking Cursor"
IsOn="{x:Bind ViewModel.CursorBlink, Mode=TwoWay}" />
<TextBlock Margin="0,0,0,8" Text="Cursor Style" />
<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,21 +1,21 @@
using FluentTerminal.App.ViewModels;
using FluentTerminal.App.ViewModels.Settings;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace FluentTerminal.App.Views.SettingsPages
{
public sealed partial class ShellSettings : Page
public sealed partial class TerminalSettings : Page
{
public SettingsViewModel ViewModel { get; private set; }
public ShellSettings()
public TerminalSettings()
{
InitializeComponent();
}
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;
}
@@ -0,0 +1,299 @@
<Page
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: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"
mc:Ignorable="d">
<Grid x:Name="Root">
<Grid.Background>
<AcrylicBrush
BackgroundSource="HostBackdrop"
FallbackColor="{x:Bind ViewModel.SelectedTheme.Background, Mode=OneWay}"
TintColor="{x:Bind ViewModel.SelectedTheme.Background, Mode=OneWay}"
TintOpacity="{x:Bind ViewModel.SelectedTheme.BackgroundOpacity, Mode=OneWay}" />
</Grid.Background>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="32" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<views:BindableColorsTitleBar x:Name="TitleBar" TitleBarForeground="White" />
<Border
Grid.RowSpan="3"
Grid.Column="0"
Background="{ThemeResource SystemControlAcrylicWindowBrush}" />
<Grid
Grid.Row="1"
Grid.ColumnSpan="2"
Margin="0,0,0,24">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Margin="24,10,0,0"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
Text="Themes" />
<CommandBar
Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="Transparent"
DefaultLabelPosition="Right"
Visibility="{x:Bind ViewModel.SelectedTheme.InEditMode, Mode=OneWay, Converter={StaticResource FalseToVisibleConverter}}">
<AppBarButton
Command="{x:Bind ViewModel.SelectedTheme.SetActiveCommand, Mode=OneWay}"
Foreground="White"
Icon="Accept"
IsEnabled="{x:Bind ViewModel.SelectedTheme.IsActive, Mode=OneWay, Converter={StaticResource NegateConverter}}"
Label="Set Active"
Style="{StaticResource ThemeAppBarButtonStyle}" />
<AppBarButton
Command="{x:Bind ViewModel.SelectedTheme.EditCommand, Mode=OneWay}"
Foreground="White"
Icon="Edit"
Label="Edit"
Style="{StaticResource ThemeAppBarButtonStyle}" />
<AppBarButton
Command="{x:Bind ViewModel.SelectedTheme.DeleteCommand, Mode=OneWay}"
Foreground="White"
Icon="Delete"
Label="Delete"
Style="{StaticResource ThemeAppBarButtonStyle}" />
</CommandBar>
<CommandBar
Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="Transparent"
DefaultLabelPosition="Right"
Visibility="{x:Bind ViewModel.SelectedTheme.InEditMode, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<AppBarButton
Command="{x:Bind ViewModel.SelectedTheme.SaveChangesCommand, Mode=OneWay}"
Foreground="White"
Icon="Save"
Label="Save"
Style="{StaticResource ThemeAppBarButtonStyle}" />
<AppBarButton
Command="{x:Bind ViewModel.SelectedTheme.CancelEditCommand, Mode=OneWay}"
Foreground="White"
Icon="Cancel"
Label="Cancel"
Style="{StaticResource ThemeAppBarButtonStyle}" />
</CommandBar>
</Grid>
<StackPanel Grid.Row="2" Grid.Column="0">
<ListView ItemsSource="{x:Bind ViewModel.Themes}" SelectedItem="{x:Bind ViewModel.SelectedTheme, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="viewmodels:ThemeViewModel">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{x:Bind Name, Mode=OneWay}" />
<Viewbox
Grid.Column="1"
Width="16"
Height="16"
HorizontalAlignment="Right">
<SymbolIcon Symbol="Accept" Visibility="{x:Bind IsActive, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}" />
</Viewbox>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
<Button
Height="48"
Margin="0,12,0,0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left"
Background="Transparent"
Command="{x:Bind ViewModel.CreateThemeCommand}"
Style="{StaticResource ButtonRevealStyle}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<Viewbox
Width="12"
Height="12"
Margin="0,0,6,0">
<SymbolIcon Symbol="Add" />
</Viewbox>
<TextBlock Text="Create new" Style="{StaticResource CaptionTextBlockStyle}" />
</StackPanel>
</Button.Content>
</Button>
</StackPanel>
<ContentControl
Grid.Row="2"
Grid.Column="1"
Margin="24,0,0,0"
Content="{x:Bind ViewModel.SelectedTheme, Mode=TwoWay}">
<ContentControl.ContentTemplate>
<DataTemplate x:DataType="viewmodels:ThemeViewModel">
<StackPanel>
<TextBlock
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{x:Bind Name, Mode=OneWay}"
Visibility="{x:Bind InEditMode, Mode=OneWay, Converter={StaticResource FalseToVisibleConverter}}">
<TextBlock.Foreground>
<SolidColorBrush Color="{x:Bind Foreground, Mode=OneWay}" />
</TextBlock.Foreground>
</TextBlock>
<TextBlock
Foreground="White"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Author, Mode=OneWay}" />
<TextBox
Header="Name"
RequestedTheme="Dark"
Text="{x:Bind Name, Mode=TwoWay}"
Visibility="{x:Bind InEditMode, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}" />
<TextBox
Margin="0,24,0,0"
Header="Author"
RequestedTheme="Dark"
Text="{x:Bind Author, Mode=TwoWay}"
Visibility="{x:Bind InEditMode, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}" />
<Grid Margin="0,48,0,0">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="Border">
<Setter Property="Margin" Value="0,0,0,0" />
<Setter Property="Width" Value="24" />
<Setter Property="Height" Value="24" />
</Style>
</Grid.Resources>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<views:TerminalColorPicker
ColorName="Black"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Black, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Red"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Red, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Green"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Green, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Yellow"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Yellow, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Blue"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Blue, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Magenta"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Magenta, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Cyan"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Cyan, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="White"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind White, Mode=TwoWay}" />
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<views:TerminalColorPicker
ColorName="Bright Black"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightBlack, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Bright Red"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightRed, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Bright Green"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightGreen, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Bright Yellow"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightYellow, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Bright Blue"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightBlue, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Bright Magenta"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightMagenta, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Bright Cyan"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightCyan, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Bright White"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightWhite, Mode=TwoWay}" />
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<views:TerminalColorPicker
ColorName="Foreground"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Foreground, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Background"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Background, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Cursor"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Cursor, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Cursor Accent"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind CursorAccent, Mode=TwoWay}" />
<views:TerminalColorPicker
ColorName="Selection"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
IsAlphaEnabled="True"
SelectedColor="{x:Bind Selection, Mode=TwoWay}" />
</StackPanel>
<TextBlock
Grid.Row="3"
Margin="0,6,0,0"
Foreground="White"
Text="Click on a color to edit"
Visibility="{x:Bind InEditMode, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}" />
</Grid>
<Slider
Margin="0,24,0,0"
Header="Background Opacity"
Maximum="1"
Minimum="0"
RequestedTheme="Dark"
StepFrequency="0.01"
Visibility="{x:Bind InEditMode, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}"
Value="{x:Bind BackgroundOpacity, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Grid>
</Page>
@@ -0,0 +1,31 @@
using FluentTerminal.App.ViewModels.Settings;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace FluentTerminal.App.Views.SettingsPages
{
public sealed partial class ThemeSettings : Page
{
public ThemesPageViewModel ViewModel { get; private set; }
public ThemeSettings()
{
InitializeComponent();
Root.DataContext = this;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is ThemesPageViewModel viewModel)
{
ViewModel = viewModel;
}
TitleBar.RestoreColors();
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
TitleBar.ResetTitleBar();
}
}
}
@@ -0,0 +1,34 @@
<UserControl
x:Class="FluentTerminal.App.Views.TerminalColorPicker"
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="24"
d:DesignWidth="24"
mc:Ignorable="d">
<Button
x:Name="Root"
IsEnabled="{x:Bind EnableEditing, Mode=OneWay}"
Style="{StaticResource ColorPreviewButtonStyle}"
ToolTipService.ToolTip="{x:Bind ColorName}">
<Button.Background>
<SolidColorBrush Color="{x:Bind SelectedColor, Mode=OneWay}" />
</Button.Background>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock
Margin="0,0,0,6"
Style="{StaticResource TitleTextBlockStyle}"
Text="{x:Bind ColorName}" />
<ColorPicker
x:Name="colorPicker"
ColorChanged="ColorPicker_ColorChanged"
IsAlphaEnabled="{x:Bind IsAlphaEnabled, Mode=OneWay}"
IsColorChannelTextInputVisible="False" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</UserControl>
@@ -0,0 +1,62 @@
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace FluentTerminal.App.Views
{
public sealed partial class TerminalColorPicker : UserControl
{
public static readonly DependencyProperty ColorNameProperty =
DependencyProperty.Register(nameof(ColorName), typeof(string), typeof(TerminalColorPicker), new PropertyMetadata(null));
public static readonly DependencyProperty EnableEditingProperty =
DependencyProperty.Register(nameof(EnableEditing), typeof(bool), typeof(TerminalColorPicker), new PropertyMetadata(false));
public static readonly DependencyProperty IsAlphaEnabledProperty =
DependencyProperty.Register(nameof(IsAlphaEnabled), typeof(bool), typeof(TerminalColorPicker), new PropertyMetadata(false));
public static readonly DependencyProperty SelectedColorProperty =
DependencyProperty.Register(nameof(SelectedColor), typeof(Color), typeof(TerminalColorPicker), new PropertyMetadata(Colors.Transparent, (s, e) =>
{
if (s is TerminalColorPicker terminalColorPicker)
{
terminalColorPicker.colorPicker.Color = (Color)e.NewValue;
}
}));
public TerminalColorPicker()
{
InitializeComponent();
Root.DataContext = this;
}
public string ColorName
{
get { return (string)GetValue(ColorNameProperty); }
set { SetValue(ColorNameProperty, value); }
}
public bool EnableEditing
{
get { return (bool)GetValue(EnableEditingProperty); }
set { SetValue(EnableEditingProperty, value); }
}
public bool IsAlphaEnabled
{
get { return (bool)GetValue(IsAlphaEnabledProperty); }
set { SetValue(IsAlphaEnabledProperty, value); }
}
public Color SelectedColor
{
get { return (Color)GetValue(SelectedColorProperty); }
set { SetValue(SelectedColorProperty, value); }
}
private void ColorPicker_ColorChanged(ColorPicker sender, ColorChangedEventArgs args)
{
SelectedColor = args.NewColor;
}
}
}
+57 -8
View File
@@ -2,26 +2,75 @@
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"
d:DesignWidth="600"
mc:Ignorable="d">
<UserControl.Resources>
<converters:TrueToVisibleConverter x:Key="TrueToVisibleConverter" />
</UserControl.Resources>
<Grid>
<Grid x:Name="WebViewContainer" Margin="12" />
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid
x:Name="WebViewContainer"
Grid.Row="0"
Margin="12" />
<Grid
Grid.Row="0"
Margin="12"
Padding="6"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Background="{ThemeResource SystemControlAccentAcrylicWindowAccentMediumHighBrush}"
Visibility="{x:Bind ViewModel.ShowResizeOverlay, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<Grid.Background>
<SolidColorBrush Color="{ThemeResource SystemAccentColor}" />
</Grid.Background>
<TextBlock Foreground="White" Text="{x:Bind ViewModel.ResizeOverlayContent, Mode=OneWay}" />
</Grid>
<RelativePanel
Grid.Row="1"
Padding="12"
Visibility="{x:Bind ViewModel.ShowSearchPanel, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<TextBlock
Name="SearchLabel"
Margin="0,6,0,0"
RelativePanel.AlignLeftWithPanel="True"
Text="Search" />
<TextBox
Name="SearchTextBox"
Width="300"
Margin="6,0,6,0"
KeyUp="SearchTextBox_KeyUp"
PlaceholderText="Enter search term"
RelativePanel.RightOf="SearchLabel"
Text="{x:Bind ViewModel.SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Button
Name="PreviousButton"
Margin="0,0,6,0"
Command="{x:Bind ViewModel.FindPreviousCommand}"
RelativePanel.RightOf="SearchTextBox"
ToolTipService.ToolTip="Find previous">
<Button.Content>
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE76B;" />
</Button.Content>
</Button>
<Button
Command="{x:Bind ViewModel.FindNextCommand}"
RelativePanel.RightOf="PreviousButton"
ToolTipService.ToolTip="Find next">
<Button.Content>
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE76C;" />
</Button.Content>
</Button>
<Button
Command="{x:Bind ViewModel.CloseSearchPanelCommand}"
RelativePanel.AlignRightWithPanel="True"
ToolTipService.ToolTip="Close search panel">
<Button.Content>
<SymbolIcon Symbol="Cancel" />
</Button.Content>
</Button>
</RelativePanel>
</Grid>
</UserControl>
+189 -64
View File
@@ -1,17 +1,24 @@
using FluentTerminal.App.ViewModels;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using FluentTerminal.RuntimeComponent.Interfaces;
using FluentTerminal.RuntimeComponent.WebAllowedObjects;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.Foundation;
using Windows.System;
using Windows.UI;
using Windows.UI.Core;
using Windows.UI.Core.Preview;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
@@ -19,43 +26,77 @@ namespace FluentTerminal.App.Views
{
public sealed partial class TerminalView : UserControl, ITerminalView, ITerminalEventListener
{
private WebView _webView;
private SemaphoreSlim _loaded;
private MenuFlyoutItem _copyMenuItem;
private BlockingCollection<Action> _dispatcherJobs;
public event EventHandler<TerminalSize> TerminalSizeChanged;
public event EventHandler<string> TerminalTitleChanged;
public TerminalViewModel ViewModel { get; }
private readonly SemaphoreSlim _loaded;
private MenuFlyoutItem _pasteMenuItem;
private WebView _webView;
public TerminalView(TerminalViewModel viewModel)
{
ViewModel = viewModel;
InitializeComponent();
Loaded += OnLoaded;
SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += OnCloseRequested; //todo move to mainpage
_loaded = new SemaphoreSlim(0, 1);
JsonConvert.DefaultSettings = () =>
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
};
settings.Converters.Add(new StringEnumConverter(true));
return settings;
};
StartMediatorTask();
}
public async Task FocusWebView()
public event EventHandler<Command> KeyboardCommandReceived;
public event EventHandler<TerminalSize> TerminalSizeChanged;
public event EventHandler<string> TerminalTitleChanged;
public TerminalViewModel ViewModel { get; }
public Task ChangeOptions(TerminalOptions options)
{
if (_webView != null)
{
_webView.Focus(FocusState.Programmatic);
await ExecuteScriptAsync("document.focus();");
}
var serialized = JsonConvert.SerializeObject(options);
return ExecuteScriptAsync($"changeOptions('{serialized}')");
}
private void OnCloseRequested(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
public Task ChangeTheme(TerminalColors theme)
{
_webView.Navigate(new Uri("about:blank"));
var serialized = JsonConvert.SerializeObject(theme);
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"));
_webView = null;
}
public Task ConnectToSocket(string url)
{
return ExecuteScriptAsync($"connectToWebSocket('{url}');");
}
public async Task<TerminalSize> CreateTerminal(TerminalOptions options, TerminalColors theme, IEnumerable<KeyBinding> keyBindings)
{
var serializedOptions = JsonConvert.SerializeObject(options);
var serializedTheme = JsonConvert.SerializeObject(theme);
var serializedKeyBindings = JsonConvert.SerializeObject(keyBindings);
var size = await ExecuteScriptAsync($"createTerminal('{serializedOptions}', '{serializedTheme}', '{serializedKeyBindings}')").ConfigureAwait(true);
return JsonConvert.DeserializeObject<TerminalSize>(size);
}
public Task<string> ExecuteScriptAsync(string script)
{
try
@@ -69,6 +110,124 @@ namespace FluentTerminal.App.Views
return Task.FromResult(string.Empty);
}
public async Task FocusTerminal()
{
if (_webView != null)
{
_webView.Focus(FocusState.Programmatic);
await ExecuteScriptAsync("document.focus();").ConfigureAwait(true);
}
}
public async Task FocusWebView()
{
if (_webView != null)
{
_webView.Focus(FocusState.Programmatic);
await ExecuteScriptAsync("document.focus();").ConfigureAwait(true);
}
}
public Task<string> GetSelection() => ExecuteScriptAsync("term.getSelection()");
public void OnKeyboardCommand(string command)
{
_dispatcherJobs.Add(() => KeyboardCommandReceived?.Invoke(this, Enum.Parse<Command>(command, true)));
}
public void OnTerminalResized(int columns, int rows)
{
_dispatcherJobs.Add(() => TerminalSizeChanged?.Invoke(this, new TerminalSize { Columns = columns, Rows = rows }));
}
public void OnTitleChanged(string title)
{
_dispatcherJobs.Add(() => TerminalTitleChanged?.Invoke(this, title));
}
public Task Write(string text)
{
text = Convert.ToBase64String(Encoding.UTF8.GetBytes(text));
return ExecuteScriptAsync($"paste('{text}')");
}
public Task FindNext(string searchText)
{
return ExecuteScriptAsync($"findNext('{searchText}')");
}
public Task FindPrevious(string searchText)
{
return ExecuteScriptAsync($"findPrevious('{searchText}')");
}
private void _webView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
_loaded.Release();
}
private void _webView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
{
var bridge = new TerminalBridge(this);
_webView.AddWebAllowedObject("terminalBridge", bridge);
}
private void Copy_Click(object sender, RoutedEventArgs e)
{
OnKeyboardCommand(nameof(Command.Copy));
}
private async void OnLoaded(object sender, RoutedEventArgs e)
{
if (WebViewContainer.Children.Any())
{
return;
}
_webView = new WebView(WebViewExecutionMode.SeparateThread)
{
DefaultBackgroundColor = Colors.Transparent
};
WebViewContainer.Children.Add(_webView);
_webView.NavigationCompleted += _webView_NavigationCompleted;
_webView.NavigationStarting += _webView_NavigationStarting;
_copyMenuItem = new MenuFlyoutItem { Text = "Copy" };
_copyMenuItem.Click += Copy_Click;
_pasteMenuItem = new MenuFlyoutItem { Text = "Paste" };
_pasteMenuItem.Click += Paste_Click;
_webView.ContextFlyout = new MenuFlyout
{
Items = { _copyMenuItem, _pasteMenuItem }
};
_webView.Navigate(new Uri("ms-appx-web:///Client/index.html"));
await _loaded.WaitAsync().ConfigureAwait(true);
_webView.Focus(FocusState.Programmatic);
await ViewModel.OnViewIsReady(this).ConfigureAwait(true);
}
public void OnRightClick(int x, int y, bool hasSelection)
{
_dispatcherJobs.Add(() =>
{
var flyout = (MenuFlyout)_webView.ContextFlyout;
_copyMenuItem.IsEnabled = hasSelection;
flyout.ShowAt(_webView, new Point(x, y));
});
}
private void Paste_Click(object sender, RoutedEventArgs e)
{
OnKeyboardCommand(nameof(Command.Paste));
}
private void StartMediatorTask()
{
_dispatcherJobs = new BlockingCollection<Action>();
@@ -89,55 +248,21 @@ namespace FluentTerminal.App.Views
});
}
private async void OnLoaded(object sender, RoutedEventArgs e)
private void SearchTextBox_KeyUp(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
{
_webView = new WebView(WebViewExecutionMode.SeparateThread)
if (e.Key == VirtualKey.Escape)
{
DefaultBackgroundColor = Colors.Transparent
};
WebViewContainer.Children.Add(_webView);
_webView.NavigationCompleted += _webView_NavigationCompleted;
_webView.NavigationStarting += _webView_NavigationStarting;
_webView.Navigate(new Uri("http://localhost:9000/Client/index.html"));
await _loaded.WaitAsync();
_webView.Focus(FocusState.Programmatic);
await ViewModel.OnViewIsReady(this);
ViewModel.CloseSearchPanelCommand.Execute(null);
}
else if (e.Key == VirtualKey.Enter)
{
ViewModel.FindNextCommand.Execute(null);
}
}
private void _webView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
public void FocusSearchTextBox()
{
_loaded.Release();
}
private void _webView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
{
var bridge = new TerminalBridge(this);
_webView.AddWebAllowedObject("terminalBridge", bridge);
}
public async Task<TerminalSize> CreateTerminal()
{
var size = await ExecuteScriptAsync($"createTerminal()");
return JsonConvert.DeserializeObject<TerminalSize>(size);
}
public Task ConnectToSocket(string url)
{
return ExecuteScriptAsync($"connectToWebSocket('{url}');");
}
public void OnTerminalResized(int columns, int rows)
{
_dispatcherJobs.Add(() => TerminalSizeChanged?.Invoke(this, new TerminalSize { Columns = columns, Rows = rows }));
}
public void OnTitleChanged(string title)
{
_dispatcherJobs.Add(() => TerminalTitleChanged?.Invoke(this, title));
SearchTextBox.Focus(FocusState.Programmatic);
}
}
}
}
+1
View File
@@ -1 +1,2 @@
node_modules/
dist/
File diff suppressed because it is too large. Load diff
-12
View File
@@ -1,12 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="xterm.css" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="terminal-container"></div>
<script src="bundle.js"></script>
</body>
</html>
-125
View File
@@ -1,125 +0,0 @@
/**
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
* https://github.com/chjj/term.js
* @license MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Originally forked from (with the author's permission):
* Fabrice Bellard's javascript vt100 for jslinux:
* http://bellard.org/jslinux/
* Copyright (c) 2011 Fabrice Bellard
* The original design remains. The terminal itself
* has been extended to include xterm CSI codes, among
* other features.
*/
/**
* Default styles for xterm.js
*/
.xterm {
font-family: courier-new, courier, monospace;
font-feature-settings: "liga" 0;
position: relative;
user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
}
.xterm.focus,
.xterm:focus {
outline: none;
}
.xterm .xterm-helpers {
position: absolute;
top: 0;
/**
* The z-index of the helpers must be higher than the canvases in order for
* IMEs to appear on top.
*/
z-index: 10;
}
.xterm .xterm-helper-textarea {
/*
* HACK: to fix IE's blinking cursor
* Move textarea out of the screen to the far left, so that the cursor is not visible.
*/
position: absolute;
opacity: 0;
left: -9999em;
top: 0;
width: 0;
height: 0;
z-index: -10;
/** Prevent wrapping so the IME appears against the textarea at the correct position */
white-space: nowrap;
overflow: hidden;
resize: none;
}
.xterm .composition-view {
/* TODO: Composition position got messed up somewhere */
background: #000;
color: #FFF;
display: none;
position: absolute;
white-space: nowrap;
z-index: 1;
}
.xterm .composition-view.active {
display: block;
}
.xterm .xterm-viewport {
/* On OS X this is required in order for the scroll bar to appear fully opaque */
background-color: #000;
overflow-y: scroll;
cursor: default;
}
.xterm canvas {
position: absolute;
left: 0;
top: 0;
}
.xterm .xterm-scroll-area {
visibility: hidden;
}
.xterm .xterm-char-measure-element {
display: inline-block;
visibility: hidden;
position: absolute;
left: -9999em;
}
.xterm.enable-mouse-events {
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
cursor: default;
}
.xterm:not(.enable-mouse-events) {
cursor: text;
}
+5 -6
View File
@@ -2472,12 +2472,6 @@
"safe-buffer": "5.1.1"
}
},
"raw-loader": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz",
"integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao=",
"dev": true
},
"read-pkg": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
@@ -3018,6 +3012,11 @@
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
"dev": true
},
"xterm": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/xterm/-/xterm-3.4.0.tgz",
"integrity": "sha512-eHH9CuKZOdKscBoUPmBxE1nTAuaKCMavcTQilyQf2u6MqB366BJP7SbkGWz+HZj7V5OjldFLLDLzlliqUzoiHQ=="
},
"y18n": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+4 -2
View File
@@ -5,12 +5,14 @@
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "xcopy /y /s ..\\xterm.js\\build\\xterm.css dist\\ && npx webpack --config webpack.config.js"
"build": "xcopy /y /s node_modules\\xterm\\dist\\xterm.css dist\\ && xcopy /y /s src\\style.css dist\\ && xcopy /y /s src\\index.html dist\\ && npx webpack --config webpack.config.js"
},
"author": "FS Apps",
"license": "GPL-3.0",
"dependencies": {},
"devDependencies": {
"webpack": "^3.10.0"
},
"dependencies": {
"xterm": "^3.4.0"
}
}
+15
View File
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="xterm.css" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="terminal-container"></div>
<script src="bundle.js"></script>
</body>
</html>
+110 -19
View File
@@ -1,29 +1,42 @@
import * as Terminal from '../../xterm.js/build/xterm';
import * as attach from '../../xterm.js/build/addons/attach/attach';
import * as fit from '../../xterm.js/build/addons/fit/fit';
import * as winptyCompat from '../../xterm.js/build/addons/winptyCompat/winptyCompat';
import * as Terminal from '../node_modules/xterm/dist/xterm';
import * as attach from '../node_modules/xterm/dist/addons/attach/attach';
import * as fit from '../node_modules/xterm/dist/addons/fit/fit';
import * as winptyCompat from '../node_modules/xterm/dist/addons/winptyCompat/winptyCompat';
import * as search from '../node_modules/xterm/dist/addons/search/search';
Terminal.applyAddon(attach);
Terminal.applyAddon(fit);
Terminal.applyAddon(winptyCompat);
Terminal.applyAddon(search);
var term, socket;
var terminalContainer = document.getElementById('terminal-container');
function start() {
function createTerminal(options, theme, keyBindings) {
while (terminalContainer.children.length) {
terminalContainer.removeChild(terminalContainer.children[0]);
}
term = new Terminal({
cursorBlink: true,
fontFamily: 'consolas',
fontSize: 13,
theme = JSON.parse(theme);
theme.background = 'transparent';
window.keyBindings = JSON.parse(keyBindings);
options = JSON.parse(options);
var terminalOptions = {
fontFamily: options.fontFamily,
fontSize: options.fontSize,
cursorStyle: options.cursorStyle,
cursorBlink: options.cursorBlink,
bellStyle: options.bellStyle,
allowTransparency: true,
theme: {
background: "transparent"
}
});
theme: theme,
experimentalCharAtlas: 'dynamic'
};
term = new Terminal(terminalOptions);
window.term = term;
@@ -46,25 +59,103 @@ function start() {
resizeTimeout = setTimeout(term.fit(), 500);
}
window.onmouseup = function (e) {
if (e.button == 2) {
terminalBridge.notifyRightClick(e.clientX, e.clientY, term.hasSelection());
}
}
term.attachCustomKeyEventHandler(function (e) {
for (var i = 0; i < window.keyBindings.length; i++) {
var keyBinding = window.keyBindings[i];
if (keyBinding.ctrl == e.ctrlKey
&& keyBinding.meta == e.metaKey
&& keyBinding.alt == e.altKey
&& keyBinding.shift == e.shiftKey
&& keyBinding.key == e.keyCode) {
if (document.visibilityState == 'visible') {
if (keyBinding.command == 'copy' && term.getSelection() == '') {
return true;
}
e.preventDefault();
terminalBridge.invokeCommand(keyBinding.command);
}
return false;
}
}
return true;
});
return JSON.stringify({
rows: term.rows,
columns: term.cols
});
}
function runRealTerminal() {
function attachTerminal() {
term.attach(socket);
term._initialized = true;
}
function createTerminal(configuration) {
return start();
}
function connectToWebSocket(url) {
socket = new WebSocket(url);
socket.onopen = runRealTerminal;
socket.onopen = attachTerminal;
socket.onclose = function() {
terminalBridge.invokeCommand('CloseTab');
};
}
function changeTheme(theme) {
theme = JSON.parse(theme);
theme.background = 'transparent';
term.setOption('theme', theme);
}
function changeOptions(options) {
options = JSON.parse(options);
term.setOption('bellStyle', options.bellStyle);
term.setOption('cursorBlink', options.cursorBlink);
term.setOption('cursorStyle', options.cursorStyle);
term.setOption('fontFamily', options.fontFamily);
term.setOption('fontSize', options.fontSize);
}
function changeKeyBindings(keyBindings) {
keyBindings = JSON.parse(keyBindings);
window.keyBindings = keyBindings;
}
function paste(content) {
content = b64DecodeUnicode(content);
term.send(content);
}
function b64DecodeUnicode(str) {
return decodeURIComponent(Array.prototype.map.call(atob(str), function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
}).join(''))
}
function findNext(content) {
term.findNext(content);
}
function findPrevious(content) {
term.findPrevious(content);
}
document.oncontextmenu = function () {
return false;
};
window.createTerminal = createTerminal;
window.connectToWebSocket = connectToWebSocket;
window.changeTheme = changeTheme;
window.changeOptions = changeOptions;
window.changeKeyBindings = changeKeyBindings;
window.paste = paste;
window.findNext = findNext;
window.findPrevious = findPrevious;
@@ -21,4 +21,4 @@ body {
.terminal {
background: transparent !important;
}
}
@@ -0,0 +1,11 @@
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; }
}
}
+8
View File
@@ -0,0 +1,8 @@
namespace FluentTerminal.Models.Enums
{
public enum BellStyle
{
None,
Sound
}
}
+17
View File
@@ -0,0 +1,17 @@
namespace FluentTerminal.Models.Enums
{
public enum Command
{
ToggleWindow,
NextTab,
PreviousTab,
NewTab,
ConfigurableNewTab,
CloseTab,
NewWindow,
ShowSettings,
Copy,
Paste,
Search
}
}
Loaded 100 of 413 files, more files were not shown because too many files have changed in this diff. Show more