Compare commits

...
15 Commits
97 changed files with 1511 additions and 1067 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; }
}
}
@@ -1,6 +1,6 @@
using System;
namespace FluentTerminal.App.Exceptions
namespace FluentTerminal.App.Services.Exceptions
{
public class ParseThemeException : Exception
{
@@ -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);
}
}
@@ -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);
}
}
@@ -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
{
@@ -1,7 +1,7 @@
using FluentTerminal.Models;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Windows.Storage;
namespace FluentTerminal.App.Services
{
@@ -9,6 +9,6 @@ namespace FluentTerminal.App.Services
{
IEnumerable<string> SupportedFileTypes { get; }
Task<TerminalTheme> Parse(StorageFile themeFile);
Task<TerminalTheme> Parse(string fileName, Stream fileContent);
}
}
@@ -1,5 +1,4 @@
using System.Collections.Generic;
using Windows.Storage;
namespace FluentTerminal.App.Services
{
@@ -7,6 +6,6 @@ namespace FluentTerminal.App.Services
{
IEnumerable<string> SupportedFileTypes { get; }
IThemeParser GetParser(StorageFile themeFile);
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()
{
@@ -32,7 +31,7 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = false,
Alt = false,
Shift = false,
Key = (int)VirtualKey.Scroll
Key = (int)ExtendedVirtualKey.Scroll
}
};
@@ -45,7 +44,7 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.Tab
Key = (int)ExtendedVirtualKey.Tab
}
};
@@ -58,7 +57,7 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = true,
Alt = false,
Shift = true,
Key = (int)VirtualKey.Tab
Key = (int)ExtendedVirtualKey.Tab
}
};
@@ -71,7 +70,7 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.T
Key = (int)ExtendedVirtualKey.T
}
};
@@ -84,7 +83,7 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = true,
Alt = false,
Shift = true,
Key = (int)VirtualKey.T
Key = (int)ExtendedVirtualKey.T
}
};
@@ -97,7 +96,7 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.W
Key = (int)ExtendedVirtualKey.W
}
};
@@ -110,7 +109,7 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.N
Key = (int)ExtendedVirtualKey.N
}
};
@@ -136,7 +135,7 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.C
Key = (int)ExtendedVirtualKey.C
}
};
@@ -149,7 +148,7 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.V
Key = (int)ExtendedVirtualKey.V
}
};
@@ -162,7 +161,7 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.F
Key = (int)ExtendedVirtualKey.F
}
};
@@ -175,7 +174,7 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = false,
Alt = true,
Shift = false,
Key = (int)VirtualKey.Enter
Key = (int)ExtendedVirtualKey.Enter
}
};
@@ -188,7 +187,7 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.A
Key = (int)ExtendedVirtualKey.A
}
};
@@ -201,7 +200,7 @@ namespace FluentTerminal.App.Services.Implementation
Ctrl = true,
Alt = false,
Shift = false,
Key = (int)VirtualKey.L
Key = (int)ExtendedVirtualKey.L
}
};
}
@@ -255,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
}
};
}
@@ -389,7 +397,39 @@ namespace FluentTerminal.App.Services.Implementation
}
};
return new[] { defaultXterm, powerShell, homebrew, tomorrow };
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;
}
}
}
}
@@ -1,14 +1,12 @@
using FluentTerminal.App.Exceptions;
using FluentTerminal.App.Utilities;
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;
using Windows.Storage;
using Windows.UI;
namespace FluentTerminal.App.Services.Implementation
{
@@ -53,14 +51,13 @@ namespace FluentTerminal.App.Services.Implementation
public const string RedComponent = "Red Component";
}
public async Task<TerminalTheme> Parse(StorageFile themeFile)
public async Task<TerminalTheme> Parse(string fileName, Stream fileContent)
{
var stream = await themeFile.OpenStreamForReadAsync().ConfigureAwait(false);
var node = PList.Load(stream) as DictionaryNode ?? throw new ParseThemeException("Root node was not a dictionary.");
var node = PList.Load(fileContent) as DictionaryNode ?? throw new ParseThemeException("Root node was not a dictionary.");
return new TerminalTheme
{
Name = Path.GetFileNameWithoutExtension(themeFile.Name),
Name = Path.GetFileNameWithoutExtension(fileName),
Colors = GetColors(node),
Id = Guid.NewGuid(),
PreInstalled = false
@@ -103,15 +100,15 @@ namespace FluentTerminal.App.Services.Implementation
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 = Color.FromArgb(alpha, GetByteValue(red), GetByteValue(green), GetByteValue(blue));
var color = $"#{alpha:X2}{GetByteValue(red):X2}{GetByteValue(green):X2}{GetByteValue(blue):X2}";
if (alpha == byte.MaxValue)
{
return color.ToColorString(false);
return $"#{GetByteValue(red):X2}{GetByteValue(green):X2}{GetByteValue(blue):X2}";
}
else
{
return color.ToColorString(true);
return $"rgba({GetByteValue(red):G}, {GetByteValue(green):G}, {GetByteValue(blue):G}, {ToDoubleString(alpha)})";
}
}
@@ -121,5 +118,10 @@ namespace FluentTerminal.App.Services.Implementation
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}");
}
}
@@ -2,43 +2,38 @@
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 KeyBindingsContainerName = "KeyBindings";
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 _keyBindings;
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<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);
_keyBindings = _roamingSettings.CreateContainer(KeyBindingsContainerName, ApplicationDataCreateDisposition.Always);
_shellProfiles = _roamingSettings.CreateContainer(ShellProfilesContainerName, ApplicationDataCreateDisposition.Always);
_themes = containers.Themes;
_keyBindings = containers.KeyBindings;
_shellProfiles = containers.ShellProfiles;
foreach (var theme in _defaultValueProvider.GetPreInstalledThemes())
{
@@ -59,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;
}
@@ -68,7 +63,7 @@ namespace FluentTerminal.App.Services.Implementation
public void SaveCurrentThemeId(Guid id)
{
_roamingSettings.Values[CurrentThemeKey] = id;
_roamingSettings.SetValue(CurrentThemeKey, id);
CurrentThemeChanged?.Invoke(this, id);
}
@@ -85,12 +80,12 @@ namespace FluentTerminal.App.Services.Implementation
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)
@@ -136,7 +131,7 @@ namespace FluentTerminal.App.Services.Implementation
{
_keyBindings.WriteValueAsJson(command.ToString(), keyBindings);
_roamingSettings.WriteValueAsJson(nameof(KeyBindings), keyBindings);
KeyBindingsChanged?.Invoke(this, EventArgs.Empty);
KeyBindingsChanged?.Invoke(this, System.EventArgs.Empty);
}
public void ResetKeyBindings()
@@ -147,12 +142,12 @@ namespace FluentTerminal.App.Services.Implementation
_keyBindings.WriteValueAsJson(command.ToString(), _defaultValueProvider.GetDefaultKeyBindings(command));
}
KeyBindingsChanged?.Invoke(this, EventArgs.Empty);
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;
}
@@ -167,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)
@@ -182,7 +177,7 @@ namespace FluentTerminal.App.Services.Implementation
public void DeleteShellProfile(Guid id)
{
_shellProfiles.Values.Remove(id.ToString());
_shellProfiles.Delete(id.ToString());
}
}
}
@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using Windows.Storage;
namespace FluentTerminal.App.Services.Implementation
{
@@ -16,9 +15,9 @@ namespace FluentTerminal.App.Services.Implementation
SupportedFileTypes = _parsers.SelectMany(p => p.SupportedFileTypes);
}
public IThemeParser GetParser(StorageFile themeFile)
public IThemeParser GetParser(string fileType)
{
return _parsers.FirstOrDefault(p => p.SupportedFileTypes.Contains(themeFile.FileType));
return _parsers.FirstOrDefault(p => p.SupportedFileTypes.Contains(fileType));
}
}
}
@@ -1,19 +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)
{
@@ -28,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) }
@@ -36,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();
@@ -53,13 +51,13 @@ 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()
@@ -71,13 +69,13 @@ namespace FluentTerminal.App.Services.Implementation
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);
}
}
}
@@ -1,7 +1,7 @@
using System;
using System.ComponentModel;
namespace FluentTerminal.App.Utilities
namespace FluentTerminal.App.Services.Utilities
{
public static class EnumHelper
{
@@ -9,7 +9,7 @@ namespace FluentTerminal.App.Utilities
{
var fieldInfo = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes?.Length > 0)
{
@@ -3,7 +3,7 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Reflection;
namespace FluentTerminal.App.Utilities
namespace FluentTerminal.App.Services.Utilities
{
public class TerminalThemeContractResolver : DefaultContractResolver
{
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.4.0</Version>
</PackageReference>
<PackageReference Include="FluentAssertions">
<Version>5.3.2</Version>
</PackageReference>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.1.5</Version>
</PackageReference>
<PackageReference Include="Moq">
<Version>4.8.3</Version>
</PackageReference>
<PackageReference Include="MSTest.TestAdapter">
<Version>1.3.2</Version>
</PackageReference>
<PackageReference Include="MSTest.TestFramework">
<Version>1.3.2</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,4 +1,5 @@
using FluentTerminal.App.Services;
using FluentTerminal.App.Services.EventArgs;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
@@ -7,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
{
@@ -23,16 +20,19 @@ 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;
@@ -40,6 +40,9 @@ namespace FluentTerminal.App.ViewModels
_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));
@@ -62,13 +65,12 @@ 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 _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
await _applicationView.RunOnDispatcherThread(() =>
{
BackgroundOpacity = e.BackgroundOpacity;
});
@@ -120,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)
@@ -137,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()
@@ -171,13 +174,11 @@ namespace FluentTerminal.App.ViewModels
private async void OnApplicationSettingsChanged(object sender, ApplicationSettings e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => _applicationSettings = e);
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);
@@ -189,7 +190,7 @@ namespace FluentTerminal.App.ViewModels
}
else
{
e.Handled = true;
e.Cancelled = true;
}
}
else
@@ -197,12 +198,11 @@ namespace FluentTerminal.App.ViewModels
CloseAllTerminals();
Closed?.Invoke(this, EventArgs.Empty);
}
deferral.Complete();
}
private async void OnCurrentThemeChanged(object sender, Guid e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
await _applicationView.RunOnDispatcherThread(() =>
{
var currentTheme = _settingsService.GetTheme(e);
Background = currentTheme.Colors.Background;
@@ -223,7 +223,7 @@ namespace FluentTerminal.App.ViewModels
if (Terminals.Count == 0)
{
Closed?.Invoke(this, EventArgs.Empty);
ApplicationView.GetForCurrentView().TryConsolidateAsync();
_applicationView.TryClose();
}
}
}
@@ -262,19 +262,10 @@ namespace FluentTerminal.App.ViewModels
{
ShowSettingsRequested?.Invoke(this, EventArgs.Empty);
}
private void ToggleFullScreen()
{
var applicationView = ApplicationView.GetForCurrentView();
if (applicationView.IsFullScreenMode)
{
applicationView.ExitFullScreenMode();
}
else
{
applicationView.TryEnterFullScreenMode();
}
_applicationView.ToggleFullScreen();
}
}
}
@@ -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);
@@ -1,5 +1,5 @@
using FluentTerminal.App.Services;
using FluentTerminal.App.Utilities;
using FluentTerminal.App.Services.Utilities;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight;
@@ -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;
@@ -198,7 +197,7 @@ namespace FluentTerminal.App.ViewModels.Settings
}
}
public TerminalPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider)
public TerminalPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider, ISystemFontService systemFontService)
{
_settingsService = settingsService;
_dialogService = dialogService;
@@ -206,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();
@@ -1,13 +1,10 @@
using FluentTerminal.App.Exceptions;
using FluentTerminal.App.Services;
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using Windows.Storage.Pickers;
using Windows.UI;
namespace FluentTerminal.App.ViewModels.Settings
{
@@ -19,15 +16,18 @@ namespace FluentTerminal.App.ViewModels.Settings
private ThemeViewModel _selectedTheme;
private double _backgroundOpacity;
private readonly IThemeParserFactory _themeParserFactory;
private readonly IFileSystemService _fileSystemService;
public event EventHandler<Color> SelectedThemeBackgroundColorChanged;
public event EventHandler<string> SelectedThemeBackgroundColorChanged;
public ThemesPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider, IThemeParserFactory themeParserFactory)
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);
@@ -39,7 +39,7 @@ namespace FluentTerminal.App.ViewModels.Settings
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;
@@ -51,7 +51,6 @@ namespace FluentTerminal.App.ViewModels.Settings
}
SelectedTheme = Themes.First(t => t.IsActive);
}
public RelayCommand CreateThemeCommand { get; }
@@ -95,7 +94,7 @@ namespace FluentTerminal.App.ViewModels.Settings
_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);
@@ -104,20 +103,10 @@ namespace FluentTerminal.App.ViewModels.Settings
private async void ImportTheme()
{
var picker = new FileOpenPicker
{
SuggestedStartLocation = PickerLocationId.ComputerFolder
};
foreach (var supportedFileType in _themeParserFactory.SupportedFileTypes)
{
picker.FileTypeFilter.Add(supportedFileType);
}
var file = await picker.PickSingleFileAsync();
var file = await _fileSystemService.OpenFile(_themeParserFactory.SupportedFileTypes).ConfigureAwait(true);
if (file != null)
{
var parser = _themeParserFactory.GetParser(file);
var parser = _themeParserFactory.GetParser(file.FileType);
if (parser == null)
{
@@ -127,11 +116,11 @@ namespace FluentTerminal.App.ViewModels.Settings
try
{
var theme = await parser.Parse(file).ConfigureAwait(true);
var theme = await parser.Parse(file.Name, file.Content).ConfigureAwait(true);
_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);
@@ -181,7 +170,7 @@ namespace FluentTerminal.App.ViewModels.Settings
BackgroundOpacity = e.BackgroundOpacity;
}
private void OnSelectedThemeBackgroundChanged(object sender, Color e)
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, IThemeParserFactory themeParserFactory)
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, themeParserFactory);
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,17 +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
{
@@ -22,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;
@@ -34,9 +32,15 @@ namespace FluentTerminal.App.ViewModels
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;
@@ -52,24 +56,23 @@ 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)
{
var keyBindings = _settingsService.GetKeyBindings();
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
await _applicationView.RunOnDispatcherThread(async () =>
{
await _terminalView.ChangeKeyBindings(FlattenKeyBindings(keyBindings)).ConfigureAwait(false);
});
@@ -191,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
@@ -202,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)
@@ -219,7 +272,7 @@ namespace FluentTerminal.App.ViewModels
private async void OnApplicationSettingsChanged(object sender, ApplicationSettings e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
await _applicationView.RunOnDispatcherThread(() =>
{
_applicationSettings = e;
RaisePropertyChanged(nameof(IsUnderlined));
@@ -228,7 +281,7 @@ namespace FluentTerminal.App.ViewModels
private async void OnCurrentThemeChanged(object sender, Guid e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
await _applicationView.RunOnDispatcherThread(async () =>
{
var currentTheme = _settingsService.GetTheme(e);
await _terminalView.ChangeTheme(currentTheme.Colors).ConfigureAwait(true);
@@ -240,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)
@@ -275,7 +325,7 @@ namespace FluentTerminal.App.ViewModels
private async void OnTerminalOptionsChanged(object sender, TerminalOptions e)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
await _applicationView.RunOnDispatcherThread(async () =>
{
await _terminalView.ChangeOptions(e).ConfigureAwait(true);
});
@@ -318,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;
}
}
}
@@ -1,16 +1,11 @@
using FluentTerminal.App.Services;
using FluentTerminal.App.Utilities;
using FluentTerminal.App.Services.Utilities;
using FluentTerminal.Models;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using Microsoft.Toolkit.Uwp.Helpers;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI;
namespace FluentTerminal.App.ViewModels
{
@@ -19,71 +14,73 @@ namespace FluentTerminal.App.ViewModels
private readonly IDialogService _dialogService;
private readonly ISettingsService _settingsService;
private string _author;
private Color _background;
private string _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 _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 Color _foreground;
private Color _green;
private string _foreground;
private string _green;
private bool _inEditMode;
private bool _isActive;
private Color _magenta;
private string _magenta;
private string _name;
private Color _red;
private Color _selection;
private string _red;
private string _selection;
private readonly TerminalTheme _theme;
private Color _white;
private Color _yellow;
private string _white;
private string _yellow;
private readonly IFileSystemService _fileSystemService;
public event EventHandler<Color> BackgroundChanged;
public event EventHandler<string> BackgroundChanged;
public ThemeViewModel(TerminalTheme theme, ISettingsService settingsService, IDialogService dialogService)
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.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();
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.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();
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.ToColor();
Foreground = _theme.Colors.Foreground.ToColor();
Cursor = _theme.Colors.Cursor.ToColor();
CursorAccent = _theme.Colors.CursorAccent.ToColor();
Selection = _theme.Colors.Selection.FromString();
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);
@@ -103,7 +100,7 @@ namespace FluentTerminal.App.ViewModels
set => Set(ref _author, value);
}
public Color Background
public string Background
{
get => _background;
set
@@ -119,61 +116,61 @@ namespace FluentTerminal.App.ViewModels
set => Set(ref _backgroundOpacity, value);
}
public Color Black
public string Black
{
get => _black;
set => Set(ref _black, value);
}
public Color Blue
public string Blue
{
get => _blue;
set => Set(ref _blue, value);
}
public Color BrightBlack
public string BrightBlack
{
get => _brightBlack;
set => Set(ref _brightBlack, value);
}
public Color BrightBlue
public string BrightBlue
{
get => _brightBlue;
set => Set(ref _brightBlue, value);
}
public Color BrightCyan
public string BrightCyan
{
get => _brightCyan;
set => Set(ref _brightCyan, value);
}
public Color BrightGreen
public string BrightGreen
{
get => _brightGreen;
set => Set(ref _brightGreen, value);
}
public Color BrightMagenta
public string BrightMagenta
{
get => _brightMagenta;
set => Set(ref _brightMagenta, value);
}
public Color BrightRed
public string BrightRed
{
get => _brightRed;
set => Set(ref _brightRed, value);
}
public Color BrightWhite
public string BrightWhite
{
get => _brightWhite;
set => Set(ref _brightWhite, value);
}
public Color BrightYellow
public string BrightYellow
{
get => _brightYellow;
set => Set(ref _brightYellow, value);
@@ -181,19 +178,19 @@ namespace FluentTerminal.App.ViewModels
public RelayCommand CancelEditCommand { get; }
public Color Cursor
public string Cursor
{
get => _cursor;
set => Set(ref _cursor, value);
}
public Color CursorAccent
public string CursorAccent
{
get => _cursorAccent;
set => Set(ref _cursorAccent, value);
}
public Color Cyan
public string Cyan
{
get => _cyan;
set => Set(ref _cyan, value);
@@ -203,13 +200,13 @@ namespace FluentTerminal.App.ViewModels
public RelayCommand EditCommand { get; }
public RelayCommand ExportCommand { get; }
public Color Foreground
public string Foreground
{
get => _foreground;
set => Set(ref _foreground, value);
}
public Color Green
public string Green
{
get => _green;
set => Set(ref _green, value);
@@ -229,7 +226,7 @@ namespace FluentTerminal.App.ViewModels
set => Set(ref _isActive, value);
}
public Color Magenta
public string Magenta
{
get => _magenta;
set => Set(ref _magenta, value);
@@ -241,7 +238,7 @@ namespace FluentTerminal.App.ViewModels
set => Set(ref _name, value);
}
public Color Red
public string Red
{
get => _red;
set => Set(ref _red, value);
@@ -249,7 +246,7 @@ namespace FluentTerminal.App.ViewModels
public RelayCommand SaveChangesCommand { get; }
public Color Selection
public string Selection
{
get => _selection;
set => Set(ref _selection, value);
@@ -257,13 +254,13 @@ namespace FluentTerminal.App.ViewModels
public RelayCommand SetActiveCommand { get; }
public Color White
public string White
{
get => _white;
set => Set(ref _white, value);
}
public Color Yellow
public string Yellow
{
get => _yellow;
set => Set(ref _yellow, value);
@@ -274,29 +271,29 @@ namespace FluentTerminal.App.ViewModels
_theme.Name = Name;
_theme.Author = Author;
_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.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.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.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.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);
_theme.Colors.Background = Background;
_theme.Colors.Foreground = Foreground;
_theme.Colors.Cursor = Cursor;
_theme.Colors.CursorAccent = CursorAccent;
_theme.Colors.Selection = Selection;
_settingsService.SaveTheme(_theme);
@@ -309,29 +306,29 @@ namespace FluentTerminal.App.ViewModels
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();
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.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();
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.ToColor();
Foreground = _fallBackColors.Foreground.ToColor();
Cursor = _fallBackColors.Cursor.ToColor();
CursorAccent = _fallBackColors.CursorAccent.ToColor();
Selection = _fallBackColors.Selection.FromString();
Background = _fallBackColors.Background;
Foreground = _fallBackColors.Foreground;
Cursor = _fallBackColors.Cursor;
CursorAccent = _fallBackColors.CursorAccent;
Selection = _fallBackColors.Selection;
Name = _fallBackName;
Author = _fallBackAuthor;
@@ -368,20 +365,10 @@ namespace FluentTerminal.App.ViewModels
Activated?.Invoke(this, EventArgs.Empty);
}
private async Task Export()
private Task Export()
{
var picker = new FileSavePicker();
picker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
picker.SuggestedFileName = Name;
picker.FileTypeChoices.Add("Fluent Terminal Theme", new List<string> { ".flutecolors" });
var file = await picker.PickSaveFileAsync();
if (file != null)
{
var content = JsonConvert.SerializeObject(_theme, Formatting.Indented, new JsonSerializerSettings { ContractResolver = new TerminalThemeContractResolver() });
await FileIO.WriteTextAsync(file, content);
}
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);
}
}
}
+1
View File
@@ -28,6 +28,7 @@
Then="Collapsed" />
<converters:IntToExtendedVirtualKeyConverter x:Key="IntToExtendedVirtualKeyConverter" />
<converters:BackgroundToApplicationThemeConverter x:Key="BackgroundToApplicationThemeConverter" />
<converters:StringToColorConverter x:Key="StringToColorConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>
+28 -2
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();
@@ -54,6 +71,15 @@ namespace FluentTerminal.App
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();
@@ -139,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);
}
@@ -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));
}
}
}
@@ -1,13 +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; }
@@ -21,5 +24,15 @@ namespace FluentTerminal.App.Dialogs
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;
}
}
}
+20 -40
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,6 +103,10 @@
<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>
@@ -111,45 +116,18 @@
<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="Exceptions\ParseThemeException.cs" />
<Compile Include="Services\IDialogService.cs" />
<Compile Include="Services\Implementation\DialogService.cs" />
<Compile Include="Services\Implementation\FluentTerminalThemeParser.cs" />
<Compile Include="Services\Implementation\KeyboardCommandService.cs" />
<Compile Include="Services\IKeyboardCommandService.cs" />
<Compile Include="Services\Implementation\ITermThemeParser.cs" />
<Compile Include="Services\Implementation\ThemeParserFactory.cs" />
<Compile Include="Services\IThemeParser.cs" />
<Compile Include="Services\IThemeParserFactory.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="Utilities\ContrastHelper.cs" />
<Compile Include="Utilities\EnumHelper.cs" />
<Compile Include="Utilities\TerminalThemeContractResolver.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\ITerminalView.cs" />
<Compile Include="Views\KeyBindingsView.xaml.cs">
<DependentUpon>KeyBindingsView.xaml</DependentUpon>
</Compile>
@@ -157,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">
@@ -293,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>
@@ -346,15 +324,9 @@
<PackageReference Include="Microsoft.Xaml.Behaviors.Uwp.Managed">
<Version>2.0.0</Version>
</PackageReference>
<PackageReference Include="MvvmLightLibs">
<Version>5.4.1</Version>
</PackageReference>
<PackageReference Include="Newtonsoft.Json">
<Version>11.0.2</Version>
</PackageReference>
<PackageReference Include="PListNet">
<Version>2.0.3</Version>
</PackageReference>
<PackageReference Include="Win2D.uwp">
<Version>1.21.0</Version>
</PackageReference>
@@ -365,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.
@@ -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;
}
}
}
@@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using FluentTerminal.Models;
using Newtonsoft.Json;
using Windows.Storage;
namespace FluentTerminal.App.Services.Implementation
{
public class FluentTerminalThemeParser : IThemeParser
{
public IEnumerable<string> SupportedFileTypes { get; } = new string[] { ".flutecolors" };
public async Task<TerminalTheme> Parse(StorageFile themeFile)
{
var content = await FileIO.ReadTextAsync(themeFile);
var theme = JsonConvert.DeserializeObject<TerminalTheme>(content);
theme.PreInstalled = false;
theme.Id = Guid.NewGuid();
return theme;
}
}
}
@@ -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();
}
}
}
@@ -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);
}
}
}
@@ -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;
}
}
}
@@ -1,4 +1,4 @@
using FluentTerminal.App.Utilities;
using FluentTerminal.App.Services.Utilities;
using FluentTerminal.App.ViewModels.Settings;
using FluentTerminal.Models.Enums;
using System;
@@ -206,92 +206,92 @@
<views:TerminalColorPicker
ColorName="Black"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Black, Mode=TwoWay}" />
SelectedColor="{x:Bind Black, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Red"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Red, Mode=TwoWay}" />
SelectedColor="{x:Bind Red, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Green"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Green, Mode=TwoWay}" />
SelectedColor="{x:Bind Green, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Yellow"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Yellow, Mode=TwoWay}" />
SelectedColor="{x:Bind Yellow, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Blue"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Blue, Mode=TwoWay}" />
SelectedColor="{x:Bind Blue, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Magenta"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Magenta, Mode=TwoWay}" />
SelectedColor="{x:Bind Magenta, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Cyan"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Cyan, Mode=TwoWay}" />
SelectedColor="{x:Bind Cyan, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="White"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind White, Mode=TwoWay}" />
SelectedColor="{x:Bind White, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<views:TerminalColorPicker
ColorName="Bright Black"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightBlack, Mode=TwoWay}" />
SelectedColor="{x:Bind BrightBlack, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Bright Red"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightRed, Mode=TwoWay}" />
SelectedColor="{x:Bind BrightRed, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Bright Green"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightGreen, Mode=TwoWay}" />
SelectedColor="{x:Bind BrightGreen, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Bright Yellow"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightYellow, Mode=TwoWay}" />
SelectedColor="{x:Bind BrightYellow, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Bright Blue"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightBlue, Mode=TwoWay}" />
SelectedColor="{x:Bind BrightBlue, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Bright Magenta"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightMagenta, Mode=TwoWay}" />
SelectedColor="{x:Bind BrightMagenta, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Bright Cyan"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightCyan, Mode=TwoWay}" />
SelectedColor="{x:Bind BrightCyan, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Bright White"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind BrightWhite, Mode=TwoWay}" />
SelectedColor="{x:Bind BrightWhite, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<views:TerminalColorPicker
ColorName="Foreground"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Foreground, Mode=TwoWay}" />
SelectedColor="{x:Bind Foreground, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Background"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Background, Mode=TwoWay}" />
SelectedColor="{x:Bind Background, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Cursor"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind Cursor, Mode=TwoWay}" />
SelectedColor="{x:Bind Cursor, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Cursor Accent"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
SelectedColor="{x:Bind CursorAccent, Mode=TwoWay}" />
SelectedColor="{x:Bind CursorAccent, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=false}" />
<views:TerminalColorPicker
ColorName="Selection"
EnableEditing="{x:Bind InEditMode, Mode=OneWay}"
IsAlphaEnabled="True"
SelectedColor="{x:Bind Selection, Mode=TwoWay}" />
SelectedColor="{x:Bind Selection, Mode=TwoWay, Converter={StaticResource StringToColorConverter}, ConverterParameter=true}" />
</StackPanel>
<TextBlock
Grid.Row="3"
@@ -1,6 +1,6 @@
using FluentTerminal.App.Utilities;
using FluentTerminal.App.ViewModels.Settings;
using Windows.UI;
using Microsoft.Toolkit.Uwp.Helpers;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
@@ -28,7 +28,7 @@ namespace FluentTerminal.App.Views.SettingsPages
}
}
private void OnSelectedThemeBackgroundColorChanged(object sender, Color e)
private void OnSelectedThemeBackgroundColorChanged(object sender, string e)
{
var theme = ContrastHelper.GetIdealThemeForBackgroundColor(e);
SetTheme(theme);
@@ -1,4 +1,5 @@
using FluentTerminal.App.ViewModels;
using FluentTerminal.App.Services;
using FluentTerminal.App.ViewModels;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using FluentTerminal.RuntimeComponent.Interfaces;
@@ -177,6 +177,8 @@ namespace FluentTerminal.Models.Enums
Period = 190,
[Description("#")]
NumberSign = 191,
[Description("`")]
GraveAccent = 192,
GamepadA = 195,
GamepadB = 196,
GamepadX = 197,
+20
View File
@@ -0,0 +1,20 @@
using System.IO;
namespace FluentTerminal.Models
{
public class File
{
public File(string name, string fileType, string path, Stream content)
{
Name = name;
FileType = fileType;
Path = path;
Content = content;
}
public string Name { get; }
public string FileType { get; }
public string Path { get; }
public Stream Content { get; }
}
}
@@ -4,8 +4,9 @@
{
public int Id { get; set; }
public bool Success { get; set; }
public string WebSocketUrl { get; set; }
public int Port { get; set; }
public string Error { get; set; }
public string ShellExecutableName { get; set; }
public string PipeName { get; set; }
}
}
@@ -1,10 +1,8 @@
using Fleck;
using FluentTerminal.Models;
using FluentTerminal.Models;
using FluentTerminal.Models.Requests;
using System;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static winpty.WinPty;
@@ -18,7 +16,7 @@ namespace FluentTerminal.SystemTray.Services
private IntPtr _handle;
private Stream _stdin;
private Stream _stdout;
private IWebSocketConnection _webSocket;
private NamedPipeServerStream _outServer;
public TerminalSession(CreateTerminalRequest request)
{
@@ -72,29 +70,17 @@ namespace FluentTerminal.SystemTray.Services
Id = port.Value;
_connectedEvent = new ManualResetEventSlim(false);
WebSocketUrl = "ws://127.0.0.1:" + port;
var webSocketServer = new WebSocketServer(WebSocketUrl);
webSocketServer.Start(socket =>
{
_webSocket = socket;
socket.OnOpen = () =>
{
Console.WriteLine("open");
_connectedEvent.Set();
};
socket.OnClose = () =>
{
Console.WriteLine("closing");
ConnectionClosed?.Invoke(this, EventArgs.Empty);
};
socket.OnMessage = message =>
{
var bytes = Encoding.UTF8.GetBytes(message);
_stdin.Write(bytes, 0, bytes.Length);
};
});
PipeName = @"LOCAL\" + Guid.NewGuid().ToString();
_outServer = new NamedPipeServerStream(PipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.None);
StreamReader reader = new StreamReader(_outServer);
ListenToStdOut();
ListenToNamedPipe();
}
~TerminalSession()
@@ -114,7 +100,9 @@ namespace FluentTerminal.SystemTray.Services
public event EventHandler ConnectionClosed;
public int Id { get; }
public string WebSocketUrl { get; }
public string PipeName { get; }
public string ShellExecutableName { get; }
public void Dispose()
@@ -178,12 +166,18 @@ namespace FluentTerminal.SystemTray.Services
return pipe;
}
private void ListenToStdOut()
private void ListenToNamedPipe()
{
new NotificationService().ShowNotification("DEBUG", "wating now");
_outServer.WaitForConnection();
new NotificationService().ShowNotification("DEBUG", "connected");
Task.Run(async () =>
{
_connectedEvent.Wait();
var reader = new StreamReader(_stdout);
//_connectedEvent.Wait();
var reader = new StreamReader(_outServer);
var writer = new StreamWriter(_stdin);
do
{
var offset = 0;
@@ -191,12 +185,34 @@ namespace FluentTerminal.SystemTray.Services
var readChars = await reader.ReadAsync(buffer, offset, buffer.Length - offset);
if (readChars > 0)
{
await _webSocket.Send(new String(buffer));
writer.Write(buffer, 0, readChars);
}
}
while (!reader.EndOfStream);
_webSocket.Close();
_stdin.Close();
});
}
private void ListenToStdOut()
{
Task.Run(async () =>
{
var reader = new StreamReader(_stdout);
var writer = new StreamWriter(_outServer);
do
{
var offset = 0;
var buffer = new char[1024];
var readChars = await reader.ReadAsync(buffer, offset, buffer.Length - offset);
if (readChars > 0)
{
writer.Write(buffer, 0, readChars);
}
}
while (!reader.EndOfStream);
_outServer.Close();
});
}
}
}
}
@@ -35,7 +35,8 @@ namespace FluentTerminal.SystemTray.Services
{
Success = true,
Id = terminal.Id,
WebSocketUrl = terminal.WebSocketUrl,
Port = Utilities.GetAvailablePort().Value,
PipeName = terminal.PipeName,
ShellExecutableName = terminal.ShellExecutableName
};
}
@@ -22,6 +22,8 @@ namespace FluentTerminal.SystemTray.Services
private bool _disposedValue;
private List<HotKey> _hotKeys;
private const int SW_MINIMIZE = 6;
public ToggleWindowService(Dispatcher dispatcher, HotKeyManager hotKeyManager, NotificationService notificationService)
{
_dispatcher = dispatcher;
@@ -103,6 +105,9 @@ namespace FluentTerminal.SystemTray.Services
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private static string GetKeyBindingRepresentation(KeyBinding keyBinding)
{
var keys = new List<string>();
@@ -145,8 +150,9 @@ namespace FluentTerminal.SystemTray.Services
private async void OnKeyPressed(object sender, KeyPressedEventArgs e)
{
if (GetActiveProcessFileName() == "Fluent Terminal")
{
SendKeys.Send("%{Tab}");
{
var hwnd = GetForegroundWindow();
ShowWindow(hwnd, SW_MINIMIZE);
}
else
{
+2
View File
@@ -326,6 +326,8 @@ namespace FluentTerminal.SystemTray
return Key.OemQuestion;
case ExtendedVirtualKey.OpenBrackets:
return Key.OemOpenBrackets;
case ExtendedVirtualKey.GraveAccent:
return Key.Oem3;
case ExtendedVirtualKey.Circumflex:
return Key.Oem5;
case ExtendedVirtualKey.AcuteAccent:
+53 -17
View File
@@ -15,7 +15,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentTerminal.RuntimeCompo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FluentTerminal.Models", "FluentTerminal.Models\FluentTerminal.Models.csproj", "{5EA40453-A0AA-449E-8406-D6EA51D7E70E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentTerminal.App.Test", "FluentTerminal.App.Test\FluentTerminal.App.Test.csproj", "{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FluentTerminal.App.Services", "FluentTerminal.App.Services\FluentTerminal.App.Services.csproj", "{A1AD7385-F92E-46AC-A349-43DC99B1E72D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FluentTerminal.App.Services.Test", "FluentTerminal.App.Services.Test\FluentTerminal.App.Services.Test.csproj", "{B353EAF4-8332-4C89-B986-B0B29F7E21FC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentTerminal.App.ViewModels", "FluentTerminal.App.ViewModels\FluentTerminal.App.ViewModels.csproj", "{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -97,22 +101,54 @@ Global
{5EA40453-A0AA-449E-8406-D6EA51D7E70E}.Release|x64.Build.0 = Release|Any CPU
{5EA40453-A0AA-449E-8406-D6EA51D7E70E}.Release|x86.ActiveCfg = Release|Any CPU
{5EA40453-A0AA-449E-8406-D6EA51D7E70E}.Release|x86.Build.0 = Release|Any CPU
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Debug|Any CPU.ActiveCfg = Debug|x86
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Debug|ARM.ActiveCfg = Debug|ARM
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Debug|ARM.Build.0 = Debug|ARM
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Debug|ARM.Deploy.0 = Debug|ARM
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Debug|x64.ActiveCfg = Debug|x64
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Debug|x64.Build.0 = Debug|x64
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Debug|x86.ActiveCfg = Debug|x86
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Debug|x86.Build.0 = Debug|x86
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Release|Any CPU.ActiveCfg = Release|x86
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Release|ARM.ActiveCfg = Release|ARM
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Release|ARM.Build.0 = Release|ARM
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Release|ARM.Deploy.0 = Release|ARM
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Release|x64.ActiveCfg = Release|x64
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Release|x64.Build.0 = Release|x64
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Release|x86.ActiveCfg = Release|x86
{812A09E4-3A05-41AB-8E9A-DC4389B5D73E}.Release|x86.Build.0 = Release|x86
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Debug|ARM.ActiveCfg = Debug|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Debug|ARM.Build.0 = Debug|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Debug|x64.ActiveCfg = Debug|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Debug|x64.Build.0 = Debug|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Debug|x86.ActiveCfg = Debug|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Debug|x86.Build.0 = Debug|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Release|Any CPU.Build.0 = Release|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Release|ARM.ActiveCfg = Release|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Release|ARM.Build.0 = Release|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Release|x64.ActiveCfg = Release|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Release|x64.Build.0 = Release|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Release|x86.ActiveCfg = Release|Any CPU
{A1AD7385-F92E-46AC-A349-43DC99B1E72D}.Release|x86.Build.0 = Release|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Debug|ARM.ActiveCfg = Debug|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Debug|ARM.Build.0 = Debug|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Debug|x64.ActiveCfg = Debug|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Debug|x64.Build.0 = Debug|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Debug|x86.ActiveCfg = Debug|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Debug|x86.Build.0 = Debug|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Release|Any CPU.Build.0 = Release|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Release|ARM.ActiveCfg = Release|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Release|ARM.Build.0 = Release|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Release|x64.ActiveCfg = Release|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Release|x64.Build.0 = Release|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Release|x86.ActiveCfg = Release|Any CPU
{B353EAF4-8332-4C89-B986-B0B29F7E21FC}.Release|x86.Build.0 = Release|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Debug|ARM.ActiveCfg = Debug|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Debug|ARM.Build.0 = Debug|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Debug|x64.ActiveCfg = Debug|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Debug|x64.Build.0 = Debug|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Debug|x86.ActiveCfg = Debug|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Debug|x86.Build.0 = Debug|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Release|Any CPU.Build.0 = Release|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Release|ARM.ActiveCfg = Release|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Release|ARM.Build.0 = Release|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Release|x64.ActiveCfg = Release|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Release|x64.Build.0 = Release|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Release|x86.ActiveCfg = Release|Any CPU
{44E8E225-F46C-47EC-9290-FFA08FCCF1B5}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+2 -2
View File
@@ -1,11 +1,11 @@
![Build status](https://fs-apps.visualstudio.com/_apis/public/build/definitions/a91787f7-3162-4680-b783-cd83e58d2754/1/badge)
[![Build status](https://ci.appveyor.com/api/projects/status/4r429bv594fxkygd?svg=true)](https://ci.appveyor.com/project/felixse/fluentterminal)
# Fluent Terminal
A Terminal Emulator based on UWP and web technologies.
## Features:
- Terminal for PowerShell, CMD, or custom shells
- Terminal for PowerShell, CMD, WSL, or custom shells
- Supports tabs and multiple windows
- Theming and appearance configuration
- Editable keybindings
+25
View File
@@ -0,0 +1,25 @@
os: Visual Studio 2017
configuration: Debug
platform:
- x64
skip_commits:
files:
- README.md
install:
- ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1'))
- cmd: appveyor-tools\secure-file -decrypt FluentTerminal.App\FluentTerminal.App_StoreKey.pfx.enc -secret %CertificationFilesSecret%
- cmd: appveyor-tools\secure-file -decrypt FluentTerminal.App\Package.StoreAssociation.xml.enc -secret %CertificationFilesSecret%
before_build:
- cmd: pushd FluentTerminal.Client && npm install && npm run build && popd
- cmd: nuget restore
build:
project: FluentTerminal.sln
parallel: true
verbosity: minimal
before_test:
- cmd: dotnet build FluentTerminal.App.Services.Test\FluentTerminal.App.Services.Test.csproj
test:
assemblies:
only:
- '**\*.Test.dll'
deploy: off