Compare commits

...
34 Commits
Author SHA1 Message Date
FelixSe 76cb528eb4 moved webSocket to App, tried to use NamedPipe between SystemTray and App, but cannot connect 2018-06-24 13:13:16 +02:00
cxfksword def3aa3683 Fix toggle window exception (#49) 2018-06-21 22:27:12 +02:00
FelixSe 77d9a42c36 Adapted KeyBoardCommandServiceTests to not use ToggleWindow command 2018-06-21 22:04:08 +02:00
cxfksword d395085064 Add support grave accent as hotkey (#48) 2018-06-21 21:29:48 +02:00
Felix 56e5d60dae Update README.md 2018-06-17 15:53:37 +02:00
FelixSe 780cbf64b1 Added AppVeyor CI 2018-06-17 15:52:31 +02:00
FelixSe 6b25d78ce6 Remove unused nuget package 2018-06-17 14:49:22 +02:00
FelixSe 53726e0e68 Moved ViewModels into a separate asembly 2018-06-17 14:34:20 +02:00
FelixSe 5e11e5d58b Move existing tests to xUnit test project 2018-06-16 23:33:11 +02:00
FelixSe 3e0417ce47 Move services to a separate assembly 2018-06-16 22:50:27 +02:00
Felix 417bc843b0 Added missing '#' in ubuntu theme 2018-06-16 10:00:54 +02:00
Felix 6d6bdcca3e Merge pull request #41 from Linard11/master
Add WSL as default profile & terminal colors used in Ubuntu Bash
2018-06-15 11:17:46 +02:00
Linard Hug b4bfe39586 Fix typo and cursor selection color 2018-06-15 10:35:16 +02:00
Linard Hug 940cb6f38b Add 'Ubuntu Bash' as default theme 2018-06-15 02:23:29 +02:00
Linard Hug 59c6a39458 Add WSL as default profile 2018-06-15 02:23:04 +02:00
FelixSe 05ce19ec8c Increase version number 2018-06-12 22:59:05 +02:00
FelixSe 7b2bd59365 Improve clear and selectAll behaviour 2018-06-12 22:39:44 +02:00
FelixSe 6a67883777 Revert updating Win2D.uwp 2018-06-12 22:22:23 +02:00
FelixSe 847e1c045a Added option to set scrollback limit, comands to select all and clear buffer, cleaned up keyBindings UI code 2018-06-11 23:11:38 +02:00
FelixSe e918c5492e Update dependencies 2018-06-11 22:04:03 +02:00
FelixSe 1aba3d4926 Fixed text margin in tabs and added option to underline the selected tab 2018-06-10 20:54:51 +02:00
FelixSe 5ad51b6bf7 Added 'Tomorrow' as default theme to showcase light themes 2018-06-10 20:27:28 +02:00
FelixSe 72cfe1168f Export themes 2018-06-10 20:17:46 +02:00
FelixSe 5a96a0387b Set application theme based on the terminal's background color 2018-06-10 15:04:41 +02:00
FelixSe 00a5b6377d Fix selection color in imported themes 2018-06-10 12:14:25 +02:00
FelixSe f610aa8a0f Import iTerm themes 2018-06-09 19:34:32 +02:00
FelixSe c32342bca8 Remember window size and position 2018-06-08 21:42:12 +02:00
FelixSe 84af36f6bc Added fullscreen mode 2018-06-07 22:18:43 +02:00
FelixSe f56465f54a Improve storage of keyBindings 2018-06-07 21:57:45 +02:00
FelixSe 2527657261 Increase version number 2018-05-31 23:51:59 +02:00
FelixSe 5414987ab6 made background opacity global 2018-05-31 22:30:07 +02:00
FelixSe 327f0d5dd5 Improve titlebar color handling for settings window 2018-05-31 21:10:02 +02:00
FelixSe bd64aacbab Add option to set scrollbar style 2018-05-30 21:09:06 +02:00
FelixSe c79b513470 Fixed bug that tied name and arguments in profile editor together 2018-05-30 19:46:19 +02:00
125 changed files with 3013 additions and 2181 deletions

No files matched your search

@@ -3,56 +3,54 @@ using System.Linq;
using System.Threading.Tasks;
using AutoFixture;
using FluentAssertions;
using FluentTerminal.App.Services;
using FluentTerminal.App.Services.Dialogs;
using FluentTerminal.App.Services.Implementation;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Xunit;
namespace FluentTerminal.App.Test.Services
namespace FluentTerminal.App.Services.Test
{
[TestClass]
public class DialogServiceTests
{
private Fixture _fixture;
private readonly Fixture _fixture;
[TestInitialize]
public void TestInitialize()
public DialogServiceTests()
{
_fixture = new Fixture();
}
[TestMethod]
[Fact]
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>());
var dialogService = new DialogService(() => Mock.Of<IShellProfileSelectionDialog>(), () => Mock.Of<IMessageDialog>(), () => Mock.Of<ICreateKeyBindingDialog>());
Func<Task<DialogButton>> invoke = () => dialogService.ShowMessageDialogAsnyc(title, content, buttons.ElementAt(0), buttons.ElementAt(1));
invoke.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("title");
}
[TestMethod]
[Fact]
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>());
var dialogService = new DialogService(() => Mock.Of<IShellProfileSelectionDialog>(), () => Mock.Of<IMessageDialog>(), () => Mock.Of<ICreateKeyBindingDialog>());
Func<Task<DialogButton>> invoke = () => dialogService.ShowMessageDialogAsnyc(title, content, buttons.ElementAt(0), buttons.ElementAt(1));
invoke.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("content");
}
[TestMethod]
[Fact]
public void ShowDialogAsync_NoButtonsPassed_ThrowsArgumentException()
{
var title = _fixture.Create<string>();
var content = _fixture.Create<string>();
var dialogService = new DialogService(Mock.Of<ISettingsService>());
var dialogService = new DialogService(() => Mock.Of<IShellProfileSelectionDialog>(), () => Mock.Of<IMessageDialog>(), () => Mock.Of<ICreateKeyBindingDialog>());
Func<Task<DialogButton>> invoke = () => dialogService.ShowMessageDialogAsnyc(title, content);
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.4.0" />
<PackageReference Include="FluentAssertions" Version="5.4.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
<PackageReference Include="Moq" Version="4.8.3" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FluentTerminal.App.Services\FluentTerminal.App.Services.csproj" />
</ItemGroup>
</Project>
@@ -2,27 +2,25 @@
using FluentAssertions;
using FluentTerminal.App.Services.Implementation;
using FluentTerminal.Models.Enums;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using Xunit;
namespace FluentTerminal.App.Test.Services
namespace FluentTerminal.App.Services.Test
{
[TestClass]
public class KeyboardCommandServiceTests
{
private Fixture _fixture;
private readonly Fixture _fixture;
[TestInitialize]
public void TestInitialize()
public KeyboardCommandServiceTests()
{
_fixture = new Fixture();
}
[TestMethod]
[Fact]
public void RegisterCommandHandler_HandlerIsNull_ThrowsArgumentNullException()
{
var command = _fixture.Create<Command>();
var command = (Command)new Random().Next(1, Enum.GetValues(typeof(Command)).Length);
Action handler = null;
var keyboardCommandService = new KeyboardCommandService();
@@ -31,10 +29,10 @@ namespace FluentTerminal.App.Test.Services
invoke.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("handler");
}
[TestMethod]
[Fact]
public void RegisterCommandHandler_CommandAlreadyRegisted_ThrowsInvalidOperationException()
{
var command = _fixture.Create<Command>();
var command = (Command)new Random().Next(1, Enum.GetValues(typeof(Command)).Length);
var handler = _fixture.Create<Action>();
var keyboardCommandService = new KeyboardCommandService();
keyboardCommandService.RegisterCommandHandler(command, handler);
@@ -44,10 +42,10 @@ namespace FluentTerminal.App.Test.Services
invoke.Should().Throw<InvalidOperationException>();
}
[TestMethod]
[Fact]
public void SendCommand_CommandIsRegistered_HandlerGetsInvoked()
{
var command = _fixture.Create<Command>();
var command = (Command)new Random().Next(1, Enum.GetValues(typeof(Command)).Length);
var handlerCalled = false;
var keyboardCommandService = new KeyboardCommandService();
keyboardCommandService.RegisterCommandHandler(command, () => handlerCalled = true);
@@ -57,10 +55,10 @@ namespace FluentTerminal.App.Test.Services
handlerCalled.Should().BeTrue();
}
[TestMethod]
[Fact]
public void SendCommand_CommandIsNotRegisted_KeyNotFoundExceptionIsThrown()
{
var command = _fixture.Create<Command>();
var command = (Command)new Random().Next(1, Enum.GetValues(typeof(Command)).Length);
var keyboardCommandService = new KeyboardCommandService();
Action invoke = () => keyboardCommandService.SendCommand(command);
@@ -0,0 +1,11 @@
namespace FluentTerminal.App.Services
{
public class ApplicationDataContainers
{
public IApplicationDataContainer LocalSettings { get; set; }
public IApplicationDataContainer RoamingSettings { get; set; }
public IApplicationDataContainer Themes { get; set; }
public IApplicationDataContainer KeyBindings { get; set; }
public IApplicationDataContainer ShellProfiles { get; set; }
}
}
@@ -0,0 +1,10 @@
using FluentTerminal.Models;
using System.Threading.Tasks;
namespace FluentTerminal.App.Services.Dialogs
{
public interface ICreateKeyBindingDialog
{
Task<KeyBinding> CreateKeyBinding();
}
}
@@ -0,0 +1,14 @@
using System.Threading.Tasks;
namespace FluentTerminal.App.Services.Dialogs
{
public interface IMessageDialog
{
string Title { get; set; }
string Content { get; set; }
void AddButton(DialogButton button);
Task<DialogButton> ShowAsync();
}
}
@@ -0,0 +1,12 @@
using FluentTerminal.Models;
using System.Threading.Tasks;
namespace FluentTerminal.App.Services.Dialogs
{
public interface IShellProfileSelectionDialog
{
ShellProfile SelectedProfile { get; }
Task<ShellProfile> SelectProfile();
}
}
@@ -0,0 +1,7 @@
namespace FluentTerminal.App.Services.EventArgs
{
public class CancelableEventArgs : System.EventArgs
{
public bool Cancelled { get; set; }
}
}
@@ -0,0 +1,23 @@
using System;
namespace FluentTerminal.App.Services.Exceptions
{
public class ParseThemeException : Exception
{
public ParseThemeException() : base()
{
}
public ParseThemeException(string message) : base(message)
{
}
public ParseThemeException(string message, Exception innerException) : base(message, innerException)
{
}
protected ParseThemeException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context)
{
}
}
}
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<LangVersion>7.1</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<LangVersion>7.1</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="PListNet" Version="2.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FluentTerminal.Models\FluentTerminal.Models.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,10 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace FluentTerminal.App.Services
{
public interface IAppServiceConnection
{
Task<IDictionary<string, string>> SendMessageAsync(IDictionary<string, string> message);
}
}
@@ -0,0 +1,19 @@
using System.Collections.Generic;
namespace FluentTerminal.App.Services
{
public interface IApplicationDataContainer
{
T ReadValueFromJson<T>(string name, T fallbackValue);
void WriteValueAsJson<T>(string name, T value);
bool TryGetValue(string key, out object value);
void SetValue(string key, object value);
void Delete(string key);
IEnumerable<object> GetAll();
}
}
@@ -0,0 +1,19 @@
using FluentTerminal.App.Services.EventArgs;
using System;
using System.Threading.Tasks;
namespace FluentTerminal.App.Services
{
public delegate Task CloseRequestedHandler(object sender, CancelableEventArgs args);
public interface IApplicationView
{
event CloseRequestedHandler CloseRequested;
string Title { get; set; }
Task RunOnDispatcherThread(Action action);
Task<bool> TryClose();
bool ToggleFullScreen();
}
}
@@ -0,0 +1,10 @@
using System.Threading.Tasks;
namespace FluentTerminal.App.Services
{
public interface IClipboardService
{
Task<string> GetText();
void SetText(string text);
}
}
@@ -1,4 +1,5 @@
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using System;
using System.Collections.Generic;
@@ -9,7 +10,7 @@ namespace FluentTerminal.App.Services
IEnumerable<ShellProfile> GetPreinstalledShellProfiles();
Guid GetDefaultShellProfileId();
TerminalOptions GetDefaultTerminalOptions();
KeyBindings GetDefaultKeyBindings();
ICollection<KeyBinding> GetDefaultKeyBindings(Command command);
ApplicationSettings GetDefaultApplicationSettings();
Guid GetDefaultThemeId();
IEnumerable<TerminalTheme> GetPreInstalledThemes();
@@ -14,5 +14,7 @@ namespace FluentTerminal.App.Services
Task<DialogButton> ShowMessageDialogAsnyc(string title, string content, params DialogButton[] buttons);
Task<ShellProfile> ShowProfileSelectionDialogAsync();
Task<KeyBinding> ShowCreateKeyBindingDialog();
}
}
@@ -0,0 +1,15 @@
using System;
namespace FluentTerminal.App.Services
{
public interface IDispatcherTimer
{
void Start();
void Stop();
TimeSpan Interval { get; set; }
bool IsEnabled { get; }
event EventHandler<object> Tick;
}
}
@@ -0,0 +1,15 @@
using FluentTerminal.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace FluentTerminal.App.Services
{
public interface IFileSystemService
{
Task<File> OpenFile(IEnumerable<string> fileTypes);
Task<string> BrowseForDirectory();
Task SaveTextFile(string name, string fileTypeDescription, string fileType, string content);
}
}
@@ -1,4 +1,5 @@
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using System;
using System.Collections.Generic;
@@ -6,9 +7,9 @@ namespace FluentTerminal.App.Services
{
public interface ISettingsService
{
event EventHandler CurrentThemeChanged;
event EventHandler TerminalOptionsChanged;
event EventHandler ApplicationSettingsChanged;
event EventHandler<Guid> CurrentThemeChanged;
event EventHandler<TerminalOptions> TerminalOptionsChanged;
event EventHandler<ApplicationSettings> ApplicationSettingsChanged;
event EventHandler KeyBindingsChanged;
Guid GetDefaultShellProfileId();
@@ -25,8 +26,9 @@ namespace FluentTerminal.App.Services
ApplicationSettings GetApplicationSettings();
void SaveApplicationSettings(ApplicationSettings applicationSettings);
KeyBindings GetKeyBindings();
void SaveKeyBindings(KeyBindings keyBindings);
IDictionary<Command, ICollection<KeyBinding>> GetKeyBindings();
void SaveKeyBindings(Command command, ICollection<KeyBinding> keyBindings);
void ResetKeyBindings();
TerminalTheme GetCurrentTheme();
Guid GetCurrentThemeId();
@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace FluentTerminal.App.Services
{
public interface ISystemFontService
{
IEnumerable<string> GetSystemFontFamilies();
}
}
@@ -4,7 +4,7 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace FluentTerminal.App.Views
namespace FluentTerminal.App.Services
{
public interface ITerminalView
{
@@ -0,0 +1,14 @@
using FluentTerminal.Models;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace FluentTerminal.App.Services
{
public interface IThemeParser
{
IEnumerable<string> SupportedFileTypes { get; }
Task<TerminalTheme> Parse(string fileName, Stream fileContent);
}
}
@@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace FluentTerminal.App.Services
{
public interface IThemeParserFactory
{
IEnumerable<string> SupportedFileTypes { get; }
IThemeParser GetParser(string fileType);
}
}
@@ -1,13 +1,12 @@
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 Initialize(IAppServiceConnection appServiceConnection);
Task<CreateTerminalResponse> CreateTerminal(TerminalSize size, ShellProfile shellProfile);
Task ResizeTerminal(int id, TerminalSize size);
Task UpdateToggleWindowKeyBindings();
@@ -2,11 +2,10 @@
using FluentTerminal.Models.Enums;
using System;
using System.Collections.Generic;
using Windows.System;
namespace FluentTerminal.App.Services.Implementation
{
internal class DefaultValueProvider : IDefaultValueProvider
public class DefaultValueProvider : IDefaultValueProvider
{
public ApplicationSettings GetDefaultApplicationSettings()
{
@@ -14,114 +13,17 @@ namespace FluentTerminal.App.Services.Implementation
{
ConfirmClosingTabs = false,
ConfirmClosingWindows = false,
UnderlineSelectedTab = false,
NewTerminalLocation = NewTerminalLocation.Tab
};
}
public KeyBindings GetDefaultKeyBindings()
public ICollection<KeyBinding> GetDefaultKeyBindings(Command command)
{
return new KeyBindings
switch (command)
{
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>
case Command.ToggleWindow:
return new List<KeyBinding>
{
new KeyBinding
{
@@ -129,10 +31,129 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = false,
Alt = false,
Shift = false,
Key = (int)VirtualKey.Scroll
Key = (int)ExtendedVirtualKey.Scroll
}
},
Search = new List<KeyBinding>
};
case Command.NextTab:
return new List<KeyBinding>
{
new KeyBinding
{
Command = Command.NextTab,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)ExtendedVirtualKey.Tab
}
};
case Command.PreviousTab:
return new List<KeyBinding>
{
new KeyBinding
{
Command = Command.PreviousTab,
Ctrl = true,
Alt = false,
Shift = true,
Key = (int)ExtendedVirtualKey.Tab
}
};
case Command.NewTab:
return new List<KeyBinding>
{
new KeyBinding
{
Command = Command.NewTab,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)ExtendedVirtualKey.T
}
};
case Command.ConfigurableNewTab:
return new List<KeyBinding>
{
new KeyBinding
{
Command = Command.ConfigurableNewTab,
Ctrl = true,
Alt = false,
Shift = true,
Key = (int)ExtendedVirtualKey.T
}
};
case Command.CloseTab:
return new List<KeyBinding>
{
new KeyBinding
{
Command = Command.CloseTab,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)ExtendedVirtualKey.W
}
};
case Command.NewWindow:
return new List<KeyBinding>
{
new KeyBinding
{
Command = Command.NewWindow,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)ExtendedVirtualKey.N
}
};
case Command.ShowSettings:
return new List<KeyBinding>
{
new KeyBinding
{
Command = Command.ShowSettings,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)ExtendedVirtualKey.Comma
}
};
case Command.Copy:
return new List<KeyBinding>
{
new KeyBinding
{
Command = Command.Copy,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)ExtendedVirtualKey.C
}
};
case Command.Paste:
return new List<KeyBinding>
{
new KeyBinding
{
Command = Command.Paste,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)ExtendedVirtualKey.V
}
};
case Command.Search:
return new List<KeyBinding>
{
new KeyBinding
{
@@ -140,10 +161,51 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.F
Key = (int)ExtendedVirtualKey.F
}
}
};
};
case Command.ToggleFullScreen:
return new List<KeyBinding>
{
new KeyBinding
{
Command = Command.ToggleFullScreen,
Ctrl = false,
Alt = true,
Shift = false,
Key = (int)ExtendedVirtualKey.Enter
}
};
case Command.SelectAll:
return new List<KeyBinding>
{
new KeyBinding
{
Command = Command.SelectAll,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)ExtendedVirtualKey.A
}
};
case Command.Clear:
return new List<KeyBinding>
{
new KeyBinding
{
Command = Command.Clear,
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)ExtendedVirtualKey.L
}
};
}
return null;
}
public Guid GetDefaultShellProfileId()
@@ -158,8 +220,11 @@ namespace FluentTerminal.App.Services.Implementation
BellStyle = BellStyle.None,
CursorBlink = true,
CursorStyle = CursorStyle.Block,
ScrollBarStyle = ScrollBarStyle.Hidden,
FontFamily = "Consolas",
FontSize = 13
FontSize = 13,
BackgroundOpacity = 0.8,
ScrollBackLimit = 1000
};
}
@@ -189,6 +254,15 @@ namespace FluentTerminal.App.Services.Implementation
Location = @"C:\Windows\System32\cmd.exe",
PreInstalled = true,
WorkingDirectory = string.Empty
},
new ShellProfile
{
Id= Guid.Parse("e5785ad6-584f-40cb-bdcd-d5b3b3953e7f"),
Name = "WSL",
Arguments = string.Empty,
Location = @"C:\windows\system32\wsl.exe",
PreInstalled = true,
WorkingDirectory = string.Empty
}
};
}
@@ -201,7 +275,6 @@ namespace FluentTerminal.App.Services.Implementation
Author = "xterm.js",
Name = "Xterm.js Default",
PreInstalled = true,
BackgroundOpacity = 0.8,
Colors = new TerminalColors
{
Black = "#2e3436",
@@ -234,7 +307,6 @@ namespace FluentTerminal.App.Services.Implementation
Author = "Microsoft",
Name = "PowerShell",
PreInstalled = true,
BackgroundOpacity = 0.8,
Colors = new TerminalColors
{
Black = "#000000",
@@ -257,7 +329,7 @@ namespace FluentTerminal.App.Services.Implementation
Background = "#012456",
Cursor = "#fedba9",
CursorAccent = "#000000",
Selection = "#fedba9"
Selection = "rgba(254, 219, 169, 0.3)"
}
};
@@ -267,7 +339,6 @@ namespace FluentTerminal.App.Services.Implementation
Author = "Hans Kokx",
Name = "Homebrew",
PreInstalled = true,
BackgroundOpacity = 0.8,
Colors = new TerminalColors
{
Black = "#000000",
@@ -294,7 +365,71 @@ namespace FluentTerminal.App.Services.Implementation
}
};
return new[] { defaultXterm, powerShell, homebrew };
var tomorrow = new TerminalTheme
{
Id = Guid.Parse("0cbbf805-fa86-4be5-ac51-75f3054dcc3a"),
Author = "Chris Kempson",
Name = "Tomorrow",
PreInstalled = true,
Colors = new TerminalColors
{
Foreground = "#4D4D4C",
Background = "#FFFFFF",
Cursor = "#4D4D4C",
CursorAccent = "#FFFFFF",
Selection = "rgba(214, 214, 214, 0.5)",
Black = "#000000",
Red = "#C82829",
Green = "#718C00",
Yellow = "#EAB700",
Blue = "#4271AE",
Magenta = "#8959A8",
Cyan = "#3E999F",
White = "#FFFFFF",
BrightBlack = "#000000",
BrightRed = "#C82829",
BrightGreen = "#718C00",
BrightYellow = "#EAB700",
BrightBlue = "#4271AE",
BrightMagenta = "#8959A8",
BrightCyan = "#3E999F",
BrightWhite = "#FFFFFF"
}
};
var ubuntu = new TerminalTheme
{
Id = Guid.Parse("32519543-bf94-4db6-92a1-7bcec3966c82"),
Author = "Canonical",
Name = "Ubuntu Bash",
PreInstalled = true,
Colors = new TerminalColors
{
Foreground = "#EEEEEE",
Background = "#300A24",
Cursor = "#CFF5DB",
CursorAccent = "#000000",
Selection = "#4DABEDC1",
Black = "#300A24",
Red = "#3465A4",
Green = "#4E9A06",
Yellow = "#06989A",
Blue = "#CC0000",
Magenta = "#75507B",
Cyan = "#C4A000",
White = "#D3D7CF",
BrightBlack = "#554E53",
BrightRed = "#729FCF",
BrightGreen = "#8AE234",
BrightYellow = "#34E2E2",
BrightBlue = "#EF2929",
BrightMagenta = "#AD7FA8",
BrightCyan = "#FCE94F",
BrightWhite = "#EEEEEE"
}
};
return new[] { defaultXterm, powerShell, homebrew, tomorrow, ubuntu };
}
}
}
}
@@ -0,0 +1,64 @@
using System;
using System.Threading.Tasks;
using FluentTerminal.App.Services.Dialogs;
using FluentTerminal.Models;
namespace FluentTerminal.App.Services.Implementation
{
public class DialogService : IDialogService
{
private readonly Func<IShellProfileSelectionDialog> _shellProfileSelectionDialogFactory;
private readonly Func<IMessageDialog> _messageDialogFactory;
private readonly Func<ICreateKeyBindingDialog> _createKeyBindingDialogFactory;
public DialogService(Func<IShellProfileSelectionDialog> shellProfileSelectionDialogFactory, Func<IMessageDialog> messageDialogFactory, Func<ICreateKeyBindingDialog> createKeyBindingDialogFactory)
{
_shellProfileSelectionDialogFactory = shellProfileSelectionDialogFactory;
_messageDialogFactory = messageDialogFactory;
_createKeyBindingDialogFactory = createKeyBindingDialogFactory;
}
public Task<KeyBinding> ShowCreateKeyBindingDialog()
{
var dialog = _createKeyBindingDialogFactory();
return dialog.CreateKeyBinding();
}
public 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 = _messageDialogFactory();
dialog.Content = content;
dialog.Title = title;
foreach (var button in buttons)
{
dialog.AddButton(button);
}
return dialog.ShowAsync();
}
public Task<ShellProfile> ShowProfileSelectionDialogAsync()
{
var dialog = _shellProfileSelectionDialogFactory();
return dialog.SelectProfile();
}
}
}
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using FluentTerminal.Models;
using Newtonsoft.Json;
namespace FluentTerminal.App.Services.Implementation
{
public class FluentTerminalThemeParser : IThemeParser
{
public IEnumerable<string> SupportedFileTypes { get; } = new string[] { ".flutecolors" };
public async Task<TerminalTheme> Parse(string fileName, Stream fileContent)
{
using (var streamReader = new StreamReader(fileContent))
{
var content = await streamReader.ReadToEndAsync();
var theme = JsonConvert.DeserializeObject<TerminalTheme>(content);
theme.PreInstalled = false;
theme.Id = Guid.NewGuid();
return theme;
}
}
}
}
@@ -0,0 +1,127 @@
using FluentTerminal.App.Services.Exceptions;
using FluentTerminal.Models;
using PListNet;
using PListNet.Nodes;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Threading.Tasks;
namespace FluentTerminal.App.Services.Implementation
{
public class ITermThemeParser : IThemeParser
{
private const byte Opacity30Percent = 77;
public IEnumerable<string> SupportedFileTypes { get; } = new string[] { ".itermcolors" };
private static class ITermThemeKeys
{
public const string Ansi0Color = "Ansi 0 Color";
public const string Ansi1Color = "Ansi 1 Color";
public const string Ansi2Color = "Ansi 2 Color";
public const string Ansi3Color = "Ansi 3 Color";
public const string Ansi4Color = "Ansi 4 Color";
public const string Ansi5Color = "Ansi 5 Color";
public const string Ansi6Color = "Ansi 6 Color";
public const string Ansi7Color = "Ansi 7 Color";
public const string Ansi8Color = "Ansi 8 Color";
public const string Ansi9Color = "Ansi 9 Color";
public const string Ansi10Color = "Ansi 10 Color";
public const string Ansi11Color = "Ansi 11 Color";
public const string Ansi12Color = "Ansi 12 Color";
public const string Ansi13Color = "Ansi 13 Color";
public const string Ansi14Color = "Ansi 14 Color";
public const string Ansi15Color = "Ansi 15 Color";
public const string BackgroundColor = "Background Color";
public const string BoldColor = "Bold Color";
public const string CursorColor = "Cursor Color";
public const string CursorTextColor = "Cursor Text Color";
public const string ForegroundColor = "Foreground Color";
public const string SelectedTextColor = "Selected Text Color";
public const string SelectionColor = "Selection Color";
}
private static class ITermThemeColorKeys
{
public const string BlueComponent = "Blue Component";
public const string GreenComponent = "Green Component";
public const string RedComponent = "Red Component";
}
public async Task<TerminalTheme> Parse(string fileName, Stream fileContent)
{
var node = PList.Load(fileContent) as DictionaryNode ?? throw new ParseThemeException("Root node was not a dictionary.");
return new TerminalTheme
{
Name = Path.GetFileNameWithoutExtension(fileName),
Colors = GetColors(node),
Id = Guid.NewGuid(),
PreInstalled = false
};
}
private TerminalColors GetColors(DictionaryNode themeDictionary)
{
return new TerminalColors
{
Background = GetColorString(themeDictionary[ITermThemeKeys.BackgroundColor]),
Foreground = GetColorString(themeDictionary[ITermThemeKeys.ForegroundColor]),
Cursor = GetColorString(themeDictionary[ITermThemeKeys.CursorColor]),
CursorAccent = GetColorString(themeDictionary[ITermThemeKeys.CursorTextColor]),
Selection = GetColorString(themeDictionary[ITermThemeKeys.SelectionColor], Opacity30Percent),
Black = GetColorString(themeDictionary[ITermThemeKeys.Ansi0Color]),
Red = GetColorString(themeDictionary[ITermThemeKeys.Ansi1Color]),
Green = GetColorString(themeDictionary[ITermThemeKeys.Ansi2Color]),
Yellow = GetColorString(themeDictionary[ITermThemeKeys.Ansi3Color]),
Blue = GetColorString(themeDictionary[ITermThemeKeys.Ansi4Color]),
Magenta = GetColorString(themeDictionary[ITermThemeKeys.Ansi5Color]),
Cyan = GetColorString(themeDictionary[ITermThemeKeys.Ansi6Color]),
White = GetColorString(themeDictionary[ITermThemeKeys.Ansi7Color]),
BrightBlack = GetColorString(themeDictionary[ITermThemeKeys.Ansi8Color]),
BrightRed = GetColorString(themeDictionary[ITermThemeKeys.Ansi9Color]),
BrightGreen = GetColorString(themeDictionary[ITermThemeKeys.Ansi10Color]),
BrightYellow = GetColorString(themeDictionary[ITermThemeKeys.Ansi11Color]),
BrightBlue = GetColorString(themeDictionary[ITermThemeKeys.Ansi12Color]),
BrightMagenta = GetColorString(themeDictionary[ITermThemeKeys.Ansi13Color]),
BrightCyan = GetColorString(themeDictionary[ITermThemeKeys.Ansi14Color]),
BrightWhite = GetColorString(themeDictionary[ITermThemeKeys.Ansi15Color]),
};
}
private string GetColorString(PNode colorNode, byte alpha = Byte.MaxValue)
{
var dictionaryNode = colorNode as DictionaryNode ?? throw new ParseThemeException("Color node was not a dictionary");
var red = dictionaryNode[ITermThemeColorKeys.RedComponent] as RealNode ?? throw new ParseThemeException("Red node value was not a real number");
var green = dictionaryNode[ITermThemeColorKeys.GreenComponent] as RealNode ?? throw new ParseThemeException("Green node value was not a real number");
var blue = dictionaryNode[ITermThemeColorKeys.BlueComponent] as RealNode ?? throw new ParseThemeException("Blue node value was not a real number");
var color = $"#{alpha:X2}{GetByteValue(red):X2}{GetByteValue(green):X2}{GetByteValue(blue):X2}";
if (alpha == byte.MaxValue)
{
return $"#{GetByteValue(red):X2}{GetByteValue(green):X2}{GetByteValue(blue):X2}";
}
else
{
return $"rgba({GetByteValue(red):G}, {GetByteValue(green):G}, {GetByteValue(blue):G}, {ToDoubleString(alpha)})";
}
}
private byte GetByteValue(RealNode node)
{
var doubleValue = node.Value * Byte.MaxValue;
return Convert.ToByte(doubleValue);
}
private static string ToDoubleString(byte alpha)
{
return (alpha / 256.0).ToString(CultureInfo.InvariantCulture);
}
}
}
@@ -25,6 +25,13 @@ namespace FluentTerminal.App.Services.Implementation
handler.Invoke();
return;
}
// already registered by SystemTray's ToggleWindowService
if (command == Command.ToggleWindow)
{
return;
}
throw new KeyNotFoundException($"No handler registered for command: {command}");
}
}
@@ -1,39 +1,39 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using FluentTerminal.App.Utilities;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using Newtonsoft.Json;
using Windows.Storage;
namespace FluentTerminal.App.Services.Implementation
{
internal class SettingsService : ISettingsService
public 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 readonly ApplicationDataContainer _localSettings;
private readonly ApplicationDataContainer _themes;
private readonly ApplicationDataContainer _shellProfiles;
private readonly ApplicationDataContainer _roamingSettings;
private readonly IApplicationDataContainer _localSettings;
private readonly IApplicationDataContainer _themes;
private readonly IApplicationDataContainer _keyBindings;
private readonly IApplicationDataContainer _shellProfiles;
private readonly IApplicationDataContainer _roamingSettings;
public event EventHandler CurrentThemeChanged;
public event EventHandler TerminalOptionsChanged;
public event EventHandler ApplicationSettingsChanged;
public event EventHandler<Guid> CurrentThemeChanged;
public event EventHandler<TerminalOptions> TerminalOptionsChanged;
public event EventHandler<ApplicationSettings> ApplicationSettingsChanged;
public event EventHandler KeyBindingsChanged;
public SettingsService(IDefaultValueProvider defaultValueProvider)
public SettingsService(IDefaultValueProvider defaultValueProvider, ApplicationDataContainers containers)
{
_defaultValueProvider = defaultValueProvider;
_localSettings = ApplicationData.Current.LocalSettings;
_roamingSettings = ApplicationData.Current.RoamingSettings;
_localSettings = containers.LocalSettings;
_roamingSettings = containers.RoamingSettings;
_themes = _roamingSettings.CreateContainer(ThemesContainerName, ApplicationDataCreateDisposition.Always);
_shellProfiles = _roamingSettings.CreateContainer(ShellProfilesContainerName, ApplicationDataCreateDisposition.Always);
_themes = containers.Themes;
_keyBindings = containers.KeyBindings;
_shellProfiles = containers.ShellProfiles;
foreach (var theme in _defaultValueProvider.GetPreInstalledThemes())
{
@@ -54,7 +54,7 @@ namespace FluentTerminal.App.Services.Implementation
public Guid GetCurrentThemeId()
{
if (_roamingSettings.Values.TryGetValue(CurrentThemeKey, out object value))
if (_roamingSettings.TryGetValue(CurrentThemeKey, out object value))
{
return (Guid)value;
}
@@ -63,9 +63,9 @@ namespace FluentTerminal.App.Services.Implementation
public void SaveCurrentThemeId(Guid id)
{
_roamingSettings.Values[CurrentThemeKey] = id;
_roamingSettings.SetValue(CurrentThemeKey, id);
CurrentThemeChanged?.Invoke(this, EventArgs.Empty);
CurrentThemeChanged?.Invoke(this, id);
}
public void SaveTheme(TerminalTheme theme)
@@ -74,18 +74,18 @@ namespace FluentTerminal.App.Services.Implementation
if (theme.Id == GetCurrentThemeId())
{
CurrentThemeChanged?.Invoke(this, EventArgs.Empty);
CurrentThemeChanged?.Invoke(this, theme.Id);
}
}
public void DeleteTheme(Guid id)
{
_themes.Values.Remove(id.ToString());
_themes.Delete(id.ToString());
}
public IEnumerable<TerminalTheme> GetThemes()
{
return _themes.Values.Select(x => JsonConvert.DeserializeObject<TerminalTheme>((string)x.Value)).ToList();
return _themes.GetAll().Select(x => JsonConvert.DeserializeObject<TerminalTheme>((string)x)).ToList();
}
public TerminalTheme GetTheme(Guid id)
@@ -101,7 +101,7 @@ namespace FluentTerminal.App.Services.Implementation
public void SaveTerminalOptions(TerminalOptions terminalOptions)
{
_roamingSettings.WriteValueAsJson(nameof(TerminalOptions), terminalOptions);
TerminalOptionsChanged?.Invoke(this, EventArgs.Empty);
TerminalOptionsChanged?.Invoke(this, terminalOptions);
}
public ApplicationSettings GetApplicationSettings()
@@ -112,36 +112,42 @@ namespace FluentTerminal.App.Services.Implementation
public void SaveApplicationSettings(ApplicationSettings applicationSettings)
{
_roamingSettings.WriteValueAsJson(nameof(ApplicationSettings), applicationSettings);
ApplicationSettingsChanged?.Invoke(this, EventArgs.Empty);
ApplicationSettingsChanged?.Invoke(this, applicationSettings);
}
public KeyBindings GetKeyBindings()
public IDictionary<Command, ICollection<KeyBinding>> GetKeyBindings()
{
var defaults = _defaultValueProvider.GetDefaultKeyBindings();
var keyBindings = _roamingSettings.ReadValueFromJson<KeyBindings>(nameof(KeyBindings), null) ?? defaults;
if (keyBindings.ConfigurableNewTab == null)
var keyBindings = new Dictionary<Command, ICollection<KeyBinding>>();
foreach (var value in Enum.GetValues(typeof(Command)))
{
keyBindings.ConfigurableNewTab = defaults.ConfigurableNewTab;
}
if (keyBindings.Search == null)
{
keyBindings.Search = defaults.Search;
var command = (Command)value;
keyBindings.Add(command, _keyBindings.ReadValueFromJson<Collection<KeyBinding>>(command.ToString(), null) ?? _defaultValueProvider.GetDefaultKeyBindings(command));
}
return keyBindings;
}
public void SaveKeyBindings(KeyBindings keyBindings)
public void SaveKeyBindings(Command command, ICollection<KeyBinding> keyBindings)
{
_keyBindings.WriteValueAsJson(command.ToString(), keyBindings);
_roamingSettings.WriteValueAsJson(nameof(KeyBindings), keyBindings);
KeyBindingsChanged?.Invoke(this, EventArgs.Empty);
KeyBindingsChanged?.Invoke(this, System.EventArgs.Empty);
}
public void ResetKeyBindings()
{
foreach (var value in Enum.GetValues(typeof(Command)))
{
var command = (Command)value;
_keyBindings.WriteValueAsJson(command.ToString(), _defaultValueProvider.GetDefaultKeyBindings(command));
}
KeyBindingsChanged?.Invoke(this, System.EventArgs.Empty);
}
public Guid GetDefaultShellProfileId()
{
if (_roamingSettings.Values.TryGetValue(DefaultShellProfileKey, out object value))
if (_roamingSettings.TryGetValue(DefaultShellProfileKey, out object value))
{
return (Guid)value;
}
@@ -156,12 +162,12 @@ namespace FluentTerminal.App.Services.Implementation
public void SaveDefaultShellProfileId(Guid id)
{
_roamingSettings.Values[DefaultShellProfileKey] = id;
_roamingSettings.SetValue(DefaultShellProfileKey, id);
}
public IEnumerable<ShellProfile> GetShellProfiles()
{
return _shellProfiles.Values.Select(x => JsonConvert.DeserializeObject<ShellProfile>((string)x.Value)).ToList();
return _shellProfiles.GetAll().Select(x => JsonConvert.DeserializeObject<ShellProfile>((string)x)).ToList();
}
public void SaveShellProfile(ShellProfile shellProfile)
@@ -171,7 +177,7 @@ namespace FluentTerminal.App.Services.Implementation
public void DeleteShellProfile(Guid id)
{
_shellProfiles.Values.Remove(id.ToString());
_shellProfiles.Delete(id.ToString());
}
}
}
@@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.Linq;
namespace FluentTerminal.App.Services.Implementation
{
public class ThemeParserFactory : IThemeParserFactory
{
private IEnumerable<IThemeParser> _parsers;
public IEnumerable<string> SupportedFileTypes { get; }
public ThemeParserFactory(IEnumerable<IThemeParser> parsers)
{
_parsers = parsers;
SupportedFileTypes = _parsers.SelectMany(p => p.SupportedFileTypes);
}
public IThemeParser GetParser(string fileType)
{
return _parsers.FirstOrDefault(p => p.SupportedFileTypes.Contains(fileType));
}
}
}
@@ -1,18 +1,17 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
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
public class TrayProcessCommunicationService : ITrayProcessCommunicationService
{
private readonly ISettingsService _settingsService;
private AppServiceConnection _appServiceConnection;
private IAppServiceConnection _appServiceConnection;
public TrayProcessCommunicationService(ISettingsService settingsService)
{
@@ -27,7 +26,7 @@ namespace FluentTerminal.App.Services.Implementation
Profile = shellProfile
};
var message = new ValueSet
var message = new Dictionary<string, string>
{
{ MessageKeys.Type, MessageTypes.CreateTerminalRequest },
{ MessageKeys.Content, JsonConvert.SerializeObject(request) }
@@ -35,10 +34,10 @@ namespace FluentTerminal.App.Services.Implementation
var responseMessage = await _appServiceConnection.SendMessageAsync(message);
return JsonConvert.DeserializeObject<CreateTerminalResponse>((string)responseMessage.Message[MessageKeys.Content]);
return JsonConvert.DeserializeObject<CreateTerminalResponse>(responseMessage[MessageKeys.Content]);
}
public Task Initialize(AppServiceConnection appServiceConnection)
public Task Initialize(IAppServiceConnection appServiceConnection)
{
_appServiceConnection = appServiceConnection;
return UpdateToggleWindowKeyBindings();
@@ -52,31 +51,31 @@ namespace FluentTerminal.App.Services.Implementation
NewSize = size
};
var message = new ValueSet
var message = new Dictionary<string, string>
{
{ MessageKeys.Type, MessageTypes.ResizeTerminalRequest },
{ MessageKeys.Content, JsonConvert.SerializeObject(request) }
};
return _appServiceConnection.SendMessageAsync(message).AsTask();
return _appServiceConnection.SendMessageAsync(message);
}
public Task UpdateToggleWindowKeyBindings()
{
var keyBindings = _settingsService.GetKeyBindings().ToggleWindow;
var keyBindings = _settingsService.GetKeyBindings()[Command.ToggleWindow];
var request = new SetToggleWindowKeyBindingsRequest
{
KeyBindings = keyBindings
};
var message = new ValueSet
var message = new Dictionary<string, string>
{
{ MessageKeys.Type, MessageTypes.SetToggleWindowKeyBindingsRequest },
{ MessageKeys.Content, JsonConvert.SerializeObject(request) }
};
return _appServiceConnection.SendMessageAsync(message).AsTask();
return _appServiceConnection.SendMessageAsync(message);
}
}
}
@@ -0,0 +1,21 @@
using System;
using System.ComponentModel;
namespace FluentTerminal.App.Services.Utilities
{
public static class EnumHelper
{
public static string GetEnumDescription(Enum value)
{
var fieldInfo = value.GetType().GetField(value.ToString());
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes?.Length > 0)
{
return attributes[0].Description;
}
return value.ToString();
}
}
}
@@ -0,0 +1,27 @@
using FluentTerminal.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Reflection;
namespace FluentTerminal.App.Services.Utilities
{
public class TerminalThemeContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType == typeof(TerminalTheme) && property.PropertyName == nameof(TerminalTheme.PreInstalled))
{
property.ShouldSerialize = (_) => false;
}
if (property.DeclaringType == typeof(TerminalTheme) && property.PropertyName == nameof(TerminalTheme.Id))
{
property.ShouldSerialize = (_) => false;
}
return property;
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

