Compare commits

..
146 changed files with 999 additions and 3208 deletions

No files matched your search

-1
View File
@@ -2,7 +2,6 @@
FluentTerminal.App/Win32
FluentTerminal.App/Client/
FluentTerminal.Client/dist
/.sonarqube
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
@@ -1,157 +0,0 @@
using FluentAssertions;
using FluentTerminal.App.Services.Implementation;
using FluentTerminal.Models.Enums;
using System.Collections.Generic;
using System.Linq;
using Xunit;
namespace FluentTerminal.App.Services.Test
{
public class DefaultValueProviderTests
{
public static IEnumerable<object[]> Commands => System.Enum.GetValues(typeof(Command)).Cast<Command>().Select(x => new object[] { x });
[Fact]
public void GetDefaultApplicationSettings_Default_DoesNotReturnNull()
{
var defaultValueProvider = new DefaultValueProvider();
var applicationSettings = defaultValueProvider.GetDefaultApplicationSettings();
applicationSettings.Should().NotBeNull();
}
[Theory]
[MemberData(nameof(Commands))]
public void GetDefaultKeyBindings_AllCommands_ReturnsANonEmptyList(Command command)
{
var defaultValueProvider = new DefaultValueProvider();
var keyBindings = defaultValueProvider.GetDefaultKeyBindings(command);
keyBindings.Should().NotBeNullOrEmpty();
}
[Fact]
public void GetDefaultShellProfileId_Default_DoesNotReturnEmptyGuid()
{
var defaultValueProvider = new DefaultValueProvider();
var defaultShellProfileId = defaultValueProvider.GetDefaultShellProfileId();
defaultShellProfileId.Should().NotBeEmpty();
}
[Fact]
public void GetDefaultShellProfileId_Default_IdIsOneOfThePreInstalledShellProfiles()
{
var defaultValueProvider = new DefaultValueProvider();
var shellProfiles = defaultValueProvider.GetPreinstalledShellProfiles();
var defaultShellProfileId = defaultValueProvider.GetDefaultShellProfileId();
shellProfiles.Select(x => x.Id).Should().Contain(defaultShellProfileId);
}
[Fact]
public void GetDefaultTerminalOptions_Default_DoesNotReturnNull()
{
var defaultValueProvider = new DefaultValueProvider();
var defaultTerminalOptions = defaultValueProvider.GetDefaultTerminalOptions();
defaultTerminalOptions.Should().NotBeNull();
}
[Fact]
public void GetDefaultThemeId_Default_DoesNotReturnEmptyGuid()
{
var defaultValueProvider = new DefaultValueProvider();
var defaultThemeId = defaultValueProvider.GetDefaultThemeId();
defaultThemeId.Should().NotBeEmpty();
}
[Fact]
public void GetDefaultThemeId_Default_IdIsOneOfThePreInstalledThemes()
{
var defaultValueProvider = new DefaultValueProvider();
var themes = defaultValueProvider.GetPreInstalledThemes();
var defaultThemeId = defaultValueProvider.GetDefaultThemeId();
themes.Select(x => x.Id).Should().Contain(defaultThemeId);
}
[Fact]
public void GetPreinstalledShellProfiles_Default_ReturnsANonEmptyList()
{
var defaultValueProvider = new DefaultValueProvider();
var shellProfiles = defaultValueProvider.GetPreinstalledShellProfiles();
shellProfiles.Should().NotBeNullOrEmpty();
}
[Fact]
public void GetPreinstalledShellProfiles_Default_HaveUniqueIds()
{
var defaultValueProvider = new DefaultValueProvider();
var shellProfiles = defaultValueProvider.GetPreinstalledShellProfiles();
shellProfiles.Select(x => x.Id).Should().OnlyHaveUniqueItems();
}
[Fact]
public void GetPreinstalledShellProfiles_Default_HavePreInstalledSetToTrue()
{
var defaultValueProvider = new DefaultValueProvider();
var shellProfiles = defaultValueProvider.GetPreinstalledShellProfiles();
shellProfiles.Select(x => x.PreInstalled).Should().AllBeEquivalentTo(true);
}
[Fact]
public void GetPreinstalledShellProfiles_Default_HaveNonEmptyLocations()
{
var defaultValueProvider = new DefaultValueProvider();
var shellProfiles = defaultValueProvider.GetPreinstalledShellProfiles();
shellProfiles.Select(x => x.Location).Should().NotBeNullOrEmpty();
}
[Fact]
public void GetPreInstalledThemes_Default_ReturnsANonEmptyList()
{
var defaultValueProvider = new DefaultValueProvider();
var themes = defaultValueProvider.GetPreInstalledThemes();
themes.Should().NotBeNullOrEmpty();
}
[Fact]
public void GetPreinstalledThemes_Default_HaveUniqueIds()
{
var defaultValueProvider = new DefaultValueProvider();
var themes = defaultValueProvider.GetPreInstalledThemes();
themes.Select(x => x.Id).Should().OnlyHaveUniqueItems();
}
[Fact]
public void GetPreinstalledThemes_Default_HavePreInstalledSetToTrue()
{
var defaultValueProvider = new DefaultValueProvider();
var themes = defaultValueProvider.GetPreInstalledThemes();
themes.Select(x => x.PreInstalled).Should().AllBeEquivalentTo(true);
}
}
}
@@ -1,11 +1,11 @@
using AutoFixture;
using System;
using System.Linq;
using System.Threading.Tasks;
using AutoFixture;
using FluentAssertions;
using FluentTerminal.App.Services.Dialogs;
using FluentTerminal.App.Services.Implementation;
using Moq;
using System;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace FluentTerminal.App.Services.Test
@@ -20,77 +20,41 @@ namespace FluentTerminal.App.Services.Test
}
[Fact]
public void ShowCreateKeyBindingDialog_Default_UsesCreateKeyBindingDialog()
{
var createKeyBindingDialog = new Mock<ICreateKeyBindingDialog>();
var dialogService = new DialogService(Mock.Of<IShellProfileSelectionDialog>, Mock.Of<IMessageDialog>, () => createKeyBindingDialog.Object);
dialogService.ShowCreateKeyBindingDialog();
createKeyBindingDialog.Verify(x => x.CreateKeyBinding(), Times.Once);
}
[Fact]
public void ShowMessageDialogAsnyc_TitleIsEmpty_ThrowsArgumentNullException()
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<IShellProfileSelectionDialog>, Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>);
var dialogService = new DialogService(() => Mock.Of<IShellProfileSelectionDialog>(), () => Mock.Of<IMessageDialog>(), () => Mock.Of<ICreateKeyBindingDialog>());
Func<Task<DialogButton>> showMessageDialogAsnyc = () => dialogService.ShowMessageDialogAsnyc(title, content, buttons.ElementAt(0), buttons.ElementAt(1));
Func<Task<DialogButton>> invoke = () => dialogService.ShowMessageDialogAsnyc(title, content, buttons.ElementAt(0), buttons.ElementAt(1));
showMessageDialogAsnyc.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("title");
invoke.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("title");
}
[Fact]
public void ShowMessageDialogAsnyc_ContentIsEmpty_ThrowsArgumentNullException()
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<IShellProfileSelectionDialog>, Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>);
var dialogService = new DialogService(() => Mock.Of<IShellProfileSelectionDialog>(), () => Mock.Of<IMessageDialog>(), () => Mock.Of<ICreateKeyBindingDialog>());
Func<Task<DialogButton>> showMessageDialogAsnyc = () => dialogService.ShowMessageDialogAsnyc(title, content, buttons.ElementAt(0), buttons.ElementAt(1));
Func<Task<DialogButton>> invoke = () => dialogService.ShowMessageDialogAsnyc(title, content, buttons.ElementAt(0), buttons.ElementAt(1));
showMessageDialogAsnyc.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("content");
invoke.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("content");
}
[Fact]
public void ShowMessageDialogAsnyc_NoButtonsPassed_ThrowsArgumentException()
public void ShowDialogAsync_NoButtonsPassed_ThrowsArgumentException()
{
var title = _fixture.Create<string>();
var content = _fixture.Create<string>();
var dialogService = new DialogService(Mock.Of<IShellProfileSelectionDialog>, Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>);
var dialogService = new DialogService(() => Mock.Of<IShellProfileSelectionDialog>(), () => Mock.Of<IMessageDialog>(), () => Mock.Of<ICreateKeyBindingDialog>());
Func<Task<DialogButton>> showMessageDialogAsnyc = () => dialogService.ShowMessageDialogAsnyc(title, content);
Func<Task<DialogButton>> invoke = () => dialogService.ShowMessageDialogAsnyc(title, content);
showMessageDialogAsnyc.Should().Throw<ArgumentException>().And.ParamName.Should().Be("buttons");
}
[Fact]
public void ShowMessageDialogAsnyc_Default_UsesMessageDialog()
{
var title = _fixture.Create<string>();
var content = _fixture.Create<string>();
var buttons = _fixture.CreateMany<DialogButton>(2);
var messageDialog = new Mock<IMessageDialog>();
var dialogService = new DialogService(Mock.Of<IShellProfileSelectionDialog>, () => messageDialog.Object, Mock.Of<ICreateKeyBindingDialog>);
dialogService.ShowMessageDialogAsnyc(title, content, buttons.ElementAt(0), buttons.ElementAt(1));
messageDialog.Verify(x => x.ShowAsync(), Times.Once);
}
[Fact]
public void ShowProfileSelectionDialogAsync_Default_UsesShellProfileSelectionDialog()
{
var shellProfileSelectionDialog = new Mock<IShellProfileSelectionDialog>();
var dialogService = new DialogService(() => shellProfileSelectionDialog.Object, Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>);
dialogService.ShowProfileSelectionDialogAsync();
shellProfileSelectionDialog.Verify(x => x.SelectProfile(), Times.Once);
invoke.Should().Throw<ArgumentException>().And.ParamName.Should().Be("buttons");
}
}
}
}
@@ -6,27 +6,16 @@
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<None Remove="TestData\AdventureTime.itermcolors" />
</ItemGroup>
<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="Newtonsoft.Json" Version="11.0.2" />
<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>
<EmbeddedResource Include="TestData\AdventureTime.itermcolors">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FluentTerminal.App.Services\FluentTerminal.App.Services.csproj" />
</ItemGroup>
@@ -1,80 +0,0 @@
using AutoFixture;
using FluentAssertions;
using FluentTerminal.App.Services.Implementation;
using FluentTerminal.Models;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace FluentTerminal.App.Services.Test
{
public class FluentTerminalThemeParserTests
{
private readonly Fixture _fixture;
public FluentTerminalThemeParserTests()
{
_fixture = new Fixture();
}
[Fact]
public async Task Parse_ValidFileStream_ReturnsTheme()
{
var theme = _fixture.Create<TerminalTheme>();
var serialized = JsonConvert.SerializeObject(theme);
var stream = new MemoryStream(Encoding.UTF8.GetBytes(serialized));
var parser = new FluentTerminalThemeParser();
var parsedTheme = await parser.Parse(theme.Name, stream);
parsedTheme.Name.Should().Be(theme.Name);
parsedTheme.Author.Should().Be(theme.Author);
parsedTheme.PreInstalled.Should().Be(false);
parsedTheme.Colors.Should().BeEquivalentTo(theme.Colors);
}
[Fact]
public void Parse_InvalidFileStream_ThrowsException()
{
var fileName = _fixture.Create<string>();
var serialized = _fixture.Create<string>();
var stream = new MemoryStream(Encoding.UTF8.GetBytes(serialized));
var parser = new FluentTerminalThemeParser();
Func<Task<TerminalTheme>> parse = () => parser.Parse(fileName, stream);
parse.Should().Throw<Exception>();
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public void Parse_InvalidFileName_ThrowsArgumentNullException(string fileName)
{
var theme = _fixture.Create<TerminalTheme>();
var serialized = JsonConvert.SerializeObject(theme);
var stream = new MemoryStream(Encoding.UTF8.GetBytes(serialized));
var parser = new FluentTerminalThemeParser();
Func<Task<TerminalTheme>> parse = () => parser.Parse(fileName, stream);
parse.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("fileName");
}
[Fact]
public void Parse_FileStreamIsNull_ThrowsArgumentNullException()
{
var fileName = _fixture.Create<string>();
Stream stream = null;
var parser = new FluentTerminalThemeParser();
Func<Task<TerminalTheme>> parse = () => parser.Parse(fileName, stream);
parse.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("fileContent");
}
}
}
@@ -1,91 +0,0 @@
using AutoFixture;
using FluentAssertions;
using FluentTerminal.App.Services.Implementation;
using FluentTerminal.Models;
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace FluentTerminal.App.Services.Test
{
public class ITermThemeParserTests
{
private readonly Fixture _fixture;
public ITermThemeParserTests()
{
_fixture = new Fixture();
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public void Parse_InvalidFileName_ThrowsArgumentNullException(string fileName)
{
var stream = typeof(ITermThemeParserTests).Assembly.GetManifestResourceStream("FluentTerminal.App.Services.Test.TestData.AdventureTime.itermcolors");
var parser = new ITermThemeParser();
Func<Task<TerminalTheme>> parse = () => parser.Parse(fileName, stream);
parse.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("fileName");
}
[Fact]
public void Parse_FileStreamIsNull_ThrowsArgumentNullException()
{
var fileName = _fixture.Create<string>();
Stream stream = null;
var parser = new ITermThemeParser();
Func<Task<TerminalTheme>> parse = () => parser.Parse(fileName, stream);
parse.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("fileContent");
}
[Fact]
public void Parse_InvalidFileStream_ThrowsException()
{
var fileName = _fixture.Create<string>();
var serialized = _fixture.Create<string>();
var stream = new MemoryStream(Encoding.UTF8.GetBytes(serialized));
var parser = new ITermThemeParser();
Func<Task<TerminalTheme>> parse = () => parser.Parse(fileName, stream);
parse.Should().Throw<Exception>();
}
[Fact]
public async Task Parse_ValidThemeFile_ParsesCorrectly()
{
var fileName = _fixture.Create<string>();
var stream = typeof(ITermThemeParserTests).Assembly.GetManifestResourceStream("FluentTerminal.App.Services.Test.TestData.AdventureTime.itermcolors");
var parser = new ITermThemeParser();
var theme = await parser.Parse(fileName, stream);
theme.Colors.Background.ToLower().Should().Be("#1f1d45");
theme.Colors.Cursor.ToLower().Should().Be("#efbf38");
theme.Colors.Foreground.ToLower().Should().Be("#f8dcc0");
theme.Colors.Black.ToLower().Should().Be("#050404");
theme.Colors.Red.ToLower().Should().Be("#bd0013");
theme.Colors.Green.ToLower().Should().Be("#4ab118");
theme.Colors.Yellow.ToLower().Should().Be("#e7741e");
theme.Colors.Blue.ToLower().Should().Be("#0f4ac6");
theme.Colors.Magenta.ToLower().Should().Be("#665993");
theme.Colors.Cyan.ToLower().Should().Be("#70a598");
theme.Colors.White.ToLower().Should().Be("#f8dcc0");
theme.Colors.BrightBlack.ToLower().Should().Be("#4e7cbf");
theme.Colors.BrightRed.ToLower().Should().Be("#fc5f5a");
theme.Colors.BrightGreen.ToLower().Should().Be("#9eff6e");
theme.Colors.BrightYellow.ToLower().Should().Be("#efc11a");
theme.Colors.BrightBlue.ToLower().Should().Be("#1997c6");
theme.Colors.BrightMagenta.ToLower().Should().Be("#9b5953");
theme.Colors.BrightCyan.ToLower().Should().Be("#c8faf4");
theme.Colors.BrightWhite.ToLower().Should().Be("#f6f5fb");
}
}
}
@@ -66,4 +66,4 @@ namespace FluentTerminal.App.Services.Test
invoke.Should().Throw<KeyNotFoundException>();
}
}
}
}
@@ -1,705 +0,0 @@
using AutoFixture;
using FluentAssertions;
using FluentTerminal.App.Services.Implementation;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using Moq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Xunit;
namespace FluentTerminal.App.Services.Test
{
public class SettingsServiceTests
{
private readonly Fixture _fixture;
public SettingsServiceTests()
{
_fixture = new Fixture();
}
[Fact]
public void Constructor_Default_WritesAllPreinstalledThemesInThemeContainer()
{
var themes = _fixture.CreateMany<TerminalTheme>(3);
var defaultValueProvider = new Mock<IDefaultValueProvider>();
defaultValueProvider.Setup(x => x.GetPreInstalledThemes()).Returns(themes);
var themesContainer = new Mock<IApplicationDataContainer>();
var applicationDataContainers = new ApplicationDataContainers
{
Themes = themesContainer.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
new SettingsService(defaultValueProvider.Object, applicationDataContainers);
defaultValueProvider.Verify(x => x.GetPreInstalledThemes(), Times.Once);
foreach (var theme in themes)
{
themesContainer.Verify(x => x.WriteValueAsJson(theme.Id.ToString(), theme), Times.Once);
}
}
[Fact]
public void Constructor_Default_WritesAllPreinstalledShellProfilesInShellProfilesContainer()
{
var shellProfiles = _fixture.CreateMany<ShellProfile>(3);
var defaultValueProvider = new Mock<IDefaultValueProvider>();
defaultValueProvider.Setup(x => x.GetPreinstalledShellProfiles()).Returns(shellProfiles);
var shellProfilesContainer = new Mock<IApplicationDataContainer>();
var applicationDataContainers = new ApplicationDataContainers
{
ShellProfiles = shellProfilesContainer.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>()
};
new SettingsService(defaultValueProvider.Object, applicationDataContainers);
defaultValueProvider.Verify(x => x.GetPreinstalledShellProfiles(), Times.Once);
foreach (var shellProfile in shellProfiles)
{
shellProfilesContainer.Verify(x => x.WriteValueAsJson(shellProfile.Id.ToString(), shellProfile), Times.Once);
}
}
[Fact]
public void GetCurrentThemeId_ValueExistsInRoamingSettings_ReturnsCurrentThemeId()
{
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var roamingSettings = new Mock<IApplicationDataContainer>();
var currentThemeId = (object)_fixture.Create<Guid>();
roamingSettings.Setup(x => x.TryGetValue(SettingsService.CurrentThemeKey, out currentThemeId)).Returns(true);
var applicationDataContainers = new ApplicationDataContainers
{
RoamingSettings = roamingSettings.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
var result = settingsService.GetCurrentThemeId();
result.Should().Be((Guid)currentThemeId);
roamingSettings.Verify(x => x.TryGetValue(SettingsService.CurrentThemeKey, out currentThemeId), Times.Once);
}
[Fact]
public void GetCurrentThemeId_ValueDoesNotExistInRoamingSettings_ReturnsDefaultThemeIdFromDefaultValueProvider()
{
var defaultValueProvider = new Mock<IDefaultValueProvider>();
var defaultThemeId = _fixture.Create<Guid>();
defaultValueProvider.Setup(x => x.GetDefaultThemeId()).Returns(defaultThemeId);
var roamingSettings = new Mock<IApplicationDataContainer>();
var currentThemeId = (object)_fixture.Create<Guid>();
roamingSettings.Setup(x => x.TryGetValue(SettingsService.CurrentThemeKey, out currentThemeId)).Returns(false);
var applicationDataContainers = new ApplicationDataContainers
{
RoamingSettings = roamingSettings.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider.Object, applicationDataContainers);
var result = settingsService.GetCurrentThemeId();
result.Should().Be(defaultThemeId);
defaultValueProvider.Verify(x => x.GetDefaultThemeId(), Times.Once);
roamingSettings.Verify(x => x.TryGetValue(SettingsService.CurrentThemeKey, out currentThemeId), Times.Once);
}
[Fact]
public void SaveCurrentThemeId_Default_SetsValueOnRoamingSettings()
{
var currentThemeId = _fixture.Create<Guid>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var roamingSettings = new Mock<IApplicationDataContainer>();
var applicationDataContainers = new ApplicationDataContainers
{
RoamingSettings = roamingSettings.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
settingsService.SaveCurrentThemeId(currentThemeId);
roamingSettings.Verify(x => x.SetValue(SettingsService.CurrentThemeKey, currentThemeId), Times.Once);
}
[Fact]
public void SaveCurrentThemeId_Default_InvokesCurrentThemeChangedEvent()
{
var currentThemeId = _fixture.Create<Guid>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var roamingSettings = new Mock<IApplicationDataContainer>();
var applicationDataContainers = new ApplicationDataContainers
{
RoamingSettings = roamingSettings.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>()
};
var currentThemeChangedEventInvoked = false;
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
settingsService.CurrentThemeChanged += (s, e) => currentThemeChangedEventInvoked = true;
settingsService.SaveCurrentThemeId(currentThemeId);
currentThemeChangedEventInvoked.Should().BeTrue();
}
[Fact]
public void SaveTheme_Default_WritesToThemesContainer()
{
var theme = _fixture.Create<TerminalTheme>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var themesContainer = new Mock<IApplicationDataContainer>();
var applicationDataContainers = new ApplicationDataContainers
{
Themes = themesContainer.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
settingsService.SaveTheme(theme);
themesContainer.Verify(x => x.WriteValueAsJson(theme.Id.ToString(), theme), Times.Once);
}
[Fact]
public void SaveTheme_ThemeIsCurrentTheme_InvokesCurrentThemeChangedEvent()
{
var theme = _fixture.Create<TerminalTheme>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var themesContainer = new Mock<IApplicationDataContainer>();
var roamingSettings = new Mock<IApplicationDataContainer>();
var currentThemeId = (object)theme.Id;
roamingSettings.Setup(x => x.TryGetValue(SettingsService.CurrentThemeKey, out currentThemeId)).Returns(true);
var currentThemeChangedEventInvoked = false;
var applicationDataContainers = new ApplicationDataContainers
{
Themes = themesContainer.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
RoamingSettings = roamingSettings.Object,
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
settingsService.CurrentThemeChanged += (s, e) => currentThemeChangedEventInvoked = true;
settingsService.SaveTheme(theme);
currentThemeChangedEventInvoked.Should().BeTrue();
}
[Fact]
public void DeleteTheme_Default_CallsDeleteOnThemesContainer()
{
var themeId = _fixture.Create<Guid>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var themesContainer = new Mock<IApplicationDataContainer>();
var applicationDataContainers = new ApplicationDataContainers
{
Themes = themesContainer.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
settingsService.DeleteTheme(themeId);
themesContainer.Verify(x => x.Delete(themeId.ToString()), Times.Once);
}
[Fact]
public void GetThemes_Default_CallsGetAllOnThemesContainer()
{
var themes = _fixture.CreateMany<TerminalTheme>(3);
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var themesContainer = new Mock<IApplicationDataContainer>();
themesContainer.Setup(x => x.GetAll()).Returns(themes.Select(JsonConvert.SerializeObject));
var applicationDataContainers = new ApplicationDataContainers
{
Themes = themesContainer.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
var result = settingsService.GetThemes();
result.Should().BeEquivalentTo(themes);
themesContainer.Verify(x => x.GetAll(), Times.Once);
}
[Fact]
public void GetTheme_ValidThemeId_ReturnsThemeFromThemesContainer()
{
var theme = _fixture.Create<TerminalTheme>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var themesContainer = new Mock<IApplicationDataContainer>();
themesContainer.Setup(x => x.ReadValueFromJson(theme.Id.ToString(), default(TerminalTheme))).Returns(theme);
var applicationDataContainers = new ApplicationDataContainers
{
Themes = themesContainer.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
var result = settingsService.GetTheme(theme.Id);
result.Should().BeEquivalentTo(theme);
themesContainer.Verify(x => x.ReadValueFromJson(theme.Id.ToString(), default(TerminalTheme)), Times.Once);
}
[Fact]
public void GetTheme_UnknownThemeId_ReturnsNull()
{
var themeId = _fixture.Create<Guid>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var themesContainer = new Mock<IApplicationDataContainer>();
themesContainer.Setup(x => x.ReadValueFromJson(themeId.ToString(), default(TerminalTheme))).Returns(value: null);
var applicationDataContainers = new ApplicationDataContainers
{
Themes = themesContainer.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
var result = settingsService.GetTheme(themeId);
result.Should().BeNull();
themesContainer.Verify(x => x.ReadValueFromJson(themeId.ToString(), default(TerminalTheme)), Times.Once);
}
[Fact]
public void GetTerminalOptions_Default_ReturnsTerminalOptionsFromRoamingSettings()
{
var terminalOptions = _fixture.Create<TerminalOptions>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var roamingSettings = new Mock<IApplicationDataContainer>();
roamingSettings.Setup(x => x.ReadValueFromJson(nameof(TerminalOptions), It.IsAny<TerminalOptions>())).Returns(terminalOptions);
var applicationDataContainers = new ApplicationDataContainers
{
RoamingSettings = roamingSettings.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
var result = settingsService.GetTerminalOptions();
result.Should().BeEquivalentTo(terminalOptions);
roamingSettings.Verify(x => x.ReadValueFromJson(nameof(TerminalOptions), It.IsAny<TerminalOptions>()), Times.Once);
}
[Fact]
public void SaveTerminalOptions_Default_WritesToRoamingSettings()
{
var terminalOptions = _fixture.Create<TerminalOptions>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var roamingSettings = new Mock<IApplicationDataContainer>();
var applicationDataContainers = new ApplicationDataContainers
{
RoamingSettings = roamingSettings.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
settingsService.SaveTerminalOptions(terminalOptions);
roamingSettings.Verify(x => x.WriteValueAsJson(nameof(TerminalOptions), terminalOptions), Times.Once);
}
[Fact]
public void SaveTerminalOptions_Default_InvokesTerminalOptionsChangedEvent()
{
var terminalOptions = _fixture.Create<TerminalOptions>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var roamingSettings = new Mock<IApplicationDataContainer>();
var terminalOptionsChangedEventInvoked = false;
var applicationDataContainers = new ApplicationDataContainers
{
RoamingSettings = roamingSettings.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
settingsService.TerminalOptionsChanged += (s, e) => terminalOptionsChangedEventInvoked = true;
settingsService.SaveTerminalOptions(terminalOptions);
terminalOptionsChangedEventInvoked.Should().BeTrue();
}
[Fact]
public void GetApplicationSettings_Default_ReturnsApplicationSettingsFromRoamingSettings()
{
var applicationSettings = _fixture.Create<ApplicationSettings>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var roamingSettings = new Mock<IApplicationDataContainer>();
roamingSettings.Setup(x => x.ReadValueFromJson(nameof(ApplicationSettings), It.IsAny<ApplicationSettings>())).Returns(applicationSettings);
var applicationDataContainers = new ApplicationDataContainers
{
RoamingSettings = roamingSettings.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
var result = settingsService.GetApplicationSettings();
result.Should().BeEquivalentTo(applicationSettings);
roamingSettings.Verify(x => x.ReadValueFromJson(nameof(ApplicationSettings), It.IsAny<ApplicationSettings>()), Times.Once);
}
[Fact]
public void SaveApplicationSettings_Default_WritesToRoamingSettings()
{
var applicationSettings = _fixture.Create<ApplicationSettings>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var roamingSettings = new Mock<IApplicationDataContainer>();
var applicationDataContainers = new ApplicationDataContainers
{
RoamingSettings = roamingSettings.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
settingsService.SaveApplicationSettings(applicationSettings);
roamingSettings.Verify(x => x.WriteValueAsJson(nameof(ApplicationSettings), applicationSettings), Times.Once);
}
[Fact]
public void SaveApplicationSettings_Default_InvokesApplicationSettingsChangedEvent()
{
var applicationSettings = _fixture.Create<ApplicationSettings>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var roamingSettings = new Mock<IApplicationDataContainer>();
var applicationSettingsChangedEventInvoked = false;
var applicationDataContainers = new ApplicationDataContainers
{
RoamingSettings = roamingSettings.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
settingsService.ApplicationSettingsChanged += (s, e) => applicationSettingsChangedEventInvoked = true;
settingsService.SaveApplicationSettings(applicationSettings);
applicationSettingsChangedEventInvoked.Should().BeTrue();
}
[Fact]
public void GetKeyBindings_KeyBindingsInKeyBindingsContainer_ReturnsKeyBindingsFromKeyBindingsContainer()
{
var keyBindings = _fixture.CreateMany<KeyBinding>(5);
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var keyBindingsContainer = new Mock<IApplicationDataContainer>();
foreach (var keyBinding in keyBindings)
{
keyBindingsContainer.Setup(x => x.ReadValueFromJson<Collection<KeyBinding>>(keyBinding.Command.ToString(), null)).Returns(new Collection<KeyBinding> { keyBinding });
}
var applicationDataContainers = new ApplicationDataContainers
{
KeyBindings = keyBindingsContainer.Object,
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
var result = settingsService.GetKeyBindings();
foreach (var keyBinding in keyBindings)
{
keyBindingsContainer.Verify(x => x.ReadValueFromJson<Collection<KeyBinding>>(keyBinding.Command.ToString(), null), Times.Once);
}
}
[Fact]
public void GetKeyBindings_KeyBindingsNotInKeyBindingsContainer_ReturnsKeyBindingsFromDefaultValueProvider()
{
var keyBindings = _fixture.CreateMany<KeyBinding>(5);
var defaultValueProvider = new Mock<IDefaultValueProvider>();
var keyBindingsContainer = new Mock<IApplicationDataContainer>();
foreach (var keyBinding in keyBindings)
{
keyBindingsContainer.Setup(x => x.ReadValueFromJson<Collection<KeyBinding>>(keyBinding.Command.ToString(), null)).Returns(new Collection<KeyBinding> { keyBinding });
}
var applicationDataContainers = new ApplicationDataContainers
{
KeyBindings = keyBindingsContainer.Object,
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider.Object, applicationDataContainers);
var result = settingsService.GetKeyBindings();
foreach (Command command in Enum.GetValues(typeof(Command)))
{
if (keyBindings.Select(x => x.Command).Contains(command))
{
continue;
}
defaultValueProvider.Verify(x => x.GetDefaultKeyBindings(command), Times.Once);
}
}
[Fact]
public void SaveKeyBindings_Default_WritesToKeyBindingsContainer()
{
var command = _fixture.Create<Command>();
var keyBindings = _fixture.Create<ICollection<KeyBinding>>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var keyBindingsContainer = new Mock<IApplicationDataContainer>();
var applicationDataContainers = new ApplicationDataContainers
{
KeyBindings = keyBindingsContainer.Object,
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
settingsService.SaveKeyBindings(command, keyBindings);
keyBindingsContainer.Verify(x => x.WriteValueAsJson(command.ToString(), keyBindings), Times.Once);
}
[Fact]
public void SaveKeyBindings_Default_InvokesKeyBindingsChangedEvent()
{
var command = _fixture.Create<Command>();
var keyBindings = _fixture.Create<Collection<KeyBinding>>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var keyBindingsContainer = new Mock<IApplicationDataContainer>();
var keyBindingsChangedEventInvoked = false;
var applicationDataContainers = new ApplicationDataContainers
{
KeyBindings = keyBindingsContainer.Object,
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
settingsService.KeyBindingsChanged += (s, e) => keyBindingsChangedEventInvoked = true;
settingsService.SaveKeyBindings(command, keyBindings);
keyBindingsChangedEventInvoked.Should().BeTrue();
}
[Fact]
public void ResetKeyBindings_Default_WritesToKeyBindingsContainerFromDefaultValueProvider()
{
var defaultValueProvider = new Mock<IDefaultValueProvider>();
var keyBindingsContainer = new Mock<IApplicationDataContainer>();
var applicationDataContainers = new ApplicationDataContainers
{
KeyBindings = keyBindingsContainer.Object,
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider.Object, applicationDataContainers);
settingsService.ResetKeyBindings();
foreach (Command command in Enum.GetValues(typeof(Command)))
{
keyBindingsContainer.Verify(x => x.WriteValueAsJson(command.ToString(), It.IsAny<ICollection<KeyBinding>>()), Times.Once);
defaultValueProvider.Verify(x => x.GetDefaultKeyBindings(command), Times.Once);
}
}
[Fact]
public void ResetKeyBindings_Default_InvokesKeyBindingsChangedEvent()
{
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var keyBindingsContainer = new Mock<IApplicationDataContainer>();
var keyBindingsChangedEventInvoked = false;
var applicationDataContainers = new ApplicationDataContainers
{
KeyBindings = keyBindingsContainer.Object,
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
settingsService.KeyBindingsChanged += (s, e) => keyBindingsChangedEventInvoked = true;
settingsService.ResetKeyBindings();
keyBindingsChangedEventInvoked.Should().BeTrue();
}
[Fact]
public void GetDefaultShellProfileId_ValueExistsInRoamingSettings_ReturnsDefaultShellProfileId()
{
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var roamingSettings = new Mock<IApplicationDataContainer>();
var defaultShellProfileId = (object)_fixture.Create<Guid>();
roamingSettings.Setup(x => x.TryGetValue(SettingsService.DefaultShellProfileKey, out defaultShellProfileId)).Returns(true);
var applicationDataContainers = new ApplicationDataContainers
{
RoamingSettings = roamingSettings.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
var result = settingsService.GetDefaultShellProfileId();
result.Should().Be((Guid)defaultShellProfileId);
roamingSettings.Verify(x => x.TryGetValue(SettingsService.DefaultShellProfileKey, out defaultShellProfileId), Times.Once);
}
[Fact]
public void GetDefaultShellProfileId_ValueDoesNotExistInRoamingSettings_ReturnsDefaultShellProfileIdFromDefaultValueProvider()
{
var defaultValueProvider = new Mock<IDefaultValueProvider>();
var defaultShellProfileId = _fixture.Create<Guid>();
defaultValueProvider.Setup(x => x.GetDefaultShellProfileId()).Returns(defaultShellProfileId);
var roamingSettings = new Mock<IApplicationDataContainer>();
var currentDefaultShellProfileId = (object)_fixture.Create<Guid>();
roamingSettings.Setup(x => x.TryGetValue(SettingsService.DefaultShellProfileKey, out currentDefaultShellProfileId)).Returns(false);
var applicationDataContainers = new ApplicationDataContainers
{
RoamingSettings = roamingSettings.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
ShellProfiles = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider.Object, applicationDataContainers);
var result = settingsService.GetDefaultShellProfileId();
result.Should().Be(defaultShellProfileId);
defaultValueProvider.Verify(x => x.GetDefaultShellProfileId(), Times.Once);
roamingSettings.Verify(x => x.TryGetValue(SettingsService.DefaultShellProfileKey, out currentDefaultShellProfileId), Times.Once);
}
[Fact]
public void GetShellProfiles_Default_CallsGetAllOnShellProfilesContainer()
{
var shellProfiles = _fixture.CreateMany<ShellProfile>(3);
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var shellProfilesContainer = new Mock<IApplicationDataContainer>();
shellProfilesContainer.Setup(x => x.GetAll()).Returns(shellProfiles.Select(JsonConvert.SerializeObject));
var applicationDataContainers = new ApplicationDataContainers
{
ShellProfiles = shellProfilesContainer.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
var result = settingsService.GetShellProfiles();
result.Should().BeEquivalentTo(shellProfiles);
shellProfilesContainer.Verify(x => x.GetAll(), Times.Once);
}
[Fact]
public void SaveShellProfile_Default_WritesToShellProfilesContainer()
{
var shellProfile = _fixture.Create<ShellProfile>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var shellProfilesContainer = new Mock<IApplicationDataContainer>();
var applicationDataContainers = new ApplicationDataContainers
{
ShellProfiles = shellProfilesContainer.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
settingsService.SaveShellProfile(shellProfile);
shellProfilesContainer.Verify(x => x.WriteValueAsJson(shellProfile.Id.ToString(), shellProfile), Times.Once);
}
[Fact]
public void DeleteShellProfile_Default_CallsDeleteOnShellProfilesContainer()
{
var shellProfileId = _fixture.Create<Guid>();
var defaultValueProvider = Mock.Of<IDefaultValueProvider>();
var shellProfilesContainer = new Mock<IApplicationDataContainer>();
var applicationDataContainers = new ApplicationDataContainers
{
ShellProfiles = shellProfilesContainer.Object,
KeyBindings = Mock.Of<IApplicationDataContainer>(),
LocalSettings = Mock.Of<IApplicationDataContainer>(),
RoamingSettings = Mock.Of<IApplicationDataContainer>(),
Themes = Mock.Of<IApplicationDataContainer>()
};
var settingsService = new SettingsService(defaultValueProvider, applicationDataContainers);
settingsService.DeleteShellProfile(shellProfileId);
shellProfilesContainer.Verify(x => x.Delete(shellProfileId.ToString()), Times.Once);
}
}
}
@@ -1,213 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Ansi 0 Color</key>
<dict>
<key>Blue Component</key>
<real>0.016337040811777115</real>
<key>Green Component</key>
<real>0.016232240945100784</real>
<key>Red Component</key>
<real>0.020433688536286354</real>
</dict>
<key>Ansi 1 Color</key>
<dict>
<key>Blue Component</key>
<real>0.075083047151565552</real>
<key>Green Component</key>
<real>0.0</real>
<key>Red Component</key>
<real>0.73976802825927734</real>
</dict>
<key>Ansi 10 Color</key>
<dict>
<key>Blue Component</key>
<real>0.43171143531799316</real>
<key>Green Component</key>
<real>1</real>
<key>Red Component</key>
<real>0.61819148063659668</real>
</dict>
<key>Ansi 11 Color</key>
<dict>
<key>Blue Component</key>
<real>0.10242157429456711</real>
<key>Green Component</key>
<real>0.7578997015953064</real>
<key>Red Component</key>
<real>0.93761706352233887</real>
</dict>
<key>Ansi 12 Color</key>
<dict>
<key>Blue Component</key>
<real>0.77801346778869629</real>
<key>Green Component</key>
<real>0.59102588891983032</real>
<key>Red Component</key>
<real>0.096501544117927551</real>
</dict>
<key>Ansi 13 Color</key>
<dict>
<key>Blue Component</key>
<real>0.32394066452980042</real>
<key>Green Component</key>
<real>0.34950375556945801</real>
<key>Red Component</key>
<real>0.60686224699020386</real>
</dict>
<key>Ansi 14 Color</key>
<dict>
<key>Blue Component</key>
<real>0.95550096035003662</real>
<key>Green Component</key>
<real>0.97915208339691162</real>
<key>Red Component</key>
<real>0.78500419855117798</real>
</dict>
<key>Ansi 15 Color</key>
<dict>
<key>Blue Component</key>
<real>0.98438382148742676</real>
<key>Green Component</key>
<real>0.96043074131011963</real>
<key>Red Component</key>
<real>0.96449893712997437</real>
</dict>
<key>Ansi 2 Color</key>
<dict>
<key>Blue Component</key>
<real>0.092498354613780975</real>
<key>Green Component</key>
<real>0.6950421929359436</real>
<key>Red Component</key>
<real>0.28945007920265198</real>
</dict>
<key>Ansi 3 Color</key>
<dict>
<key>Blue Component</key>
<real>0.1164485365152359</real>
<key>Green Component</key>
<real>0.45553147792816162</real>
<key>Red Component</key>
<real>0.90543299913406372</real>
</dict>
<key>Ansi 4 Color</key>
<dict>
<key>Blue Component</key>
<real>0.77829605340957642</real>
<key>Green Component</key>
<real>0.28880593180656433</real>
<key>Red Component</key>
<real>0.059818677604198456</real>
</dict>
<key>Ansi 5 Color</key>
<dict>
<key>Blue Component</key>
<real>0.57602518796920776</real>
<key>Green Component</key>
<real>0.35004982352256775</real>
<key>Red Component</key>
<real>0.40191537141799927</real>
</dict>
<key>Ansi 6 Color</key>
<dict>
<key>Blue Component</key>
<real>0.59465551376342773</real>
<key>Green Component</key>
<real>0.64633101224899292</real>
<key>Red Component</key>
<real>0.43781715631484985</real>
</dict>
<key>Ansi 7 Color</key>
<dict>
<key>Blue Component</key>
<real>0.75428962707519531</real>
<key>Green Component</key>
<real>0.86175870895385742</real>
<key>Red Component</key>
<real>0.97308963537216187</real>
</dict>
<key>Ansi 8 Color</key>
<dict>
<key>Blue Component</key>
<real>0.7491685152053833</real>
<key>Green Component</key>
<real>0.48549851775169373</real>
<key>Red Component</key>
<real>0.30726605653762817</real>
</dict>
<key>Ansi 9 Color</key>
<dict>
<key>Blue Component</key>
<real>0.35247993469238281</real>
<key>Green Component</key>
<real>0.37095117568969727</real>
<key>Red Component</key>
<real>0.98876720666885376</real>
</dict>
<key>Background Color</key>
<dict>
<key>Blue Component</key>
<real>0.27054747939109802</real>
<key>Green Component</key>
<real>0.11274909973144531</real>
<key>Red Component</key>
<real>0.12003477662801743</real>
</dict>
<key>Bold Color</key>
<dict>
<key>Blue Component</key>
<real>0.075083047151565552</real>
<key>Green Component</key>
<real>0.0</real>
<key>Red Component</key>
<real>0.73976802825927734</real>
</dict>
<key>Cursor Color</key>
<dict>
<key>Blue Component</key>
<real>0.21945112943649292</real>
<key>Green Component</key>
<real>0.74987590312957764</real>
<key>Red Component</key>
<real>0.93704277276992798</real>
</dict>
<key>Cursor Text Color</key>
<dict>
<key>Blue Component</key>
<real>0.037519864737987518</real>
<key>Green Component</key>
<real>0.032785907387733459</real>
<key>Red Component</key>
<real>0.02988031692802906</real>
</dict>
<key>Foreground Color</key>
<dict>
<key>Blue Component</key>
<real>0.75428962707519531</real>
<key>Green Component</key>
<real>0.86175870895385742</real>
<key>Red Component</key>
<real>0.97308963537216187</real>
</dict>
<key>Selected Text Color</key>
<dict>
<key>Blue Component</key>
<real>0.767447829246521</real>
<key>Green Component</key>
<real>0.85237473249435425</real>
<key>Red Component</key>
<real>0.95287787914276123</real>
</dict>
<key>Selection Color</key>
<dict>
<key>Blue Component</key>
<real>0.30699285864830017</real>
<key>Green Component</key>
<real>0.41871801018714905</real>
<key>Red Component</key>
<real>0.43789717555046082</real>
</dict>
</dict>
</plist>
@@ -1,45 +0,0 @@
using AutoFixture;
using FluentAssertions;
using FluentTerminal.App.Services.Implementation;
using Moq;
using Xunit;
namespace FluentTerminal.App.Services.Test
{
public class ThemeParserFactoryTests
{
private readonly Fixture _fixture;
public ThemeParserFactoryTests()
{
_fixture = new Fixture();
}
[Fact]
public void GetParser_SupportedFileType_ReturnsParser()
{
var supportedFileType = _fixture.Create<string>();
var parser = new Mock<IThemeParser>();
parser.Setup(x => x.SupportedFileTypes).Returns(new string[] { supportedFileType });
var themeParserFactory = new ThemeParserFactory(new IThemeParser[] { parser.Object });
var result = themeParserFactory.GetParser(supportedFileType);
parser.Should().Be(parser);
}
[Fact]
public void GetParser_UnsupportedFileType_ReturnsNull()
{
var unSupportedFileType = _fixture.Create<string>();
var supportedFileType = _fixture.Create<string>();
var parser = new Mock<IThemeParser>();
parser.Setup(x => x.SupportedFileTypes).Returns(new string[] { supportedFileType });
var themeParserFactory = new ThemeParserFactory(new IThemeParser[] { parser.Object });
var result = themeParserFactory.GetParser(unSupportedFileType);
result.Should().BeNull();
}
}
}
@@ -1,200 +0,0 @@
using AutoFixture;
using FluentAssertions;
using FluentTerminal.App.Services.Implementation;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using FluentTerminal.Models.Requests;
using FluentTerminal.Models.Responses;
using Moq;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace FluentTerminal.App.Services.Test
{
public class TrayProcessCommunicationServiceTests
{
private readonly Fixture _fixture;
public TrayProcessCommunicationServiceTests()
{
_fixture = new Fixture();
}
[Fact]
public async Task CreateTerminal_Default_ReturnsResponseFromAppServiceConnection()
{
var settingsService = new Mock<ISettingsService>();
var keyBindings = _fixture.CreateMany<KeyBinding>(3);
settingsService.Setup(x => x.GetKeyBindings()).Returns(new Dictionary<Command, ICollection<KeyBinding>>
{
[Command.ToggleWindow] = keyBindings.ToList()
});
var appServiceConnection = new Mock<IAppServiceConnection>();
var response = _fixture.Create<CreateTerminalResponse>();
var responseMessage = new Dictionary<string, string>
{
[MessageKeys.Type] = _fixture.Create<string>(),
[MessageKeys.Content] = JsonConvert.SerializeObject(response)
};
appServiceConnection.Setup(x => x.SendMessageAsync(It.IsAny<IDictionary<string, string>>())).Returns(Task.FromResult((IDictionary<string, string>)responseMessage));
var terminalSize = _fixture.Create<TerminalSize>();
var shellProfile = _fixture.Create<ShellProfile>();
var trayProcessCommunicationService = new TrayProcessCommunicationService(settingsService.Object);
await trayProcessCommunicationService.Initialize(appServiceConnection.Object);
var result = await trayProcessCommunicationService.CreateTerminal(terminalSize, shellProfile);
result.Should().BeEquivalentTo(response);
}
[Fact]
public async Task Initialize_Default_SendsSetToggleWindowKeyBindingsRequest()
{
var settingsService = new Mock<ISettingsService>();
var keyBindings = _fixture.CreateMany<KeyBinding>(3);
settingsService.Setup(x => x.GetKeyBindings()).Returns(new Dictionary<Command, ICollection<KeyBinding>>
{
[Command.ToggleWindow] = keyBindings.ToList()
});
var appServiceConnection = new Mock<IAppServiceConnection>();
var trayProcessCommunicationService = new TrayProcessCommunicationService(settingsService.Object);
await trayProcessCommunicationService.Initialize(appServiceConnection.Object);
appServiceConnection.Verify(x => x.SendMessageAsync(It.Is<IDictionary<string, string>>(d => d[MessageKeys.Type] == nameof(SetToggleWindowKeyBindingsRequest))), Times.Once);
}
[Fact]
public async Task ResizeTerminal_Default_SendsResizeTerminalRequest()
{
var terminalId = _fixture.Create<int>();
var terminalSize = _fixture.Create<TerminalSize>();
var settingsService = new Mock<ISettingsService>();
var keyBindings = _fixture.CreateMany<KeyBinding>(3);
settingsService.Setup(x => x.GetKeyBindings()).Returns(new Dictionary<Command, ICollection<KeyBinding>>
{
[Command.ToggleWindow] = keyBindings.ToList()
});
var appServiceConnection = new Mock<IAppServiceConnection>();
var trayProcessCommunicationService = new TrayProcessCommunicationService(settingsService.Object);
await trayProcessCommunicationService.Initialize(appServiceConnection.Object);
await trayProcessCommunicationService.ResizeTerminal(terminalId, terminalSize);
appServiceConnection.Verify(x => x.SendMessageAsync(It.Is<IDictionary<string, string>>(d => d[MessageKeys.Type] == nameof(ResizeTerminalRequest))), Times.Once);
}
[Fact]
public async Task WriteText_Default_SendsWriteTextRequest()
{
var terminalId = _fixture.Create<int>();
var text = _fixture.Create<string>();
var settingsService = new Mock<ISettingsService>();
var keyBindings = _fixture.CreateMany<KeyBinding>(3);
settingsService.Setup(x => x.GetKeyBindings()).Returns(new Dictionary<Command, ICollection<KeyBinding>>
{
[Command.ToggleWindow] = keyBindings.ToList()
});
var appServiceConnection = new Mock<IAppServiceConnection>();
var trayProcessCommunicationService = new TrayProcessCommunicationService(settingsService.Object);
await trayProcessCommunicationService.Initialize(appServiceConnection.Object);
await trayProcessCommunicationService.WriteText(terminalId, text);
appServiceConnection.Verify(x => x.SendMessageAsync(It.Is<IDictionary<string, string>>(d => d[MessageKeys.Type] == nameof(WriteTextRequest))), Times.Once);
}
[Fact]
public async Task CloseTerminal_Default_SendsTerminalExitedRequest()
{
var terminalId = _fixture.Create<int>();
var settingsService = new Mock<ISettingsService>();
var keyBindings = _fixture.CreateMany<KeyBinding>(3);
settingsService.Setup(x => x.GetKeyBindings()).Returns(new Dictionary<Command, ICollection<KeyBinding>>
{
[Command.ToggleWindow] = keyBindings.ToList()
});
var appServiceConnection = new Mock<IAppServiceConnection>();
var trayProcessCommunicationService = new TrayProcessCommunicationService(settingsService.Object);
await trayProcessCommunicationService.Initialize(appServiceConnection.Object);
await trayProcessCommunicationService.CloseTerminal(terminalId);
appServiceConnection.Verify(x => x.SendMessageAsync(It.Is<IDictionary<string, string>>(d => d[MessageKeys.Type] == nameof(TerminalExitedRequest))), Times.Once);
}
[Fact]
public async Task OnMessageReceived_TerminalExitedRequest_InvokesTerminalExitedEvent()
{
var terminalId = _fixture.Create<int>();
var receivedTerminalId = 0;
var terminalExitedEventCalled = false;
var request = new TerminalExitedRequest
{
TerminalId = terminalId
};
var message = new Dictionary<string, string>
{
[MessageKeys.Type] = nameof(TerminalExitedRequest),
[MessageKeys.Content] = JsonConvert.SerializeObject(request)
};
var settingsService = new Mock<ISettingsService>();
var keyBindings = _fixture.CreateMany<KeyBinding>(3);
settingsService.Setup(x => x.GetKeyBindings()).Returns(new Dictionary<Command, ICollection<KeyBinding>>
{
[Command.ToggleWindow] = keyBindings.ToList()
});
var trayProcessCommunicationService = new TrayProcessCommunicationService(settingsService.Object);
var appServiceConnection = new Mock<IAppServiceConnection>();
await trayProcessCommunicationService.Initialize(appServiceConnection.Object);
trayProcessCommunicationService.TerminalExited += (s, e) =>
{
terminalExitedEventCalled = true;
receivedTerminalId = e;
};
appServiceConnection.Raise(x => x.MessageReceived += null, null, message);
terminalExitedEventCalled.Should().BeTrue();
receivedTerminalId.Should().Be(terminalId);
}
[Fact]
public async Task OnMessageReceived_DisplayTerminalOutputRequest_InvokesCorrectOutputHandler()
{
var terminalId = _fixture.Create<int>();
var output = _fixture.Create<string>();
var receivedOutput = string.Empty;
var request = new DisplayTerminalOutputRequest
{
TerminalId = terminalId,
Output = output
};
var message = new Dictionary<string, string>
{
[MessageKeys.Type] = nameof(DisplayTerminalOutputRequest),
[MessageKeys.Content] = JsonConvert.SerializeObject(request)
};
var settingsService = new Mock<ISettingsService>();
var keyBindings = _fixture.CreateMany<KeyBinding>(3);
settingsService.Setup(x => x.GetKeyBindings()).Returns(new Dictionary<Command, ICollection<KeyBinding>>
{
[Command.ToggleWindow] = keyBindings.ToList()
});
var trayProcessCommunicationService = new TrayProcessCommunicationService(settingsService.Object);
var appServiceConnection = new Mock<IAppServiceConnection>();
await trayProcessCommunicationService.Initialize(appServiceConnection.Object);
trayProcessCommunicationService.SubscribeForTerminalOutput(terminalId, o =>
{
receivedOutput = o;
});
appServiceConnection.Raise(x => x.MessageReceived += null, null, message);
receivedOutput.Should().Be(output);
}
}
}
@@ -8,4 +8,4 @@
public IApplicationDataContainer KeyBindings { get; set; }
public IApplicationDataContainer ShellProfiles { get; set; }
}
}
}
@@ -7,4 +7,4 @@ namespace FluentTerminal.App.Services.Dialogs
{
Task<KeyBinding> CreateKeyBinding();
}
}
}
@@ -11,4 +11,4 @@ namespace FluentTerminal.App.Services.Dialogs
Task<DialogButton> ShowAsync();
}
}
}
@@ -9,4 +9,4 @@ namespace FluentTerminal.App.Services.Dialogs
Task<ShellProfile> SelectProfile();
}
}
}
@@ -4,4 +4,4 @@
{
public bool Cancelled { get; set; }
}
}
}
@@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace FluentTerminal.App.Services
{
public interface IAppServiceConnection
{
event EventHandler<IDictionary<string, string>> MessageReceived;
Task<IDictionary<string, string>> SendMessageAsync(IDictionary<string, string> message);
}
}
}
@@ -16,4 +16,4 @@ namespace FluentTerminal.App.Services
IEnumerable<object> GetAll();
}
}
}
@@ -13,9 +13,7 @@ namespace FluentTerminal.App.Services
string Title { get; set; }
Task RunOnDispatcherThread(Action action);
Task<bool> TryClose();
bool ToggleFullScreen();
}
}
}
@@ -5,7 +5,6 @@ namespace FluentTerminal.App.Services
public interface IClipboardService
{
Task<string> GetText();
void SetText(string text);
}
}
}
@@ -8,17 +8,11 @@ namespace FluentTerminal.App.Services
public interface IDefaultValueProvider
{
IEnumerable<ShellProfile> GetPreinstalledShellProfiles();
Guid GetDefaultShellProfileId();
TerminalOptions GetDefaultTerminalOptions();
ICollection<KeyBinding> GetDefaultKeyBindings(Command command);
ApplicationSettings GetDefaultApplicationSettings();
Guid GetDefaultThemeId();
IEnumerable<TerminalTheme> GetPreInstalledThemes();
}
}
}
@@ -17,4 +17,4 @@ namespace FluentTerminal.App.Services
Task<KeyBinding> ShowCreateKeyBindingDialog();
}
}
}
@@ -5,7 +5,6 @@ namespace FluentTerminal.App.Services
public interface IDispatcherTimer
{
void Start();
void Stop();
TimeSpan Interval { get; set; }
@@ -13,4 +12,4 @@ namespace FluentTerminal.App.Services
event EventHandler<object> Tick;
}
}
}
@@ -12,4 +12,4 @@ namespace FluentTerminal.App.Services
Task SaveTextFile(string name, string fileTypeDescription, string fileType, string content);
}
}
}
@@ -6,7 +6,6 @@ namespace FluentTerminal.App.Services
public interface IKeyboardCommandService
{
void RegisterCommandHandler(Command command, Action handler);
void SendCommand(Command command);
}
}
}
@@ -8,51 +8,35 @@ namespace FluentTerminal.App.Services
public interface ISettingsService
{
event EventHandler<Guid> CurrentThemeChanged;
event EventHandler<TerminalOptions> TerminalOptionsChanged;
event EventHandler<ApplicationSettings> ApplicationSettingsChanged;
event EventHandler KeyBindingsChanged;
Guid GetDefaultShellProfileId();
ShellProfile GetDefaultShellProfile();
void SaveDefaultShellProfileId(Guid id);
IEnumerable<ShellProfile> GetShellProfiles();
void SaveShellProfile(ShellProfile shellProfile);
void DeleteShellProfile(Guid id);
TerminalOptions GetTerminalOptions();
void SaveTerminalOptions(TerminalOptions terminalOptions);
ApplicationSettings GetApplicationSettings();
void SaveApplicationSettings(ApplicationSettings applicationSettings);
IDictionary<Command, ICollection<KeyBinding>> GetKeyBindings();
void SaveKeyBindings(Command command, ICollection<KeyBinding> keyBindings);
void ResetKeyBindings();
TerminalTheme GetCurrentTheme();
Guid GetCurrentThemeId();
TerminalTheme GetTheme(Guid id);
void SaveCurrentThemeId(Guid id);
IEnumerable<TerminalTheme> GetThemes();
void SaveTheme(TerminalTheme theme);
void DeleteTheme(Guid id);
}
}
}
@@ -6,4 +6,4 @@ namespace FluentTerminal.App.Services
{
IEnumerable<string> GetSystemFontFamilies();
}
}
}
+1 -12
View File
@@ -9,31 +9,20 @@ namespace FluentTerminal.App.Services
public interface ITerminalView
{
event EventHandler<TerminalSize> TerminalSizeChanged;
event EventHandler<string> TerminalTitleChanged;
event EventHandler<Command> KeyboardCommandReceived;
Task ChangeTheme(TerminalColors theme);
Task ChangeOptions(TerminalOptions options);
Task ChangeKeyBindings(IEnumerable<KeyBinding> keyBindings);
Task<TerminalSize> CreateTerminal(TerminalOptions options, TerminalColors theme, IEnumerable<KeyBinding> keyBindings);
Task ConnectToSocket(string url);
void Close();
Task FocusTerminal();
Task<string> GetSelection();
Task Write(string text);
Task FindNext(string searchText);
Task FindPrevious(string searchText);
void FocusSearchTextBox();
}
}
+1 -1
View File
@@ -11,4 +11,4 @@ namespace FluentTerminal.App.Services
Task<TerminalTheme> Parse(string fileName, Stream fileContent);
}
}
}
@@ -8,4 +8,4 @@ namespace FluentTerminal.App.Services
IThemeParser GetParser(string fileType);
}
}
}
@@ -1,26 +1,14 @@
using FluentTerminal.Models;
using FluentTerminal.Models.Responses;
using System;
using System.Threading.Tasks;
namespace FluentTerminal.App.Services
{
public interface ITrayProcessCommunicationService
{
event EventHandler<int> TerminalExited;
Task Initialize(IAppServiceConnection appServiceConnection);
Task<CreateTerminalResponse> CreateTerminal(TerminalSize size, ShellProfile shellProfile);
Task ResizeTerminal(int id, TerminalSize size);
Task UpdateToggleWindowKeyBindings();
Task WriteText(int terminalId, string text);
void SubscribeForTerminalOutput(int terminalId, Action<string> callback);
Task CloseTerminal(int terminalId);
}
}
}
@@ -14,11 +14,7 @@ namespace FluentTerminal.App.Services.Implementation
ConfirmClosingTabs = false,
ConfirmClosingWindows = false,
UnderlineSelectedTab = false,
NewTerminalLocation = NewTerminalLocation.Tab,
TabsPosition = TabsPosition.Top,
CopyOnSelect = false,
MouseMiddleClickAction = MouseAction.None,
MouseRightClickAction = MouseAction.ContextMenu
NewTerminalLocation = NewTerminalLocation.Tab
};
}
@@ -27,7 +23,7 @@ namespace FluentTerminal.App.Services.Implementation
switch (command)
{
case Command.ToggleWindow:
return new List<KeyBinding>
return new List<KeyBinding>
{
new KeyBinding
{
@@ -40,7 +36,7 @@ namespace FluentTerminal.App.Services.Implementation
};
case Command.NextTab:
return new List<KeyBinding>
return new List<KeyBinding>
{
new KeyBinding
{
@@ -53,7 +49,7 @@ namespace FluentTerminal.App.Services.Implementation
};
case Command.PreviousTab:
return new List<KeyBinding>
return new List<KeyBinding>
{
new KeyBinding
{
@@ -66,7 +62,7 @@ namespace FluentTerminal.App.Services.Implementation
};
case Command.NewTab:
return new List<KeyBinding>
return new List<KeyBinding>
{
new KeyBinding
{
@@ -79,7 +75,7 @@ namespace FluentTerminal.App.Services.Implementation
};
case Command.ConfigurableNewTab:
return new List<KeyBinding>
return new List<KeyBinding>
{
new KeyBinding
{
@@ -92,7 +88,7 @@ namespace FluentTerminal.App.Services.Implementation
};
case Command.CloseTab:
return new List<KeyBinding>
return new List<KeyBinding>
{
new KeyBinding
{
@@ -105,7 +101,7 @@ namespace FluentTerminal.App.Services.Implementation
};
case Command.NewWindow:
return new List<KeyBinding>
return new List<KeyBinding>
{
new KeyBinding
{
@@ -118,7 +114,7 @@ namespace FluentTerminal.App.Services.Implementation
};
case Command.ShowSettings:
return new List<KeyBinding>
return new List<KeyBinding>
{
new KeyBinding
{
@@ -131,7 +127,7 @@ namespace FluentTerminal.App.Services.Implementation
};
case Command.Copy:
return new List<KeyBinding>
return new List<KeyBinding>
{
new KeyBinding
{
@@ -144,7 +140,7 @@ namespace FluentTerminal.App.Services.Implementation
};
case Command.Paste:
return new List<KeyBinding>
return new List<KeyBinding>
{
new KeyBinding
{
@@ -157,7 +153,7 @@ namespace FluentTerminal.App.Services.Implementation
};
case Command.Search:
return new List<KeyBinding>
return new List<KeyBinding>
{
new KeyBinding
{
@@ -170,7 +166,7 @@ namespace FluentTerminal.App.Services.Implementation
};
case Command.ToggleFullScreen:
return new List<KeyBinding>
return new List<KeyBinding>
{
new KeyBinding
{
@@ -183,7 +179,7 @@ namespace FluentTerminal.App.Services.Implementation
};
case Command.SelectAll:
return new List<KeyBinding>
return new List<KeyBinding>
{
new KeyBinding
{
@@ -196,7 +192,7 @@ namespace FluentTerminal.App.Services.Implementation
};
case Command.Clear:
return new List<KeyBinding>
return new List<KeyBinding>
{
new KeyBinding
{
@@ -415,18 +411,18 @@ namespace FluentTerminal.App.Services.Implementation
CursorAccent = "#000000",
Selection = "#4DABEDC1",
Black = "#300A24",
Red = "#CC0000",
Red = "#3465A4",
Green = "#4E9A06",
Yellow = "#06989A",
Blue = "#3465A4",
Blue = "#CC0000",
Magenta = "#75507B",
Cyan = "#C4A000",
White = "#D3D7CF",
BrightBlack = "#554E53",
BrightRed = "#EF2929",
BrightRed = "#729FCF",
BrightGreen = "#8AE234",
BrightYellow = "#34E2E2",
BrightBlue = "#729FCF",
BrightBlue = "#EF2929",
BrightMagenta = "#AD7FA8",
BrightCyan = "#FCE94F",
BrightWhite = "#EEEEEE"
@@ -436,4 +432,4 @@ namespace FluentTerminal.App.Services.Implementation
return new[] { defaultXterm, powerShell, homebrew, tomorrow, ubuntu };
}
}
}
}
@@ -1,7 +1,7 @@
using FluentTerminal.App.Services.Dialogs;
using FluentTerminal.Models;
using System;
using System;
using System.Threading.Tasks;
using FluentTerminal.App.Services.Dialogs;
using FluentTerminal.Models;
namespace FluentTerminal.App.Services.Implementation
{
@@ -61,4 +61,4 @@ namespace FluentTerminal.App.Services.Implementation
return dialog.SelectProfile();
}
}
}
}
@@ -1,9 +1,9 @@
using FluentTerminal.Models;
using Newtonsoft.Json;
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using FluentTerminal.Models;
using Newtonsoft.Json;
namespace FluentTerminal.App.Services.Implementation
{
@@ -13,16 +13,6 @@ namespace FluentTerminal.App.Services.Implementation
public async Task<TerminalTheme> Parse(string fileName, Stream fileContent)
{
if (string.IsNullOrWhiteSpace(fileName))
{
throw new ArgumentNullException(nameof(fileName));
}
if (fileContent == null)
{
throw new ArgumentNullException(nameof(fileContent));
}
using (var streamReader = new StreamReader(fileContent))
{
var content = await streamReader.ReadToEndAsync();
@@ -35,4 +25,4 @@ namespace FluentTerminal.App.Services.Implementation
}
}
}
}
}
@@ -53,16 +53,6 @@ namespace FluentTerminal.App.Services.Implementation
public async Task<TerminalTheme> Parse(string fileName, Stream fileContent)
{
if (string.IsNullOrWhiteSpace(fileName))
{
throw new ArgumentNullException(nameof(fileName));
}
if (fileContent == null)
{
throw new ArgumentNullException(nameof(fileContent));
}
var node = PList.Load(fileContent) as DictionaryNode ?? throw new ParseThemeException("Root node was not a dictionary.");
return new TerminalTheme
@@ -134,4 +124,4 @@ namespace FluentTerminal.App.Services.Implementation
return (alpha / 256.0).ToString(CultureInfo.InvariantCulture);
}
}
}
}
@@ -1,6 +1,6 @@
using FluentTerminal.Models.Enums;
using System;
using System;
using System.Collections.Generic;
using FluentTerminal.Models.Enums;
namespace FluentTerminal.App.Services.Implementation
{
@@ -35,4 +35,4 @@ namespace FluentTerminal.App.Services.Implementation
throw new KeyNotFoundException($"No handler registered for command: {command}");
}
}
}
}
@@ -1,10 +1,10 @@
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using Newtonsoft.Json;
using System;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using Newtonsoft.Json;
namespace FluentTerminal.App.Services.Implementation
{
@@ -21,11 +21,8 @@ namespace FluentTerminal.App.Services.Implementation
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, ApplicationDataContainers containers)
@@ -121,8 +118,9 @@ namespace FluentTerminal.App.Services.Implementation
public IDictionary<Command, ICollection<KeyBinding>> GetKeyBindings()
{
var keyBindings = new Dictionary<Command, ICollection<KeyBinding>>();
foreach (Command command in Enum.GetValues(typeof(Command)))
foreach (var value in Enum.GetValues(typeof(Command)))
{
var command = (Command)value;
keyBindings.Add(command, _keyBindings.ReadValueFromJson<Collection<KeyBinding>>(command.ToString(), null) ?? _defaultValueProvider.GetDefaultKeyBindings(command));
}
@@ -132,13 +130,15 @@ namespace FluentTerminal.App.Services.Implementation
public void SaveKeyBindings(Command command, ICollection<KeyBinding> keyBindings)
{
_keyBindings.WriteValueAsJson(command.ToString(), keyBindings);
_roamingSettings.WriteValueAsJson(nameof(KeyBindings), keyBindings);
KeyBindingsChanged?.Invoke(this, System.EventArgs.Empty);
}
public void ResetKeyBindings()
{
foreach (Command command in Enum.GetValues(typeof(Command)))
foreach (var value in Enum.GetValues(typeof(Command)))
{
var command = (Command)value;
_keyBindings.WriteValueAsJson(command.ToString(), _defaultValueProvider.GetDefaultKeyBindings(command));
}
@@ -20,4 +20,4 @@ namespace FluentTerminal.App.Services.Implementation
return _parsers.FirstOrDefault(p => p.SupportedFileTypes.Contains(fileType));
}
}
}
}
@@ -1,12 +1,10 @@
using FluentTerminal.Models;
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 System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
namespace FluentTerminal.App.Services.Implementation
{
@@ -14,14 +12,10 @@ namespace FluentTerminal.App.Services.Implementation
{
private readonly ISettingsService _settingsService;
private IAppServiceConnection _appServiceConnection;
private Dictionary<int, Action<string>> _terminalOutputHandlers;
public event EventHandler<int> TerminalExited;
public TrayProcessCommunicationService(ISettingsService settingsService)
{
_settingsService = settingsService;
_terminalOutputHandlers = new Dictionary<int, Action<string>>();
}
public async Task<CreateTerminalResponse> CreateTerminal(TerminalSize size, ShellProfile shellProfile)
@@ -32,7 +26,13 @@ namespace FluentTerminal.App.Services.Implementation
Profile = shellProfile
};
var responseMessage = await _appServiceConnection.SendMessageAsync(CreateMessage(request));
var message = new Dictionary<string, string>
{
{ MessageKeys.Type, MessageTypes.CreateTerminalRequest },
{ MessageKeys.Content, JsonConvert.SerializeObject(request) }
};
var responseMessage = await _appServiceConnection.SendMessageAsync(message);
return JsonConvert.DeserializeObject<CreateTerminalResponse>(responseMessage[MessageKeys.Content]);
}
@@ -40,36 +40,9 @@ namespace FluentTerminal.App.Services.Implementation
public Task Initialize(IAppServiceConnection appServiceConnection)
{
_appServiceConnection = appServiceConnection;
_appServiceConnection.MessageReceived += OnMessageReceived;
return UpdateToggleWindowKeyBindings();
}
private void OnMessageReceived(object sender, IDictionary<string, string> e)
{
var messageType = e[MessageKeys.Type];
var messageContent = e[MessageKeys.Content];
if (messageType == nameof(DisplayTerminalOutputRequest))
{
var request = JsonConvert.DeserializeObject<DisplayTerminalOutputRequest>(messageContent);
if (_terminalOutputHandlers.ContainsKey(request.TerminalId))
{
_terminalOutputHandlers[request.TerminalId].Invoke(request.Output);
}
else
{
Debug.WriteLine("output was not handled: " + request.Output);
}
}
else if (messageType == nameof(TerminalExitedRequest))
{
var request = JsonConvert.DeserializeObject<TerminalExitedRequest>(messageContent);
TerminalExited?.Invoke(this, request.TerminalId);
}
}
public Task ResizeTerminal(int id, TerminalSize size)
{
var request = new ResizeTerminalRequest
@@ -78,12 +51,13 @@ namespace FluentTerminal.App.Services.Implementation
NewSize = size
};
return _appServiceConnection.SendMessageAsync(CreateMessage(request));
}
var message = new Dictionary<string, string>
{
{ MessageKeys.Type, MessageTypes.ResizeTerminalRequest },
{ MessageKeys.Content, JsonConvert.SerializeObject(request) }
};
public void SubscribeForTerminalOutput(int terminalId, Action<string> callback)
{
_terminalOutputHandlers[terminalId] = callback;
return _appServiceConnection.SendMessageAsync(message);
}
public Task UpdateToggleWindowKeyBindings()
@@ -95,37 +69,13 @@ namespace FluentTerminal.App.Services.Implementation
KeyBindings = keyBindings
};
return _appServiceConnection.SendMessageAsync(CreateMessage(request));
}
public Task WriteText(int id, string text)
{
var request = new WriteTextRequest
var message = new Dictionary<string, string>
{
TerminalId = id,
Text = text
{ MessageKeys.Type, MessageTypes.SetToggleWindowKeyBindingsRequest },
{ MessageKeys.Content, JsonConvert.SerializeObject(request) }
};
return _appServiceConnection.SendMessageAsync(CreateMessage(request));
}
public Task CloseTerminal(int terminalId)
{
var request = new TerminalExitedRequest
{
TerminalId = terminalId
};
return _appServiceConnection.SendMessageAsync(CreateMessage(request));
}
private IDictionary<string, string> CreateMessage(object content)
{
return new Dictionary<string, string>
{
[MessageKeys.Type] = content.GetType().Name,
[MessageKeys.Content] = JsonConvert.SerializeObject(content)
};
return _appServiceConnection.SendMessageAsync(message);
}
}
}
}
@@ -18,4 +18,4 @@ namespace FluentTerminal.App.Services.Utilities
return value.ToString();
}
}
}
}
@@ -24,4 +24,4 @@ namespace FluentTerminal.App.Services.Utilities
return property;
}
}
}
}
+48 -28
View File
@@ -13,18 +13,23 @@ namespace FluentTerminal.App.ViewModels
{
public class MainViewModel : ViewModelBase
{
private readonly IApplicationView _applicationView;
private readonly IClipboardService _clipboardService;
private readonly IDialogService _dialogService;
private readonly IDispatcherTimer _dispatcherTimer;
private readonly IKeyboardCommandService _keyboardCommandService;
private readonly ISettingsService _settingsService;
private readonly ITrayProcessCommunicationService _trayProcessCommunicationService;
private ApplicationSettings _applicationSettings;
private string _background;
private double _backgroundOpacity;
private int _nextTerminalId;
private TerminalViewModel _selectedTerminal;
private TabsPosition _tabsPosition;
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,
IApplicationView applicationView, IDispatcherTimer dispatcherTimer, IClipboardService clipboardService)
@@ -52,19 +57,24 @@ namespace FluentTerminal.App.ViewModels
Background = currentTheme.Colors.Background;
BackgroundOpacity = options.BackgroundOpacity;
_applicationSettings = _settingsService.GetApplicationSettings();
TabsPosition = _applicationSettings.TabsPosition;
AddTerminalCommand = new RelayCommand(() => AddTerminal(null, false));
ShowSettingsCommand = new RelayCommand(ShowSettings);
Terminals.CollectionChanged += OnTerminalsCollectionChanged;
Title = "Fluent Terminal";
_applicationView.CloseRequested += OnCloseRequest;
}
public event EventHandler Closed;
public event EventHandler NewWindowRequested;
public event EventHandler ShowSettingsRequested;
private async void OnTerminalOptionsChanged(object sender, TerminalOptions e)
{
await _applicationView.RunOnDispatcherThread(() =>
{
BackgroundOpacity = e.BackgroundOpacity;
});
}
public RelayCommand AddTerminalCommand { get; }
@@ -102,14 +112,14 @@ namespace FluentTerminal.App.ViewModels
public RelayCommand ShowSettingsCommand { get; }
public TabsPosition TabsPosition
{
get => _tabsPosition;
set => Set(ref _tabsPosition, value);
}
public ObservableCollection<TerminalViewModel> Terminals { get; } = new ObservableCollection<TerminalViewModel>();
public string Title
{
get => _title;
set => Set(ref _title, value);
}
public Task AddTerminal(string startupDirectory, bool showProfileSelection)
{
return _applicationView.RunOnDispatcherThread(async () =>
@@ -129,9 +139,10 @@ namespace FluentTerminal.App.ViewModels
profile = _settingsService.GetDefaultShellProfile();
}
var terminal = new TerminalViewModel(_settingsService, _trayProcessCommunicationService, _dialogService, _keyboardCommandService,
var terminal = new TerminalViewModel(GetNextTerminalId(), _settingsService, _trayProcessCommunicationService, _dialogService, _keyboardCommandService,
_applicationSettings, startupDirectory, profile, _applicationView, _dispatcherTimer, _clipboardService);
terminal.Closed += OnTerminalCloseRequested;
terminal.CloseRequested += OnTerminalCloseRequested;
terminal.TitleChanged += OnTitleChanged;
Terminals.Add(terminal);
SelectedTerminal = terminal;
@@ -151,6 +162,11 @@ namespace FluentTerminal.App.ViewModels
SelectedTerminal?.CloseCommand.Execute(null);
}
private int GetNextTerminalId()
{
return _nextTerminalId++;
}
private void NewWindow()
{
NewWindowRequested?.Invoke(this, EventArgs.Empty);
@@ -158,11 +174,7 @@ namespace FluentTerminal.App.ViewModels
private async void OnApplicationSettingsChanged(object sender, ApplicationSettings e)
{
await _applicationView.RunOnDispatcherThread(() =>
{
_applicationSettings = e;
TabsPosition = e.TabsPosition;
});
await _applicationView.RunOnDispatcherThread(() => _applicationSettings = e);
}
private async Task OnCloseRequest(object sender, CancelableEventArgs e)
@@ -216,12 +228,20 @@ namespace FluentTerminal.App.ViewModels
}
}
private async void OnTerminalOptionsChanged(object sender, TerminalOptions e)
private void OnTerminalsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
await _applicationView.RunOnDispatcherThread(() =>
if (Terminals.Any())
{
BackgroundOpacity = e.BackgroundOpacity;
});
Title = Terminals.First().Title;
}
}
private void OnTitleChanged(object sender, string e)
{
if (sender is TerminalViewModel terminal && Terminals.First() == terminal)
{
Title = e;
}
}
private void SelectNextTab()
@@ -242,7 +262,7 @@ namespace FluentTerminal.App.ViewModels
{
ShowSettingsRequested?.Invoke(this, EventArgs.Empty);
}
private void ToggleFullScreen()
{
_applicationView.ToggleFullScreen();
@@ -14,7 +14,6 @@ namespace FluentTerminal.App.ViewModels.Settings
private readonly ISettingsService _settingsService;
private readonly ApplicationSettings _applicationSettings;
private bool _editingNewTerminalLocation;
private bool _editingTabsPosition;
public GeneralPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider)
{
@@ -100,39 +99,9 @@ namespace FluentTerminal.App.ViewModels.Settings
set => NewTerminalLocation = NewTerminalLocation.Window;
}
public TabsPosition TabsPosition
{
get => _applicationSettings.TabsPosition;
set
{
if (_applicationSettings.TabsPosition != value && !_editingTabsPosition)
{
_editingTabsPosition = true;
_applicationSettings.TabsPosition = value;
_settingsService.SaveApplicationSettings(_applicationSettings);
RaisePropertyChanged();
RaisePropertyChanged(nameof(TopIsSelected));
RaisePropertyChanged(nameof(BottomIsSelected));
_editingTabsPosition = false;
}
}
}
public bool TopIsSelected
{
get => TabsPosition == TabsPosition.Top;
set => TabsPosition = TabsPosition.Top;
}
public bool BottomIsSelected
{
get => TabsPosition == TabsPosition.Bottom;
set => TabsPosition = TabsPosition.Bottom;
}
private async Task RestoreDefaults()
{
var result = await _dialogService.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to restore the general settings?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true);
var result = await _dialogService.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to restore the general settings?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(false);
if (result == DialogButton.OK)
{
@@ -1,135 +0,0 @@
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.Text;
using System.Threading.Tasks;
namespace FluentTerminal.App.ViewModels.Settings
{
public class MousePageViewModel : ViewModelBase
{
private readonly ISettingsService _settingsService;
private readonly IDialogService _dialogService;
private readonly IDefaultValueProvider _defaultValueProvider;
private readonly ApplicationSettings _applicationSettings;
private bool _editingMouseRightClickAction;
private bool _editingMouseMiddleClickAction;
public MousePageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider)
{
_settingsService = settingsService;
_dialogService = dialogService;
_defaultValueProvider = defaultValueProvider;
_applicationSettings = _settingsService.GetApplicationSettings();
RestoreDefaultsCommand = new RelayCommand(async () => await RestoreDefaults().ConfigureAwait(false));
}
public bool CopyOnSelect
{
get => _applicationSettings.CopyOnSelect;
set
{
if (_applicationSettings.CopyOnSelect != value)
{
_applicationSettings.CopyOnSelect = value;
_settingsService.SaveApplicationSettings(_applicationSettings);
RaisePropertyChanged();
}
}
}
public MouseAction MouseRightClickAction
{
get => _applicationSettings.MouseRightClickAction;
set
{
if (_applicationSettings.MouseRightClickAction != value && !_editingMouseRightClickAction)
{
_editingMouseRightClickAction = true;
_applicationSettings.MouseRightClickAction = value;
_settingsService.SaveApplicationSettings(_applicationSettings);
RaisePropertyChanged();
RaisePropertyChanged(nameof(MouseRightClickNoneIsSelected));
RaisePropertyChanged(nameof(MouseRightClickContextMenuIsSelected));
RaisePropertyChanged(nameof(MouseRightClickPasteIsSelected));
_editingMouseRightClickAction = false;
}
}
}
public bool MouseRightClickNoneIsSelected
{
get => MouseRightClickAction == MouseAction.None;
set => MouseRightClickAction = MouseAction.None;
}
public bool MouseRightClickContextMenuIsSelected
{
get => MouseRightClickAction == MouseAction.ContextMenu;
set => MouseRightClickAction = MouseAction.ContextMenu;
}
public bool MouseRightClickPasteIsSelected
{
get => MouseRightClickAction == MouseAction.Paste;
set => MouseRightClickAction = MouseAction.Paste;
}
public MouseAction MouseMiddleClickAction
{
get => _applicationSettings.MouseMiddleClickAction;
set
{
if (_applicationSettings.MouseMiddleClickAction != value && !_editingMouseMiddleClickAction)
{
_editingMouseMiddleClickAction = true;
_applicationSettings.MouseMiddleClickAction = value;
_settingsService.SaveApplicationSettings(_applicationSettings);
RaisePropertyChanged();
RaisePropertyChanged(nameof(MouseMiddleClickNoneIsSelected));
RaisePropertyChanged(nameof(MouseMiddleClickContextMenuIsSelected));
RaisePropertyChanged(nameof(MouseMiddleClickPasteIsSelected));
_editingMouseMiddleClickAction = false;
}
}
}
public bool MouseMiddleClickNoneIsSelected
{
get => MouseMiddleClickAction == MouseAction.None;
set => MouseMiddleClickAction = MouseAction.None;
}
public bool MouseMiddleClickContextMenuIsSelected
{
get => MouseMiddleClickAction == MouseAction.ContextMenu;
set => MouseMiddleClickAction = MouseAction.ContextMenu;
}
public bool MouseMiddleClickPasteIsSelected
{
get => MouseMiddleClickAction == MouseAction.Paste;
set => MouseMiddleClickAction = MouseAction.Paste;
}
public RelayCommand RestoreDefaultsCommand { get; }
private async Task RestoreDefaults()
{
var result = await _dialogService.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to restore the mouse settings?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true);
if (result == DialogButton.OK)
{
var defaults = _defaultValueProvider.GetDefaultApplicationSettings();
CopyOnSelect = defaults.CopyOnSelect;
MouseMiddleClickAction = defaults.MouseMiddleClickAction;
MouseRightClickAction = defaults.MouseRightClickAction;
}
}
}
}
@@ -15,6 +15,7 @@ namespace FluentTerminal.App.ViewModels.Settings
private readonly ISettingsService _settingsService;
private readonly IFileSystemService _fileSystemService;
private ShellProfileViewModel _selectedShellProfile;
public ProfilesPageViewModel(ISettingsService settingsService, IDialogService dialogService, IDefaultValueProvider defaultValueProvider, IFileSystemService fileSystemService)
{
@@ -211,4 +211,4 @@ namespace FluentTerminal.App.ViewModels.Settings
_terminalOptions = _settingsService.GetTerminalOptions();
}
}
}
}
@@ -15,7 +15,6 @@ namespace FluentTerminal.App.ViewModels
Shell = new ProfilesPageViewModel(settingsService, dialogService, defaultValueProvider, fileSystemService);
Terminal = new TerminalPageViewModel(settingsService, dialogService, defaultValueProvider, systemFontService);
Themes = new ThemesPageViewModel(settingsService, dialogService, defaultValueProvider, themeParserFactory, fileSystemService);
Mouse = new MousePageViewModel(settingsService, dialogService, defaultValueProvider);
}
public event EventHandler Closed;
@@ -25,7 +24,6 @@ namespace FluentTerminal.App.ViewModels
public ProfilesPageViewModel Shell { get; }
public TerminalPageViewModel Terminal { get; }
public ThemesPageViewModel Themes { get; }
public MousePageViewModel Mouse { get; }
public void Close()
{
@@ -47,7 +47,6 @@ namespace FluentTerminal.App.ViewModels
}
public event EventHandler Deleted;
public event EventHandler SetAsDefault;
public RelayCommand DeleteCommand { get; }
@@ -175,4 +174,4 @@ namespace FluentTerminal.App.ViewModels
}
}
}
}
}
+150 -100
View File
@@ -6,84 +6,87 @@ 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.Threading;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
namespace FluentTerminal.App.ViewModels
{
public class TerminalViewModel : ViewModelBase
{
private readonly IApplicationView _applicationView;
private readonly IClipboardService _clipboardService;
private readonly ManualResetEventSlim _connectedEvent;
private readonly IDialogService _dialogService;
private readonly IKeyboardCommandService _keyboardCommandService;
private readonly IDispatcherTimer _resizeOverlayTimer;
private readonly ISettingsService _settingsService;
private readonly ShellProfile _shellProfile;
private readonly string _startupDirectory;
private readonly ITrayProcessCommunicationService _trayProcessCommunicationService;
private bool _isSelected;
private ApplicationSettings _applicationSettings;
private string _resizeOverlayContent;
private string _searchText;
private bool _showResizeOverlay;
private bool _showSearchPanel;
private readonly string _startupDirectory;
private int _terminalId;
private ITerminalView _terminalView;
private string _title;
private readonly ShellProfile _shellProfile;
private bool _showSearchPanel;
private string _searchText;
private bool _isSelected;
private readonly IApplicationView _applicationView;
private readonly IDispatcherTimer _resizeOverlayTimer;
private readonly IClipboardService _clipboardService;
private IWebSocketConnection _webSocket;
private NamedPipeClientStream _namedPipe;
public TerminalViewModel(ISettingsService settingsService, ITrayProcessCommunicationService trayProcessCommunicationService, IDialogService dialogService,
public TerminalViewModel(int id, ISettingsService settingsService, ITrayProcessCommunicationService trayProcessCommunicationService, IDialogService dialogService,
IKeyboardCommandService keyboardCommandService, ApplicationSettings applicationSettings, string startupDirectory, ShellProfile shellProfile,
IApplicationView applicationView, IDispatcherTimer dispatcherTimer, IClipboardService clipboardService)
{
Id = id;
Title = DefaultTitle;
_connectedEvent = new ManualResetEventSlim(false);
_settingsService = settingsService;
_settingsService.CurrentThemeChanged += OnCurrentThemeChanged;
_settingsService.TerminalOptionsChanged += OnTerminalOptionsChanged;
_settingsService.ApplicationSettingsChanged += OnApplicationSettingsChanged;
_settingsService.KeyBindingsChanged += OnKeyBindingsChanged;
_trayProcessCommunicationService = trayProcessCommunicationService;
_trayProcessCommunicationService.TerminalExited += OnTerminalExited;
_dialogService = dialogService;
_keyboardCommandService = keyboardCommandService;
ApplicationSettings = applicationSettings;
_applicationSettings = applicationSettings;
_startupDirectory = startupDirectory;
_shellProfile = shellProfile;
_applicationView = applicationView;
_clipboardService = clipboardService;
_resizeOverlayTimer = dispatcherTimer;
_resizeOverlayTimer.Interval = new TimeSpan(0, 0, 2);
_resizeOverlayTimer.Tick += OnResizeOverlayTimerFinished;
CloseCommand = new RelayCommand(async () => await TryClose().ConfigureAwait(false));
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);
}
public ApplicationSettings ApplicationSettings { get; private set; }
private async void OnKeyBindingsChanged(object sender, EventArgs e)
{
var keyBindings = _settingsService.GetKeyBindings();
await _applicationView.RunOnDispatcherThread(async () =>
{
await _terminalView.ChangeKeyBindings(FlattenKeyBindings(keyBindings)).ConfigureAwait(false);
});
}
public event EventHandler Closed;
public event EventHandler CloseRequested;
public event EventHandler<string> TitleChanged;
public RelayCommand CloseCommand { get; }
public RelayCommand CloseSearchPanelCommand { get; }
public string DefaultTitle { get; private set; } = string.Empty;
public RelayCommand FindNextCommand { get; }
public RelayCommand FindPreviousCommand { get; }
public bool Initialized { get; private set; }
public RelayCommand FindNextCommand { get; }
public RelayCommand CloseSearchPanelCommand { get; }
public bool IsSelected
{
@@ -92,22 +95,18 @@ namespace FluentTerminal.App.ViewModels
{
if (Set(ref _isSelected, value))
{
if (IsSelected)
{
_applicationView.Title = Title;
}
RaisePropertyChanged(nameof(IsUnderlined));
}
}
}
public bool IsUnderlined => IsSelected && ApplicationSettings.UnderlineSelectedTab;
public bool IsUnderlined => IsSelected && _applicationSettings.UnderlineSelectedTab;
public string ResizeOverlayContent
{
get => _resizeOverlayContent;
set => Set(ref _resizeOverlayContent, value);
}
public int Id { get; }
public bool Initialized { get; private set; }
public string DefaultTitle { get; private set; } = "Fluent Terminal";
public string SearchText
{
@@ -115,6 +114,18 @@ namespace FluentTerminal.App.ViewModels
set => Set(ref _searchText, value);
}
public bool ShowSearchPanel
{
get => _showSearchPanel;
set => Set(ref _showSearchPanel, value);
}
public string ResizeOverlayContent
{
get => _resizeOverlayContent;
set => Set(ref _resizeOverlayContent, value);
}
public bool ShowResizeOverlay
{
get => _showResizeOverlay;
@@ -132,12 +143,6 @@ namespace FluentTerminal.App.ViewModels
}
}
public bool ShowSearchPanel
{
get => _showSearchPanel;
set => Set(ref _showSearchPanel, value);
}
public string Title
{
get => _title;
@@ -145,17 +150,16 @@ namespace FluentTerminal.App.ViewModels
{
value = string.IsNullOrWhiteSpace(value) ? DefaultTitle : value;
if (Set(ref _title, value) && IsSelected)
if (Set(ref _title, value))
{
_applicationView.Title = Title;
TitleChanged?.Invoke(this, Title);
}
}
}
public async Task CloseView()
public void CloseView()
{
_terminalView.Close();
await _trayProcessCommunicationService.CloseTerminal(_terminalId).ConfigureAwait(true);
}
public Task FocusTerminal()
@@ -187,24 +191,39 @@ namespace FluentTerminal.App.ViewModels
_terminalView.TerminalTitleChanged += OnTerminalTitleChanged;
_terminalView.KeyboardCommandReceived += OnKeyboardCommandReceived;
_trayProcessCommunicationService.SubscribeForTerminalOutput(_terminalId, t =>
{
_connectedEvent.Wait();
_webSocket.Send(t);
});
DefaultTitle = response.ShellExecutableName;
Title = DefaultTitle;
var webSocketUrl = "ws://127.0.0.1:" + response.Id;
_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 = () => _connectedEvent.Set();
socket.OnMessage = message => _trayProcessCommunicationService.WriteText(_terminalId, message);
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;
}
@@ -216,33 +235,46 @@ namespace FluentTerminal.App.ViewModels
await FocusTerminal().ConfigureAwait(true);
}
private void CloseSearchPanel()
private void ListenToNamedPipe()
{
SearchText = string.Empty;
ShowSearchPanel = false;
_terminalView.FocusTerminal();
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 Task FindNext()
private async Task InvokeCloseRequested()
{
return _terminalView.FindNext(SearchText);
}
if (_applicationSettings.ConfirmClosingTabs)
{
var result = await _dialogService.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to close this tab?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true);
private Task FindPrevious()
{
return _terminalView.FindPrevious(SearchText);
}
if (result == DialogButton.Cancel)
{
return;
}
}
private IEnumerable<KeyBinding> FlattenKeyBindings(IDictionary<Command, ICollection<KeyBinding>> keyBindings)
{
return keyBindings.Values.SelectMany(k => k);
CloseRequested?.Invoke(this, EventArgs.Empty);
}
private async void OnApplicationSettingsChanged(object sender, ApplicationSettings e)
{
await _applicationView.RunOnDispatcherThread(() =>
{
ApplicationSettings = e;
_applicationSettings = e;
RaisePropertyChanged(nameof(IsUnderlined));
});
}
@@ -256,15 +288,6 @@ namespace FluentTerminal.App.ViewModels
});
}
private async void OnKeyBindingsChanged(object sender, EventArgs e)
{
var keyBindings = _settingsService.GetKeyBindings();
await _applicationView.RunOnDispatcherThread(async () =>
{
await _terminalView.ChangeKeyBindings(FlattenKeyBindings(keyBindings)).ConfigureAwait(false);
});
}
private async void OnKeyboardCommandReceived(object sender, Command e)
{
if (e == Command.Copy)
@@ -277,7 +300,7 @@ namespace FluentTerminal.App.ViewModels
var content = await _clipboardService.GetText().ConfigureAwait(true);
if (content != null)
{
await _trayProcessCommunicationService.WriteText(_terminalId, content).ConfigureAwait(true);
await _terminalView.Write(content).ConfigureAwait(true);
}
}
else if (e == Command.Search)
@@ -300,14 +323,6 @@ namespace FluentTerminal.App.ViewModels
ShowResizeOverlay = false;
}
private void OnTerminalExited(object sender, int e)
{
if (e == _terminalId)
{
_applicationView.RunOnDispatcherThread(() => Closed?.Invoke(this, EventArgs.Empty));
}
}
private async void OnTerminalOptionsChanged(object sender, TerminalOptions e)
{
await _applicationView.RunOnDispatcherThread(async () =>
@@ -332,20 +347,55 @@ namespace FluentTerminal.App.ViewModels
Title = e;
}
private async Task TryClose()
private IEnumerable<KeyBinding> FlattenKeyBindings(IDictionary<Command, ICollection<KeyBinding>> keyBindings)
{
if (ApplicationSettings.ConfirmClosingTabs)
{
var result = await _dialogService.ShowMessageDialogAsnyc("Please confirm", "Are you sure you want to close this tab?", DialogButton.OK, DialogButton.Cancel).ConfigureAwait(true);
return keyBindings.Values.SelectMany(k => k);
}
if (result == DialogButton.Cancel)
private Task FindNext()
{
return _terminalView.FindNext(SearchText);
}
private Task FindPrevious()
{
return _terminalView.FindPrevious(SearchText);
}
private void CloseSearchPanel()
{
SearchText = string.Empty;
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;
return i;
}
}
await _trayProcessCommunicationService.CloseTerminal(_terminalId).ConfigureAwait(true);
Closed?.Invoke(this, EventArgs.Empty);
return null;
}
}
}
@@ -1,5 +1,4 @@
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@@ -12,24 +11,9 @@ namespace FluentTerminal.App.Adapters
{
private readonly AppServiceConnection _appServiceConnection;
public event EventHandler<IDictionary<string, string>> MessageReceived;
public AppServiceConnectionAdapter(AppServiceConnection appServiceConnection)
{
_appServiceConnection = appServiceConnection;
_appServiceConnection.RequestReceived += OnRequestReceived;
}
private void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
var messageType = (string)args.Request.Message[MessageKeys.Type];
var messageContent = (string)args.Request.Message[MessageKeys.Content];
MessageReceived?.Invoke(this, new Dictionary<string, string>
{
[MessageKeys.Type] = messageType,
[MessageKeys.Content] = messageContent
});
}
public async Task<IDictionary<string, string>> SendMessageAsync(IDictionary<string, string> message)
@@ -55,4 +39,4 @@ namespace FluentTerminal.App.Adapters
return null;
}
}
}
}
@@ -50,9 +50,10 @@ namespace FluentTerminal.App.Adapters
return _applicationDataContainer.Values.TryGetValue(key, out value);
}
public void WriteValueAsJson<T>(string name, T value)
{
_applicationDataContainer.Values[name] = JsonConvert.SerializeObject(value);
}
}
}
}
@@ -64,4 +64,5 @@ namespace FluentTerminal.App.Adapters
deferral.Complete();
}
}
}
}
@@ -1,5 +1,5 @@
using FluentTerminal.App.Services;
using System;
using System;
using FluentTerminal.App.Services;
using Windows.UI.Xaml;
namespace FluentTerminal.App.Adapters
@@ -39,4 +39,4 @@ namespace FluentTerminal.App.Adapters
_dispatcherTimer.Stop();
}
}
}
}
+1 -2
View File
@@ -29,7 +29,6 @@
<converters:IntToExtendedVirtualKeyConverter x:Key="IntToExtendedVirtualKeyConverter" />
<converters:BackgroundToApplicationThemeConverter x:Key="BackgroundToApplicationThemeConverter" />
<converters:StringToColorConverter x:Key="StringToColorConverter" />
<converters:EnumValueToVisibiltyConverter x:Key="EnumValueToVisibiltyConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>
</Application>
Binary file not shown.
@@ -14,8 +14,7 @@ namespace FluentTerminal.App.Converters
if (value is string colorString)
{
color = colorString.ToColor();
}
else if (value is Color)
} else if (value is Color)
{
color = (Color)value;
}
@@ -33,4 +32,4 @@ namespace FluentTerminal.App.Converters
throw new NotImplementedException();
}
}
}
}
@@ -1,23 +0,0 @@
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
namespace FluentTerminal.App.Converters
{
public class EnumValueToVisibiltyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value.GetType().IsEnum && Enum.TryParse(value.GetType(), parameter.ToString(), true, out object result))
{
return Equals(value, result) ? Visibility.Visible : Visibility.Collapsed;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}
@@ -24,4 +24,4 @@ namespace FluentTerminal.App.Converters
return null;
}
}
}
}
@@ -21,4 +21,4 @@ namespace FluentTerminal.App.Converters
throw new NotImplementedException();
}
}
}
}
@@ -19,4 +19,4 @@ namespace FluentTerminal.App.Converters
throw new NotImplementedException();
}
}
}
}
@@ -25,4 +25,4 @@ namespace FluentTerminal.App.Converters
return null;
}
}
}
}
@@ -8,24 +8,24 @@ namespace FluentTerminal.App.Converters
{
internal class TerminalViewModelToViewConverter : IValueConverter
{
private readonly Dictionary<TerminalViewModel, TerminalView> _viewDictionary;
private readonly Dictionary<int, TerminalView> _viewDictionary;
public TerminalViewModelToViewConverter()
{
_viewDictionary = new Dictionary<TerminalViewModel, TerminalView>();
_viewDictionary = new Dictionary<int, TerminalView>();
}
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is TerminalViewModel terminal)
{
if (_viewDictionary.TryGetValue(terminal, out TerminalView view))
if (_viewDictionary.TryGetValue(terminal.Id, out TerminalView view))
{
return view;
}
var newView = new TerminalView(terminal);
_viewDictionary.Add(terminal, newView);
_viewDictionary.Add(terminal.Id, newView);
return newView;
}
return null;
@@ -24,4 +24,4 @@ namespace FluentTerminal.App.Converters
return null;
}
}
}
}
@@ -76,4 +76,4 @@
PreviewKeyDown="OnResetButtonPreviewKeyDown" />
</StackPanel>
</StackPanel>
</ContentDialog>
</ContentDialog>
@@ -1,13 +1,13 @@
using FluentTerminal.App.Services.Dialogs;
using FluentTerminal.Models;
using GalaSoft.MvvmLight.Command;
using System;
using System.ComponentModel;
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
{
@@ -92,20 +92,16 @@ namespace FluentTerminal.App.Dialogs
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;
@@ -14,4 +14,4 @@
DisplayMemberPath="Name"
ItemsSource="{x:Bind Profiles}"
SelectedItem="{x:Bind SelectedProfile, Mode=TwoWay}" />
</ContentDialog>
</ContentDialog>
@@ -1,8 +1,8 @@
using FluentTerminal.App.Services;
using System;
using FluentTerminal.App.Services;
using FluentTerminal.App.Services.Dialogs;
using FluentTerminal.App.Utilities;
using FluentTerminal.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -35,4 +35,4 @@ namespace FluentTerminal.App.Dialogs
return null;
}
}
}
}
+1 -17
View File
@@ -25,7 +25,6 @@
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppInstallerUpdateFrequency>1</AppInstallerUpdateFrequency>
<AppInstallerCheckForUpdateFrequency>OnApplicationRun</AppInstallerCheckForUpdateFrequency>
<AppxSymbolPackageEnabled>True</AppxSymbolPackageEnabled>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
@@ -113,7 +112,6 @@
</Compile>
<Compile Include="Behaviors\MiddleClickBehavior.cs" />
<Compile Include="Converters\BackgroundToApplicationThemeConverter.cs" />
<Compile Include="Converters\EnumValueToVisibiltyConverter.cs" />
<Compile Include="Converters\FalseToVisibleConverter.cs" />
<Compile Include="Converters\IntToExtendedVirtualKeyConverter.cs" />
<Compile Include="Converters\IntToVisibilityConverter.cs" />
@@ -143,9 +141,6 @@
<Compile Include="Views\SettingsPage.xaml.cs">
<DependentUpon>SettingsPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\SettingsPages\MouseSettings.xaml.cs">
<DependentUpon>MouseSettings.xaml</DependentUpon>
</Compile>
<Compile Include="Views\SettingsPages\ThemeSettings.xaml.cs">
<DependentUpon>ThemeSettings.xaml</DependentUpon>
</Compile>
@@ -161,9 +156,6 @@
<Compile Include="Views\SettingsPages\ShellProfileSettings.xaml.cs">
<DependentUpon>ShellProfileSettings.xaml</DependentUpon>
</Compile>
<Compile Include="Views\TabBar.xaml.cs">
<DependentUpon>TabBar.xaml</DependentUpon>
</Compile>
<Compile Include="Views\TerminalColorPicker.xaml.cs">
<DependentUpon>TerminalColorPicker.xaml</DependentUpon>
</Compile>
@@ -177,13 +169,13 @@
</AppxManifest>
<Content Include="Assets\settingsicons.ttf" />
<Content Include="Win32\Autofac.dll" />
<Content Include="Win32\Fleck.dll" />
<Content Include="Win32\FluentTerminal.Models.dll" />
<Content Include="Win32\FluentTerminal.Models.pdb" />
<Content Include="Win32\FluentTerminal.SystemTray.exe" />
<Content Include="Win32\FluentTerminal.SystemTray.pdb" />
<Content Include="Win32\GlobalHotKey.dll" />
<Content Include="Win32\Newtonsoft.Json.dll" />
<Content Include="Win32\RestSharp.dll" />
<Content Include="Win32\System.Data.Common.dll" />
<Content Include="Win32\System.Diagnostics.StackTrace.dll" />
<Content Include="Win32\System.Diagnostics.Tracing.dll" />
@@ -287,10 +279,6 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\SettingsPages\MouseSettings.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\SettingsPages\ThemeSettings.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -311,10 +299,6 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\TabBar.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\TerminalColorPicker.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" IgnorableNamespaces="uap mp desktop rescap">
<Identity Name="53621FSApps.FluentTerminal" Publisher="CN=BDC72197-B634-438A-B863-16DCB7D90C85" Version="0.1.13.0" />
<Identity Name="53621FSApps.FluentTerminal" Publisher="CN=BDC72197-B634-438A-B863-16DCB7D90C85" Version="0.1.11.0" />
<mp:PhoneIdentity PhoneProductId="f7225014-f405-4342-ad2e-ebf6ac60ea2c" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>Fluent Terminal</DisplayName>
@@ -1,7 +1,8 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("FluentTerminal.App")]
@@ -16,11 +17,11 @@ using System.Runtime.InteropServices;
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
+5 -2
View File
@@ -6,7 +6,7 @@
Laufzeitdirektiven sind hier dokumentiert: https://go.microsoft.com/fwlink/?LinkID=391919
Vollständige Aktivierung der Reflektion von "App1.MyClass" und allen zugehörigen öffentlichen/privaten Membern:
<Type Name="App1.MyClass" Dynamic="Required All" />
<Type Name="App1.MyClass" Dynamic="Required All"/>
Aktivierung der dynamischen Erstellung der spezifischen Instanziierung von "AppClass<T>" über "System.Int32":
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
@@ -22,7 +22,10 @@
Anwendungspaket. Die Sternchen sind keine Platzhalter.
-->
<Assembly Name="*Application*" Dynamic="Required All" />
<!-- Fügen Sie hier Ihre anwendungsspezifischen Laufzeitdirektiven ein. -->
</Application>
</Directives>
@@ -23,4 +23,4 @@ namespace FluentTerminal.App.Services
Clipboard.SetContent(dataPackage);
}
}
}
}
@@ -1,4 +1,5 @@
using System;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
@@ -58,4 +59,4 @@ namespace FluentTerminal.App.Services
}
}
}
}
}
@@ -10,4 +10,4 @@ namespace FluentTerminal.App.Services
return CanvasTextFormat.GetSystemFontFamilies();
}
}
}
}
+2 -65
View File
@@ -65,70 +65,6 @@
</Setter>
</Style>
<Style x:Key="TitleBarRepeatButtonStyle" TargetType="RepeatButton">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals" Value="True" />
<Setter Property="Width" Value="47" />
<Setter Property="Height" Value="32" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RepeatButton">
<Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
<ContentPresenter
x:Name="ContentPresenter"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="Transparent" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemListLowColor}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemListMediumColor}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ColorPreviewButtonStyle" TargetType="Button">
<Setter Property="Width" Value="24" />
<Setter Property="Height" Value="24" />
@@ -159,4 +95,5 @@
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</ResourceDictionary>
@@ -46,4 +46,4 @@ namespace FluentTerminal.App.Utilities
}
}
}
}
}
@@ -48,13 +48,10 @@ namespace FluentTerminal.App.Utilities
{
case "SystemBaseHighColor":
return new Color { A = 0xFF, R = 0x00, G = 0x00, B = 0x00 };
case "SystemListLowColor":
return new Color { A = 0x19, R = 0x00, G = 0x00, B = 0x00 };
case "SystemListMediumColor":
return new Color { A = 0x33, R = 0x00, G = 0x00, B = 0x00 };
default:
return null;
}
@@ -65,17 +62,14 @@ namespace FluentTerminal.App.Utilities
{
case "SystemBaseHighColor":
return new Color { A = 0xFF, R = 0xFF, G = 0xFF, B = 0xFF };
case "SystemListLowColor":
return new Color { A = 0x19, R = 0xFF, G = 0xFF, B = 0xFF };
case "SystemListMediumColor":
return new Color { A = 0x33, R = 0xFF, G = 0xFF, B = 0xFF };
default:
return null;
}
}
}
}
}
}
@@ -92,4 +92,4 @@
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
</UserControl>
+97 -52
View File
@@ -2,10 +2,13 @@
x:Class="FluentTerminal.App.Views.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:behaviors="using:FluentTerminal.App.Behaviors"
xmlns:converters="using:FluentTerminal.App.Converters"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="using:FluentTerminal.App.Views"
xmlns:viewmodels="using:FluentTerminal.App.ViewModels"
RequestedTheme="{x:Bind ViewModel.Background, Mode=OneWay, Converter={StaticResource BackgroundToApplicationThemeConverter}}"
mc:Ignorable="d">
<Page.Resources>
@@ -22,64 +25,113 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Rectangle x:Name="TitleBar" Fill="Transparent" />
<Grid
x:Name="TitleBarContents"
Grid.Row="0"
Height="{Binding CoreTitleBarHeight, Mode=OneWay}"
Margin="{Binding CoreTitleBarPadding, Mode=OneWay}">
Margin="{Binding CoreTitleBarPadding, Mode=OneWay}"
SizeChanged="Grid_SizeChanged">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button
x:Name="Hamburger"
Height="32"
Style="{StaticResource TitleBarButtonStyle}">
<Button.Content>
<Viewbox Width="16" Height="16">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE700;" />
</Viewbox>
</Button.Content>
<Button.Flyout>
<MenuFlyout>
<MenuFlyoutItem Command="{x:Bind ViewModel.ShowSettingsCommand}" Text="Settings">
<MenuFlyoutItem.Icon>
<SymbolIcon Symbol="Setting" />
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
</MenuFlyout>
</Button.Flyout>
</Button>
<TextBlock
Grid.Column="0"
IsHitTestVisible="False"
Style="{StaticResource WindowTitleTextBlockStyle}"
Text="{x:Bind ViewModel.Title, Mode=OneWay}"
Visibility="{x:Bind ViewModel.Terminals.Count, Mode=OneWay, Converter={StaticResource OneToVisibleConverter}}" />
<ListView
x:Name="Tabs"
Grid.Column="0"
AllowDrop="True"
CanDragItems="True"
CanReorderItems="True"
ItemsSource="{x:Bind ViewModel.Terminals}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollMode="Auto"
SelectedItem="{x:Bind ViewModel.SelectedTerminal, Mode=TwoWay}"
Visibility="{x:Bind ViewModel.Terminals.Count, Mode=OneWay, Converter={StaticResource OneToCollapsedConverter}}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="viewmodels:TerminalViewModel">
<Grid
Height="32"
Margin="0"
VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Interactivity:Interaction.Behaviors>
<behaviors:MiddleClickBehavior>
<behaviors:MiddleClickBehavior.Actions>
<core:InvokeCommandAction Command="{x:Bind CloseCommand}" />
</behaviors:MiddleClickBehavior.Actions>
</behaviors:MiddleClickBehavior>
</Interactivity:Interaction.Behaviors>
<Border
Grid.ColumnSpan="3"
Height="3"
VerticalAlignment="Bottom"
Background="{ThemeResource SystemAccentColor}"
Visibility="{x:Bind IsUnderlined, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}" />
<TextBlock
Grid.Column="0"
Margin="12,8,6,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Title, Mode=OneWay}" />
<Button
Grid.Column="2"
Width="32"
Command="{x:Bind CloseCommand}"
Style="{StaticResource TitleBarButtonStyle}"
ToolTipService.ToolTip="Close">
<Viewbox Width="12" Height="12">
<SymbolIcon Symbol="Cancel" />
</Viewbox>
</Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="MinWidth" Value="24" />
<Setter Property="MinHeight" Value="32" />
<Setter Property="Padding" Value="0" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
<StackPanel
Grid.Column="1"
Orientation="Horizontal"
Visibility="{x:Bind ViewModel.Terminals.Count, Mode=OneWay, Converter={StaticResource OneToVisibleConverter}}">
<TextBlock
IsHitTestVisible="False"
Style="{StaticResource WindowTitleTextBlockStyle}"
Text="{x:Bind ViewModel.SelectedTerminal.Title, Mode=OneWay}" />
x:Name="TitleBarButtons"
Grid.Column="2"
Orientation="Horizontal">
<Button
x:Name="Add"
Command="{x:Bind ViewModel.AddTerminalCommand}"
Style="{StaticResource TitleBarButtonStyle}"
ToolTipService.ToolTip="New tab">
<Button.Content>
<Viewbox Width="12" Height="12">
<SymbolIcon Symbol="Add" />
</Viewbox>
</Button.Content>
ToolTipService.ToolTip="New Tab">
<Viewbox Width="12" Height="12">
<SymbolIcon Symbol="Add" />
</Viewbox>
</Button>
<Button
HorizontalAlignment="Right"
Command="{x:Bind ViewModel.ShowSettingsCommand}"
Style="{StaticResource TitleBarButtonStyle}"
ToolTipService.ToolTip="Settings">
<Viewbox Width="12" Height="12">
<SymbolIcon Symbol="Setting" />
</Viewbox>
</Button>
</StackPanel>
<views:TabBar
Grid.Column="1"
HorizontalAlignment="Left"
AddCommand="{x:Bind ViewModel.AddTerminalCommand}"
ItemsSource="{x:Bind ViewModel.Terminals, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.SelectedTerminal, Mode=TwoWay}"
Visibility="{x:Bind ViewModel.TabsPosition, Mode=OneWay, Converter={StaticResource EnumValueToVisibiltyConverter}, ConverterParameter=Top}" />
</Grid>
<ContentControl
x:Name="TerminalContainer"
@@ -87,12 +139,5 @@
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Content="{x:Bind ViewModel.SelectedTerminal, Mode=OneWay, Converter={StaticResource TerminalViewModelToViewConverter}}" />
<views:TabBar
Grid.Row="2"
HorizontalAlignment="Left"
AddCommand="{x:Bind ViewModel.AddTerminalCommand}"
ItemsSource="{x:Bind ViewModel.Terminals, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.SelectedTerminal, Mode=TwoWay}"
Visibility="{x:Bind ViewModel.TabsPosition, Mode=OneWay, Converter={StaticResource EnumValueToVisibiltyConverter}, ConverterParameter=Bottom}" />
</Grid>
</Page>
+11 -1
View File
@@ -2,6 +2,7 @@
using FluentTerminal.App.ViewModels;
using System.ComponentModel;
using Windows.ApplicationModel.Core;
using Windows.UI;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
@@ -83,6 +84,7 @@ namespace FluentTerminal.App.Views
UpdateLayoutMetrics();
}
private void UpdateLayoutMetrics()
{
if (PropertyChanged != null)
@@ -91,5 +93,13 @@ namespace FluentTerminal.App.Views
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CoreTitleBarPadding)));
}
}
private void Grid_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (sender is Grid grid)
{
Tabs.MaxWidth = grid.ActualWidth - grid.ColumnDefinitions[2].ActualWidth;
}
}
}
}
}
@@ -57,14 +57,6 @@
ToolTipService.ToolTip="Keybindings" />
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem Content="Mouse" Tag="mouse">
<NavigationViewItem.Icon>
<FontIcon
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="g"
ToolTipService.ToolTip="Keybindings" />
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem Content="Themes" Tag="themes">
<NavigationViewItem.Icon>
<FontIcon
@@ -1,15 +1,18 @@
using FluentTerminal.App.Utilities;
using FluentTerminal.App.ViewModels;
using FluentTerminal.App.ViewModels;
using FluentTerminal.App.Views.SettingsPages;
using System.Linq;
using System;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Core;
using Windows.UI.Core.Preview;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using FluentTerminal.App.Utilities;
namespace FluentTerminal.App.Views
{
@@ -103,10 +106,6 @@ namespace FluentTerminal.App.Views
case "keyBindings":
ContentFrame.Navigate(typeof(KeyBindingSettings), ViewModel.KeyBindings);
break;
case "mouse":
ContentFrame.Navigate(typeof(MouseSettings), ViewModel.Mouse);
break;
}
}
@@ -36,25 +36,11 @@
</Grid>
<StackPanel Grid.Row="2" Margin="24,0,0,0">
<TextBlock Margin="0,0,0,8" Text="Open new terminals as" />
<RadioButton
Content="Tabs"
GroupName="NewTerminalLocation"
IsChecked="{x:Bind ViewModel.TabIsSelected, Mode=TwoWay}" />
<RadioButton Content="Tabs" IsChecked="{x:Bind ViewModel.TabIsSelected, Mode=TwoWay}" />
<RadioButton
Margin="0,0,0,24"
Content="Windows"
GroupName="NewTerminalLocation"
IsChecked="{x:Bind ViewModel.WindowIsSelected, Mode=TwoWay}" />
<TextBlock Margin="0,0,0,8" Text="Show tabs on" />
<RadioButton
Content="Top"
GroupName="TabsPosition"
IsChecked="{x:Bind ViewModel.TopIsSelected, Mode=TwoWay}" />
<RadioButton
Margin="0,0,0,24"
Content="Bottom"
GroupName="TabsPosition"
IsChecked="{x:Bind ViewModel.BottomIsSelected, Mode=TwoWay}" />
<ToggleSwitch
Margin="0,0,0,24"
Header="Underline selected tab"
@@ -64,6 +50,7 @@
Header="Ask before closing windows"
IsOn="{x:Bind ViewModel.ConfirmClosingWindows, Mode=TwoWay}" />
<ToggleSwitch Header="Ask before closing tabs" IsOn="{x:Bind ViewModel.ConfirmClosingTabs, Mode=TwoWay}" />
</StackPanel>
</Grid>
</Page>
</Page>
@@ -21,4 +21,4 @@ namespace FluentTerminal.App.Views.SettingsPages
}
}
}
}
}
@@ -52,4 +52,4 @@
</ItemsControl>
</ScrollViewer>
</Grid>
</Page>
</Page>
@@ -35,4 +35,4 @@ namespace FluentTerminal.App.Views.SettingsPages
}
}
}
}
}
@@ -1,74 +0,0 @@
<Page
x:Class="FluentTerminal.App.Views.SettingsPages.MouseSettings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="1" Margin="24,00,0,24">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock
Margin="0,10,0,0"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
Text="Mouse" />
<CommandBar
Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
DefaultLabelPosition="Right">
<AppBarButton
Command="{x:Bind ViewModel.RestoreDefaultsCommand}"
Icon="Undo"
Label="Restore Defaults" />
</CommandBar>
</Grid>
<StackPanel Grid.Row="2" Margin="24,0,0,0">
<ToggleSwitch
Margin="0,0,0,24"
Header="Copy on select"
IsOn="{x:Bind ViewModel.CopyOnSelect, Mode=TwoWay}" />
<TextBlock Margin="0,0,0,8" Text="Middle button action" />
<RadioButton
Content="Nothing"
GroupName="MiddleButton"
IsChecked="{x:Bind ViewModel.MouseMiddleClickNoneIsSelected, Mode=TwoWay}" />
<RadioButton
Content="Context menu"
GroupName="MiddleButton"
IsChecked="{x:Bind ViewModel.MouseMiddleClickContextMenuIsSelected, Mode=TwoWay}" />
<RadioButton
Margin="0,0,0,24"
Content="Paste"
GroupName="MiddleButton"
IsChecked="{x:Bind ViewModel.MouseMiddleClickPasteIsSelected, Mode=TwoWay}" />
<TextBlock Margin="0,0,0,8" Text="Right button action" />
<RadioButton
Content="Nothing"
GroupName="RightButton"
IsChecked="{x:Bind ViewModel.MouseRightClickNoneIsSelected, Mode=TwoWay}" />
<RadioButton
Content="Context menu"
GroupName="RightButton"
IsChecked="{x:Bind ViewModel.MouseRightClickContextMenuIsSelected, Mode=TwoWay}" />
<RadioButton
Margin="0,0,0,24"
Content="Paste"
GroupName="RightButton"
IsChecked="{x:Bind ViewModel.MouseRightClickPasteIsSelected, Mode=TwoWay}" />
</StackPanel>
</Grid>
</Page>
@@ -1,24 +0,0 @@
using FluentTerminal.App.ViewModels.Settings;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace FluentTerminal.App.Views.SettingsPages
{
public sealed partial class MouseSettings : Page
{
public MouseSettings()
{
this.InitializeComponent();
}
public MousePageViewModel ViewModel { get; private set; }
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is MousePageViewModel viewModel)
{
ViewModel = viewModel;
}
}
}
}
@@ -175,6 +175,7 @@
IsEnabled="{x:Bind InEditMode, Mode=OneWay}"
IsSpellCheckEnabled="False"
Text="{x:Bind Arguments, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
<StackPanel Visibility="{x:Bind InEditMode, Mode=OneWay, Converter={StaticResource FalseToVisibleConverter}}">
<TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{x:Bind Name, Mode=OneWay}" />
@@ -191,9 +192,10 @@
Header="Arguments"
Text="{x:Bind Arguments, Mode=OneWay}" />
</StackPanel>
</Grid>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Grid>
</Page>
</Page>
@@ -21,4 +21,4 @@ namespace FluentTerminal.App.Views.SettingsPages
}
}
}
}
}
@@ -98,4 +98,4 @@
</StackPanel>
</ScrollViewer>
</Grid>
</Page>
</Page>
@@ -304,4 +304,4 @@
</ContentControl.ContentTemplate>
</ContentControl>
</Grid>
</Page>
</Page>
@@ -1,5 +1,6 @@
using FluentTerminal.App.Utilities;
using FluentTerminal.App.ViewModels.Settings;
using Microsoft.Toolkit.Uwp.Helpers;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
@@ -45,4 +46,4 @@ namespace FluentTerminal.App.Views.SettingsPages
ContrastHelper.SetTitleBarButtonsForTheme(theme);
}
}
}
}
-144
View File
@@ -1,144 +0,0 @@
<UserControl
x:Class="FluentTerminal.App.Views.TabBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:behaviors="using:FluentTerminal.App.Behaviors"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewmodels="using:FluentTerminal.App.ViewModels"
d:DesignHeight="32"
d:DesignWidth="200"
mc:Ignorable="d">
<Grid x:Name="Tabs" Visibility="{x:Bind ItemsSource.Count, Mode=OneWay, Converter={StaticResource OneToCollapsedConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<RepeatButton
x:Name="ScrollLeftButton"
Grid.Column="0"
Width="24"
Padding="0,0,0,0"
Click="OnScrollLeftButtonTapped"
Style="{StaticResource TitleBarRepeatButtonStyle}"
ToolTipService.ToolTip="Scroll left"
Visibility="Collapsed">
<RepeatButton.Content>
<Viewbox Width="12" Height="12">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE76B;" />
</Viewbox>
</RepeatButton.Content>
</RepeatButton>
<ScrollViewer
x:Name="ScrollViewer"
Grid.Column="1"
HorizontalScrollBarVisibility="Hidden"
HorizontalScrollMode="Enabled"
VerticalScrollBarVisibility="Hidden"
VerticalScrollMode="Disabled">
<ListView
x:Name="ListView"
AllowDrop="True"
CanDragItems="True"
CanReorderItems="True"
ItemsSource="{x:Bind ItemsSource}"
SelectedItem="{x:Bind SelectedItem, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="viewmodels:TerminalViewModel">
<RelativePanel
Height="32"
Margin="0"
VerticalAlignment="Stretch">
<Interactivity:Interaction.Behaviors>
<behaviors:MiddleClickBehavior>
<behaviors:MiddleClickBehavior.Actions>
<core:InvokeCommandAction Command="{x:Bind CloseCommand}" />
</behaviors:MiddleClickBehavior.Actions>
</behaviors:MiddleClickBehavior>
</Interactivity:Interaction.Behaviors>
<Border
Grid.ColumnSpan="3"
Height="3"
VerticalAlignment="Bottom"
Background="{ThemeResource SystemAccentColor}"
RelativePanel.AlignBottomWithPanel="True"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
Visibility="{x:Bind IsUnderlined, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}" />
<TextBlock
Grid.Column="0"
Margin="12,8,6,0"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.LeftOf="CloseButton"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Title, Mode=OneWay}" />
<Button
x:Name="CloseButton"
Grid.Column="2"
Width="32"
Command="{x:Bind CloseCommand}"
RelativePanel.AlignRightWithPanel="True"
Style="{StaticResource TitleBarButtonStyle}"
ToolTipService.ToolTip="Close">
<Viewbox Width="12" Height="12">
<SymbolIcon Symbol="Cancel" />
</Viewbox>
</Button>
</RelativePanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Template>
<ControlTemplate>
<ItemsPresenter />
</ControlTemplate>
</ListView.Template>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="MinWidth" Value="100" />
<Setter Property="MinHeight" Value="32" />
<Setter Property="Padding" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
</ScrollViewer>
<RepeatButton
x:Name="ScrollRightButton"
Grid.Column="2"
Width="24"
Padding="0,0,0,0"
Click="OnScrollRightButtonTapped"
Style="{StaticResource TitleBarRepeatButtonStyle}"
ToolTipService.ToolTip="Scroll right"
Visibility="Collapsed">
<RepeatButton.Content>
<Viewbox Width="12" Height="12">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE76C;" />
</Viewbox>
</RepeatButton.Content>
</RepeatButton>
<Button
x:Name="Add"
Grid.Column="3"
Command="{x:Bind AddCommand}"
Style="{StaticResource TitleBarButtonStyle}"
ToolTipService.ToolTip="New tab">
<Button.Content>
<Viewbox Width="12" Height="12">
<SymbolIcon Symbol="Add" />
</Viewbox>
</Button.Content>
</Button>
</Grid>
</UserControl>
-116
View File
@@ -1,116 +0,0 @@
using FluentTerminal.App.ViewModels;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace FluentTerminal.App.Views
{
public sealed partial class TabBar : UserControl
{
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register(nameof(ItemsSource), typeof(ObservableCollection<TerminalViewModel>), typeof(TabBar), new PropertyMetadata(null));
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register(nameof(AddCommand), typeof(RelayCommand), typeof(TabBar), new PropertyMetadata(null));
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register(nameof(SelectedItem), typeof(object), typeof(TabBar), new PropertyMetadata(null));
public TabBar()
{
InitializeComponent();
ScrollViewer.RegisterPropertyChangedCallback(ScrollViewer.ScrollableWidthProperty, OnScrollableWidthChanged);
ListView.SelectionChanged += OnListViewSelectionChanged;
ScrollLeftButton.Tapped += OnScrollLeftButtonTapped;
ScrollRightButton.Tapped += OnScrollRightButtonTapped;
}
public RelayCommand AddCommand
{
get { return (RelayCommand)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
public ObservableCollection<TerminalViewModel> ItemsSource
{
get { return (ObservableCollection<TerminalViewModel>)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
private void OnListViewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var item = ListView.SelectedItem;
if (item != null)
{
var container = ListView.ContainerFromItem(item);
if (container != null)
{
((UIElement)container).StartBringIntoView();
SetScrollButtonsEnabledState();
}
else
{
Task.Run(async () =>
{
do
{
await Task.Delay(50);
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => container = ListView.ContainerFromItem(item));
}
while (container == null);
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
((UIElement)container).StartBringIntoView();
SetScrollButtonsEnabledState();
});
});
}
}
}
private void OnScrollableWidthChanged(DependencyObject sender, DependencyProperty property)
{
if (ScrollViewer.ScrollableWidth > 0)
{
ScrollLeftButton.Visibility = Visibility.Visible;
ScrollRightButton.Visibility = Visibility.Visible;
}
else
{
ScrollLeftButton.Visibility = Visibility.Collapsed;
ScrollRightButton.Visibility = Visibility.Collapsed;
}
}
private void OnScrollLeftButtonTapped(object sender, RoutedEventArgs e)
{
var offset = ScrollViewer.HorizontalOffset - 10;
ScrollViewer.ChangeView(offset, null, null);
SetScrollButtonsEnabledState();
}
private void OnScrollRightButtonTapped(object sender, RoutedEventArgs e)
{
var offset = ScrollViewer.HorizontalOffset + 10;
ScrollViewer.ChangeView(offset, null, null);
SetScrollButtonsEnabledState();
}
private void SetScrollButtonsEnabledState()
{
ScrollLeftButton.IsEnabled = ScrollViewer.HorizontalOffset > 0;
ScrollRightButton.IsEnabled = ScrollViewer.HorizontalOffset < ScrollViewer.ScrollableWidth;
}
}
}
@@ -31,4 +31,4 @@
</Flyout>
</Button.Flyout>
</Button>
</UserControl>
</UserControl>
+1 -1
View File
@@ -70,4 +70,4 @@
</Button>
</RelativePanel>
</Grid>
</UserControl>
</UserControl>
+17 -47
View File
@@ -2,7 +2,6 @@
using FluentTerminal.App.ViewModels;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using FluentTerminal.RuntimeComponent.Enums;
using FluentTerminal.RuntimeComponent.Interfaces;
using FluentTerminal.RuntimeComponent.WebAllowedObjects;
using Newtonsoft.Json;
@@ -13,6 +12,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
@@ -55,9 +55,7 @@ namespace FluentTerminal.App.Views
}
public event EventHandler<Command> KeyboardCommandReceived;
public event EventHandler<TerminalSize> TerminalSizeChanged;
public event EventHandler<string> TerminalTitleChanged;
public TerminalViewModel ViewModel { get; }
@@ -148,6 +146,12 @@ namespace FluentTerminal.App.Views
_dispatcherJobs.Add(() => TerminalTitleChanged?.Invoke(this, title));
}
public Task Write(string text)
{
text = Convert.ToBase64String(Encoding.UTF8.GetBytes(text));
return ExecuteScriptAsync($"paste('{text}')");
}
public Task FindNext(string searchText)
{
return ExecuteScriptAsync($"findNext('{searchText}')");
@@ -210,6 +214,16 @@ namespace FluentTerminal.App.Views
await ViewModel.OnViewIsReady(this).ConfigureAwait(true);
}
public void OnRightClick(int x, int y, bool hasSelection)
{
_dispatcherJobs.Add(() =>
{
var flyout = (MenuFlyout)_webView.ContextFlyout;
_copyMenuItem.IsEnabled = hasSelection;
flyout.ShowAt(_webView, new Point(x, y));
});
}
private void Paste_Click(object sender, RoutedEventArgs e)
{
OnKeyboardCommand(nameof(Command.Paste));
@@ -251,49 +265,5 @@ namespace FluentTerminal.App.Views
{
SearchTextBox.Focus(FocusState.Programmatic);
}
public void OnMouseClick(MouseButton mouseButton, int x, int y, bool hasSelection)
{
_dispatcherJobs.Add(() =>
{
if (mouseButton == MouseButton.Middle)
{
if (ViewModel.ApplicationSettings.MouseMiddleClickAction == MouseAction.ContextMenu)
{
ShowContextMenu(x, y, hasSelection);
}
else if (ViewModel.ApplicationSettings.MouseMiddleClickAction == MouseAction.Paste)
{
OnKeyboardCommand(nameof(Command.Paste));
}
}
else if (mouseButton == MouseButton.Right)
{
if (ViewModel.ApplicationSettings.MouseRightClickAction == MouseAction.ContextMenu)
{
ShowContextMenu(x, y, hasSelection);
}
else if (ViewModel.ApplicationSettings.MouseRightClickAction == MouseAction.Paste)
{
OnKeyboardCommand(nameof(Command.Paste));
}
}
});
}
public void OnSelectionChanged(string selection)
{
if (ViewModel.ApplicationSettings.CopyOnSelect)
{
_dispatcherJobs.Add(() => OnKeyboardCommand(nameof(Command.Copy)));
}
}
private void ShowContextMenu(int x, int y, bool terminalHasSelection)
{
var flyout = (MenuFlyout)_webView.ContextFlyout;
_copyMenuItem.IsEnabled = terminalHasSelection;
flyout.ShowAt(_webView, new Point(x, y));
}
}
}
+3 -3
View File
@@ -3013,9 +3013,9 @@
"dev": true
},
"xterm": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/xterm/-/xterm-3.5.1.tgz",
"integrity": "sha512-syTMd35T+gDXKkDfwZz8CC685OsSnRujXMO+3lYcD9U+dG3FShc+Ydx71IEjfYg7TYqD+qv6SU9KAKMuiAIiAg=="
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/xterm/-/xterm-3.4.0.tgz",
"integrity": "sha512-eHH9CuKZOdKscBoUPmBxE1nTAuaKCMavcTQilyQf2u6MqB366BJP7SbkGWz+HZj7V5OjldFLLDLzlliqUzoiHQ=="
},
"y18n": {
"version": "3.2.1",
+1 -1
View File
@@ -13,6 +13,6 @@
"webpack": "^3.10.0"
},
"dependencies": {
"xterm": "^3.5.1"
"xterm": "^3.4.0"
}
}
Loaded 100 of 146 files, more files were not shown because too many files have changed in this diff. Show more