@@ -1,171 +0,0 @@
<?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>
@@ -1,45 +0,0 @@
<?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>
@@ -1,18 +0,0 @@
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)]
@@ -1,29 +0,0 @@
<!--
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>
-8
View File
@@ -1,8 +0,0 @@
<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
@@ -1,102 +0,0 @@
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();
}
}
}
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Fleck" Version="1.0.3" />
<PackageReference Include="MvvmLightLibs" Version="5.4.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FluentTerminal.App.Services\FluentTerminal.App.Services.csproj" />
<ProjectReference Include="..\FluentTerminal.Models\FluentTerminal.Models.csproj" />
</ItemGroup>
</Project>
@@ -1,5 +1,5 @@
using FluentTerminal.App.Dialogs;
using FluentTerminal.App.Services;
using FluentTerminal.App.Services;
using FluentTerminal.App.Services.EventArgs;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
@@ -8,10 +8,6 @@ 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
{
@@ -24,22 +20,29 @@ namespace FluentTerminal.App.ViewModels
private ApplicationSettings _applicationSettings;
private string _background;
private double _backgroundOpacity;
private readonly CoreDispatcher _dispatcher;
private int _nextTerminalId;
private TerminalViewModel _selectedTerminal;
private string _title;
private readonly IApplicationView _applicationView;
private readonly IDispatcherTimer _dispatcherTimer;
private readonly IClipboardService _clipboardService;
public event EventHandler Closed;
public event EventHandler NewWindowRequested;
public event EventHandler ShowSettingsRequested;
public MainViewModel(ISettingsService settingsService, ITrayProcessCommunicationService trayProcessCommunicationService, IDialogService dialogService, IKeyboardCommandService keyboardCommandService)
public MainViewModel(ISettingsService settingsService, ITrayProcessCommunicationService trayProcessCommunicationService, IDialogService dialogService, IKeyboardCommandService keyboardCommandService,
IApplicationView applicationView, IDispatcherTimer dispatcherTimer, IClipboardService clipboardService)
{
_settingsService = settingsService;
_settingsService.CurrentThemeChanged += OnCurrentThemeChanged;
_settingsService.ApplicationSettingsChanged += OnApplicationSettingsChanged;
_settingsService.TerminalOptionsChanged += OnTerminalOptionsChanged;
_trayProcessCommunicationService = trayProcessCommunicationService;
_dialogService = dialogService;
_applicationView = applicationView;
_dispatcherTimer = dispatcherTimer;
_clipboardService = clipboardService;
_keyboardCommandService = keyboardCommandService;
_keyboardCommandService.RegisterCommandHandler(Command.NewTab, () => AddTerminal(null, false));
_keyboardCommandService.RegisterCommandHandler(Command.ConfigurableNewTab, () => AddTerminal(null, true));
@@ -48,9 +51,11 @@ namespace FluentTerminal.App.ViewModels
_keyboardCommandService.RegisterCommandHandler(Command.PreviousTab, SelectPreviousTab);
_keyboardCommandService.RegisterCommandHandler(Command.NewWindow, NewWindow);
_keyboardCommandService.RegisterCommandHandler(Command.ShowSettings, ShowSettings);
_keyboardCommandService.RegisterCommandHandler(Command.ToggleFullScreen, ToggleFullScreen);
var currentTheme = _settingsService.GetCurrentTheme();
var options = _settingsService.GetTerminalOptions();
Background = currentTheme.Colors.Background;
BackgroundOpacity = currentTheme.BackgroundOpacity;
BackgroundOpacity = options.BackgroundOpacity;
_applicationSettings = _settingsService.GetApplicationSettings();
AddTerminalCommand = new RelayCommand(() => AddTerminal(null, false));
@@ -60,8 +65,15 @@ namespace FluentTerminal.App.ViewModels
Title = "Fluent Terminal";
_dispatcher = CoreApplication.GetCurrentView().Dispatcher;
SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += OnCloseRequest;
_applicationView.CloseRequested += OnCloseRequest;
}
private async void OnTerminalOptionsChanged(object sender, TerminalOptions e)
{
await _applicationView.RunOnDispatcherThread(() =>
{
BackgroundOpacity = e.BackgroundOpacity;
});
}
public RelayCommand AddTerminalCommand { get; }
@@ -83,9 +95,17 @@ namespace FluentTerminal.App.ViewModels
get => _selectedTerminal;
set
{
if (SelectedTerminal != null)
{
_selectedTerminal.IsSelected = false;
}
if (Set(ref _selectedTerminal, value))
{
SelectedTerminal?.FocusTerminal();
if (SelectedTerminal != null)
{
SelectedTerminal.IsSelected = true;
}
}
}
}
@@ -102,7 +122,7 @@ namespace FluentTerminal.App.ViewModels
public Task AddTerminal(string startupDirectory, bool showProfileSelection)
{
return _dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
return _applicationView.RunOnDispatcherThread(async () =>
{
ShellProfile profile = null;
if (showProfileSelection)
@@ -119,13 +139,14 @@ namespace FluentTerminal.App.ViewModels
profile = _settingsService.GetDefaultShellProfile();
}
var terminal = new TerminalViewModel(GetNextTerminalId(), _settingsService, _trayProcessCommunicationService, _dialogService, _keyboardCommandService, _applicationSettings, startupDirectory, profile);
var terminal = new TerminalViewModel(GetNextTerminalId(), _settingsService, _trayProcessCommunicationService, _dialogService, _keyboardCommandService,
_applicationSettings, startupDirectory, profile, _applicationView, _dispatcherTimer, _clipboardService);
terminal.CloseRequested += OnTerminalCloseRequested;
terminal.TitleChanged += OnTitleChanged;
Terminals.Add(terminal);
SelectedTerminal = terminal;
}).AsTask();
});
}
public void CloseAllTerminals()
@@ -151,15 +172,13 @@ namespace FluentTerminal.App.ViewModels
NewWindowRequested?.Invoke(this, EventArgs.Empty);
}
private async void OnApplicationSettingsChanged(object sender, EventArgs e)
private async void OnApplicationSettingsChanged(object sender, ApplicationSettings e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => _applicationSettings = _settingsService.GetApplicationSettings());
await _applicationView.RunOnDispatcherThread(() => _applicationSettings = e);
}
private async void OnCloseRequest(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
private async Task OnCloseRequest(object sender, CancelableEventArgs 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);
@@ -171,7 +190,7 @@ namespace FluentTerminal.App.ViewModels
}
else
{
e.Handled = true;
e.Cancelled = true;
}
}
else
@@ -179,16 +198,14 @@ namespace FluentTerminal.App.ViewModels
CloseAllTerminals();
Closed?.Invoke(this, EventArgs.Empty);
}
deferral.Complete();
}
private async void OnCurrentThemeChanged(object sender, System.EventArgs e)
private async void OnCurrentThemeChanged(object sender, Guid e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
await _applicationView.RunOnDispatcherThread(() =>
{
var currentTheme = _settingsService.GetCurrentTheme();
var currentTheme = _settingsService.GetTheme(e);
Background = currentTheme.Colors.Background;
BackgroundOpacity = currentTheme.BackgroundOpacity;
});
}
@@ -206,7 +223,7 @@ namespace FluentTerminal.App.ViewModels
if (Terminals.Count == 0)
{
Closed?.Invoke(this, EventArgs.Empty);
ApplicationView.GetForCurrentView().TryConsolidateAsync();
_applicationView.TryClose();
}
}
}
@@ -245,5 +262,10 @@ namespace FluentTerminal.App.ViewModels
{
ShowSettingsRequested?.Invoke(this, EventArgs.Empty);
}
private void ToggleFullScreen()
{
_applicationView.ToggleFullScreen();
}
}
}
@@ -53,6 +53,20 @@ namespace FluentTerminal.App.ViewModels.Settings
}
}
public bool UnderlineSelectedTab
{
get => _applicationSettings.UnderlineSelectedTab;
set
{
if (_applicationSettings.UnderlineSelectedTab != value)
{
_applicationSettings.UnderlineSelectedTab = value;
_settingsService.SaveApplicationSettings(_applicationSettings);
RaisePropertyChanged();
}
}
}
public NewTerminalLocation NewTerminalLocation
{
get => _applicationSettings.NewTerminalLocation;
@@ -94,6 +108,7 @@ namespace FluentTerminal.App.ViewModels.Settings
var defaults = _defaultValueProvider.GetDefaultApplicationSettings();
ConfirmClosingWindows = defaults.ConfirmClosingWindows;
ConfirmClosingTabs = defaults.ConfirmClosingTabs;
UnderlineSelectedTab = defaults.UnderlineSelectedTab;
NewTerminalLocation = defaults.NewTerminalLocation;
}
}
@@ -1,11 +1,9 @@
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
{
@@ -97,16 +95,15 @@ namespace FluentTerminal.App.ViewModels.Settings
public async Task<bool> Edit()
{
var dialog = new CreateKeyBindingDialog(_dialogService);
var result = await dialog.ShowAsync();
var keyBinding = await _dialogService.ShowCreateKeyBindingDialog().ConfigureAwait(true);
if (result == ContentDialogResult.Primary)
if (keyBinding != null)
{
Alt = dialog.KeyBinding.Alt;
Ctrl = dialog.KeyBinding.Ctrl;
Shift = dialog.KeyBinding.Shift;
Meta = dialog.KeyBinding.Meta;
Key = dialog.KeyBinding.Key;
Alt = keyBinding.Alt;
Ctrl = keyBinding.Ctrl;
Shift = keyBinding.Shift;
Meta = keyBinding.Meta;
Key = keyBinding.Key;
Edited?.Invoke(this, EventArgs.Empty);
@@ -0,0 +1,86 @@
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
namespace FluentTerminal.App.ViewModels.Settings
{
public class KeyBindingsPageViewModel : ViewModelBase
{
private readonly IDefaultValueProvider _defaultValueProvider;
private readonly IDialogService _dialogService;
private readonly ISettingsService _settingsService;
private readonly ITrayProcessCommunicationService _trayProcessCommunicationService;
private IDictionary<Command, ICollection<KeyBinding>> _keyBindings;
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());
}
public RelayCommand<Command> AddCommand { get; }
public ObservableCollection<KeyBindingsViewModel> KeyBindings { get; } = new ObservableCollection<KeyBindingsViewModel>();
public RelayCommand RestoreDefaultsCommand { get; }
private async Task Add(Command command)
{
var keyBinding = KeyBindings.FirstOrDefault(k => k.Command == command);
await keyBinding?.Add();
}
private void ClearKeyBindings()
{
foreach (var keyBinding in KeyBindings)
{
keyBinding.Edited -= OnEdited;
}
KeyBindings.Clear();
}
private void Initialize(IDictionary<Command, ICollection<KeyBinding>> keyBindings)
{
_keyBindings = keyBindings;
ClearKeyBindings();
foreach (var value in Enum.GetValues(typeof(Command)))
{
var command = (Command)value;
var viewModel = new KeyBindingsViewModel(command, _keyBindings[command], _dialogService);
viewModel.Edited += OnEdited;
KeyBindings.Add(viewModel);
}
}
private void OnEdited(Command command, ICollection<KeyBinding> keyBindings)
{
_settingsService.SaveKeyBindings(command, keyBindings);
_trayProcessCommunicationService.UpdateToggleWindowKeyBindings();
}
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)
{
_settingsService.ResetKeyBindings();
Initialize(_settingsService.GetKeyBindings());
}
}
}
}
@@ -1,4 +1,5 @@
using FluentTerminal.App.Services;
using FluentTerminal.App.Services.Utilities;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
@@ -11,16 +12,17 @@ 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;
Command = command;
_keyBindings = keyBindings;
_dialogService = dialogService;
CommandName = EnumHelper.GetEnumDescription(command);
foreach (var binding in keyBindings)
{
var viewModel = new KeyBindingViewModel(binding, _dialogService);
@@ -30,13 +32,19 @@ namespace FluentTerminal.App.ViewModels.Settings
}
}
public event EventHandler Edited;
public delegate void EditedEvent(Command command, ICollection<KeyBinding> keyBindings);
public event EditedEvent Edited;
public Command Command { get; }
public string CommandName { get; }
public ObservableCollection<KeyBindingViewModel> KeyBindings { get; } = new ObservableCollection<KeyBindingViewModel>();
public async Task Add()
{
var newKeyBinding = new KeyBindingViewModel(new KeyBinding { Command = _command }, _dialogService);
var newKeyBinding = new KeyBindingViewModel(new KeyBinding { Command = Command }, _dialogService);
if (await newKeyBinding.Edit().ConfigureAwait(true))
{
@@ -44,7 +52,7 @@ namespace FluentTerminal.App.ViewModels.Settings
newKeyBinding.Edited += ViewModel_Edited;
KeyBindings.Add(newKeyBinding);
_keyBindings.Add(newKeyBinding.Model);
Edited?.Invoke(this, EventArgs.Empty);
Edited?.Invoke(Command, _keyBindings);
}
}
@@ -54,13 +62,13 @@ namespace FluentTerminal.App.ViewModels.Settings
{
_keyBindings.Remove(keyBinding.Model);
KeyBindings.Remove(keyBinding);
Edited?.Invoke(this, EventArgs.Empty);
Edited?.Invoke(Command, _keyBindings);
}
}
private void ViewModel_Edited(object sender, EventArgs e)
{
Edited?.Invoke(this, EventArgs.Empty);
Edited?.Invoke(Command, _keyBindings);
}
}
}
@@ -13,20 +13,23 @@ namespace FluentTerminal.App.ViewModels.Settings
private readonly IDefaultValueProvider _defaultValueProvider;
private readonly IDialogService _dialogService;
private readonly ISettingsService _settingsService;
private readonly IFileSystemService _fileSystemService;
private ShellProfileViewModel _selectedShellProfile;
public ProfilesPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider)
public ProfilesPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider, IFileSystemService fileSystemService)
{
_settingsService = settingsService;
_dialogService = dialogService;
_defaultValueProvider = defaultValueProvider;
_fileSystemService = fileSystemService;
CreateShellProfileCommand = new RelayCommand(CreateShellProfile);
var defaultShellProfileId = _settingsService.GetDefaultShellProfileId();
foreach (var shellProfile in _settingsService.GetShellProfiles())
{
var viewModel = new ShellProfileViewModel(shellProfile, settingsService, dialogService);
var viewModel = new ShellProfileViewModel(shellProfile, settingsService, dialogService, fileSystemService);
viewModel.Deleted += OnShellProfileDeleted;
viewModel.SetAsDefault += OnShellProfileSetAsDefault;
@@ -85,7 +88,7 @@ namespace FluentTerminal.App.ViewModels.Settings
_settingsService.SaveShellProfile(shellProfile);
var viewModel = new ShellProfileViewModel(shellProfile, _settingsService, _dialogService);
var viewModel = new ShellProfileViewModel(shellProfile, _settingsService, _dialogService, _fileSystemService);
viewModel.EditCommand.Execute(null);
viewModel.SetAsDefault += OnShellProfileSetAsDefault;
viewModel.Deleted += OnShellProfileDeleted;
@@ -3,7 +3,6 @@ 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;
@@ -17,6 +16,7 @@ namespace FluentTerminal.App.ViewModels.Settings
private readonly IDialogService _dialogService;
private readonly IDefaultValueProvider _defaultValueProvider;
private bool _isEditingCursorStyle;
private bool _isEditingScrollBarStyle;
public bool BarIsSelected
{
@@ -30,6 +30,30 @@ namespace FluentTerminal.App.ViewModels.Settings
set => CursorStyle = CursorStyle.Block;
}
public bool UnderlineIsSelected
{
get => CursorStyle == CursorStyle.Underline;
set => CursorStyle = CursorStyle.Underline;
}
public bool HiddenIsSelected
{
get => ScrollBarStyle == ScrollBarStyle.Hidden;
set => ScrollBarStyle = ScrollBarStyle.Hidden;
}
public bool AutoHidingIsSelected
{
get => ScrollBarStyle == ScrollBarStyle.AutoHiding;
set => ScrollBarStyle = ScrollBarStyle.AutoHiding;
}
public bool VisibleIsSelected
{
get => ScrollBarStyle == ScrollBarStyle.Visible;
set => ScrollBarStyle = ScrollBarStyle.Visible;
}
public bool CursorBlink
{
get => _terminalOptions.CursorBlink;
@@ -58,6 +82,46 @@ namespace FluentTerminal.App.ViewModels.Settings
}
}
public double BackgroundOpacity
{
get => _terminalOptions.BackgroundOpacity;
set
{
if (_terminalOptions.BackgroundOpacity != value)
{
_terminalOptions.BackgroundOpacity = value;
_settingsService.SaveTerminalOptions(_terminalOptions);
RaisePropertyChanged();
}
}
}
public string ScrollBackLimit
{
get => _terminalOptions.ScrollBackLimit.ToString();
set
{
var oldValue = _terminalOptions.ScrollBackLimit;
if (uint.TryParse(value, out uint intValue))
{
if (intValue == uint.MinValue)
{
intValue = uint.MaxValue;
}
if (_terminalOptions.ScrollBackLimit != intValue)
{
_terminalOptions.ScrollBackLimit = intValue;
_settingsService.SaveTerminalOptions(_terminalOptions);
RaisePropertyChanged();
}
}
else
{
RaisePropertyChanged();
}
}
}
public IEnumerable<string> Fonts { get; }
public int FontSize
@@ -76,12 +140,6 @@ namespace FluentTerminal.App.ViewModels.Settings
public IEnumerable<int> Sizes { get; }
public bool UnderlineIsSelected
{
get => CursorStyle == CursorStyle.Underline;
set => CursorStyle = CursorStyle.Underline;
}
public RelayCommand RestoreDefaultsCommand { get; }
private CursorStyle CursorStyle
@@ -103,21 +161,43 @@ namespace FluentTerminal.App.ViewModels.Settings
}
}
private ScrollBarStyle ScrollBarStyle
{
get => _terminalOptions.ScrollBarStyle;
set
{
if (_terminalOptions.ScrollBarStyle != value && !_isEditingScrollBarStyle)
{
_isEditingScrollBarStyle = true;
_terminalOptions.ScrollBarStyle = value;
_settingsService.SaveTerminalOptions(_terminalOptions);
RaisePropertyChanged();
RaisePropertyChanged(nameof(HiddenIsSelected));
RaisePropertyChanged(nameof(AutoHidingIsSelected));
RaisePropertyChanged(nameof(VisibleIsSelected));
_isEditingScrollBarStyle = 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);
var result = await _dialogService.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to restore the default terminal options?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true);
if (result == DialogButton.OK)
{
var defaults = _defaultValueProvider.GetDefaultTerminalOptions();
CursorBlink = defaults.CursorBlink;
CursorStyle = defaults.CursorStyle;
ScrollBarStyle = defaults.ScrollBarStyle;
FontFamily = defaults.FontFamily;
FontSize = defaults.FontSize;
BackgroundOpacity = defaults.BackgroundOpacity;
ScrollBackLimit = defaults.ScrollBackLimit.ToString();
}
}
public TerminalPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider)
public TerminalPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider, ISystemFontService systemFontService)
{
_settingsService = settingsService;
_dialogService = dialogService;
@@ -125,7 +205,7 @@ namespace FluentTerminal.App.ViewModels.Settings
RestoreDefaultsCommand = new RelayCommand(async () => await RestoreDefaults().ConfigureAwait(false));
Fonts = CanvasTextFormat.GetSystemFontFamilies().OrderBy(s => s);
Fonts = systemFontService.GetSystemFontFamilies().OrderBy(s => s);
Sizes = Enumerable.Range(1, 72);
_terminalOptions = _settingsService.GetTerminalOptions();
@@ -14,19 +14,32 @@ namespace FluentTerminal.App.ViewModels.Settings
private readonly IDialogService _dialogService;
private readonly ISettingsService _settingsService;
private ThemeViewModel _selectedTheme;
private double _backgroundOpacity;
private readonly IThemeParserFactory _themeParserFactory;
private readonly IFileSystemService _fileSystemService;
public ThemesPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider)
public event EventHandler<string> SelectedThemeBackgroundColorChanged;
public ThemesPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider,
IThemeParserFactory themeParserFactory, IFileSystemService fileSystemService)
{
_settingsService = settingsService;
_dialogService = dialogService;
_defaultValueProvider = defaultValueProvider;
_themeParserFactory = themeParserFactory;
_fileSystemService = fileSystemService;
CreateThemeCommand = new RelayCommand(CreateTheme);
ImportThemeCommand = new RelayCommand(ImportTheme);
_settingsService.TerminalOptionsChanged += OnTerminalOptionsChanged;
BackgroundOpacity = _settingsService.GetTerminalOptions().BackgroundOpacity;
var activeThemeId = _settingsService.GetCurrentThemeId();
foreach (var theme in _settingsService.GetThemes())
{
var viewModel = new ThemeViewModel(theme, _settingsService, _dialogService);
var viewModel = new ThemeViewModel(theme, _settingsService, _dialogService, fileSystemService);
viewModel.Activated += OnThemeActivated;
viewModel.Deleted += OnThemeDeleted;
@@ -41,11 +54,29 @@ namespace FluentTerminal.App.ViewModels.Settings
}
public RelayCommand CreateThemeCommand { get; }
public RelayCommand ImportThemeCommand { get; }
public double BackgroundOpacity
{
get => _backgroundOpacity;
set => Set(ref _backgroundOpacity, value);
}
public ThemeViewModel SelectedTheme
{
get => _selectedTheme;
set => Set(ref _selectedTheme, value);
set
{
if (_selectedTheme != null)
{
_selectedTheme.BackgroundChanged -= OnSelectedThemeBackgroundChanged;
}
Set(ref _selectedTheme, value);
if (value != null)
{
value.BackgroundChanged += OnSelectedThemeBackgroundChanged;
}
}
}
public ObservableCollection<ThemeViewModel> Themes { get; } = new ObservableCollection<ThemeViewModel>();
@@ -58,19 +89,50 @@ namespace FluentTerminal.App.ViewModels.Settings
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);
var viewModel = new ThemeViewModel(theme, _settingsService, _dialogService, _fileSystemService);
viewModel.Activated += OnThemeActivated;
viewModel.Deleted += OnThemeDeleted;
Themes.Add(viewModel);
SelectedTheme = viewModel;
}
private async void ImportTheme()
{
var file = await _fileSystemService.OpenFile(_themeParserFactory.SupportedFileTypes).ConfigureAwait(true);
if (file != null)
{
var parser = _themeParserFactory.GetParser(file.FileType);
if (parser == null)
{
await _dialogService.ShowMessageDialogAsnyc("Import theme failed", "No suitable parser found", DialogButton.OK).ConfigureAwait(false);
return;
}
try
{
var theme = await parser.Parse(file.Name, file.Content).ConfigureAwait(true);
_settingsService.SaveTheme(theme);
var viewModel = new ThemeViewModel(theme, _settingsService, _dialogService, _fileSystemService);
viewModel.Activated += OnThemeActivated;
viewModel.Deleted += OnThemeDeleted;
Themes.Add(viewModel);
SelectedTheme = viewModel;
}
catch (Exception exception)
{
await _dialogService.ShowMessageDialogAsnyc("Import theme failed", exception.Message, DialogButton.OK).ConfigureAwait(false);
}
}
}
private void OnThemeActivated(object sender, EventArgs e)
{
if (sender is ThemeViewModel activatedTheme)
@@ -102,5 +164,15 @@ namespace FluentTerminal.App.ViewModels.Settings
_settingsService.DeleteTheme(theme.Id);
}
}
private void OnTerminalOptionsChanged(object sender, TerminalOptions e)
{
BackgroundOpacity = e.BackgroundOpacity;
}
private void OnSelectedThemeBackgroundChanged(object sender, string e)
{
SelectedThemeBackgroundColorChanged?.Invoke(this, e);
}
}
}
@@ -7,13 +7,14 @@ namespace FluentTerminal.App.ViewModels
{
public class SettingsViewModel : ViewModelBase
{
public SettingsViewModel(ISettingsService settingsService, IDefaultValueProvider defaultValueProvider, IDialogService dialogService, ITrayProcessCommunicationService trayProcessCommunicationService)
public SettingsViewModel(ISettingsService settingsService, IDefaultValueProvider defaultValueProvider, IDialogService dialogService,
ITrayProcessCommunicationService trayProcessCommunicationService, IThemeParserFactory themeParserFactory, ISystemFontService systemFontService, IFileSystemService fileSystemService)
{
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);
Shell = new ProfilesPageViewModel(settingsService, dialogService, defaultValueProvider, fileSystemService);
Terminal = new TerminalPageViewModel(settingsService, dialogService, defaultValueProvider, systemFontService);
Themes = new ThemesPageViewModel(settingsService, dialogService, defaultValueProvider, themeParserFactory, fileSystemService);
}
public event EventHandler Closed;
@@ -4,7 +4,6 @@ using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Threading.Tasks;
using Windows.Storage.Pickers;
namespace FluentTerminal.App.ViewModels
{
@@ -23,12 +22,14 @@ namespace FluentTerminal.App.ViewModels
private bool _inEditMode;
private readonly ISettingsService _settingsService;
private readonly IDialogService _dialogService;
private readonly IFileSystemService _fileSystemService;
public ShellProfileViewModel(ShellProfile shellProfile, ISettingsService settingsService, IDialogService dialogService)
public ShellProfileViewModel(ShellProfile shellProfile, ISettingsService settingsService, IDialogService dialogService, IFileSystemService fileSystemService)
{
_shellProfile = shellProfile;
_settingsService = settingsService;
_dialogService = dialogService;
_fileSystemService = fileSystemService;
Id = shellProfile.Id;
Name = shellProfile.Name;
@@ -157,13 +158,7 @@ namespace FluentTerminal.App.ViewModels
private async Task BrowseForCustomShell()
{
var picker = new FileOpenPicker
{
SuggestedStartLocation = PickerLocationId.ComputerFolder
};
picker.FileTypeFilter.Add(".exe");
var file = await picker.PickSingleFileAsync();
var file = await _fileSystemService.OpenFile(new[] { ".exe" }).ConfigureAwait(true);
if (file != null)
{
Location = file.Path;
@@ -172,14 +167,10 @@ namespace FluentTerminal.App.ViewModels
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)
var directory = await _fileSystemService.BrowseForDirectory().ConfigureAwait(true);
if (directory != null)
{
WorkingDirectory = folder.Path;
WorkingDirectory = directory;
}
}
}
@@ -1,16 +1,17 @@
using FluentTerminal.App.Services;
using FluentTerminal.App.Views;
using Fleck;
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.ApplicationModel.DataTransfer;
using Windows.UI.Core;
using Windows.UI.Xaml;
namespace FluentTerminal.App.ViewModels
{
@@ -21,9 +22,7 @@ namespace FluentTerminal.App.ViewModels
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;
@@ -32,9 +31,16 @@ namespace FluentTerminal.App.ViewModels
private readonly ShellProfile _shellProfile;
private bool _showSearchPanel;
private string _searchText;
private bool _isSelected;
private readonly IApplicationView _applicationView;
private readonly IDispatcherTimer _resizeOverlayTimer;
private readonly IClipboardService _clipboardService;
private IWebSocketConnection _webSocket;
private NamedPipeClientStream _namedPipe;
public TerminalViewModel(int id, ISettingsService settingsService, ITrayProcessCommunicationService trayProcessCommunicationService, IDialogService dialogService,
IKeyboardCommandService keyboardCommandService, ApplicationSettings applicationSettings, string startupDirectory, ShellProfile shellProfile)
IKeyboardCommandService keyboardCommandService, ApplicationSettings applicationSettings, string startupDirectory, ShellProfile shellProfile,
IApplicationView applicationView, IDispatcherTimer dispatcherTimer, IClipboardService clipboardService)
{
Id = id;
Title = DefaultTitle;
@@ -50,26 +56,25 @@ namespace FluentTerminal.App.ViewModels
_applicationSettings = applicationSettings;
_startupDirectory = startupDirectory;
_shellProfile = shellProfile;
_resizeOverlayTimer = new DispatcherTimer
{
Interval = new TimeSpan(0, 0, 2)
};
_applicationView = applicationView;
_clipboardService = clipboardService;
_resizeOverlayTimer = dispatcherTimer;
_resizeOverlayTimer.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 _applicationView.RunOnDispatcherThread(async () =>
{
var keyBindings = _settingsService.GetKeyBindings();
await _terminalView.ChangeKeyBindings(GetKeyBindingsCollection(keyBindings)).ConfigureAwait(false);
await _terminalView.ChangeKeyBindings(FlattenKeyBindings(keyBindings)).ConfigureAwait(false);
});
}
@@ -83,6 +88,20 @@ namespace FluentTerminal.App.ViewModels
public RelayCommand FindNextCommand { get; }
public RelayCommand CloseSearchPanelCommand { get; }
public bool IsSelected
{
get => _isSelected;
set
{
if (Set(ref _isSelected, value))
{
RaisePropertyChanged(nameof(IsUnderlined));
}
}
}
public bool IsUnderlined => IsSelected && _applicationSettings.UnderlineSelectedTab;
public int Id { get; }
public bool Initialized { get; private set; }
@@ -129,7 +148,7 @@ namespace FluentTerminal.App.ViewModels
get => _title;
set
{
value = string.IsNullOrWhiteSpace(value) ? DefaultTitle: value;
value = string.IsNullOrWhiteSpace(value) ? DefaultTitle : value;
if (Set(ref _title, value))
{
@@ -156,7 +175,7 @@ namespace FluentTerminal.App.ViewModels
var theme = _settingsService.GetCurrentTheme();
var keyBindings = _settingsService.GetKeyBindings();
var size = await _terminalView.CreateTerminal(options, theme.Colors, GetKeyBindingsCollection(keyBindings)).ConfigureAwait(true);
var size = await _terminalView.CreateTerminal(options, theme.Colors, FlattenKeyBindings(keyBindings)).ConfigureAwait(true);
if (!string.IsNullOrWhiteSpace(_startupDirectory))
{
@@ -175,7 +194,37 @@ namespace FluentTerminal.App.ViewModels
DefaultTitle = response.ShellExecutableName;
Title = DefaultTitle;
await _terminalView.ConnectToSocket(response.WebSocketUrl).ConfigureAwait(true);
_namedPipe = new NamedPipeClientStream(".", response.PipeName, PipeDirection.InOut, PipeOptions.None);
if (!_namedPipe.IsConnected)
{
_namedPipe.Connect();
}
var webSocketUrl = "ws://127.0.0.1:" + response.Port;
var webSocketServer = new WebSocketServer(webSocketUrl);
webSocketServer.Start(socket =>
{
_webSocket = socket;
socket.OnOpen = () =>
{
Console.WriteLine("open");
//_connectedEvent.Set();
};
socket.OnClose = () =>
{
Console.WriteLine("closing");
_namedPipe.Close();
};
socket.OnMessage = message =>
{
var bytes = Encoding.UTF8.GetBytes(message);
_namedPipe.Write(bytes, 0, bytes.Length);
};
});
ListenToNamedPipe();
await _terminalView.ConnectToSocket(webSocketUrl).ConfigureAwait(true);
Initialized = true;
}
else
@@ -186,6 +235,26 @@ namespace FluentTerminal.App.ViewModels
await FocusTerminal().ConfigureAwait(true);
}
private void ListenToNamedPipe()
{
Task.Run(async () =>
{
var reader = new StreamReader(_namedPipe);
do
{
var offset = 0;
var buffer = new char[1024];
var readChars = await reader.ReadAsync(buffer, offset, buffer.Length - offset);
if (readChars > 0)
{
await _webSocket.Send(new String(buffer));
}
}
while (!reader.EndOfStream);
_webSocket.Close();
});
}
private async Task InvokeCloseRequested()
{
if (_applicationSettings.ConfirmClosingTabs)
@@ -201,16 +270,20 @@ namespace FluentTerminal.App.ViewModels
CloseRequested?.Invoke(this, EventArgs.Empty);
}
private async void OnApplicationSettingsChanged(object sender, EventArgs e)
private async void OnApplicationSettingsChanged(object sender, ApplicationSettings e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => _applicationSettings = _settingsService.GetApplicationSettings());
await _applicationView.RunOnDispatcherThread(() =>
{
_applicationSettings = e;
RaisePropertyChanged(nameof(IsUnderlined));
});
}
private async void OnCurrentThemeChanged(object sender, EventArgs e)
private async void OnCurrentThemeChanged(object sender, Guid e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
await _applicationView.RunOnDispatcherThread(async () =>
{
var currentTheme = _settingsService.GetCurrentTheme();
var currentTheme = _settingsService.GetTheme(e);
await _terminalView.ChangeTheme(currentTheme.Colors).ConfigureAwait(true);
});
}
@@ -220,17 +293,14 @@ namespace FluentTerminal.App.ViewModels
if (e == Command.Copy)
{
var selection = await _terminalView.GetSelection().ConfigureAwait(true);
var dataPackage = new DataPackage();
dataPackage.SetText(selection);
Clipboard.SetContent(dataPackage);
_clipboardService.SetText(selection);
}
else if (e == Command.Paste)
{
var content = Clipboard.GetContent();
if (content.Contains(StandardDataFormats.Text))
var content = await _clipboardService.GetText().ConfigureAwait(true);
if (content != null)
{
var text = await content.GetTextAsync();
await _terminalView.Write(text).ConfigureAwait(true);
await _terminalView.Write(content).ConfigureAwait(true);
}
}
else if (e == Command.Search)
@@ -253,12 +323,11 @@ namespace FluentTerminal.App.ViewModels
ShowResizeOverlay = false;
}
private async void OnTerminalOptionsChanged(object sender, EventArgs e)
private async void OnTerminalOptionsChanged(object sender, TerminalOptions e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
await _applicationView.RunOnDispatcherThread(async () =>
{
var options = _settingsService.GetTerminalOptions();
await _terminalView.ChangeOptions(options).ConfigureAwait(true);
await _terminalView.ChangeOptions(e).ConfigureAwait(true);
});
}
@@ -278,21 +347,9 @@ namespace FluentTerminal.App.ViewModels
Title = e;
}
private IEnumerable<KeyBinding> GetKeyBindingsCollection(KeyBindings keyBindings)
private IEnumerable<KeyBinding> FlattenKeyBindings(IDictionary<Command, ICollection<KeyBinding>> 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;
return keyBindings.Values.SelectMany(k => k);
}
private Task FindNext()
@@ -311,5 +368,34 @@ namespace FluentTerminal.App.ViewModels
ShowSearchPanel = false;
_terminalView.FocusTerminal();
}
private const int FirstDynamicPort = 49151;
public static int? GetAvailablePort()
{
var usedPorts = new List<int>();
var properties = IPGlobalProperties.GetIPGlobalProperties();
var connections = properties.GetActiveTcpConnections();
usedPorts.AddRange(connections.Where(c => c.LocalEndPoint.Port >= FirstDynamicPort).Select(c => c.LocalEndPoint.Port));
var endPoints = properties.GetActiveTcpListeners();
usedPorts.AddRange(endPoints.Where(e => e.Port >= FirstDynamicPort).Select(e => e.Port));
endPoints = properties.GetActiveUdpListeners();
usedPorts.AddRange(endPoints.Where(e => e.Port >= FirstDynamicPort).Select(e => e.Port));
usedPorts.Sort();
for (var i = FirstDynamicPort; i < UInt16.MaxValue; i++)
{
if (!usedPorts.Contains(i))
{
return i;
}
}
return null;
}
}
}
@@ -0,0 +1,374 @@
using FluentTerminal.App.Services;
using FluentTerminal.App.Services.Utilities;
using FluentTerminal.Models;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using Newtonsoft.Json;
using System;
using System.Threading.Tasks;
namespace FluentTerminal.App.ViewModels
{
public class ThemeViewModel : ViewModelBase
{
private readonly IDialogService _dialogService;
private readonly ISettingsService _settingsService;
private string _author;
private string _background;
private double _backgroundOpacity;
private string _black;
private string _blue;
private string _brightBlack;
private string _brightBlue;
private string _brightCyan;
private string _brightGreen;
private string _brightMagenta;
private string _brightRed;
private string _brightWhite;
private string _brightYellow;
private string _cursor;
private string _cursorAccent;
private string _cyan;
private string _fallBackAuthor;
private TerminalColors _fallBackColors;
private string _fallBackName;
private string _foreground;
private string _green;
private bool _inEditMode;
private bool _isActive;
private string _magenta;
private string _name;
private string _red;
private string _selection;
private readonly TerminalTheme _theme;
private string _white;
private string _yellow;
private readonly IFileSystemService _fileSystemService;
public event EventHandler<string> BackgroundChanged;
public ThemeViewModel(TerminalTheme theme, ISettingsService settingsService, IDialogService dialogService, IFileSystemService fileSystemService)
{
_theme = theme;
_settingsService = settingsService;
_dialogService = dialogService;
_fileSystemService = fileSystemService;
Name = _theme.Name;
Author = _theme.Author;
Id = _theme.Id;
Black = _theme.Colors.Black;
Red = _theme.Colors.Red;
Green = _theme.Colors.Green;
Yellow = _theme.Colors.Yellow;
Blue = _theme.Colors.Blue;
Magenta = _theme.Colors.Magenta;
Cyan = _theme.Colors.Cyan;
White = _theme.Colors.White;
BrightBlack = _theme.Colors.BrightBlack;
BrightRed = _theme.Colors.BrightRed;
BrightGreen = _theme.Colors.BrightGreen;
BrightYellow = _theme.Colors.BrightYellow;
BrightBlue = _theme.Colors.BrightBlue;
BrightMagenta = _theme.Colors.BrightMagenta;
BrightCyan = _theme.Colors.BrightCyan;
BrightWhite = _theme.Colors.BrightWhite;
Background = _theme.Colors.Background;
Foreground = _theme.Colors.Foreground;
Cursor = _theme.Colors.Cursor;
CursorAccent = _theme.Colors.CursorAccent;
Selection = _theme.Colors.Selection;
SetActiveCommand = new RelayCommand(SetActive);
DeleteCommand = new RelayCommand(async () => await Delete().ConfigureAwait(false), NotPreInstalled);
EditCommand = new RelayCommand(Edit, NotPreInstalled);
CancelEditCommand = new RelayCommand(async () => await CancelEdit().ConfigureAwait(false));
SaveChangesCommand = new RelayCommand(SaveChanges);
ExportCommand = new RelayCommand(async () => await Export().ConfigureAwait(false), NotPreInstalled);
}
public event EventHandler Activated;
public event EventHandler Deleted;
public string Author
{
get => _author;
set => Set(ref _author, value);
}
public string Background
{
get => _background;
set
{
Set(ref _background, value);
BackgroundChanged?.Invoke(this, value);
}
}
public double BackgroundOpacity
{
get => _backgroundOpacity;
set => Set(ref _backgroundOpacity, value);
}
public string Black
{
get => _black;
set => Set(ref _black, value);
}
public string Blue
{
get => _blue;
set => Set(ref _blue, value);
}
public string BrightBlack
{
get => _brightBlack;
set => Set(ref _brightBlack, value);
}
public string BrightBlue
{
get => _brightBlue;
set => Set(ref _brightBlue, value);
}
public string BrightCyan
{
get => _brightCyan;
set => Set(ref _brightCyan, value);
}
public string BrightGreen
{
get => _brightGreen;
set => Set(ref _brightGreen, value);
}
public string BrightMagenta
{
get => _brightMagenta;
set => Set(ref _brightMagenta, value);
}
public string BrightRed
{
get => _brightRed;
set => Set(ref _brightRed, value);
}
public string BrightWhite
{
get => _brightWhite;
set => Set(ref _brightWhite, value);
}
public string BrightYellow
{
get => _brightYellow;
set => Set(ref _brightYellow, value);
}
public RelayCommand CancelEditCommand { get; }
public string Cursor
{
get => _cursor;
set => Set(ref _cursor, value);
}
public string CursorAccent
{
get => _cursorAccent;
set => Set(ref _cursorAccent, value);
}
public string Cyan
{
get => _cyan;
set => Set(ref _cyan, value);
}
public RelayCommand DeleteCommand { get; }
public RelayCommand EditCommand { get; }
public RelayCommand ExportCommand { get; }
public string Foreground
{
get => _foreground;
set => Set(ref _foreground, value);
}
public string 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 string Magenta
{
get => _magenta;
set => Set(ref _magenta, value);
}
public string Name
{
get => _name;
set => Set(ref _name, value);
}
public string Red
{
get => _red;
set => Set(ref _red, value);
}
public RelayCommand SaveChangesCommand { get; }
public string Selection
{
get => _selection;
set => Set(ref _selection, value);
}
public RelayCommand SetActiveCommand { get; }
public string White
{
get => _white;
set => Set(ref _white, value);
}
public string Yellow
{
get => _yellow;
set => Set(ref _yellow, value);
}
public void SaveChanges()
{
_theme.Name = Name;
_theme.Author = Author;
_theme.Colors.Black = Black;
_theme.Colors.Red = Red;
_theme.Colors.Green = Green;
_theme.Colors.Yellow = Yellow;
_theme.Colors.Blue = Blue;
_theme.Colors.Magenta = Magenta;
_theme.Colors.Cyan = Cyan;
_theme.Colors.White = White;
_theme.Colors.BrightBlack = BrightBlack;
_theme.Colors.BrightRed = BrightRed;
_theme.Colors.BrightGreen = BrightGreen;
_theme.Colors.BrightYellow = BrightYellow;
_theme.Colors.BrightBlue = BrightBlue;
_theme.Colors.BrightMagenta = BrightMagenta;
_theme.Colors.BrightCyan = BrightCyan;
_theme.Colors.BrightWhite = BrightWhite;
_theme.Colors.Background = Background;
_theme.Colors.Foreground = Foreground;
_theme.Colors.Cursor = Cursor;
_theme.Colors.CursorAccent = CursorAccent;
_theme.Colors.Selection = Selection;
_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;
Red = _fallBackColors.Red;
Green = _fallBackColors.Green;
Yellow = _fallBackColors.Yellow;
Blue = _fallBackColors.Blue;
Magenta = _fallBackColors.Magenta;
Cyan = _fallBackColors.Cyan;
White = _fallBackColors.White;
BrightBlack = _fallBackColors.BrightBlack;
BrightRed = _fallBackColors.BrightRed;
BrightGreen = _fallBackColors.BrightGreen;
BrightYellow = _fallBackColors.BrightYellow;
BrightBlue = _fallBackColors.BrightBlue;
BrightMagenta = _fallBackColors.BrightMagenta;
BrightCyan = _fallBackColors.BrightCyan;
BrightWhite = _fallBackColors.BrightWhite;
Background = _fallBackColors.Background;
Foreground = _fallBackColors.Foreground;
Cursor = _fallBackColors.Cursor;
CursorAccent = _fallBackColors.CursorAccent;
Selection = _fallBackColors.Selection;
Name = _fallBackName;
Author = _fallBackAuthor;
InEditMode = false;
}
}
private bool NotPreInstalled()
{
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;
InEditMode = true;
}
private void SetActive()
{
Activated?.Invoke(this, EventArgs.Empty);
}
private Task Export()
{
var content = JsonConvert.SerializeObject(_theme, Formatting.Indented, new JsonSerializerSettings { ContractResolver = new TerminalThemeContractResolver() });
return _fileSystemService.SaveTextFile(Name, "Fluent Terminal Theme", ".flutecolors", content);
}
}
}
@@ -0,0 +1,42 @@
using FluentTerminal.App.Services;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.ApplicationModel.AppService;
using Windows.Foundation.Collections;
namespace FluentTerminal.App.Adapters
{
public class AppServiceConnectionAdapter : IAppServiceConnection
{
private readonly AppServiceConnection _appServiceConnection;
public AppServiceConnectionAdapter(AppServiceConnection appServiceConnection)
{
_appServiceConnection = appServiceConnection;
}
public async Task<IDictionary<string, string>> SendMessageAsync(IDictionary<string, string> message)
{
var valueSet = new ValueSet();
foreach (var pair in message)
{
valueSet.Add(pair.Key, pair.Value);
}
var response = await _appServiceConnection.SendMessageAsync(valueSet).AsTask();
if (response.Status == AppServiceResponseStatus.Success)
{
var responseDict = new Dictionary<string, string>();
foreach (var pair in response.Message)
{
responseDict.Add(pair.Key, (string)pair.Value);
}
return responseDict;
}
return null;
}
}
}
@@ -0,0 +1,59 @@
using FluentTerminal.App.Services;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using Windows.Storage;
namespace FluentTerminal.App.Adapters
{
public class ApplicationDataContainerAdapter : IApplicationDataContainer
{
private readonly ApplicationDataContainer _applicationDataContainer;
public ApplicationDataContainerAdapter(ApplicationDataContainer applicationDataContainer)
{
_applicationDataContainer = applicationDataContainer;
}
public void Delete(string key)
{
_applicationDataContainer.Values.Remove(key);
}
public IEnumerable<object> GetAll()
{
return _applicationDataContainer.Values.Select(x => x.Value);
}
public T ReadValueFromJson<T>(string name, T fallbackValue)
{
if (_applicationDataContainer.Values.TryGetValue(name, out object value))
{
if (EqualityComparer<T>.Default.Equals(fallbackValue, default))
{
fallbackValue = Activator.CreateInstance<T>();
}
JsonConvert.PopulateObject((string)value, fallbackValue);
}
return fallbackValue;
}
public void SetValue(string key, object value)
{
_applicationDataContainer.Values[key] = value;
}
public bool TryGetValue(string key, out object value)
{
return _applicationDataContainer.Values.TryGetValue(key, out value);
}
public void WriteValueAsJson<T>(string name, T value)
{
_applicationDataContainer.Values[name] = JsonConvert.SerializeObject(value);
}
}
}
@@ -0,0 +1,68 @@
using FluentTerminal.App.Services;
using FluentTerminal.App.Services.EventArgs;
using System;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.UI.Core;
using Windows.UI.Core.Preview;
using Windows.UI.ViewManagement;
namespace FluentTerminal.App.Adapters
{
public class ApplicationViewAdapter : IApplicationView
{
private readonly ApplicationView _applicationView;
private readonly CoreDispatcher _dispatcher;
public event CloseRequestedHandler CloseRequested;
public ApplicationViewAdapter()
{
_applicationView = ApplicationView.GetForCurrentView();
_dispatcher = CoreApplication.GetCurrentView().Dispatcher;
SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += OnCloseRequest;
}
public string Title
{
get => _applicationView.Title;
set => _applicationView.Title = value;
}
public Task RunOnDispatcherThread(Action action)
{
return _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action()).AsTask();
}
public Task<bool> TryClose()
{
return _applicationView.TryConsolidateAsync().AsTask();
}
public bool ToggleFullScreen()
{
if (_applicationView.IsFullScreenMode)
{
_applicationView.ExitFullScreenMode();
return true;
}
else
{
return _applicationView.TryEnterFullScreenMode();
}
}
private async void OnCloseRequest(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
{
var deferral = e.GetDeferral();
var args = new CancelableEventArgs();
await CloseRequested?.Invoke(this, args);
e.Handled = args.Cancelled;
deferral.Complete();
}
}
}
@@ -0,0 +1,42 @@
using System;
using FluentTerminal.App.Services;
using Windows.UI.Xaml;
namespace FluentTerminal.App.Adapters
{
public class DispatcherTimerAdapter : IDispatcherTimer
{
private readonly DispatcherTimer _dispatcherTimer;
public DispatcherTimerAdapter()
{
_dispatcherTimer = new DispatcherTimer();
_dispatcherTimer.Tick += OnDispatcherTimerTick;
}
private void OnDispatcherTimerTick(object sender, object e)
{
Tick?.Invoke(this, null);
}
public TimeSpan Interval
{
get => _dispatcherTimer.Interval;
set => _dispatcherTimer.Interval = value;
}
public bool IsEnabled => _dispatcherTimer.IsEnabled;
public event EventHandler<object> Tick;
public void Start()
{
_dispatcherTimer.Start();
}
public void Stop()
{
_dispatcherTimer.Stop();
}
}
}
@@ -0,0 +1,42 @@
using FluentTerminal.App.Services;
using FluentTerminal.App.Services.Dialogs;
using System;
using System.Threading.Tasks;
using Windows.UI.Popups;
namespace FluentTerminal.App.Adapters
{
public class MessageDialogAdapter : IMessageDialog
{
private readonly MessageDialog _messageDialog;
public MessageDialogAdapter()
{
_messageDialog = new MessageDialog(string.Empty);
}
public string Title
{
get => _messageDialog.Title;
set => _messageDialog.Title = value;
}
public string Content
{
get => _messageDialog.Content;
set => _messageDialog.Content = value;
}
public void AddButton(DialogButton button)
{
_messageDialog.Commands.Add(new UICommand(button.ToString()));
}
public async Task<DialogButton> ShowAsync()
{
var result = await _messageDialog.ShowAsync();
return Enum.Parse<DialogButton>(result.Label);
}
}
}
+2
View File
@@ -27,6 +27,8 @@
If="0"
Then="Collapsed" />
<converters:IntToExtendedVirtualKeyConverter x:Key="IntToExtendedVirtualKeyConverter" />
<converters:BackgroundToApplicationThemeConverter x:Key="BackgroundToApplicationThemeConverter" />
<converters:StringToColorConverter x:Key="StringToColorConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>
+33 -4
View File
@@ -1,5 +1,8 @@
using Autofac;
using FluentTerminal.App.Adapters;
using FluentTerminal.App.Dialogs;
using FluentTerminal.App.Services;
using FluentTerminal.App.Services.Dialogs;
using FluentTerminal.App.Services.Implementation;
using FluentTerminal.App.ViewModels;
using FluentTerminal.App.Views;
@@ -15,6 +18,7 @@ using Windows.ApplicationModel.Activation;
using Windows.ApplicationModel.AppService;
using Windows.ApplicationModel.Background;
using Windows.ApplicationModel.Core;
using Windows.Storage;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
@@ -25,6 +29,10 @@ namespace FluentTerminal.App
{
public sealed partial class App : Application
{
public const string ThemesContainerName = "Themes";
public const string KeyBindingsContainerName = "KeyBindings";
public const string ShellProfilesContainerName = "ShellProfiles";
public TaskCompletionSource<int> _trayReady = new TaskCompletionSource<int>();
private readonly ISettingsService _settingsService;
private readonly ITrayProcessCommunicationService _trayProcessCommunicationService;
@@ -34,7 +42,7 @@ namespace FluentTerminal.App
private readonly List<MainViewModel> _mainViewModels;
private SettingsViewModel _settingsViewModel;
private int? _settingsWindowId;
private AppServiceConnection _appServiceConnection;
private IAppServiceConnection _appServiceConnection;
private BackgroundTaskDeferral _appServiceDeferral;
public App()
@@ -43,6 +51,15 @@ namespace FluentTerminal.App
InitializeComponent();
var applicationDataContainers = new ApplicationDataContainers
{
LocalSettings = new ApplicationDataContainerAdapter(ApplicationData.Current.LocalSettings),
RoamingSettings = new ApplicationDataContainerAdapter(ApplicationData.Current.RoamingSettings),
KeyBindings = new ApplicationDataContainerAdapter(ApplicationData.Current.RoamingSettings.CreateContainer(KeyBindingsContainerName, ApplicationDataCreateDisposition.Always)),
ShellProfiles = new ApplicationDataContainerAdapter(ApplicationData.Current.LocalSettings.CreateContainer(ShellProfilesContainerName, ApplicationDataCreateDisposition.Always)),
Themes = new ApplicationDataContainerAdapter(ApplicationData.Current.RoamingSettings.CreateContainer(ThemesContainerName, ApplicationDataCreateDisposition.Always))
};
var builder = new ContainerBuilder();
builder.RegisterType<SettingsService>().As<ISettingsService>().SingleInstance();
builder.RegisterType<DefaultValueProvider>().As<IDefaultValueProvider>().SingleInstance();
@@ -51,6 +68,18 @@ namespace FluentTerminal.App
builder.RegisterType<KeyboardCommandService>().As<IKeyboardCommandService>().InstancePerDependency();
builder.RegisterType<MainViewModel>().InstancePerDependency();
builder.RegisterType<SettingsViewModel>().InstancePerDependency();
builder.RegisterType<ThemeParserFactory>().As<IThemeParserFactory>().SingleInstance();
builder.RegisterType<ITermThemeParser>().As<IThemeParser>().SingleInstance();
builder.RegisterType<FluentTerminalThemeParser>().As<IThemeParser>().SingleInstance();
builder.RegisterType<ClipboardService>().As<IClipboardService>().SingleInstance();
builder.RegisterType<FileSystemService>().As<IFileSystemService>().SingleInstance();
builder.RegisterType<SystemFontService>().As<ISystemFontService>().SingleInstance();
builder.RegisterType<ShellProfileSelectionDialog>().As<IShellProfileSelectionDialog>().InstancePerDependency();
builder.RegisterType<CreateKeyBindingDialog>().As<ICreateKeyBindingDialog>().InstancePerDependency();
builder.RegisterType<MessageDialogAdapter>().As<IMessageDialog>().InstancePerDependency();
builder.RegisterType<ApplicationViewAdapter>().As<IApplicationView>().InstancePerDependency();
builder.RegisterType<DispatcherTimerAdapter>().As<IDispatcherTimer>().InstancePerDependency();
builder.RegisterInstance(applicationDataContainers);
_container = builder.Build();
@@ -136,7 +165,7 @@ namespace FluentTerminal.App
_appServiceDeferral = args.TaskInstance.GetDeferral();
args.TaskInstance.Canceled += OnTaskCanceled;
_appServiceConnection = details.AppServiceConnection;
_appServiceConnection = new AppServiceConnectionAdapter(details.AppServiceConnection);
_trayReady.SetResult(0);
}
@@ -222,9 +251,9 @@ namespace FluentTerminal.App
return windowId;
}
private void OnApplicationSettingsChanged(object sender, EventArgs e)
private void OnApplicationSettingsChanged(object sender, ApplicationSettings e)
{
_applicationSettings = _settingsService.GetApplicationSettings();
_applicationSettings = e;
}
private void OnMainViewModelClosed(object sender, EventArgs e)
@@ -0,0 +1,35 @@
using FluentTerminal.App.Utilities;
using Microsoft.Toolkit.Uwp.Helpers;
using System;
using Windows.UI;
using Windows.UI.Xaml.Data;
namespace FluentTerminal.App.Converters
{
public class BackgroundToApplicationThemeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
Color color;
if (value is string colorString)
{
color = colorString.ToColor();
} else if (value is Color)
{
color = (Color)value;
}
if (color != null)
{
return ContrastHelper.GetIdealThemeForBackgroundColor(color);
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}
@@ -1,6 +1,6 @@
using FluentTerminal.Models.Enums;
using FluentTerminal.App.Services.Utilities;
using FluentTerminal.Models.Enums;
using System;
using System.ComponentModel;
using Windows.UI.Xaml.Data;
namespace FluentTerminal.App.Converters
@@ -11,7 +11,7 @@ namespace FluentTerminal.App.Converters
{
if (value is int intValue)
{
return GetEnumDescription((ExtendedVirtualKey)intValue);
return EnumHelper.GetEnumDescription((ExtendedVirtualKey)intValue);
}
return null;
}
@@ -20,24 +20,5 @@ namespace FluentTerminal.App.Converters
{
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,28 @@
using FluentTerminal.App.Utilities;
using System;
using Windows.UI;
using Windows.UI.Xaml.Data;
namespace FluentTerminal.App.Converters
{
public class StringToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is string colorString)
{
return colorString.FromString();
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
if (value is Color color && bool.TryParse((string)parameter, out bool allowTransparency))
{
return color.ToColorString(allowTransparency);
}
return null;
}
}
}
@@ -1,5 +1,5 @@
<ContentDialog
x:Class="FluentTerminal.App.Views.CreateKeyBindingDialog"
x:Class="FluentTerminal.App.Dialogs.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"
@@ -17,7 +17,7 @@
Height="32"
Margin="0,0,6,0"
Background="{ThemeResource SystemControlBackgroundBaseLowBrush}"
Visibility="{x:Bind KeyBinding.Ctrl, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
Visibility="{x:Bind Ctrl, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
@@ -28,7 +28,7 @@
Height="32"
Margin="0,0,6,0"
Background="{ThemeResource SystemControlBackgroundBaseLowBrush}"
Visibility="{x:Bind KeyBinding.Meta, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
Visibility="{x:Bind Meta, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<FontIcon
HorizontalAlignment="Center"
VerticalAlignment="Center"
@@ -40,7 +40,7 @@
Height="32"
Margin="0,0,6,0"
Background="{ThemeResource SystemControlBackgroundBaseLowBrush}"
Visibility="{x:Bind KeyBinding.Alt, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
Visibility="{x:Bind Alt, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
@@ -51,7 +51,7 @@
Height="32"
Margin="0,0,6,0"
Background="{ThemeResource SystemControlBackgroundBaseLowBrush}"
Visibility="{x:Bind KeyBinding.Shift, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
Visibility="{x:Bind Shift, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
@@ -62,11 +62,11 @@
Height="32"
Margin="0,0,6,0"
Background="{ThemeResource SystemControlBackgroundBaseLowBrush}"
Visibility="{x:Bind KeyBinding.Key, Mode=OneWay, Converter={StaticResource ZeroToCollapsedConverter}}">
Visibility="{x:Bind Key, Mode=OneWay, Converter={StaticResource ZeroToCollapsedConverter}}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{x:Bind KeyBinding.Key, Mode=OneWay, Converter={StaticResource IntToExtendedVirtualKeyConverter}}" />
Text="{x:Bind Key, Mode=OneWay, Converter={StaticResource IntToExtendedVirtualKeyConverter}}" />
</Grid>
<HyperlinkButton
x:Name="ResetButton"
@@ -0,0 +1,131 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using FluentTerminal.App.Services.Dialogs;
using FluentTerminal.Models;
using GalaSoft.MvvmLight.Command;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using System;
namespace FluentTerminal.App.Dialogs
{
public sealed partial class CreateKeyBindingDialog : ContentDialog, ICreateKeyBindingDialog, INotifyPropertyChanged
{
private bool _ctrl;
private bool _shift;
private bool _alt;
private bool _meta;
private int _key;
public bool Ctrl
{
get => _ctrl;
set => Set(ref _ctrl, value);
}
public bool Shift
{
get => _shift;
set => Set(ref _shift, value);
}
public bool Alt
{
get => _alt;
set => Set(ref _alt, value);
}
public bool Meta
{
get => _meta;
set => Set(ref _meta, value);
}
public int Key
{
get => _key;
set => Set(ref _key, value);
}
public CreateKeyBindingDialog()
{
InitializeComponent();
ResetCommand = new RelayCommand(Reset);
PreviewKeyDown += RegisterKeyBindingDialog_PreviewKeyDown;
Reset();
}
public RelayCommand ResetCommand { get; }
public event PropertyChangedEventHandler PropertyChanged;
public async Task<KeyBinding> CreateKeyBinding()
{
var result = await ShowAsync();
if (result == ContentDialogResult.Primary)
{
return new KeyBinding
{
Alt = Alt,
Ctrl = Ctrl,
Key = Key,
Meta = Meta,
Shift = Shift
};
}
return null;
}
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:
Ctrl = true;
break;
case VirtualKey.Shift:
Shift = true;
break;
case VirtualKey.Menu:
Alt = true;
break;
case VirtualKey.LeftWindows:
case VirtualKey.RightWindows:
Meta = true;
break;
default:
Key = (int)e.Key;
break;
}
ResetButton.Visibility = Visibility.Visible;
e.Handled = true;
}
private void Reset()
{
Alt = false;
Ctrl = false;
Meta = false;
Shift = false;
Key = 0;
ResetButton.Visibility = Visibility.Collapsed;
}
private void Set<T>(ref T field, T value, [CallerMemberName]string propertyName = "")
{
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
@@ -8,7 +8,6 @@
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
CloseButtonText="Cancel"
PrimaryButtonText="Start"
RequestedTheme="Dark"
mc:Ignorable="d">
<ComboBox
HorizontalAlignment="Stretch"
@@ -1,12 +1,16 @@
using FluentTerminal.App.Services;
using System;
using FluentTerminal.App.Services;
using FluentTerminal.App.Services.Dialogs;
using FluentTerminal.App.Utilities;
using FluentTerminal.Models;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
namespace FluentTerminal.App.Dialogs
{
public sealed partial class ShellProfileSelectionDialog : ContentDialog
public sealed partial class ShellProfileSelectionDialog : ContentDialog, IShellProfileSelectionDialog
{
public IEnumerable<ShellProfile> Profiles { get; }
@@ -17,6 +21,18 @@ namespace FluentTerminal.App.Dialogs
Profiles = settingsService.GetShellProfiles();
SelectedProfile = Profiles.First();
this.InitializeComponent();
var currentTheme = settingsService.GetCurrentTheme();
RequestedTheme = ContrastHelper.GetIdealThemeForBackgroundColor(currentTheme.Colors.Background);
}
public async Task<ShellProfile> SelectProfile()
{
var result = await ShowAsync();
if (result == ContentDialogResult.Primary)
{
return SelectedProfile;
}
return null;
}
}
}
+26 -34
View File
@@ -36,6 +36,7 @@
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<LangVersion>7.1</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
@@ -102,45 +103,31 @@
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<ItemGroup>
<Compile Include="Adapters\ApplicationDataContainerAdapter.cs" />
<Compile Include="Adapters\ApplicationViewAdapter.cs" />
<Compile Include="Adapters\AppServiceConnectionAdapter.cs" />
<Compile Include="Adapters\DispatcherTimerAdapter.cs" />
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="Behaviors\MiddleClickBehavior.cs" />
<Compile Include="Converters\BackgroundToApplicationThemeConverter.cs" />
<Compile Include="Converters\FalseToVisibleConverter.cs" />
<Compile Include="Converters\IntToExtendedVirtualKeyConverter.cs" />
<Compile Include="Converters\IntToVisibilityConverter.cs" />
<Compile Include="Converters\NegateConverter.cs" />
<Compile Include="Converters\StringToColorConverter.cs" />
<Compile Include="Converters\TerminalViewModelToViewConverter.cs" />
<Compile Include="Converters\TrueToVisibleConverter.cs" />
<Compile Include="Adapters\MessageDialogAdapter.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\TrayProcessCommunicationService.cs" />
<Compile Include="Services\ISettingsService.cs" />
<Compile Include="Services\ITrayProcessCommunicationService.cs" />
<Compile Include="Services\ClipboardService.cs" />
<Compile Include="Services\FileSystemService.cs" />
<Compile Include="Services\SystemFontService.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="Utilities\ContrastHelper.cs" />
<Compile Include="Views\KeyBindingsView.xaml.cs">
<DependentUpon>KeyBindingsView.xaml</DependentUpon>
</Compile>
@@ -148,7 +135,7 @@
<DependentUpon>MainPage.xaml</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Views\CreateKeyBindingDialog.xaml.cs">
<Compile Include="Dialogs\CreateKeyBindingDialog.xaml.cs">
<DependentUpon>CreateKeyBindingDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Views\SettingsPage.xaml.cs">
@@ -284,7 +271,7 @@
<Generator>MSBuild:Compile</Generator>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Page>
<Page Include="Views\CreateKeyBindingDialog.xaml">
<Page Include="Dialogs\CreateKeyBindingDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
@@ -323,23 +310,20 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac">
<Version>4.8.0</Version>
<Version>4.8.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.0.6</Version>
<Version>6.1.5</Version>
</PackageReference>
<PackageReference Include="Microsoft.Toolkit.Uwp.UI">
<Version>2.1.1</Version>
<Version>3.0.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls">
<Version>2.1.1</Version>
<Version>3.0.0</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>11.0.2</Version>
</PackageReference>
@@ -353,6 +337,14 @@
</SDKReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FluentTerminal.App.Services\FluentTerminal.App.Services.csproj">
<Project>{a1ad7385-f92e-46ac-a349-43dc99b1e72d}</Project>
<Name>FluentTerminal.App.Services</Name>
</ProjectReference>
<ProjectReference Include="..\FluentTerminal.App.ViewModels\FluentTerminal.App.ViewModels.csproj">
<Project>{44e8e225-f46c-47ec-9290-ffa08fccf1b5}</Project>
<Name>FluentTerminal.App.ViewModels</Name>
</ProjectReference>
<ProjectReference Include="..\FluentTerminal.Models\FluentTerminal.Models.csproj">
<Project>{5EA40453-A0AA-449E-8406-D6EA51D7E70E}</Project>
<Name>FluentTerminal.Models</Name>
Binary file not shown.
+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.9.0" />
<Identity Name="53621FSApps.FluentTerminal" Publisher="CN=BDC72197-B634-438A-B863-16DCB7D90C85" Version="0.1.11.0" />
<mp:PhoneIdentity PhoneProductId="f7225014-f405-4342-ad2e-ebf6ac60ea2c" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>Fluent Terminal</DisplayName>
@@ -0,0 +1,26 @@
using System;
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer;
namespace FluentTerminal.App.Services
{
public class ClipboardService : IClipboardService
{
public Task<string> GetText()
{
var content = Clipboard.GetContent();
if (content.Contains(StandardDataFormats.Text))
{
return content.GetTextAsync().AsTask();
}
return null;
}
public void SetText(string text)
{
var dataPackage = new DataPackage();
dataPackage.SetText(text);
Clipboard.SetContent(dataPackage);
}
}
}
@@ -0,0 +1,62 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Pickers;
using File = FluentTerminal.Models.File;
namespace FluentTerminal.App.Services
{
public class FileSystemService : IFileSystemService
{
public async Task<string> BrowseForDirectory()
{
var picker = new FolderPicker();
picker.FileTypeFilter.Add(".whatever"); // else a ComException is thrown
picker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
var folder = await picker.PickSingleFolderAsync();
return folder?.Path;
}
public async Task<File> OpenFile(IEnumerable<string> fileTypes)
{
var picker = new FileOpenPicker
{
SuggestedStartLocation = PickerLocationId.ComputerFolder
};
foreach (var fileType in fileTypes)
{
picker.FileTypeFilter.Add(fileType);
}
var file = await picker.PickSingleFileAsync();
if (file != null)
{
var stream = await file.OpenStreamForReadAsync().ConfigureAwait(true);
return new File(file.DisplayName, file.FileType, file.Path, stream);
}
return null;
}
public async Task SaveTextFile(string name, string fileTypeDescription, string fileType, string content)
{
var picker = new FileSavePicker();
picker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
picker.SuggestedFileName = name;
picker.FileTypeChoices.Add(fileTypeDescription, new List<string> { fileType });
var file = await picker.PickSaveFileAsync();
if (file != null)
{
await FileIO.WriteTextAsync(file, content);
}
}
}
}
@@ -1,61 +0,0 @@
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,13 @@
using Microsoft.Graphics.Canvas.Text;
using System.Collections.Generic;
namespace FluentTerminal.App.Services
{
public class SystemFontService : ISystemFontService
{
public IEnumerable<string> GetSystemFontFamilies()
{
return CanvasTextFormat.GetSystemFontFamilies();
}
}
}
+2 -250
View File
@@ -8,11 +8,6 @@
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<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" />
<Setter Property="BorderThickness" Value="0" />
@@ -51,14 +46,14 @@
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource TitleBarHoverBackgroundColor}" />
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemListLowColor}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource TitleBarPressedBackgroundColor}" />
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemListMediumColor}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
@@ -101,247 +96,4 @@
</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,29 +0,0 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using Windows.Storage;
namespace FluentTerminal.App.Utilities
{
public static class ApplicationDataContainerExtensions
{
public static T ReadValueFromJson<T>(this ApplicationDataContainer container, string name, T fallbackValue)
{
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;
}
public static void WriteValueAsJson<T>(this ApplicationDataContainer container, string name, T value)
{
container.Values[name] = JsonConvert.SerializeObject(value);
}
}
}
@@ -0,0 +1,75 @@
using Microsoft.Toolkit.Uwp.Helpers;
using Windows.UI;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
namespace FluentTerminal.App.Utilities
{
public static class ContrastHelper
{
public static ElementTheme GetIdealThemeForBackgroundColor(string color)
{
return GetIdealThemeForBackgroundColor(color.ToColor());
}
public static ElementTheme GetIdealThemeForBackgroundColor(Color color)
{
if (((color.R * 0.299) + (color.G * 0.587) + (color.B * 0.114)) > 186)
{
return ElementTheme.Light;
}
else
{
return ElementTheme.Dark;
}
}
public static void SetTitleBarButtonsForTheme(ElementTheme theme)
{
var titleBar = ApplicationView.GetForCurrentView().TitleBar;
titleBar.ButtonBackgroundColor = Colors.Transparent;
titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
titleBar.ButtonForegroundColor = GetColor("SystemBaseHighColor", theme);
titleBar.ButtonInactiveForegroundColor = GetColor("SystemBaseHighColor", theme);
titleBar.ButtonHoverForegroundColor = GetColor("SystemBaseHighColor", theme);
titleBar.ButtonPressedForegroundColor = GetColor("SystemBaseHighColor", theme);
titleBar.ButtonHoverBackgroundColor = GetColor("SystemListLowColor", theme);
titleBar.ButtonPressedBackgroundColor = GetColor("SystemListMediumColor", theme);
}
private static Color? GetColor(string name, ElementTheme theme)
{
if (theme == ElementTheme.Light)
{
switch (name)
{
case "SystemBaseHighColor":
return new Color { A = 0xFF, R = 0x00, G = 0x00, B = 0x00 };
case "SystemListLowColor":
return new Color { A = 0x19, R = 0x00, G = 0x00, B = 0x00 };
case "SystemListMediumColor":
return new Color { A = 0x33, R = 0x00, G = 0x00, B = 0x00 };
default:
return null;
}
}
else
{
switch (name)
{
case "SystemBaseHighColor":
return new Color { A = 0xFF, R = 0xFF, G = 0xFF, B = 0xFF };
case "SystemListLowColor":
return new Color { A = 0x19, R = 0xFF, G = 0xFF, B = 0xFF };
case "SystemListMediumColor":
return new Color { A = 0x33, R = 0xFF, G = 0xFF, B = 0xFF };
default:
return null;
}
}
}
}
}
@@ -1,131 +0,0 @@
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();
}
}
}
@@ -1,369 +0,0 @@
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);
}
}
}
@@ -1,100 +0,0 @@
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;
}
}
}
@@ -1,72 +0,0 @@
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;
}
}
}
@@ -9,11 +9,15 @@
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}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Margin="0,6,24,0"
Text="{x:Bind ViewModel.CommandName, Mode=OneWay}" />
<ItemsControl Grid.Column="1" ItemsSource="{x:Bind ViewModel.KeyBindings, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="settings:KeyBindingViewModel">
<StackPanel
@@ -7,7 +7,7 @@ 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));
DependencyProperty.Register(nameof(ViewModel), typeof(KeyBindingsViewModel), typeof(KeyBindingsView), new PropertyMetadata(null));
public KeyBindingsView()
{
+8 -2
View File
@@ -9,7 +9,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewmodels="using:FluentTerminal.App.ViewModels"
RequestedTheme="Dark"
RequestedTheme="{x:Bind ViewModel.Background, Mode=OneWay, Converter={StaticResource BackgroundToApplicationThemeConverter}}"
mc:Ignorable="d">
<Page.Resources>
<converters:TerminalViewModelToViewConverter x:Key="TerminalViewModelToViewConverter" />
@@ -72,9 +72,15 @@
</behaviors:MiddleClickBehavior.Actions>
</behaviors:MiddleClickBehavior>
</Interactivity:Interaction.Behaviors>
<Border
Grid.ColumnSpan="3"
Height="3"
VerticalAlignment="Bottom"
Background="{ThemeResource SystemAccentColor}"
Visibility="{x:Bind IsUnderlined, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}" />
<TextBlock
Grid.Column="0"
Margin="12,8,0,0"
Margin="12,8,6,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Title, Mode=OneWay}" />
<Button
+7 -16
View File
@@ -1,4 +1,5 @@
using FluentTerminal.App.ViewModels;
using FluentTerminal.App.Utilities;
using FluentTerminal.App.ViewModels;
using System.ComponentModel;
using Windows.ApplicationModel.Core;
using Windows.UI;
@@ -39,14 +40,16 @@ namespace FluentTerminal.App.Views
{
InitializeComponent();
Root.DataContext = this;
SetTitleBarColors();
Window.Current.SetTitleBar(TitleBar);
Loaded += OnLoaded;
Unloaded += OnUnloaded;
Window.Current.Activated += OnWindowActivated;
RegisterPropertyChangedCallback(RequestedThemeProperty, (s, e) =>
{
ContrastHelper.SetTitleBarButtonsForTheme(RequestedTheme);
});
ApplicationView.PreferredLaunchViewSize = new Windows.Foundation.Size(800, 600);
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize;
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.Auto;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
@@ -81,18 +84,6 @@ namespace FluentTerminal.App.Views
UpdateLayoutMetrics();
}
private void SetTitleBarColors()
{
var titleBar = ApplicationView.GetForCurrentView().TitleBar;
titleBar.ButtonBackgroundColor = Colors.Transparent;
titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
titleBar.ButtonForegroundColor = Colors.White;
titleBar.ButtonInactiveForegroundColor = Colors.White;
titleBar.ButtonPressedForegroundColor = Colors.White;
titleBar.ButtonHoverForegroundColor = Colors.White;
titleBar.ButtonHoverBackgroundColor = Color.FromArgb(24, 255, 255, 255);
titleBar.ButtonPressedBackgroundColor = Color.FromArgb(48, 255, 255, 255);
}
private void UpdateLayoutMetrics()
{
@@ -4,6 +4,7 @@
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"
Loaded="Page_Loaded"
mc:Ignorable="d">
<Grid x:Name="Root">
<TextBlock
+48 -3
View File
@@ -1,34 +1,66 @@
using FluentTerminal.App.ViewModels;
using FluentTerminal.App.Views.SettingsPages;
using System.Linq;
using System;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.Foundation;
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;
using Windows.UI.Xaml.Navigation;
using FluentTerminal.App.Utilities;
namespace FluentTerminal.App.Views
{
public sealed partial class SettingsPage : Page
{
private readonly UISettings _uiSettings;
private readonly ApplicationViewTitleBar _titleBar;
private readonly CoreDispatcher _dispatcher;
private bool _onThemesPage;
public SettingsPage()
{
InitializeComponent();
Root.DataContext = this;
ApplicationView.PreferredLaunchViewSize = new Windows.Foundation.Size(1024, 768);
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize;
ApplicationView.GetForCurrentView().Title = "Settings";
CoreApplicationViewTitleBar coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
coreTitleBar.LayoutMetricsChanged += TitleBar_LayoutMetricsChanged;
CoreTitleBarHeight = coreTitleBar.Height;
_titleBar = ApplicationView.GetForCurrentView().TitleBar;
_dispatcher = Window.Current.Dispatcher;
SetTitleBarColors();
_uiSettings = new UISettings();
_uiSettings.ColorValuesChanged += OnColorValuesChanged;
SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += SettingsPage_CloseRequested;
}
private void OnColorValuesChanged(UISettings sender, object args)
{
if (_onThemesPage == false)
{
SetTitleBarColors();
}
}
private IAsyncAction SetTitleBarColors()
{
return _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var theme = Application.Current.RequestedTheme == ApplicationTheme.Light ? ElementTheme.Light : ElementTheme.Dark;
ContrastHelper.SetTitleBarButtonsForTheme(theme);
});
}
public double CoreTitleBarHeight { get; }
public SettingsViewModel ViewModel { get; private set; }
@@ -48,6 +80,8 @@ namespace FluentTerminal.App.Views
private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
_onThemesPage = false;
if (args.SelectedItem is NavigationViewItem item)
{
switch (item.Tag)
@@ -62,6 +96,7 @@ namespace FluentTerminal.App.Views
case "themes":
ContentFrame.Navigate(typeof(ThemeSettings), ViewModel.Themes);
_onThemesPage = true;
break;
case "terminal":
@@ -73,6 +108,11 @@ namespace FluentTerminal.App.Views
break;
}
}
if (!_onThemesPage)
{
SetTitleBarColors();
}
}
private void SettingsPage_CloseRequested(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
@@ -84,5 +124,10 @@ namespace FluentTerminal.App.Views
{
AppTitle.Margin = new Thickness(CoreApplication.GetCurrentView().TitleBar.SystemOverlayLeftInset + 12, 8, 0, 0);
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
ApplicationView.GetForCurrentView().TryResizeView(new Size { Width = 800, Height = 600 });
}
}
}
@@ -41,6 +41,10 @@
Margin="0,0,0,24"
Content="Windows"
IsChecked="{x:Bind ViewModel.WindowIsSelected, Mode=TwoWay}" />
<ToggleSwitch
Margin="0,0,0,24"
Header="Underline selected tab"
IsOn="{x:Bind ViewModel.UnderlineSelectedTab, Mode=TwoWay}" />
<ToggleSwitch
Margin="0,0,0,24"
Header="Ask before closing windows"
@@ -3,8 +3,8 @@
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:enums="using:FluentTerminal.Models.Enums"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:settings="using:FluentTerminal.App.ViewModels.Settings"
xmlns:views="using:FluentTerminal.App.Views"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
@@ -32,63 +32,7 @@
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>
<MenuFlyout x:Name="AddCommandMenu" />
</AppBarButton.Flyout>
</AppBarButton>
<AppBarButton
@@ -99,146 +43,13 @@
</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>
<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>
<ItemsControl ItemsSource="{x:Bind ViewModel.KeyBindings, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="settings:KeyBindingsViewModel">
<views:KeyBindingsView Margin="0,0,0,24" ViewModel="{x:Bind}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Page>
@@ -1,4 +1,7 @@
using FluentTerminal.App.ViewModels.Settings;
using FluentTerminal.App.Services.Utilities;
using FluentTerminal.App.ViewModels.Settings;
using FluentTerminal.Models.Enums;
using System;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
@@ -18,6 +21,17 @@ namespace FluentTerminal.App.Views.SettingsPages
if (e.Parameter is KeyBindingsPageViewModel viewModel)
{
ViewModel = viewModel;
foreach (var value in Enum.GetValues(typeof(Command)))
{
var command = (Command)value;
AddCommandMenu.Items.Add(new MenuFlyoutItem
{
Text = EnumHelper.GetEnumDescription(command),
Command = ViewModel.AddCommand,
CommandParameter = command
});
}
}
}
}
@@ -135,7 +135,7 @@
Header="Name"
IsEnabled="{x:Bind InEditMode, Mode=OneWay}"
IsSpellCheckEnabled="False"
Text="{x:Bind Arguments, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Text="{x:Bind Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<StackPanel Margin="0,24,0,0" Orientation="Horizontal">
<TextBox
Loaded 100 of 125 files, more files were not shown because too many files have changed in this diff. Show more