Compare commits

...
17 Commits
Author SHA1 Message Date
amacocianandGitHub b455c89ddc Minor improvements (#36)
Deprecate Microsoft.Xaml.Behaviors.Wpf
Reverse version order in management view
2022-08-04 23:05:55 +02:00
amacocianandGitHub 782b76cd8e Remove admin mode when updating (#31) 2022-08-04 21:59:55 +02:00
amacocianandGitHub 230c2d9457 Setup executable installer (#29)
* Setup executable installer

* Increment update to 0.9.3

* Improve installer
2022-08-04 21:39:17 +02:00
amacocianandGitHub 63531e3b8c Hide console window (#25) 2022-08-04 19:52:54 +02:00
amacocianandGitHub ac430305f4 Update to .net 6 and update dependencies (#24)
* Update to .net 6 and update dependencies
2022-08-04 19:25:53 +02:00
amacocianandGitHub 3d830cfc16 Update dependencies (#23) 2021-07-10 13:39:00 +03:00
amacocianandGitHub b529aa8861 Fix logging on startup when ILogger is null (#22) 2021-07-10 12:45:44 +03:00
amacocianandGitHub 3798daa54e Update dependencies (#21)
* Update dependencies
* Minor nit fixes
* Fix UTs
2021-07-10 12:08:43 +03:00
amacocianandGitHub 624380ed86 Use IOptions instead of IConfigurationManager (#20)
* Use IOptions instead of dependency on IConfigurationManager
2021-06-22 15:48:37 +03:00
amacocianandGitHub 2b025e225b Updated wpfextended dependency 2021-06-11 13:50:58 +02:00
amacocianandGitHub 15a67ea28c Minor fixes
Stop showing browser when browser is disabled
Prevent setting address of browser when browser is disabled (should prevent browser from instantiating when disabled)
Ignore errors from browser caused by switching view before the browser could be initialized
Provide expression to filter logs
Button to export logs to json file
2021-06-07 14:33:54 +02:00
amacocianandGitHub c6b62fd5fd Logging improvements
Log uncaught exceptions
Logview expander
2021-06-07 00:34:43 +02:00
amacocianandGitHub 3c0877c1a0 Ability to keep a local cache of icons (#16) 2021-06-03 21:12:31 +02:00
967b57b9a8 Fix build code encoding/decoding view (#15)
Co-authored-by: Alexandru Macocian <almacoci@microsoft.com>
2021-06-03 20:40:56 +02:00
amacocianandGitHub f47cc319b5 Build template code field 2021-06-03 19:57:29 +02:00
amacocianandGitHub 26da84c4e7 Update to new version of wpfextended
Fix a bug where version parsing would ignore all 0s before the first digit
Remove LoggerFactory and LoggerProviders duplicated in WpfExtended
2021-06-03 14:48:35 +02:00
a39e8dc5c6 Separate CV from message (#12)
Co-authored-by: Alexandru Macocian <almacoci@microsoft.com>
2021-06-01 21:57:27 +02:00
67 changed files with 857 additions and 801 deletions
+7 -2
View File
@@ -52,7 +52,7 @@ jobs:
- name: Install .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.202'
dotnet-version: '6.x'
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.0.1
@@ -70,11 +70,16 @@ jobs:
$version = .\Scripts\GetBuildVersion.ps1
echo "::set-env name=Version::$version"
- name: Create publish files
- name: Create publish launcher files
run: dotnet publish .\Daybreak\Daybreak.csproj -c $env:Configuration -r $env:RuntimeIdentifier -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -o .\Publish
env:
RuntimeIdentifier: win-${{ matrix.targetplatform }}
- name: Create publish installer files
run: dotnet publish .\Daybreak.Installer\Daybreak.Installer.csproj -c $env:Configuration -r $env:RuntimeIdentifier -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -o .\Publish
env:
RuntimeIdentifier: win-${{ matrix.targetplatform }}
- name: Pack publish files
run: |
Write-Host $env
+1 -1
View File
@@ -38,7 +38,7 @@ jobs:
- name: Install .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.202'
dotnet-version: '6.x'
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.0.1
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
+41
View File
@@ -0,0 +1,41 @@
// See https://aka.ms/new-console-template for more information
using System.Diagnostics;
using System.IO.Compression;
const string tempFile = "tempfile.zip";
const string executableName = "Daybreak.exe";
Console.Title = "Daybreak Installer";
Console.WriteLine("Starting installation...");
if (File.Exists(tempFile) is false)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Unable to find launcher package. Aborting installation");
Console.ReadKey();
return;
}
Console.WriteLine("Unpacking files...");
try
{
ZipFile.ExtractToDirectory(tempFile, AppContext.BaseDirectory, true);
}
catch
{
}
Console.WriteLine("Deleting package");
File.Delete(tempFile);
Console.WriteLine("Launching application");
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = executableName
}
};
if (process.Start() is false)
{
Console.WriteLine("Failed to launch application");
Console.ReadKey();
}
+8 -9
View File
@@ -1,19 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0-windows</TargetFramework>
<TargetFramework>net6.0-windows</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.0.0-alpha0002" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
<PackageReference Include="System.Linq.Async" Version="5.0.0" />
<PackageReference Include="FluentAssertions" Version="6.7.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0-preview-20220707-01" />
<PackageReference Include="Moq" Version="4.18.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
</ItemGroup>
<ItemGroup>
+2
View File
@@ -10,6 +10,8 @@ namespace Daybreak.Tests.Models
[TestClass]
public class VersionTests
{
[DataRow("v0.1.0.0.1", "v0.1.0.0.1")]
[DataRow("v0.1.0.0.1.0.0.0.0", "v0.1.0.0.1")]
[DataRow("v0.1.0", "v0.1")]
[DataRow("0.1.0", "0.1")]
[DataRow("v0.1.0.0.0", "v0.1")]
@@ -0,0 +1,63 @@
using Daybreak.Configuration;
using Daybreak.Services.Configuration;
using Daybreak.Services.Options;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
namespace Daybreak.Tests.Services
{
[TestClass]
public class ApplicationConfigurationOptionsManagerTests
{
private ApplicationConfigurationOptionsManager applicationConfigurationOptionsManager;
[TestInitialize]
public void TestInitialize()
{
var configurationManagerMock = new Mock<IConfigurationManager>();
configurationManagerMock
.Setup(u => u.GetConfiguration())
.Returns(new ApplicationConfiguration());
this.applicationConfigurationOptionsManager = new ApplicationConfigurationOptionsManager(configurationManagerMock.Object);
}
[TestMethod]
public void GetApplicationConfiguration_ReturnsObject()
{
var config = this.applicationConfigurationOptionsManager.GetOptions<ApplicationConfiguration>();
config.Should().NotBeNull();
}
[TestMethod]
public void GetOtherOptions_ThrowsInvalidOperationException()
{
var action = new Action(() =>
{
this.applicationConfigurationOptionsManager.GetOptions<object>();
});
action.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public void UpdateOptions_OnApplicationConfiguration_Succeeds()
{
this.applicationConfigurationOptionsManager.UpdateOptions(new ApplicationConfiguration());
}
[TestMethod]
public void UpdateOptions_OnOthers_ThrowsInvalidOperationException()
{
var action = new Action(() =>
{
this.applicationConfigurationOptionsManager.UpdateOptions(new object());
});
action.Should().Throw<InvalidOperationException>();
}
}
}
@@ -4,6 +4,8 @@ using LiteDB;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
using System.Linq;
using System.Logging;
namespace Daybreak.Tests.Services
{
@@ -20,7 +22,7 @@ namespace Daybreak.Tests.Services
File.Delete("Daybreak.db");
this.liteDatabase = new LiteDatabase("Daybreak.db");
this.logsManager = new JsonLogsManager(this.liteDatabase);
this.loggerProvider = new JsonLoggerProvider(this.logsManager);
this.loggerProvider = new CVLoggerProvider(this.logsManager);
}
[TestCleanup]
@@ -36,6 +38,18 @@ namespace Daybreak.Tests.Services
logger.Should().NotBeNull();
}
[TestMethod]
public void LoggerLogsAndReaderReadsFiltered()
{
var logger = this.loggerProvider.CreateLogger("SomeCategory");
logger.LogTrace("Logging some trace");
logger.LogInformation("Logging some stuff");
logger.LogError("Logging some error");
this.logsManager.GetLogs(l => l.LogLevel < LogLevel.Information).Should().HaveCount(1);
var log = this.logsManager.GetLogs(l => l.LogLevel < LogLevel.Information).First();
log.LogLevel.Should().Be(LogLevel.Error);
}
[TestMethod]
public void LoggerLogsAndReaderReads()
{
var logger = this.loggerProvider.CreateLogger("SomeCategory");
+18 -2
View File
@@ -1,12 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31005.135
# Visual Studio Version 17
VisualStudioVersion = 17.2.32616.157
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Daybreak", "Daybreak\Daybreak.csproj", "{AA45C2B1-8BD0-466C-9271-699F168905AF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Daybreak.Tests", "Daybreak.Tests\Daybreak.Tests.csproj", "{C911C1C2-6566-419C-89C7-F802EB3FE709}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Pipelines", "Pipelines", "{067BF93F-E5B2-4E99-886E-039C04F35EAB}"
ProjectSection(SolutionItems) = preProject
.github\workflows\cd.yaml = .github\workflows\cd.yaml
.github\workflows\ci.yaml = .github\workflows\ci.yaml
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Daybreak.Installer", "Daybreak.Installer\Daybreak.Installer.csproj", "{4E2BB805-135D-4F02-8C53-3D8B6876D323}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -31,6 +39,14 @@ Global
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|Any CPU.Build.0 = Release|Any CPU
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x64.ActiveCfg = Release|Any CPU
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x64.Build.0 = Release|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x64.ActiveCfg = Debug|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x64.Build.0 = Debug|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|Any CPU.Build.0 = Release|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x64.ActiveCfg = Release|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+2 -2
View File
@@ -1,9 +1,9 @@
using System;
using Microsoft.Xaml.Behaviors;
using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;
namespace Daybreak.Behaviors
+2 -2
View File
@@ -1,7 +1,7 @@
using System;
using Microsoft.Xaml.Behaviors;
using System;
using System.Extensions;
using System.Windows.Controls;
using System.Windows.Interactivity;
namespace Daybreak.Behaviors
{
@@ -37,5 +37,7 @@ namespace Daybreak.Configuration
public bool PlaceShortcut { get; set; }
[JsonProperty("AutoCheckUpdate")]
public bool AutoCheckUpdate { get; set; } = true;
[JsonProperty("KeepLocalIconCache")]
public bool KeepLocalIconCache { get; set; } = true;
}
}
+14 -25
View File
@@ -1,5 +1,4 @@
using Daybreak.Services.ApplicationLauncher;
using Daybreak.Services.ApplicationLifetime;
using Daybreak.Services.Bloogum;
using Daybreak.Services.BuildTemplates;
using Daybreak.Services.Configuration;
@@ -8,7 +7,6 @@ using Daybreak.Services.IconRetrieve;
using Daybreak.Services.Logging;
using Daybreak.Services.Mutex;
using Daybreak.Services.Privilege;
using Daybreak.Services.Runtime;
using Daybreak.Services.Screens;
using Daybreak.Services.Screenshots;
using Daybreak.Services.Shortcuts;
@@ -20,9 +18,10 @@ using Microsoft.Extensions.Logging;
using Slim;
using System.Extensions;
using System.Net.Http;
using System.Windows.Extensions.Http;
using LiteDB;
using Daybreak.Controls;
using Daybreak.Services.Options;
using Daybreak.Models;
using Microsoft.CorrelationVector;
namespace Daybreak.Configuration
{
@@ -32,27 +31,23 @@ namespace Daybreak.Configuration
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterScoped<ILoggerFactory, CVLoggerFactory>((sp) => new CVLoggerFactory(sp.GetService<ILogsManager>()));
serviceManager.RegisterResolver(
new HttpClientResolver()
.WithHttpMessageHandlerFactory((serviceProvider, categoryType) =>
{
var loggerType = typeof(ILogger<>).MakeGenericType(categoryType);
var logger = serviceProvider.GetService(loggerType).As<ILogger>();
var handler = new LoggingHttpMessageHandler(logger) { InnerHandler = new HttpClientHandler() };
return handler;
}));
serviceManager.RegisterHttpFactory((serviceProvider, categoryType) =>
{
var loggerType = typeof(ILogger<>).MakeGenericType(categoryType);
var logger = serviceProvider.GetService(loggerType).As<ILogger>();
var handler = new LoggingHttpMessageHandler(logger) { InnerHandler = new HttpClientHandler() };
return handler;
});
serviceManager.RegisterOptionsManager<ApplicationConfigurationOptionsManager>();
}
public static void RegisterServices(IServiceProducer serviceProducer)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceProducer.RegisterSingleton<ApplicationLifetimeManager>();
serviceProducer.RegisterSingleton<ViewManager>();
serviceProducer.RegisterSingleton<ViewManager>(registerAllInterfaces: true);
serviceProducer.RegisterSingleton<IConfigurationManager, ConfigurationManager>();
serviceProducer.RegisterSingleton<ILiteDatabase, LiteDatabase>(sp => new LiteDatabase("Daybreak.db"));
serviceProducer.RegisterSingleton<IRuntimeStore, RuntimeStore>();
serviceProducer.RegisterSingleton<IMutexHandler, MutexHandler>();
serviceProducer.RegisterSingleton<IShortcutManager, ShortcutManager>();
serviceProducer.RegisterScoped<ICredentialManager, CredentialManager>();
@@ -64,16 +59,10 @@ namespace Daybreak.Configuration
serviceProducer.RegisterScoped<IIconRetriever, IconRetriever>();
serviceProducer.RegisterScoped<IPrivilegeManager, PrivilegeManager>();
serviceProducer.RegisterScoped<IScreenManager, ScreenManager>();
serviceProducer.RegisterScoped<ILogsManager, JsonLogsManager>();
serviceProducer.RegisterLogWriter<ILogsManager, JsonLogsManager>();
serviceProducer.RegisterScoped((sp) => new ScopeMetadata(new CorrelationVector()));
}
public static void RegisterLifetimeServices(IApplicationLifetimeProducer applicationLifetimeProducer)
{
applicationLifetimeProducer.ThrowIfNull(nameof(applicationLifetimeProducer));
applicationLifetimeProducer.RegisterService<IScreenshotProvider>();
applicationLifetimeProducer.RegisterService<IApplicationUpdater>();
applicationLifetimeProducer.RegisterService<IShortcutManager>();
}
public static void RegisterViews(IViewProducer viewProducer)
{
viewProducer.ThrowIfNull(nameof(viewProducer));
+1 -1
View File
@@ -4,7 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
xmlns:converters="clr-namespace:Daybreak.Converters"
x:Name="_this"
@@ -1,11 +1,12 @@
using Daybreak.Models.Browser;
using Daybreak.Configuration;
using Daybreak.Models.Browser;
using Daybreak.Models.Builds;
using Daybreak.Services.BuildTemplates;
using Daybreak.Services.Configuration;
using Daybreak.Utils;
using Microsoft.Extensions.Logging;
using Microsoft.Web.WebView2.Core;
using System;
using System.Configuration;
using System.Diagnostics;
using System.Extensions;
using System.Threading.Tasks;
@@ -22,13 +23,16 @@ namespace Daybreak.Controls
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
public partial class ChromiumBrowserWrapper : UserControl
{
public static readonly DependencyProperty AddressProperty =
DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, string>(nameof(Address));
private const string BrowserDownloadLink = "https://developer.microsoft.com/en-us/microsoft-edge/webview2/";
public event EventHandler<string> FavoriteUriChanged;
public event EventHandler MaximizeClicked;
public event EventHandler<Build> BuildDecoded;
private IConfigurationManager configurationManager;
private ILiveOptions<ApplicationConfiguration> liveOptions;
private ILogger<ChromiumBrowserWrapper> logger;
private IBuildTemplateManager buildTemplateManager;
private CoreWebView2Environment coreWebView2Environment;
@@ -49,8 +53,17 @@ namespace Daybreak.Controls
private bool navigating;
[GenerateDependencyProperty]
private string favoriteAddress;
[GenerateDependencyProperty]
private string address;
public string Address
{
get => this.GetTypedValue<string>(AddressProperty);
set
{
if (this.BrowserSupported is true)
{
this.SetValue(AddressProperty, value);
}
}
}
public ChromiumBrowserWrapper()
{
@@ -68,11 +81,11 @@ namespace Daybreak.Controls
}
public async void InitializeBrowser(
IConfigurationManager configurationManager,
ILiveOptions<ApplicationConfiguration> liveOptions,
IBuildTemplateManager buildTemplateManager,
ILogger<ChromiumBrowserWrapper> logger)
{
this.configurationManager = configurationManager;
this.liveOptions = liveOptions;
this.buildTemplateManager = buildTemplateManager;
this.logger = logger;
this.InitializeEnvironment();
@@ -86,7 +99,7 @@ namespace Daybreak.Controls
private void InitializeEnvironment()
{
if (this.configurationManager.GetConfiguration().BrowsersEnabled is false)
if (this.liveOptions.Value.BrowsersEnabled is false)
{
this.BrowserSupported = false;
return;
@@ -110,8 +123,8 @@ namespace Daybreak.Controls
{
this.WebBrowser.IsEnabled = true;
await this.WebBrowser.EnsureCoreWebView2Async(this.coreWebView2Environment);
this.AddressBarReadonly = this.configurationManager.GetConfiguration().AddressBarReadonly;
this.CanDownloadBuild = this.configurationManager.GetConfiguration().ExperimentalFeatures.DynamicBuildLoading;
this.AddressBarReadonly = this.liveOptions.Value.AddressBarReadonly;
this.CanDownloadBuild = this.liveOptions.Value.ExperimentalFeatures.DynamicBuildLoading;
this.WebBrowser.CoreWebView2.NewWindowRequested += (browser, args) => args.Handled = true;
this.WebBrowser.NavigationStarting += (browser, args) =>
{
@@ -184,6 +197,7 @@ namespace Daybreak.Controls
{
this.logger.LogError(e, $"Exception encountered when deserializing {nameof(BrowserPayload)}");
}
if (payload?.Key == BrowserPayload.PayloadKeys.ContextMenu)
{
var contextMenuPayload = args.WebMessageAsJson.Deserialize<BrowserPayload<OnContextMenuPayload>>();
@@ -15,6 +15,7 @@ namespace Daybreak.Controls
public partial class AttributeTemplate : UserControl
{
public event EventHandler<AttributeEntry> HelpClicked;
public event EventHandler<AttributeEntry> AttributeChanged;
[GenerateDependencyProperty(InitialValue = false)]
private bool canAdd;
@@ -50,6 +51,7 @@ namespace Daybreak.Controls
this.DataContext.As<AttributeEntry>().Points--;
this.CanSubtract = this.DataContext.As<AttributeEntry>().Points > 0;
this.CanAdd = true;
this.AttributeChanged?.Invoke(this, this.DataContext.As<AttributeEntry>());
}
}
@@ -60,6 +62,7 @@ namespace Daybreak.Controls
this.DataContext.As<AttributeEntry>().Points++;
this.CanAdd = this.DataContext.As<AttributeEntry>().Points < 12;
this.CanSubtract = true;
this.AttributeChanged?.Invoke(this, this.DataContext.As<AttributeEntry>());
}
}
@@ -4,7 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
xmlns:interactivity="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:interactivity="http://schemas.microsoft.com/xaml/behaviors"
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
xmlns:converters="clr-namespace:Daybreak.Converters"
mc:Ignorable="d"
@@ -75,7 +75,7 @@
HorizontalContentAlignment="Stretch" BorderThickness="0">
<ListBox.ItemTemplate>
<DataTemplate>
<local:AttributeTemplate HelpClicked="AttributeTemplate_HelpClicked"></local:AttributeTemplate>
<local:AttributeTemplate HelpClicked="AttributeTemplate_HelpClicked" AttributeChanged="AttributeTemplate_AttributeChanged"></local:AttributeTemplate>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
@@ -1,10 +1,12 @@
using Daybreak.Models.Builds;
using Daybreak.Configuration;
using Daybreak.Models.Builds;
using Daybreak.Services.BuildTemplates;
using Daybreak.Services.Configuration;
using Daybreak.Services.IconRetrieve;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Extensions;
using System.Linq;
using System.Windows;
@@ -23,10 +25,13 @@ namespace Daybreak.Controls
private const string InfoNamePlaceholder = "[NAME]";
private const string BaseAddress = $"https://wiki.guildwars.com/wiki/{InfoNamePlaceholder}";
private bool suppressBuildChanged = false;
private bool loadedProperties = false;
private BuildEntry loadedBuild;
private SkillTemplate selectingSkillTemplate;
public event EventHandler BuildChanged;
[GenerateDependencyProperty]
private Profession primaryProfession;
[GenerateDependencyProperty]
@@ -55,16 +60,16 @@ namespace Daybreak.Controls
{
this.InitializeComponent();
this.InitializeProperties();
this.DataContextChanged += BuildTemplate_DataContextChanged;
this.DataContextChanged += this.BuildTemplate_DataContextChanged;
}
public void InitializeTemplate(
IIconRetriever iconRetriever,
IConfigurationManager configurationManager,
ILiveOptions<ApplicationConfiguration> liveOptions,
IBuildTemplateManager buildTemplateManager,
ILogger<ChromiumBrowserWrapper> logger)
{
this.SkillBrowser.InitializeBrowser(configurationManager, buildTemplateManager, logger);
this.SkillBrowser.InitializeBrowser(liveOptions, buildTemplateManager, logger);
this.SkillTemplate0.InitializeSkillTemplate(iconRetriever);
this.SkillTemplate1.InitializeSkillTemplate(iconRetriever);
this.SkillTemplate2.InitializeSkillTemplate(iconRetriever);
@@ -93,8 +98,36 @@ namespace Daybreak.Controls
{
this.loadedBuild.Build.Secondary = this.SecondaryProfession;
}
this.LoadSkills();
this.LoadAttributes();
if (this.suppressBuildChanged is false)
{
this.BuildChanged?.Invoke(this, new EventArgs());
}
}
if (e.Property == Skill0Property ||
e.Property == Skill1Property ||
e.Property == Skill2Property ||
e.Property == Skill3Property ||
e.Property == Skill4Property ||
e.Property == Skill5Property ||
e.Property == Skill6Property ||
e.Property == Skill7Property)
{
if (this.suppressBuildChanged is false)
{
this.loadedBuild.Build.Skills[0] = this.Skill0;
this.loadedBuild.Build.Skills[1] = this.Skill1;
this.loadedBuild.Build.Skills[2] = this.Skill2;
this.loadedBuild.Build.Skills[3] = this.Skill3;
this.loadedBuild.Build.Skills[4] = this.Skill4;
this.loadedBuild.Build.Skills[5] = this.Skill5;
this.loadedBuild.Build.Skills[6] = this.Skill6;
this.loadedBuild.Build.Skills[7] = this.Skill7;
this.BuildChanged?.Invoke(this, new EventArgs());
}
}
}
@@ -161,55 +194,62 @@ namespace Daybreak.Controls
private void LoadSkills()
{
var possibleSkills = Skill.Skills
.Where(s => s.Profession == PrimaryProfession || s.Profession == SecondaryProfession || s.Profession == Profession.None)
.Where(s => s.Profession == this.PrimaryProfession || s.Profession == this.SecondaryProfession || s.Profession == Profession.None)
.Where(s => s != Skill.NoSkill)
.OrderBy(s => s.Name);
this.AvailableSkills.ClearAnd().AddRange(possibleSkills);
if (this.Skill0.Profession != PrimaryProfession &&
this.Skill0.Profession != SecondaryProfession &&
if (this.Skill0.Profession != this.PrimaryProfession &&
this.Skill0.Profession != this.SecondaryProfession &&
this.Skill0.Profession != Profession.None)
{
this.Skill0 = Skill.NoSkill;
}
if (this.Skill1.Profession != PrimaryProfession &&
this.Skill1.Profession != SecondaryProfession &&
if (this.Skill1.Profession != this.PrimaryProfession &&
this.Skill1.Profession != this.SecondaryProfession &&
this.Skill1.Profession != Profession.None)
{
this.Skill1 = Skill.NoSkill;
}
if (this.Skill2.Profession != PrimaryProfession &&
this.Skill2.Profession != SecondaryProfession &&
if (this.Skill2.Profession != this.PrimaryProfession &&
this.Skill2.Profession != this.SecondaryProfession &&
this.Skill2.Profession != Profession.None)
{
this.Skill2 = Skill.NoSkill;
}
if (this.Skill3.Profession != PrimaryProfession &&
this.Skill3.Profession != SecondaryProfession &&
if (this.Skill3.Profession != this.PrimaryProfession &&
this.Skill3.Profession != this.SecondaryProfession &&
this.Skill3.Profession != Profession.None)
{
this.Skill3 = Skill.NoSkill;
}
if (this.Skill4.Profession != PrimaryProfession &&
this.Skill4.Profession != SecondaryProfession &&
if (this.Skill4.Profession != this.PrimaryProfession &&
this.Skill4.Profession != this.SecondaryProfession &&
this.Skill4.Profession != Profession.None)
{
this.Skill4 = Skill.NoSkill;
}
if (this.Skill5.Profession != PrimaryProfession &&
this.Skill5.Profession != SecondaryProfession &&
if (this.Skill5.Profession != this.PrimaryProfession &&
this.Skill5.Profession != this.SecondaryProfession &&
this.Skill5.Profession != Profession.None)
{
this.Skill5 = Skill.NoSkill;
}
if (this.Skill6.Profession != PrimaryProfession &&
this.Skill6.Profession != SecondaryProfession &&
if (this.Skill6.Profession != this.PrimaryProfession &&
this.Skill6.Profession != this.SecondaryProfession &&
this.Skill6.Profession != Profession.None)
{
this.Skill6 = Skill.NoSkill;
}
if (this.Skill7.Profession != PrimaryProfession &&
this.Skill7.Profession != SecondaryProfession &&
if (this.Skill7.Profession != this.PrimaryProfession &&
this.Skill7.Profession != this.SecondaryProfession &&
this.Skill7.Profession != Profession.None)
{
this.Skill7 = Skill.NoSkill;
@@ -218,6 +258,7 @@ namespace Daybreak.Controls
private void LoadBuild()
{
this.suppressBuildChanged = true;
var build = this.DataContext.As<BuildEntry>();
this.loadedBuild = build;
this.PrimaryProfession = build.Build.Primary;
@@ -230,6 +271,7 @@ namespace Daybreak.Controls
this.Skill5 = build.Build.Skills[5];
this.Skill6 = build.Build.Skills[6];
this.Skill7 = build.Build.Skills[7];
this.suppressBuildChanged = false;
}
private void BrowseToInfo(string infoName)
@@ -241,13 +283,19 @@ namespace Daybreak.Controls
private void ShowInfoBrowser()
{
this.SkillBrowser.Width = 400;
this.SkillsListView.Width = 0;
if (this.SkillBrowser.BrowserSupported is true)
{
this.SkillBrowser.Width = 400;
this.SkillsListView.Width = 0;
}
}
private void HideInfoBrowser()
{
this.SkillBrowser.Width = 0;
if (this.SkillBrowser.BrowserSupported is true)
{
this.SkillBrowser.Width = 0;
}
}
private void ShowSkillListView()
@@ -268,7 +316,7 @@ namespace Daybreak.Controls
return;
}
this.BrowseToInfo(PrimaryProfession.Name);
this.BrowseToInfo(this.PrimaryProfession.Name);
if (e is RoutedEventArgs routedEventArgs)
{
routedEventArgs.Handled = true;
@@ -294,6 +342,11 @@ namespace Daybreak.Controls
this.BrowseToInfo(e.Attribute.Name);
}
private void AttributeTemplate_AttributeChanged(object sender, AttributeEntry e)
{
this.BuildChanged?.Invoke(this, new EventArgs());
}
private void SkillTemplate_Clicked(object sender, RoutedEventArgs e)
{
var skill = sender.As<SkillTemplate>().DataContext.As<Skill>();
@@ -306,6 +359,7 @@ namespace Daybreak.Controls
{
this.BrowseToInfo(skill.Name);
}
e.Handled = true;
}
@@ -324,14 +378,14 @@ namespace Daybreak.Controls
this.selectingSkillTemplate.DataContext = sender.As<ListView>().SelectedItem;
this.HideSkillListView();
this.loadedBuild.Build.Skills[0] = Skill0;
this.loadedBuild.Build.Skills[1] = Skill1;
this.loadedBuild.Build.Skills[2] = Skill2;
this.loadedBuild.Build.Skills[3] = Skill3;
this.loadedBuild.Build.Skills[4] = Skill4;
this.loadedBuild.Build.Skills[5] = Skill5;
this.loadedBuild.Build.Skills[6] = Skill6;
this.loadedBuild.Build.Skills[7] = Skill7;
this.loadedBuild.Build.Skills[0] = this.Skill0;
this.loadedBuild.Build.Skills[1] = this.Skill1;
this.loadedBuild.Build.Skills[2] = this.Skill2;
this.loadedBuild.Build.Skills[3] = this.Skill3;
this.loadedBuild.Build.Skills[4] = this.Skill4;
this.loadedBuild.Build.Skills[5] = this.Skill5;
this.loadedBuild.Build.Skills[6] = this.Skill6;
this.loadedBuild.Build.Skills[7] = this.Skill7;
}
private void ListView_NavigateWithMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
@@ -0,0 +1,18 @@
<UserControl x:Class="Daybreak.Controls.LogMessageTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
x:Name="_this"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"></BooleanToVisibilityConverter>
</UserControl.Resources>
<Grid HorizontalAlignment="Stretch">
<TextBlock Text="{Binding ElementName=_this, Path=Message, Mode=OneWay}" Background="Transparent"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
MouseLeftButtonDown="TextBox_MouseLeftButtonDown" MaxHeight="18" TextWrapping="Wrap"></TextBlock>
</Grid>
</UserControl>
@@ -0,0 +1,36 @@
using System.Windows.Extensions;
using System.Windows.Controls;
using System.Windows.Input;
using System.Extensions;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for LogTemplate.xaml
/// </summary>
public partial class LogMessageTemplate : UserControl
{
private bool expanded;
[GenerateDependencyProperty]
private string message;
public LogMessageTemplate()
{
this.InitializeComponent();
}
private void TextBox_MouseLeftButtonDown(object sender, MouseButtonEventArgs eventArgs)
{
this.expanded = !this.expanded;
if (this.expanded)
{
sender.As<TextBlock>().MaxHeight = double.MaxValue;
}
else
{
sender.As<TextBlock>().MaxHeight = 18;
}
}
}
}
+23 -15
View File
@@ -1,35 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<Platforms>AnyCPU</Platforms>
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<LangVersion>preview</LangVersion>
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
<Version>0.9</Version>
<Version>0.9.3.2</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.11.32" />
<PackageReference Include="LiteDB" Version="5.0.10" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.43" />
<PackageReference Include="LiteDB" Version="5.0.12" />
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.864.35" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1264.42" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NReco.Logging.File" Version="1.1.1" />
<PackageReference Include="NReco.Logging.File" Version="1.1.5" />
<PackageReference Include="securifybv.ShellLink" Version="0.1.0" />
<PackageReference Include="Slim" Version="1.4.2" />
<PackageReference Include="System.Windows.Interactivity.WPF" Version="2.0.20525" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.2.0" />
<PackageReference Include="Slim" Version="1.7.3" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.5.0" />
<PackageReference Include="WCL" Version="1.0.2" />
<PackageReference Include="WpfExtended" Version="0.3.3" />
<PackageReference Include="WpfExtended" Version="0.6.2" />
<PackageReference Include="WpfExtended.SourceGeneration" Version="0.1.1" />
<PackageReference Include="WpfScreenHelper" Version="1.0.0" />
<PackageReference Include="WpfScreenHelper" Version="2.0.0" />
</ItemGroup>
<ItemGroup>
@@ -74,4 +74,12 @@
<Exec Command="echo.&gt;$(Version).version" />
</Target>
<Target Name="RemoveDuplicateAnalyzers" BeforeTargets="CoreCompile">
<!-- Work around https://github.com/dotnet/wpf/issues/6792 -->
<ItemGroup>
<FilteredAnalyzer Include="@(Analyzer-&gt;Distinct())" />
<Analyzer Remove="@(Analyzer)" />
<Analyzer Include="@(FilteredAnalyzer)" />
</ItemGroup>
</Target>
</Project>
+21 -10
View File
@@ -1,6 +1,5 @@
using Daybreak.Configuration;
using Daybreak.Exceptions;
using Daybreak.Services.ApplicationLifetime;
using Daybreak.Services.ViewManagement;
using Microsoft.Extensions.Logging;
using Slim;
@@ -16,7 +15,7 @@ namespace Daybreak.Launch
{
public sealed class Launcher : ExtendedApplication<MainWindow>
{
public static IServiceManager ApplicationServiceManager { get; private set; }
private ILogger logger;
private readonly static Launcher launcher = new();
[STAThread]
@@ -27,14 +26,12 @@ namespace Daybreak.Launch
protected override void SetupServiceManager(IServiceManager serviceManager)
{
ApplicationServiceManager = this.ServiceManager;
ProjectConfiguration.RegisterResolvers(serviceManager);
}
protected override void RegisterServices(IServiceProducer serviceProducer)
{
ProjectConfiguration.RegisterServices(this.ServiceManager);
ServiceManager.BuildSingletons();
ProjectConfiguration.RegisterLifetimeServices(this.ServiceManager.GetService<IApplicationLifetimeManager>());
ProjectConfiguration.RegisterViews(this.ServiceManager.GetService<IViewManager>());
}
protected override bool HandleException(Exception e)
@@ -44,17 +41,21 @@ namespace Daybreak.Launch
return false;
}
this.ServiceManager.GetService<ILogger>().LogCritical(e, $"Unhandled exception");
if (this.logger is null)
{
return false;
}
if (e is FatalException fatalException)
{
this.ServiceManager.GetService<ILogger>().LogCritical(e, $"{nameof(FatalException)} encountered. Closing application.");
this.logger.LogCritical(e, $"{nameof(FatalException)} encountered. Closing application");
MessageBox.Show(fatalException.ToString());
File.WriteAllText("crash.log", e.ToString());
return false;
}
else if (e is TargetInvocationException targetInvocationException && e.InnerException is FatalException innerFatalException)
{
this.ServiceManager.GetService<ILogger>().LogCritical(e, $"{nameof(FatalException)} encountered. Closing application.");
this.logger.LogCritical(e, $"{nameof(FatalException)} encountered. Closing application");
MessageBox.Show(innerFatalException.ToString());
File.WriteAllText("crash.log", e.ToString());
return false;
@@ -66,23 +67,33 @@ namespace Daybreak.Launch
{
/*
* Ignore exception caused by browser failing to initialize due to missing window.
* Likely caused by switching windows before browser was initialized.
* Likely caused by switching views before browser was initialized.
*/
this.logger.LogError(e, "Failed to initialize browser");
return true;
}
}
else if (e.Message.Contains("Invalid window handle.") && e.StackTrace.Contains("CoreWebView2Environment.CreateCoreWebView2ControllerAsync"))
{
/*
* Ignore exception caused by browser failing to initialize due to missing window.
* Likely caused by switching views before the browser was initialized.
*/
this.logger.LogError(e, "Failed to initialize browser");
return true;
}
this.logger.LogError(e, $"Unhandled exception caught {e.GetType()}");
MessageBox.Show(e.ToString());
return true;
}
protected override void ApplicationStarting()
{
this.ServiceManager.GetService<IApplicationLifetimeManager>().OnStartup();
this.logger = this.ServiceManager.GetService<ILogger<Launcher>>();
this.RegisterViewContainer();
}
protected override void ApplicationClosing()
{
this.ServiceManager.GetService<IApplicationLifetimeManager>().OnClosing();
}
private void RegisterViewContainer()
+7 -16
View File
@@ -1,13 +1,13 @@
using Daybreak.Services.Bloogum;
using Daybreak.Services.Configuration;
using Daybreak.Configuration;
using Daybreak.Services.Bloogum;
using Daybreak.Services.Privilege;
using Daybreak.Services.Runtime;
using Daybreak.Services.Screenshots;
using Daybreak.Services.Updater;
using Daybreak.Services.ViewManagement;
using Daybreak.Views;
using Pepa.Wpf.Utilities;
using System;
using System.Configuration;
using System.Diagnostics;
using System.Extensions;
using System.Threading;
@@ -32,11 +32,9 @@ namespace Daybreak.Launch
private readonly IBloogumClient bloogumClient;
private readonly IApplicationUpdater applicationUpdater;
private readonly IPrivilegeManager privilegeManager;
private readonly IConfigurationManager configurationManager;
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
private readonly CancellationTokenSource cancellationToken = new();
private bool canCheckUpdate = false;
[GenerateDependencyProperty]
private string creditText;
[GenerateDependencyProperty]
@@ -50,26 +48,19 @@ namespace Daybreak.Launch
IBloogumClient bloogumClient,
IApplicationUpdater applicationUpdater,
IPrivilegeManager privilegeManager,
IConfigurationManager configurationManager)
ILiveOptions<ApplicationConfiguration> liveOptions)
{
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.screenshotProvider = screenshotProvider.ThrowIfNull(nameof(screenshotProvider));
this.bloogumClient = bloogumClient.ThrowIfNull(nameof(bloogumClient));
this.applicationUpdater = applicationUpdater.ThrowIfNull(nameof(applicationUpdater));
this.privilegeManager = privilegeManager.ThrowIfNull(nameof(privilegeManager));
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.liveOptions = liveOptions.ThrowIfNull(nameof(liveOptions));
this.InitializeComponent();
this.LoadConfiguration();
this.configurationManager.ConfigurationChanged += (s, e) => this.LoadConfiguration();
this.CurrentVersionText = this.applicationUpdater.CurrentVersion.ToString();
this.IsRunningAsAdmin = this.privilegeManager.AdminPrivileges;
}
private void LoadConfiguration()
{
var configuration = this.configurationManager.GetConfiguration();
this.canCheckUpdate = configuration.AutoCheckUpdate;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
@@ -178,7 +169,7 @@ namespace Daybreak.Launch
private async void CheckForUpdates()
{
var updateAvailable = this.canCheckUpdate is true && await this.applicationUpdater.UpdateAvailable().ConfigureAwait(true);
var updateAvailable = this.liveOptions.Value.AutoCheckUpdate is true && await this.applicationUpdater.UpdateAvailable().ConfigureAwait(true);
if (updateAvailable)
{
this.viewManager.ShowView<AskUpdateView>();
+5 -10
View File
@@ -1,20 +1,15 @@
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
namespace Daybreak.Models
{
public sealed class Log
{
[JsonProperty("DateTime")]
public DateTime LogTime { get; set; }
[JsonProperty("Category")]
public string Category { get; set; }
[JsonProperty("EventId")]
public string EventId { get; set; }
[JsonProperty("LogLevel")]
public LogLevel LogLevel { get; set; }
[JsonProperty("Message")]
public string Message { get; set; }
public string Category { get; set; }
public LogLevel LogLevel { get; set; }
public string CorrelationVector { get; set; }
public string EventId { get; set; }
public DateTime LogTime { get; set; }
}
}
+14 -18
View File
@@ -9,49 +9,45 @@ namespace Daybreak.Models
[Serializable]
public sealed class SecureString
{
public static SecureString Empty { get => new SecureString(string.Empty); }
public static SecureString Empty { get => new(string.Empty); }
private byte[] encryptedBytes;
private readonly byte[] key;
private byte[] DecryptedValue
{
get => encryptedBytes.DecryptBytes(key);
set => encryptedBytes = value.EncryptBytes(key);
get => this.encryptedBytes.DecryptBytes(key);
set => this.encryptedBytes = value.EncryptBytes(key);
}
[JsonProperty("value")]
public string Value
{
get
{
return encryptedBytes.DecryptBytes(key).AsString();
return this.encryptedBytes.DecryptBytes(key).AsString();
}
set
{
encryptedBytes = value.AsBytes().EncryptBytes(key);
this.encryptedBytes = value.AsBytes().EncryptBytes(key);
}
}
private SecureString(byte[] value)
{
key = new byte[32];
using (var crypto = new RNGCryptoServiceProvider())
{
crypto.GetBytes(key);
}
this.key = new byte[32];
using var crypto = RandomNumberGenerator.Create();
crypto.GetBytes(key);
this.DecryptedValue = value;
}
public SecureString(string value)
{
key = new byte[32];
using (var crypto = new RNGCryptoServiceProvider())
{
crypto.GetBytes(key);
}
this.key = new byte[32];
using var crypto = RandomNumberGenerator.Create();
crypto.GetBytes(key);
this.Value = value;
}
public static implicit operator string(SecureString ss) => ss is null ? string.Empty : ss.Value;
public static implicit operator SecureString(string s) => new SecureString(s);
public static implicit operator SecureString(string s) => new(s);
public static SecureString operator +(SecureString ss1, SecureString ss2)
{
if (ss1 is null) throw new ArgumentNullException(nameof(ss1));
@@ -123,12 +119,12 @@ namespace Daybreak.Models
public override int GetHashCode()
{
return Value.GetHashCode();
return this.Value.GetHashCode();
}
public override string ToString()
{
return Value;
return this.Value;
}
}
}
+4
View File
@@ -68,6 +68,10 @@ namespace Daybreak.Models.Versioning
{
parts.RemoveAt(i);
}
else
{
break;
}
}
parsedVersion = new Version
@@ -1,5 +1,5 @@
using Daybreak.Exceptions;
using Daybreak.Services.Configuration;
using Daybreak.Configuration;
using Daybreak.Exceptions;
using Daybreak.Services.Credentials;
using Daybreak.Services.Mutex;
using Daybreak.Services.Privilege;
@@ -9,6 +9,7 @@ using Microsoft.Win32;
using Pepa.Wpf.Utilities;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Extensions;
using System.IO;
@@ -29,7 +30,7 @@ namespace Daybreak.Services.ApplicationLauncher
private const string ProcessName = "gw";
private const string ArenaNetMutex = "AN-Mute";
private readonly IConfigurationManager configurationManager;
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
private readonly ICredentialManager credentialManager;
private readonly IMutexHandler mutexHandler;
private readonly ILogger<ApplicationLauncher> logger;
@@ -40,7 +41,7 @@ namespace Daybreak.Services.ApplicationLauncher
public bool IsToolboxRunning => GuildwarsToolboxProcessDetected();
public ApplicationLauncher(
IConfigurationManager configurationManager,
ILiveOptions<ApplicationConfiguration> liveOptions,
ICredentialManager credentialManager,
IMutexHandler mutexHandler,
ILogger<ApplicationLauncher> logger,
@@ -49,13 +50,13 @@ namespace Daybreak.Services.ApplicationLauncher
this.logger = logger.ThrowIfNull(nameof(logger));
this.mutexHandler = mutexHandler.ThrowIfNull(nameof(mutexHandler));
this.credentialManager = credentialManager.ThrowIfNull(nameof(credentialManager));
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.liveOptions = liveOptions.ThrowIfNull(nameof(liveOptions));
this.privilegeManager = privilegeManager.ThrowIfNull(nameof(privilegeManager));
}
public async Task<bool> LaunchGuildwars()
{
var configuration = this.configurationManager.GetConfiguration();
var configuration = this.liveOptions.Value;
var auth = await this.credentialManager.GetDefaultCredentials().ConfigureAwait(false);
return await auth.Switch(
onSome: async (credentials) =>
@@ -68,10 +69,10 @@ namespace Daybreak.Services.ApplicationLauncher
return false;
}
ClearGwLocks();
this.ClearGwLocks();
}
return await LaunchGuildwarsProcess(credentials.Username, credentials.Password, credentials.CharacterName);
return await this.LaunchGuildwarsProcess(credentials.Username, credentials.Password, credentials.CharacterName);
},
onNone: () =>
{
@@ -84,7 +85,7 @@ namespace Daybreak.Services.ApplicationLauncher
{
return Task.Run(() =>
{
var configuration = this.configurationManager.GetConfiguration();
var configuration = this.liveOptions.Value;
var executable = configuration.ToolboxPath;
if (File.Exists(executable) is false)
{
@@ -102,7 +103,7 @@ namespace Daybreak.Services.ApplicationLauncher
{
return Task.Run(() =>
{
var configuration = this.configurationManager.GetConfiguration();
var configuration = this.liveOptions.Value;
var executable = configuration.TexmodPath;
if (File.Exists(executable) is false)
{
@@ -145,7 +146,7 @@ namespace Daybreak.Services.ApplicationLauncher
private async Task<bool> LaunchGuildwarsProcess(string email, Models.SecureString password, string character)
{
var executable = this.configurationManager.GetConfiguration().GuildwarsPaths.Where(path => path.Default).FirstOrDefault();
var executable = this.liveOptions.Value.GuildwarsPaths.Where(path => path.Default).FirstOrDefault();
if (executable is null)
{
throw new ExecutableNotFoundException($"No executable selected");
@@ -169,7 +170,7 @@ namespace Daybreak.Services.ApplicationLauncher
args.Add(character);
}
var identity = this.configurationManager.GetConfiguration().ExperimentalFeatures.LaunchGuildwarsAsCurrentUser ?
var identity = this.liveOptions.Value.ExperimentalFeatures.LaunchGuildwarsAsCurrentUser ?
System.Security.Principal.WindowsIdentity.GetCurrent().Name :
System.Security.Principal.WindowsIdentity.GetAnonymous().Name;
this.logger.LogInformation($"Launching guildwars as [{identity}] identity");
@@ -221,11 +222,11 @@ namespace Daybreak.Services.ApplicationLauncher
private bool GuildwarsProcessDetected()
{
if (this.configurationManager.GetConfiguration().ExperimentalFeatures.MultiLaunchSupport is true)
if (this.liveOptions.Value.ExperimentalFeatures.MultiLaunchSupport is true)
{
try
{
var path = this.configurationManager.GetConfiguration().GuildwarsPaths.Where(path => path.Default).FirstOrDefault();
var path = this.liveOptions.Value.GuildwarsPaths.Where(path => path.Default).FirstOrDefault();
if (path is null)
{
return false;
@@ -253,7 +254,7 @@ namespace Daybreak.Services.ApplicationLauncher
private void SetRegistryGuildwarsPath()
{
var path = this.configurationManager.GetConfiguration().GuildwarsPaths.Where(path => path.Default).FirstOrDefault();
var path = this.liveOptions.Value.GuildwarsPaths.Where(path => path.Default).FirstOrDefault();
if (path is null)
{
throw new ExecutableNotFoundException("No executable currently selected");
@@ -1,43 +0,0 @@
using System;
using System.Collections.Generic;
using System.Extensions;
using IServiceProvider = Slim.IServiceProvider;
namespace Daybreak.Services.ApplicationLifetime
{
public sealed class ApplicationLifetimeManager : IApplicationLifetimeManager
{
private readonly IServiceProvider serviceProvider;
private List<Type> RegisteredTypes { get; } = new List<Type>();
public ApplicationLifetimeManager(IServiceProvider serviceProvider)
{
serviceProvider.ThrowIfNull(nameof(serviceProvider));
this.serviceProvider = serviceProvider;
}
public void RegisterService<T>() where T : IApplicationLifetimeService
{
this.RegisteredTypes.Add(typeof(T));
}
public void OnStartup()
{
foreach (var serviceType in this.RegisteredTypes)
{
var service = this.serviceProvider.GetService(serviceType);
service.As<IApplicationLifetimeService>().OnStartup();
}
}
public void OnClosing()
{
foreach (var serviceType in this.RegisteredTypes)
{
var service = this.serviceProvider.GetService(serviceType);
service.As<IApplicationLifetimeService>().OnClosing();
}
}
}
}
@@ -1,8 +0,0 @@
namespace Daybreak.Services.ApplicationLifetime
{
public interface IApplicationLifetimeManager : IApplicationLifetimeProducer
{
void OnStartup();
void OnClosing();
}
}
@@ -1,7 +0,0 @@
namespace Daybreak.Services.ApplicationLifetime
{
public interface IApplicationLifetimeProducer
{
void RegisterService<T>() where T : IApplicationLifetimeService;
}
}
@@ -1,8 +0,0 @@
namespace Daybreak.Services.ApplicationLifetime
{
public interface IApplicationLifetimeService
{
void OnStartup();
void OnClosing();
}
}
+1 -1
View File
@@ -2,8 +2,8 @@
using Microsoft.Extensions.Logging;
using System;
using System.Extensions;
using System.Http;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
namespace Daybreak.Services.Bloogum
@@ -26,7 +26,7 @@ namespace Daybreak.Services.Configuration
}
catch(Exception e)
{
this.logger.LogWarning($"No configuration detected. Loading default configuration. Details: {e}");
this.logger.LogWarning(e, $"Failed to load configuration. Falling back to default configuration");
this.applicationConfiguration = new ApplicationConfiguration();
}
}
@@ -1,8 +1,9 @@
using Daybreak.Models;
using Daybreak.Services.Configuration;
using Daybreak.Configuration;
using Daybreak.Models;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Extensions;
using System.Linq;
using System.Security.Cryptography;
@@ -15,13 +16,13 @@ namespace Daybreak.Services.Credentials
{
private static readonly byte[] Entropy = Convert.FromBase64String("R3VpbGR3YXJz");
private readonly ILogger<CredentialManager> logger;
private readonly IConfigurationManager configurationManager;
private readonly ILiveUpdateableOptions<ApplicationConfiguration> liveOptions;
public CredentialManager(
ILogger<CredentialManager> logger,
IConfigurationManager configurationManager)
ILiveUpdateableOptions<ApplicationConfiguration> liveOptions)
{
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.liveOptions = liveOptions.ThrowIfNull(nameof(liveOptions));
this.logger = logger.ThrowIfNull(nameof(logger));
}
@@ -53,7 +54,7 @@ namespace Daybreak.Services.Credentials
return Task.Run(() =>
{
this.logger.LogInformation("Retrieving credentials");
var config = this.configurationManager.GetConfiguration();
var config = this.liveOptions.Value;
if (config.ProtectedLoginCredentials is null || config.ProtectedLoginCredentials.Count == 0)
{
this.logger.LogInformation("No credentials found");
@@ -62,9 +63,9 @@ namespace Daybreak.Services.Credentials
return config
.ProtectedLoginCredentials
.Select(UnprotectCredentials)
.Where(CredentialsUnprotected)
.Select(ExtractCredentials)
.Select(this.UnprotectCredentials)
.Where(this.CredentialsUnprotected)
.Select(this.ExtractCredentials)
.ToList();
});
}
@@ -73,13 +74,12 @@ namespace Daybreak.Services.Credentials
return Task.Run(() =>
{
this.logger.LogInformation("Storing credentials");
var config = this.configurationManager.GetConfiguration();
config.ProtectedLoginCredentials = loginCredentials
.Select(ProtectCredentials)
.Where(CredentialsProtected)
.Select(ExtractProtectedCredentials)
this.liveOptions.Value.ProtectedLoginCredentials = loginCredentials
.Select(this.ProtectCredentials)
.Where(this.CredentialsProtected)
.Select(this.ExtractProtectedCredentials)
.ToList();
this.configurationManager.SaveConfiguration(config);
this.liveOptions.UpdateOption();
});
}
@@ -1,11 +1,13 @@
using Daybreak.Models.Builds;
using Daybreak.Configuration;
using Daybreak.Models.Builds;
using HtmlAgilityPack;
using Microsoft.Extensions.Logging;
using System;
using System.Configuration;
using System.Extensions;
using System.Http;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace Daybreak.Services.IconRetrieve
@@ -15,20 +17,48 @@ namespace Daybreak.Services.IconRetrieve
private const string NamePlaceholder = "[SKILLNAME]";
private const string BaseUrl = "https://wiki.guildwars.com";
private const string QueryUrl = $"wiki/File:{NamePlaceholder}.jpg";
private const string IconsDirectoryName = "Icons";
private const string IconsLocation = $"{IconsDirectoryName}/{NamePlaceholder}.jpg";
private readonly IHttpClient<IconRetriever> httpClient;
private readonly ILogger<IconRetriever> logger;
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
public IconRetriever(
ILogger<IconRetriever> logger,
IHttpClient<IconRetriever> httpClient)
IHttpClient<IconRetriever> httpClient,
ILiveOptions<ApplicationConfiguration> liveOptions)
{
this.logger = logger.ThrowIfNull(nameof(logger));
this.httpClient = httpClient.ThrowIfNull(nameof(httpClient));
this.liveOptions = liveOptions.ThrowIfNull(nameof(liveOptions));
this.httpClient.BaseAddress = new Uri(BaseUrl);
if (Directory.Exists(IconsDirectoryName) is false)
{
Directory.CreateDirectory(IconsDirectoryName);
}
}
public async Task<Optional<Stream>> GetIcon(Skill skill)
{
if (this.liveOptions.Value.KeepLocalIconCache)
{
this.logger.LogInformation($"{nameof(IconRetriever)} configured to look first in cache before downloading icons");
var maybeIcon = await this.GetLocalIcon(skill);
if (maybeIcon.ExtractValue() is Stream stream)
{
return stream;
}
}
else
{
this.logger.LogInformation($"{nameof(IconRetriever)} configured to skip local cache. Downloading icon");
}
return await this.DownloadIcon(skill);
}
private async Task<Optional<Stream>> DownloadIcon(Skill skill)
{
var curedSkillName = skill.Name
.Replace(" ", "_");
@@ -56,13 +86,43 @@ namespace Daybreak.Services.IconRetrieve
if (response.IsSuccessStatusCode)
{
this.logger.LogInformation("Retrieved latest icon stream");
return new MemoryStream(await iconResponse.Content.ReadAsByteArrayAsync());
var iconData = await iconResponse.Content.ReadAsByteArrayAsync();
if (this.liveOptions.Value.KeepLocalIconCache)
{
await SaveIconLocally(skill, iconData);
}
return new MemoryStream(iconData);
}
this.logger.LogError($"Failed to retrieve icon from {BaseUrl + "/" + url}");
return Optional.None<Stream>();
}
private async Task<Optional<Stream>> GetLocalIcon(Skill skill)
{
var curedSkillName = skill.Name
.Replace(" ", "_")
.Replace("\"", "");
this.logger.LogInformation("Checking local icon cache");
if (File.Exists(IconsLocation.Replace(NamePlaceholder, curedSkillName)))
{
this.logger.LogInformation("Local icon cache found. Retrieving icon");
return new MemoryStream(await File.ReadAllBytesAsync(IconsLocation.Replace(NamePlaceholder, curedSkillName)));
}
this.logger.LogWarning("No local icon cache found");
return Optional.None<Stream>();
}
private static async Task SaveIconLocally(Skill skill, byte[] data)
{
var curedSkillName = skill.Name
.Replace(" ", "_")
.Replace("\"", "");
await File.WriteAllBytesAsync(IconsLocation.Replace(NamePlaceholder, curedSkillName), data);
}
private static string GetHref(HtmlDocument doc)
{
foreach (var child in doc.DocumentNode.Descendants("a"))
@@ -1,6 +1,6 @@
using Daybreak.Models;
using Daybreak.Services.ApplicationLifetime;
using System;
using System.Windows.Extensions.Services;
namespace Daybreak.Services.KeyboardHook
{
@@ -1,4 +1,4 @@
using Daybreak.Services.ApplicationLifetime;
using System.Windows.Extensions.Services;
namespace Daybreak.Services.KeyboardMacros
{
@@ -1,10 +1,10 @@
using Daybreak.Models;
using Daybreak.Services.Configuration;
using Daybreak.Configuration;
using Daybreak.Models;
using Daybreak.Services.KeyboardHook;
using Microsoft.Extensions.Logging;
using Pepa.Wpf.Utilities;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Extensions;
using System.Linq;
using System.Text;
@@ -17,32 +17,23 @@ namespace Daybreak.Services.KeyboardMacros
{
private readonly CancellationTokenSource cancellationTokenSource = new();
private readonly IKeyboardHookService keyboardHookService;
private readonly IConfigurationManager configurationManager;
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
private readonly HashSet<Keys> KeysDown = new();
private IEnumerable<KeyMacro> loadedMacros;
private bool gameActive, hookEnabled;
private bool gameActive;
private IntPtr gwWindowHwnd;
public MacroService(
IKeyboardHookService keyboardHookService,
IConfigurationManager configurationManager)
ILiveOptions<ApplicationConfiguration> liveOptions)
{
this.keyboardHookService = keyboardHookService.ThrowIfNull(nameof(keyboardHookService));
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.liveOptions = liveOptions.ThrowIfNull(nameof(liveOptions));
this.configurationManager.ConfigurationChanged += (s, e) => this.LoadConfiguration();
this.LoadConfiguration();
this.keyboardHookService.KeyboardPressed += this.KeyboardHookService_KeyboardPressed;
this.SetupGameActiveChecker();
}
private void LoadConfiguration()
{
this.hookEnabled = this.configurationManager.GetConfiguration().ExperimentalFeatures.CanInterceptKeys;
this.loadedMacros = this.configurationManager.GetConfiguration().ExperimentalFeatures.Macros ?? new List<KeyMacro>();
}
private void SetupGameActiveChecker()
{
TaskExtensions.RunPeriodicAsync(() =>
@@ -62,12 +53,12 @@ namespace Daybreak.Services.KeyboardMacros
},
TimeSpan.Zero,
TimeSpan.FromMilliseconds(33),
cancellationTokenSource.Token);
this.cancellationTokenSource.Token);
}
private void KeyboardHookService_KeyboardPressed(object sender, KeyboardHookEventArgs e)
{
if (this.gameActive && this.hookEnabled)
if (this.gameActive && this.liveOptions.Value.ExperimentalFeatures.CanInterceptKeys)
{
if (e.KeyboardState == KeyboardState.KeyDown)
{
@@ -79,7 +70,7 @@ namespace Daybreak.Services.KeyboardMacros
return;
}
e.Handled = this.loadedMacros
e.Handled = this.liveOptions.Value.ExperimentalFeatures.Macros
.Where(keyMacro => MacroContainsKey(keyMacro, e.KeyboardInput.Key))
.Where(this.MacroHit)
.Do(this.HandleMacro)
@@ -1,30 +0,0 @@
using Microsoft.Extensions.Logging;
using System;
namespace Daybreak.Services.Logging
{
public sealed class CVLoggerFactory : ILoggerFactory
{
private readonly LoggerFactory loggerFactory = new();
public CVLoggerFactory(ILogsManager logsManager)
{
this.loggerFactory.AddProvider(new JsonLoggerProvider(logsManager));
}
public void AddProvider(ILoggerProvider provider)
{
((ILoggerFactory)this.loggerFactory).AddProvider(provider);
}
public ILogger CreateLogger(string categoryName)
{
return ((ILoggerFactory)this.loggerFactory).CreateLogger(categoryName);
}
public void Dispose()
{
((IDisposable)this.loggerFactory).Dispose();
}
}
}
+6 -3
View File
@@ -1,12 +1,15 @@
using Daybreak.Models;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Logging;
namespace Daybreak.Services.Logging
{
public interface ILogsManager
public interface ILogsManager : ILogsWriter
{
void WriteLog(Log log);
IEnumerable<Log> GetLogs();
IEnumerable<Models.Log> GetLogs(Expression<Func<Models.Log, bool>> filter);
IEnumerable<Models.Log> GetLogs();
int DeleteLogs();
}
}
-45
View File
@@ -1,45 +0,0 @@
using Daybreak.Models;
using Microsoft.Extensions.Logging;
using System;
using System.Extensions;
namespace Daybreak.Services.Logging
{
public sealed class JsonLogger : ILogger
{
private readonly string category;
private readonly JsonLoggerProvider jsonLoggerProvider;
public JsonLogger(string category, JsonLoggerProvider jsonLoggerProvider)
{
this.category = category;
this.jsonLoggerProvider = jsonLoggerProvider.ThrowIfNull(nameof(jsonLoggerProvider));
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
var message = formatter(state, exception);
var log = new Log
{
LogLevel = logLevel,
EventId = eventId.Name,
Message = message,
Category = category,
LogTime = DateTime.Now
};
this.jsonLoggerProvider.LogEntry(log);
}
}
}
@@ -1,44 +0,0 @@
using Daybreak.Models;
using Microsoft.CorrelationVector;
using Microsoft.Extensions.Logging;
using System.Extensions;
namespace Daybreak.Services.Logging
{
public sealed class JsonLoggerProvider : ILoggerProvider
{
private readonly ILogsManager logsManager;
private CorrelationVector correlationVector;
public JsonLoggerProvider(ILogsManager logsManager)
{
this.logsManager = logsManager.ThrowIfNull(nameof(logsManager));
this.correlationVector = new CorrelationVector();
}
public void LogEntry(Log log)
{
if (this.correlationVector is not null)
{
log.Message = $"[{this.correlationVector.Value}] {log.Message}";
this.correlationVector.Increment();
}
this.logsManager.WriteLog(log);
}
public ILogger CreateLogger(string categoryName)
{
if (this.correlationVector is not null)
{
this.correlationVector = CorrelationVector.Extend(this.correlationVector.ToString());
}
return new JsonLogger(categoryName, this);
}
public void Dispose()
{
}
}
}
+22 -6
View File
@@ -1,7 +1,9 @@
using Daybreak.Models;
using LiteDB;
using LiteDB;
using System;
using System.Collections.Generic;
using System.Extensions;
using System.Linq.Expressions;
using System.Logging;
namespace Daybreak.Services.Logging
{
@@ -14,17 +16,31 @@ namespace Daybreak.Services.Logging
this.liteDatabase = liteDatabase.ThrowIfNull(nameof(liteDatabase));
}
public IEnumerable<Log> GetLogs()
public IEnumerable<Models.Log> GetLogs(Expression<Func<Models.Log, bool>> filter)
{
return this.liteDatabase.GetCollection<Log>().FindAll();
return this.liteDatabase.GetCollection<Models.Log>().Find(filter);
}
public IEnumerable<Models.Log> GetLogs()
{
return this.liteDatabase.GetCollection<Models.Log>().FindAll();
}
public void WriteLog(Log log)
{
this.liteDatabase.GetCollection<Log>().Insert(log);
var dbLog = new Models.Log
{
EventId = log.EventId,
Message = log.Exception is null ? log.Message : $"{log.Message}{Environment.NewLine}{log.Exception}",
Category = log.Category,
LogLevel = log.LogLevel,
LogTime = log.LogTime,
CorrelationVector = log.CorrelationVector
};
this.liteDatabase.GetCollection<Models.Log>().Insert(dbLog);
}
public int DeleteLogs()
{
return this.liteDatabase.GetCollection<Log>().DeleteAll();
return this.liteDatabase.GetCollection<Models.Log>().DeleteAll();
}
}
}
@@ -56,7 +56,6 @@ namespace Daybreak.Services.ViewManagement
private void ShowViewInner(Type viewType, object dataContext)
{
var scopedManager = this.serviceManager.CreateScope();
scopedManager.As<IServiceManager>().RegisterScoped<ScopeMetadata, ScopeMetadata>((sp) => new ScopeMetadata(new CorrelationVector()));
Application.Current.Dispatcher.Invoke(() =>
{
var view = scopedManager.GetService(viewType).As<UserControl>();
@@ -0,0 +1,39 @@
using Daybreak.Configuration;
using Daybreak.Services.Configuration;
using System;
using System.Configuration;
using System.Extensions;
namespace Daybreak.Services.Options
{
public sealed class ApplicationConfigurationOptionsManager : IOptionsManager
{
private readonly IConfigurationManager configurationManager;
public ApplicationConfigurationOptionsManager(IConfigurationManager configurationManager)
{
this.configurationManager = configurationManager;
}
public T GetOptions<T>() where T : class
{
if (typeof(T) == typeof(ApplicationConfiguration))
{
return this.configurationManager.GetConfiguration().Cast<T>();
}
throw new InvalidOperationException($"{nameof(ApplicationConfigurationOptionsManager)} cannot return options of type {typeof(T).Name}");
}
public void UpdateOptions<T>(T value) where T : class
{
if (typeof(T) == typeof(ApplicationConfiguration))
{
this.configurationManager.SaveConfiguration(value.Cast<ApplicationConfiguration>());
return;
}
throw new InvalidOperationException($"{nameof(ApplicationConfigurationOptionsManager)} cannot save options of type {typeof(T).Name}");
}
}
}
@@ -1,9 +0,0 @@
namespace Daybreak.Services.Runtime
{
public interface IRuntimeStore
{
void StoreValue<T>(string name, T value);
bool TryGetValue<T>(string name, out T value);
T GetValue<T>(string name);
}
}
-36
View File
@@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using System.Extensions;
namespace Daybreak.Services.Runtime
{
public sealed class RuntimeStore : IRuntimeStore
{
private Dictionary<string, object> InnerStore { get; } = new Dictionary<string, object>();
public T GetValue<T>(string name)
{
if(this.InnerStore.TryGetValue(name, out var value))
{
return value.Cast<T>();
}
throw new InvalidOperationException($"Could not find any value stored with name {name}");
}
public void StoreValue<T>(string name, T value)
{
this.InnerStore[name] = value;
}
public bool TryGetValue<T>(string name, out T value)
{
if (this.InnerStore.TryGetValue(name, out var valueObj))
{
value = valueObj.Cast<T>();
return true;
}
value = default;
return false;
}
}
}
@@ -1,5 +1,5 @@
using Daybreak.Services.ApplicationLifetime;
using System.Extensions;
using System.Extensions;
using System.Windows.Extensions.Services;
using System.Windows.Media;
namespace Daybreak.Services.Screenshots
@@ -1,4 +1,4 @@
using Daybreak.Services.ApplicationLifetime;
using System.Windows.Extensions.Services;
namespace Daybreak.Services.Shortcuts
{
+13 -6
View File
@@ -1,16 +1,20 @@
using Daybreak.Services.Configuration;
using Daybreak.Configuration;
using Daybreak.Services.Configuration;
using ShellLink;
using System.Configuration;
using System.Diagnostics;
using System.Extensions;
using System.IO;
namespace Daybreak.Services.Shortcuts
{
//TODO: Fix dependency on IConfigurationManager
public sealed class ShortcutManager : IShortcutManager
{
private const string ShortcutName = "Daybreak.lnk";
private readonly IConfigurationManager configurationManager;
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
public bool ShortcutEnabled {
get => this.ShortcutExists();
@@ -27,16 +31,19 @@ namespace Daybreak.Services.Shortcuts
}
}
public ShortcutManager(IConfigurationManager configurationManager)
public ShortcutManager(
IConfigurationManager configurationManager,
ILiveOptions<ApplicationConfiguration> liveOptions)
{
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.liveOptions = liveOptions.ThrowIfNull(nameof(liveOptions));
this.configurationManager.ConfigurationChanged += (_, _) => this.LoadConfiguration();
this.LoadConfiguration();
}
private void LoadConfiguration()
{
var shortcutEnabled = this.configurationManager.GetConfiguration().PlaceShortcut;
var shortcutEnabled = this.liveOptions.Value.PlaceShortcut;
if (shortcutEnabled && this.ShortcutEnabled is false)
{
this.ShortcutEnabled = true;
@@ -49,7 +56,7 @@ namespace Daybreak.Services.Shortcuts
private bool ShortcutExists()
{
var shortcutFolder = this.configurationManager.GetConfiguration().ShortcutLocation;
var shortcutFolder = this.liveOptions.Value.ShortcutLocation;
var shortcutPath = $"{shortcutFolder}\\{ShortcutName}";
if (File.Exists(shortcutPath))
{
@@ -73,7 +80,7 @@ namespace Daybreak.Services.Shortcuts
return;
}
var shortcutFolder = this.configurationManager.GetConfiguration().ShortcutLocation;
var shortcutFolder = this.liveOptions.Value.ShortcutLocation;
var shortcutPath = $"{shortcutFolder}\\{ShortcutName}";
var currentExecutable = Process.GetCurrentProcess()?.MainModule?.FileName;
var shortcut = Shortcut.CreateShortcut(currentExecutable);
@@ -92,7 +99,7 @@ namespace Daybreak.Services.Shortcuts
return;
}
var shortcutFolder = this.configurationManager.GetConfiguration().ShortcutLocation;
var shortcutFolder = this.liveOptions.Value.ShortcutLocation;
var shortcutPath = $"{shortcutFolder}\\{ShortcutName}";
File.Delete(shortcutPath);
}
+12 -167
View File
@@ -1,17 +1,16 @@
using Daybreak.Exceptions;
using Daybreak.Configuration;
using Daybreak.Exceptions;
using Daybreak.Models;
using Daybreak.Models.Github;
using Daybreak.Services.Runtime;
using Daybreak.Services.ViewManagement;
using Daybreak.Utils;
using Daybreak.Views;
using Microsoft.Extensions.Logging;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Extensions;
using System.Http;
using System.IO;
using System.Linq;
using System.Net.Http;
@@ -25,53 +24,32 @@ namespace Daybreak.Services.Updater
{
public sealed class ApplicationUpdater : IApplicationUpdater
{
private const string LaunchActionName = "Launch_Daybreak";
private const string UpdateDesiredKey = "UpdateDesired";
private const string ExecutionPolicyKey = "ExecutionPolicy";
private const string InstallerFileName = "Daybreak.Installer.exe";
private const string UpdatedKey = "Updating";
private const string RegistryKey = "Daybreak";
private const string ExtractAndRunPs1 = "ExtractAndRun.ps1";
private const string TempFile = "tempfile.zip";
private const string VersionTag = "{VERSION}";
private const string InputFileTag = "{INPUTFILE}";
private const string OutputPathTag = "{OUTPUTPATH}";
private const string ExecutionPolicyTag = "{EXECUTIONPOLICY}";
private const string ProcessIdTag = "{PROCESSID}";
private const string ExecutableNameTag = "{EXECUTABLE}";
private const string WorkingDirectoryTag = "{WORKINGDIRECTORY}";
private const string RefTagPrefix = "/refs/tags";
private const string VersionListUrl = "https://api.github.com/repos/AlexMacocian/Daybreak/git/refs/tags";
private const string Url = "https://github.com/AlexMacocian/Daybreak/releases/latest";
private const string DownloadUrl = $"https://github.com/AlexMacocian/Daybreak/releases/download/{VersionTag}/Daybreak{VersionTag}.zip";
private const string GetExecutionPolicyCommand = "Get-ExecutionPolicy -Scope CurrentUser";
private const string SetExecutionPolicyCommand = $"Set-ExecutionPolicy {ExecutionPolicyTag} -Scope CurrentUser";
private const string WaitCommand = $"Wait-Process -Id {ProcessIdTag}";
private const string ExtractCommandTemplate = $"Expand-Archive -Path '{InputFileTag}' -DestinationPath '{OutputPathTag}' -Force";
private const string PrepareScheduledAction = $"$action = New-ScheduledTaskAction -Execute {ExecutableNameTag} -WorkingDirectory {WorkingDirectoryTag}";
private const string PrepareTriggerForAction = $"$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date)";
private const string RegisterScheduledAction = $"Register-ScheduledTask -Action $action -Trigger $trigger -TaskName {LaunchActionName} | Out-Null";
private const string LaunchScheduledAction = $"Start-ScheduledTask -TaskName {LaunchActionName}";
private const string SleepOneSecond = $"Start-Sleep -s 1";
private const string UnregisterScheduledAction = $"Unregister-ScheduledTask -TaskName {LaunchActionName} -Confirm:$false";
private const string RemoveTempFile = $"Remove-item {TempFile}";
private const string RemovePs1 = $"Remove-item {ExtractAndRunPs1}";
private readonly CancellationTokenSource updateCancellationTokenSource = new();
private readonly ILogger<ApplicationUpdater> logger;
private readonly IViewManager viewManager;
private readonly IRuntimeStore runtimeStore;
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
private readonly IHttpClient<ApplicationUpdater> httpClient;
public Version CurrentVersion { get; }
public ApplicationUpdater(
ILogger<ApplicationUpdater> logger,
IRuntimeStore runtimeStore,
ILiveOptions<ApplicationConfiguration> liveOptions,
IViewManager viewManager,
IHttpClient<ApplicationUpdater> httpClient)
{
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.runtimeStore = runtimeStore.ThrowIfNull(nameof(runtimeStore));
this.liveOptions = liveOptions.ThrowIfNull(nameof(liveOptions));
this.logger = logger.ThrowIfNull(nameof(logger));
this.httpClient = httpClient.ThrowIfNull(nameof(httpClient));
this.httpClient.DefaultRequestHeaders.Add("user-agent", "Daybreak Client");
@@ -176,7 +154,7 @@ namespace Daybreak.Services.Updater
{
System.Extensions.TaskExtensions.RunPeriodicAsync(async () =>
{
if (this.runtimeStore.TryGetValue<bool>(UpdateDesiredKey, out var desiringUpdate) && desiringUpdate is false)
if (this.liveOptions.Value.AutoCheckUpdate is false)
{
this.updateCancellationTokenSource.Cancel();
return;
@@ -191,23 +169,7 @@ namespace Daybreak.Services.Updater
public void FinalizeUpdate()
{
var maybeExecutionPolicy = this.RetrieveExecutionPolicy();
maybeExecutionPolicy.DoAny(
onNone: () =>
{
throw new InvalidOperationException("Failed to retrieve execution policy");
});
var executionPolicy = maybeExecutionPolicy.ExtractValue();
if (executionPolicy is not ExecutionPolicies.Bypass ||
executionPolicy is not ExecutionPolicies.Unrestricted)
{
this.logger.LogInformation($"Execution policy is set to {executionPolicy}. Setting to {ExecutionPolicies.Bypass}");
}
SaveExecutionPolicyValueToRegistry(executionPolicy);
MarkUpdateInRegistry();
this.SetExecutionPolicy(ExecutionPolicies.Bypass);
this.LaunchExtractor();
}
@@ -216,16 +178,6 @@ namespace Daybreak.Services.Updater
if (UpdateMarkedInRegistry())
{
UnmarkUpdateInRegistry();
var maybeExecutionPolicy = LoadExecutionPolicyValueFromRegistry();
maybeExecutionPolicy.Do(
onSome: policy =>
{
SetExecutionPolicy(policy);
},
onNone: () =>
{
throw new InvalidOperationException("Found update marked in registry but no execution policy");
});
}
}
@@ -245,92 +197,19 @@ namespace Daybreak.Services.Updater
return Optional.None<string>();
}
private Optional<ExecutionPolicies> RetrieveExecutionPolicy()
{
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = "powershell",
Arguments = GetExecutionPolicyCommand,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true
}
};
process.Start();
this.logger.LogInformation("Checking current execution policy");
var output = process.StandardOutput.ReadToEnd();
if (!Enum.TryParse(typeof(ExecutionPolicies), output, out var executionPolicy))
{
var error = process.StandardError.ReadToEnd();
this.logger.LogError($"Failed to retrieve current user execution policy. Stdout: {output}. Stderr: {error}");
return Optional.None<ExecutionPolicies>();
}
return executionPolicy.Cast<ExecutionPolicies>();
}
private void SetExecutionPolicy(ExecutionPolicies executionPolicy)
{
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = "powershell",
Arguments = SetExecutionPolicyCommand.Replace(ExecutionPolicyTag, executionPolicy.ToString()),
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true
}
};
process.Start();
this.logger.LogInformation($"Setting execution policy to {executionPolicy}");
var output = process.StandardOutput.ReadToEnd();
if (!string.IsNullOrWhiteSpace(output))
{
var error = process.StandardError.ReadToEnd();
throw new InvalidOperationException($"Failed to set execution policy to {executionPolicy}. Stdout: {output}. Stderr: {error}");
}
}
private void LaunchExtractor()
{
File.WriteAllLines(ExtractAndRunPs1, new List<string>()
{
WaitCommand.Replace(ProcessIdTag, Environment.ProcessId.ToString()),
ExtractCommandTemplate
.Replace(InputFileTag, Path.GetFullPath(TempFile))
.Replace(OutputPathTag, Directory.GetCurrentDirectory()),
RemoveTempFile,
PrepareScheduledAction
.Replace(ExecutableNameTag, Process.GetCurrentProcess()?.MainModule?.FileName)
.Replace(WorkingDirectoryTag, Directory.GetCurrentDirectory()),
PrepareTriggerForAction,
RegisterScheduledAction,
LaunchScheduledAction,
SleepOneSecond,
UnregisterScheduledAction,
RemovePs1,
});
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = "powershell.exe",
Arguments = $@"{Directory.GetCurrentDirectory()}\{ExtractAndRunPs1}",
UseShellExecute = true,
WindowStyle = ProcessWindowStyle.Maximized,
WorkingDirectory = Directory.GetCurrentDirectory(),
Verb = "runas"
},
FileName = InstallerFileName
}
};
this.logger.LogInformation("Created extractor script. Attempting to launch powershell");
this.logger.LogInformation("Launching installer");
if (process.Start() is false)
{
throw new InvalidOperationException("Failed to create and start powershell script");
throw new InvalidOperationException("Failed to launch installer");
}
}
@@ -368,40 +247,6 @@ namespace Daybreak.Services.Updater
return false;
}
private static void SaveExecutionPolicyValueToRegistry(ExecutionPolicies executionPolicy)
{
var homeRegistryKey = GetOrCreateHomeKey();
homeRegistryKey.SetValue(ExecutionPolicyKey, executionPolicy.ToString());
homeRegistryKey.Close();
}
private static Optional<ExecutionPolicies> LoadExecutionPolicyValueFromRegistry()
{
var homeRegistryKey = GetOrCreateHomeKey();
var executionPolicy = homeRegistryKey.GetValue(ExecutionPolicyKey);
homeRegistryKey.Close();
if (executionPolicy is null)
{
return Optional.None<ExecutionPolicies>();
}
else if (executionPolicy is string executionPolicyString)
{
if (Enum.TryParse<ExecutionPolicies>(executionPolicyString, out var executionPolicyValue))
{
return executionPolicyValue;
}
else
{
throw new InvalidOperationException($"Found execution policy with value {executionPolicy}");
}
}
else
{
throw new InvalidOperationException($"Found execution policy of type {executionPolicy.GetType()}.");
}
}
private static RegistryKey GetOrCreateHomeKey()
{
var homeRegistryKey = Registry.CurrentUser.OpenSubKey("Software", true).OpenSubKey(RegistryKey, true);
@@ -1,8 +1,8 @@
using Daybreak.Models;
using Daybreak.Models.Versioning;
using Daybreak.Services.ApplicationLifetime;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Extensions.Services;
namespace Daybreak.Services.Updater
{
+27 -46
View File
@@ -22,7 +22,7 @@ namespace Daybreak
}
}
private static int Iterations { get; } = 10000;
private static RNGCryptoServiceProvider Rng { get; } = new RNGCryptoServiceProvider();
private static RandomNumberGenerator Rng { get; } = RandomNumberGenerator.Create();
public static int BlockSize { get => Aes.BlockSize; }
@@ -31,29 +31,19 @@ namespace Daybreak
var saltBytes = Generate128BitsOfRandomEntropy();
var ivBytes = Generate128BitsOfRandomEntropy();
using (var password = new Rfc2898DeriveBytes(key, saltBytes, Iterations))
{
var keyBytes = password.GetBytes(Aes.KeySize / 8);
using (var encryptor = Aes.CreateEncryptor(keyBytes, ivBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(bytes, 0, bytes.Length);
cryptoStream.FlushFinalBlock();
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
using (var encryptedMemoryStream = new MemoryStream((int)(saltBytes.Length + ivBytes.Length + memoryStream.Length)))
{
encryptedMemoryStream.Write(saltBytes, 0, saltBytes.Length);
encryptedMemoryStream.Write(ivBytes, 0, ivBytes.Length);
encryptedMemoryStream.Write(memoryStream.ToArray(), 0, (int)memoryStream.Length);
return encryptedMemoryStream.ToArray();
}
}
}
}
}
using var password = new Rfc2898DeriveBytes(key, saltBytes, Iterations);
var keyBytes = password.GetBytes(Aes.KeySize / 8);
using var encryptor = Aes.CreateEncryptor(keyBytes, ivBytes);
using var memoryStream = new MemoryStream();
using var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(bytes, 0, bytes.Length);
cryptoStream.FlushFinalBlock();
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
using var encryptedMemoryStream = new MemoryStream((int)(saltBytes.Length + ivBytes.Length + memoryStream.Length));
encryptedMemoryStream.Write(saltBytes, 0, saltBytes.Length);
encryptedMemoryStream.Write(ivBytes, 0, ivBytes.Length);
encryptedMemoryStream.Write(memoryStream.ToArray(), 0, (int)memoryStream.Length);
return encryptedMemoryStream.ToArray();
}
public static byte[] DecryptBytes(this byte[] bytes, byte[] key)
@@ -61,29 +51,20 @@ namespace Daybreak
var saltBytes = new byte[Aes.BlockSize / 8];
var ivBytes = new byte[Aes.BlockSize / 8];
var cipherBytes = new byte[bytes.Length - Aes.BlockSize / 4];
using (MemoryStream encryptedStream = new MemoryStream(bytes))
{
encryptedStream.Read(saltBytes, 0, saltBytes.Length);
encryptedStream.Read(ivBytes, 0, ivBytes.Length);
encryptedStream.Read(cipherBytes, 0, cipherBytes.Length);
}
using (var password = new Rfc2898DeriveBytes(key, saltBytes, Iterations))
{
var keyBytes = password.GetBytes(Aes.KeySize / 8);
using (var decryptor = Aes.CreateDecryptor(keyBytes, ivBytes))
{
using (var memoryStream = new MemoryStream(cipherBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[memoryStream.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
return plainTextBytes.Take(decryptedByteCount).ToArray();
}
}
}
}
using var encryptedStream = new MemoryStream(bytes);
encryptedStream.Read(saltBytes, 0, saltBytes.Length);
encryptedStream.Read(ivBytes, 0, ivBytes.Length);
encryptedStream.Read(cipherBytes, 0, cipherBytes.Length);
using var password = new Rfc2898DeriveBytes(key, saltBytes, Iterations);
var keyBytes = password.GetBytes(Aes.KeySize / 8);
using var decryptor = Aes.CreateDecryptor(keyBytes, ivBytes);
using var memoryStream = new MemoryStream(cipherBytes);
using var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
var plainTextBytes = new byte[memoryStream.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
return plainTextBytes.Take(decryptedByteCount).ToArray();
}
private static byte[] Generate128BitsOfRandomEntropy()
+1 -12
View File
@@ -1,20 +1,9 @@
using Newtonsoft.Json;
using System.Text;
using System.Text;
namespace Daybreak.Utils
{
public static class SerializationExtensions
{
public static string Serialize<T>(this T obj)
{
return JsonConvert.SerializeObject(obj);
}
public static T Deserialize<T>(this string serializedObject)
{
return JsonConvert.DeserializeObject<T>(serializedObject);
}
public static byte[] AsBytes(this string s)
{
return Encoding.UTF8.GetBytes(s);
+8 -25
View File
@@ -1,8 +1,9 @@
using Daybreak.Services.Privilege;
using Daybreak.Services.Runtime;
using Daybreak.Configuration;
using Daybreak.Services.Privilege;
using Daybreak.Services.Updater;
using Daybreak.Services.ViewManagement;
using Microsoft.Extensions.Logging;
using System.Configuration;
using System.Extensions;
using System.Linq;
using System.Windows.Controls;
@@ -14,56 +15,38 @@ namespace Daybreak.Views
/// </summary>
public partial class AskUpdateView : UserControl
{
private const string UpdateDesiredKey = "UpdateDesired";
private readonly ILogger<AskUpdateView> logger;
private readonly IViewManager viewManager;
private readonly IRuntimeStore runtimeStore;
private readonly ILiveUpdateableOptions<ApplicationConfiguration> liveOptions;
private readonly IPrivilegeManager privilegeManager;
private readonly IApplicationUpdater applicationUpdater;
public AskUpdateView(
ILogger<AskUpdateView> logger,
IViewManager viewManager,
IRuntimeStore runtimeStore,
ILiveUpdateableOptions<ApplicationConfiguration> liveOptions,
IPrivilegeManager privilegeManager,
IApplicationUpdater applicationUpdater)
{
this.logger = logger.ThrowIfNull(nameof(logger));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.runtimeStore = runtimeStore.ThrowIfNull(nameof(runtimeStore));
this.liveOptions = liveOptions.ThrowIfNull(nameof(liveOptions));
this.privilegeManager = privilegeManager.ThrowIfNull(nameof(privilegeManager));
this.applicationUpdater = applicationUpdater.ThrowIfNull(nameof(applicationUpdater));
this.InitializeComponent();
}
private bool CheckIfAdmin()
{
if (this.privilegeManager.AdminPrivileges is false)
{
this.privilegeManager.RequestAdminPrivileges<MainView>("Application needs to be in administrator mode in order to update.");
return false;
}
return true;
}
private void NoButton_Clicked(object sender, System.EventArgs e)
{
this.logger.LogInformation("User declined update");
this.runtimeStore.StoreValue(UpdateDesiredKey, false);
this.liveOptions.Value.AutoCheckUpdate = false;
this.liveOptions.UpdateOption();
this.viewManager.ShowView<MainView>();
}
private async void YesButton_Clicked(object sender, System.EventArgs e)
{
this.logger.LogInformation("User accepted update");
this.runtimeStore.StoreValue(UpdateDesiredKey, true);
if (this.CheckIfAdmin() is false)
{
return;
}
var latestVersion = (await this.applicationUpdater.GetVersions()).Last();
this.viewManager.ShowView<UpdateView>(latestVersion);
}
+12 -1
View File
@@ -11,6 +11,7 @@
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="#A0202020">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
@@ -35,7 +36,17 @@
<controls:SaveButton Foreground="White" Height="30" Width="30" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5"
Clicked="SaveButton_Clicked" Grid.Column="2" IsEnabled="{Binding ElementName=_this, Path=SaveButtonEnabled, Mode=OneWay}"></controls:SaveButton>
</Grid>
<controls:BuildTemplate x:Name="BuildTemplate" Grid.Row="1" DataContext="{Binding ElementName=_this, Path=CurrentBuild, Mode=OneWay}">
<Grid Grid.Row="1" Margin="10, 0, 10, 0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="Code: " Foreground="White" Background="Transparent" FontSize="16"></TextBlock>
<TextBox Grid.Column="1" Foreground="White" Background="Transparent" FontSize="16"
Text="{Binding ElementName=_this, Path=CurrentBuildCode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</Grid>
<controls:BuildTemplate x:Name="BuildTemplate" Grid.Row="2" DataContext="{Binding ElementName=_this, Path=CurrentBuild, Mode=OneWay}"
BuildChanged="BuildTemplate_BuildChanged">
</controls:BuildTemplate>
</Grid>
</UserControl>
+60 -22
View File
@@ -1,11 +1,12 @@
using Daybreak.Controls;
using Daybreak.Configuration;
using Daybreak.Controls;
using Daybreak.Models.Builds;
using Daybreak.Services.BuildTemplates;
using Daybreak.Services.Configuration;
using Daybreak.Services.IconRetrieve;
using Daybreak.Services.ViewManagement;
using Microsoft.Extensions.Logging;
using System;
using System.Configuration;
using System.Extensions;
using System.Linq;
using System.Windows;
@@ -21,51 +22,89 @@ namespace Daybreak.Views
{
private const string DisallowedChars = "\r\n\\/.";
public readonly static DependencyProperty CurrentBuildProperty =
DependencyPropertyExtensions.Register<BuildTemplateView, BuildEntry>(nameof(CurrentBuild));
public readonly static DependencyProperty SaveButtonEnabledProperty =
DependencyPropertyExtensions.Register<BuildTemplateView, bool>(nameof(SaveButtonEnabled), new PropertyMetadata(false));
private bool supressDecode = false;
private readonly IViewManager viewManager;
private readonly IBuildTemplateManager buildTemplateManager;
private readonly ILogger<BuildTemplateView> logger;
public bool SaveButtonEnabled
{
get => this.GetTypedValue<bool>(SaveButtonEnabledProperty);
set => this.SetValue(SaveButtonEnabledProperty, value);
}
public BuildEntry CurrentBuild
{
get => this.GetTypedValue<BuildEntry>(CurrentBuildProperty);
set => this.SetValue(CurrentBuildProperty, value);
}
[GenerateDependencyProperty(InitialValue = false)]
private bool saveButtonEnabled;
[GenerateDependencyProperty]
private BuildEntry currentBuild;
[GenerateDependencyProperty]
private string currentBuildCode;
public BuildTemplateView(
IViewManager viewManager,
IBuildTemplateManager buildTemplateManager,
IIconRetriever iconRetriever,
IConfigurationManager configurationManager,
ILogger<ChromiumBrowserWrapper> logger)
ILiveOptions<ApplicationConfiguration> liveOptions,
ILogger<ChromiumBrowserWrapper> chromiumLogger,
ILogger<BuildTemplateView> logger)
{
this.buildTemplateManager = buildTemplateManager.ThrowIfNull(nameof(buildTemplateManager));
this.logger = logger.ThrowIfNull(nameof(logger));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.InitializeComponent();
this.BuildTemplate.InitializeTemplate(iconRetriever, configurationManager, buildTemplateManager, logger);
this.BuildTemplate.InitializeTemplate(iconRetriever, liveOptions, buildTemplateManager, chromiumLogger);
this.DataContextChanged += (sender, contextArgs) =>
{
if (contextArgs.NewValue is BuildEntry)
{
this.logger.LogInformation("Received data context. Setting current build");
this.CurrentBuild = contextArgs.NewValue.As<BuildEntry>();
this.CurrentBuildCode = this.buildTemplateManager.EncodeTemplate(this.CurrentBuild.Build);
}
};
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == CurrentBuildCodeProperty && this.supressDecode is false)
{
this.logger.LogInformation($"Attempting to decode provided template {this.CurrentBuildCode}");
try
{
this.CurrentBuild = new BuildEntry
{
Name = this.CurrentBuild.Name,
PreviousName = this.CurrentBuild.PreviousName,
Build = this.buildTemplateManager.DecodeTemplate(this.CurrentBuildCode)
};
this.logger.LogInformation($"Template {CurrentBuildCode} decoded");
}
catch
{
this.logger.LogWarning($"Failed to decode {this.CurrentBuildCode}. Reverting to default build");
this.CurrentBuild = new BuildEntry
{
Name = this.CurrentBuild.Name,
PreviousName = this.CurrentBuild.PreviousName,
Build = new Build()
};
}
}
}
private void BuildTemplate_BuildChanged(object sender, EventArgs e)
{
try
{
this.supressDecode = true;
this.CurrentBuildCode = this.buildTemplateManager.EncodeTemplate(this.CurrentBuild.Build);
}
finally
{
this.supressDecode = false;
}
}
private void BackButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<BuildsListView>();
}
private void SaveButton_Clicked(object sender, EventArgs e)
{
this.buildTemplateManager.SaveBuild(this.CurrentBuild);
@@ -79,7 +118,6 @@ namespace Daybreak.Views
e.Handled = true;
}
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (string.IsNullOrWhiteSpace(sender.As<TextBox>().Text))
+10 -10
View File
@@ -1,10 +1,10 @@
using Daybreak.Controls;
using Daybreak.Configuration;
using Daybreak.Controls;
using Daybreak.Models;
using Daybreak.Services.Configuration;
using Daybreak.Services.ViewManagement;
using Microsoft.Win32;
using System;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Extensions;
using System.Linq;
using System.Windows.Controls;
@@ -17,15 +17,15 @@ namespace Daybreak.Views
/// </summary>
public partial class ExecutablesView : UserControl
{
private readonly IConfigurationManager configurationManager;
private readonly ILiveUpdateableOptions<ApplicationConfiguration> liveUpdateableOptions;
private readonly IViewManager viewManager;
public ObservableCollection<GuildwarsPath> Paths { get; } = new();
public ExecutablesView(
IConfigurationManager configurationManager,
ILiveUpdateableOptions<ApplicationConfiguration> liveUpdateableOptions,
IViewManager viewManager)
{
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.liveUpdateableOptions = liveUpdateableOptions.ThrowIfNull(nameof(liveUpdateableOptions));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.InitializeComponent();
this.GetPaths();
@@ -33,7 +33,7 @@ namespace Daybreak.Views
private void GetPaths()
{
this.Paths.AddRange(this.configurationManager.GetConfiguration().GuildwarsPaths);
this.Paths.AddRange(this.liveUpdateableOptions.Value.GuildwarsPaths);
}
private void BackButton_Clicked(object sender, EventArgs e)
@@ -53,9 +53,8 @@ namespace Daybreak.Views
private void SaveButton_Clicked(object sender, EventArgs e)
{
var config = this.configurationManager.GetConfiguration();
config.GuildwarsPaths = this.Paths.ToList();
this.configurationManager.SaveConfiguration(config);
this.liveUpdateableOptions.Value.GuildwarsPaths = this.Paths.ToList();
this.liveUpdateableOptions.UpdateOption();
this.viewManager.ShowView<SettingsCategoryView>();
}
@@ -81,6 +80,7 @@ namespace Daybreak.Views
{
path.Default = false;
}
gwPath.Default = true;
var view = CollectionViewSource.GetDefaultView(this.Paths);
view.Refresh();
@@ -1,6 +1,7 @@
using Daybreak.Services.Configuration;
using Daybreak.Configuration;
using Daybreak.Services.ViewManagement;
using System;
using System.Configuration;
using System.Extensions;
using System.Linq;
using System.Windows;
@@ -27,7 +28,7 @@ namespace Daybreak.Views
DependencyPropertyExtensions.Register<ExperimentalSettingsView, bool>(nameof(MacrosEnabled));
private readonly IViewManager viewManager;
private readonly IConfigurationManager configurationManager;
private readonly ILiveUpdateableOptions<ApplicationConfiguration> liveUpdateableOptions;
public bool LaunchAsCurrentUser
{
@@ -57,17 +58,17 @@ namespace Daybreak.Views
public ExperimentalSettingsView(
IViewManager viewManager,
IConfigurationManager configurationManager)
ILiveUpdateableOptions<ApplicationConfiguration> liveUpdateableOptions)
{
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.liveUpdateableOptions = liveUpdateableOptions.ThrowIfNull(nameof(liveUpdateableOptions));
this.InitializeComponent();
this.LoadExperimentalSettings();
}
private void LoadExperimentalSettings()
{
var config = this.configurationManager.GetConfiguration();
var config = this.liveUpdateableOptions.Value;
this.MultiLaunch = config.ExperimentalFeatures.MultiLaunchSupport;
this.GWToolboxLaunchDelay = config.ExperimentalFeatures.ToolboxAutoLaunchDelay.ToString();
this.DynamicBuildLoading = config.ExperimentalFeatures.DynamicBuildLoading;
@@ -77,7 +78,7 @@ namespace Daybreak.Views
private void SaveExperimentalSettings()
{
var config = this.configurationManager.GetConfiguration();
var config = this.liveUpdateableOptions.Value;
config.ExperimentalFeatures.MultiLaunchSupport = this.MultiLaunch;
config.ExperimentalFeatures.DynamicBuildLoading = this.DynamicBuildLoading;
config.ExperimentalFeatures.LaunchGuildwarsAsCurrentUser = this.LaunchAsCurrentUser;
@@ -87,7 +88,7 @@ namespace Daybreak.Views
config.ExperimentalFeatures.ToolboxAutoLaunchDelay = gwToolboxLaunchDelay;
}
this.configurationManager.SaveConfiguration(config);
this.liveUpdateableOptions.UpdateOption();
}
private void SaveButton_Clicked(object sender, EventArgs e)
+14 -1
View File
@@ -24,6 +24,12 @@
Clicked="BinButton_Clicked"></controls:BinButton>
<controls:RefreshGlyph Foreground="White" Height="30" Width="30" HorizontalAlignment="Right" Margin="0, 5, 45, 5"
Clicked="RefreshGlyph_Clicked"></controls:RefreshGlyph>
<controls:BackButton Foreground="White" Height="30" Width="30" HorizontalAlignment="Right" Margin="0, 5, 85, 5"
Clicked="ExportButton_Clicked">
<controls:BackButton.RenderTransform>
<RotateTransform Angle="270" CenterX="15" CenterY="15"></RotateTransform>
</controls:BackButton.RenderTransform>
</controls:BackButton>
<DataGrid IsReadOnly="True" Background="Transparent" Foreground="White" Grid.Row="1"
ItemsSource="{Binding ElementName=_this, Path=Logs, Mode=OneWay}" HorizontalScrollBarVisibility="Disabled"
AutoGenerateColumns="False" HeadersVisibility="Column" EnableColumnVirtualization="True"
@@ -50,10 +56,17 @@
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn IsReadOnly="True" Header="DateTime" Binding="{Binding LogTime}" ElementStyle="{StaticResource WrapText}" Width="auto"/>
<DataGridTextColumn IsReadOnly="True" Header="CV" Binding="{Binding CorrelationVector}" ElementStyle="{StaticResource WrapText}" Width="auto"/>
<DataGridTextColumn IsReadOnly="True" Header="Category" Binding="{Binding Category}" ElementStyle="{StaticResource WrapText}" Width="auto"/>
<DataGridTextColumn IsReadOnly="True" Header="LogLevel" Binding="{Binding LogLevel}" ElementStyle="{StaticResource WrapText}" Width="auto"/>
<DataGridTextColumn IsReadOnly="True" Header="EventId" Binding="{Binding EventId}" ElementStyle="{StaticResource WrapText}" Width="auto"/>
<DataGridTextColumn IsReadOnly="True" Header="Message" Binding="{Binding Message}" ElementStyle="{StaticResource WrapText}" Width="*"/>
<DataGridTemplateColumn IsReadOnly="True" Header="Message" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<controls:LogMessageTemplate Message="{Binding Message}" Foreground="White"></controls:LogMessageTemplate>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
+34 -4
View File
@@ -1,10 +1,15 @@
using Daybreak.Services.Logging;
using Daybreak.Models;
using Daybreak.Services.Logging;
using Daybreak.Services.ViewManagement;
using Daybreak.Utils;
using Microsoft.Extensions.Logging;
using Microsoft.Win32;
using System;
using System.Collections.ObjectModel;
using System.Extensions;
using System.IO;
using System.Linq;
using System.Windows.Controls;
using Daybreak.Models;
namespace Daybreak.Views
{
@@ -15,22 +20,47 @@ namespace Daybreak.Views
{
private readonly IViewManager viewManager;
private readonly ILogsManager logManager;
private readonly ILogger<LogsView> logger;
public ObservableCollection<Log> Logs { get; } = new ObservableCollection<Log>();
public LogsView(
IViewManager viewManager,
ILogsManager logManager)
ILogsManager logManager,
ILogger<LogsView> logger)
{
this.logManager = logManager.ThrowIfNull(nameof(logManager));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.logger = logger.ThrowIfNull(nameof(logger));
this.InitializeComponent();
this.UpdateLogs();
}
private void UpdateLogs()
{
this.Logs.ClearAnd().AddRange(this.logManager.GetLogs());
this.Logs.ClearAnd().AddRange(this.logManager.GetLogs(l => l.LogLevel < Microsoft.Extensions.Logging.LogLevel.Trace));
}
private async void ExportButton_Clicked(object sender, EventArgs e)
{
this.logger.LogInformation("Exporting logs");
var saveFileDialog = new SaveFileDialog
{
DefaultExt = "json",
Filter = "Json files (*.json)|*.json",
Title = "Export logs",
ValidateNames = true,
CreatePrompt = true
};
if (saveFileDialog.ShowDialog() is true)
{
var fileName = saveFileDialog.FileName;
this.logger.LogInformation($"Exporting to {fileName}");
await File.WriteAllTextAsync(fileName, this.logManager.GetLogs().ToList().Serialize());
}
else
{
this.logger.LogInformation("Exporting canceled");
}
}
private void BackButton_Clicked(object sender, EventArgs e)
{
+19 -17
View File
@@ -1,13 +1,14 @@
using Daybreak.Controls;
using Daybreak.Configuration;
using Daybreak.Controls;
using Daybreak.Exceptions;
using Daybreak.Models.Builds;
using Daybreak.Services.ApplicationLauncher;
using Daybreak.Services.BuildTemplates;
using Daybreak.Services.Configuration;
using Daybreak.Services.Screens;
using Daybreak.Services.ViewManagement;
using Microsoft.Extensions.Logging;
using System;
using System.Configuration;
using System.Extensions;
using System.Linq;
using System.Threading;
@@ -27,7 +28,7 @@ namespace Daybreak.Views
{
private readonly IApplicationLauncher applicationDetector;
private readonly IViewManager viewManager;
private readonly IConfigurationManager configurationManager;
private readonly ILiveUpdateableOptions<ApplicationConfiguration> liveOptions;
private readonly IScreenManager screenManager;
private readonly IBuildTemplateManager buildTemplateManager;
private readonly ILogger<ChromiumBrowserWrapper> browserLogger;
@@ -58,7 +59,7 @@ namespace Daybreak.Views
public MainView(
IApplicationLauncher applicationDetector,
IViewManager viewManager,
IConfigurationManager configurationManager,
ILiveUpdateableOptions<ApplicationConfiguration> liveOptions,
IScreenManager screenManager,
IBuildTemplateManager buildTemplateManager,
ILogger<ChromiumBrowserWrapper> browserLogger)
@@ -66,7 +67,7 @@ namespace Daybreak.Views
this.browserLogger = browserLogger;
this.buildTemplateManager = buildTemplateManager.ThrowIfNull(nameof(buildTemplateManager));
this.screenManager = screenManager.ThrowIfNull(nameof(screenManager));
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.liveOptions = liveOptions.ThrowIfNull(nameof(liveOptions));
this.applicationDetector = applicationDetector.ThrowIfNull(nameof(applicationDetector));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.InitializeComponent();
@@ -77,13 +78,13 @@ namespace Daybreak.Views
private void InitializeBrowsers()
{
this.LeftWebBrowser.InitializeBrowser(this.configurationManager, this.buildTemplateManager, this.browserLogger);
this.RightWebBrowser.InitializeBrowser(this.configurationManager, this.buildTemplateManager, this.browserLogger);
this.LeftWebBrowser.InitializeBrowser(this.liveOptions, this.buildTemplateManager, this.browserLogger);
this.RightWebBrowser.InitializeBrowser(this.liveOptions, this.buildTemplateManager, this.browserLogger);
}
private void NavigateToDefaults()
{
var applicationConfiguration = this.configurationManager.GetConfiguration();
var applicationConfiguration = this.liveOptions.Value;
if (applicationConfiguration.BrowsersEnabled)
{
this.LeftBrowserFavoriteAddress = applicationConfiguration.LeftBrowserDefault;
@@ -127,21 +128,22 @@ namespace Daybreak.Views
return;
}
if (this.configurationManager.GetConfiguration().SetGuildwarsWindowSizeOnLaunch)
if (this.liveOptions.Value.SetGuildwarsWindowSizeOnLaunch)
{
var id = this.configurationManager.GetConfiguration().DesiredGuildwarsScreen;
var id = this.liveOptions.Value.DesiredGuildwarsScreen;
var desiredScreen = this.screenManager.Screens.Skip(id).FirstOrDefault();
if (desiredScreen is null)
{
throw new InvalidOperationException($"Unable to set guildwars on desired screen. No screen with id {id}");
}
await Task.Delay(1000);
this.screenManager.MoveGuildwarsToScreen(desiredScreen);
}
if (this.configurationManager.GetConfiguration().ToolboxAutoLaunch is true)
if (this.liveOptions.Value.ToolboxAutoLaunch is true)
{
var delay = this.configurationManager.GetConfiguration().ExperimentalFeatures.ToolboxAutoLaunchDelay;
var delay = this.liveOptions.Value.ExperimentalFeatures.ToolboxAutoLaunchDelay;
await Task.Delay(delay);
await this.applicationDetector.LaunchGuildwarsToolbox();
}
@@ -180,23 +182,23 @@ namespace Daybreak.Views
}
}
private void ChromiumBrowserWrapper_BuildDecoded(object sender, Models.Builds.Build e)
private void ChromiumBrowserWrapper_BuildDecoded(object sender, Build e)
{
this.viewManager.ShowView<BuildTemplateView>(new BuildEntry { Build = e, Name = string.Empty });
}
private void LeftBrowser_FavoriteUriChanged(object sender, string e)
{
var config = this.configurationManager.GetConfiguration();
var config = this.liveOptions.Value;
config.LeftBrowserDefault = e;
this.configurationManager.SaveConfiguration(config);
this.liveOptions.UpdateOption();
}
private void RightBrowser_FavoriteUriChanged(object sender, string e)
{
var config = this.configurationManager.GetConfiguration();
var config = this.liveOptions.Value;
config.RightBrowserDefault = e;
this.configurationManager.SaveConfiguration(config);
this.liveOptions.UpdateOption();
}
private void LeftChromiumBrowserWrapper_MaximizeClicked(object sender, EventArgs e)
+10 -10
View File
@@ -1,13 +1,13 @@
using Daybreak.Controls.Templates;
using Daybreak.Configuration;
using Daybreak.Controls.Templates;
using Daybreak.Models;
using Daybreak.Services.ApplicationLauncher;
using Daybreak.Services.Configuration;
using Daybreak.Services.Screens;
using Daybreak.Services.ViewManagement;
using System;
using System.Configuration;
using System.Extensions;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Media;
@@ -23,7 +23,7 @@ namespace Daybreak.Views
{
private readonly IScreenManager screenManager;
private readonly IViewManager viewManager;
private readonly IConfigurationManager configurationManager;
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
private readonly IApplicationLauncher applicationLauncher;
private int selectedId;
@@ -33,15 +33,15 @@ namespace Daybreak.Views
public ScreenChoiceView(
IViewManager viewManager,
IScreenManager screenManager,
IConfigurationManager configurationManager,
ILiveOptions<ApplicationConfiguration> liveOptions,
IApplicationLauncher applicationLauncher)
{
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.screenManager = screenManager.ThrowIfNull(nameof(screenManager));
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.liveOptions = liveOptions.ThrowIfNull(nameof(liveOptions));
this.applicationLauncher = applicationLauncher.ThrowIfNull(nameof(applicationLauncher));
this.InitializeComponent();
this.selectedId = configurationManager.GetConfiguration().DesiredGuildwarsScreen;
this.selectedId = this.liveOptions.Value.DesiredGuildwarsScreen;
this.CanTest = applicationLauncher.IsGuildwarsRunning;
this.SetupView();
}
@@ -59,8 +59,8 @@ namespace Daybreak.Views
VerticalAlignment = System.Windows.VerticalAlignment.Top,
HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
Foreground = screen.Id == this.selectedId ? Brushes.LightGreen : Brushes.White
};
screenTemplate.Clicked += ScreenTemplate_Clicked;
};
screenTemplate.Clicked += this.ScreenTemplate_Clicked;
this.ScreenContainer.Children.Add(screenTemplate);
}
}
@@ -86,7 +86,7 @@ namespace Daybreak.Views
private void SaveButton_Clicked(object sender, EventArgs e)
{
this.configurationManager.GetConfiguration().DesiredGuildwarsScreen = this.selectedId;
this.liveOptions.Value.DesiredGuildwarsScreen = this.selectedId;
this.viewManager.ShowView<SettingsCategoryView>();
}
+3
View File
@@ -94,6 +94,7 @@
<TextBlock Text="Desired screen id: " FontSize="22" Foreground="White" Height="30"></TextBlock>
<TextBlock Text="Place Shortcut: " FontSize="22" Foreground="White" Height="30"></TextBlock>
<TextBlock Text="Shortcut folder: " FontSize="22" Foreground="White" Height="30"></TextBlock>
<TextBlock Text="Keep local cache of icons: " FontSize="22" Foreground="White" Height="30"></TextBlock>
</StackPanel>
<StackPanel Orientation="Vertical" Grid.Row="1" Grid.Column="1">
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
@@ -148,6 +149,8 @@
Foreground="White" BorderBrush="Gray" BorderThickness="0"
Clicked="ShortcutFolderPickerGlyph_Clicked"></controls:FilePickerGlyph>
</Grid>
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=KeepLocalIconCache, Mode=TwoWay}"></ToggleButton>
</StackPanel>
</Grid>
</ScrollViewer>
+12 -11
View File
@@ -1,11 +1,8 @@
using Daybreak.Services.Configuration;
using Daybreak.Services.Shortcuts;
using Daybreak.Configuration;
using Daybreak.Services.ViewManagement;
using Microsoft.Win32;
using System;
using System.Configuration;
using System.Extensions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Forms;
@@ -18,7 +15,7 @@ namespace Daybreak.Views
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
public partial class SettingsView : System.Windows.Controls.UserControl
{
private readonly IConfigurationManager configurationManager;
private readonly ILiveUpdateableOptions<ApplicationConfiguration> liveUpdateableOptions;
private readonly IViewManager viewManager;
[GenerateDependencyProperty]
@@ -45,12 +42,14 @@ namespace Daybreak.Views
private bool shortcutPlaced;
[GenerateDependencyProperty]
private bool autoCheckUpdate;
[GenerateDependencyProperty]
private bool keepLocalIconCache;
public SettingsView(
IConfigurationManager configurationManager,
ILiveUpdateableOptions<ApplicationConfiguration> liveUpdateableOptions,
IViewManager viewManager)
{
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.liveUpdateableOptions = liveUpdateableOptions.ThrowIfNull(nameof(liveUpdateableOptions));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.InitializeComponent();
this.LoadSettings();
@@ -58,7 +57,7 @@ namespace Daybreak.Views
private void LoadSettings()
{
var config = this.configurationManager.GetConfiguration();
var config = this.liveUpdateableOptions.Value;
this.AddressBarReadonly = config.AddressBarReadonly;
this.ToolboxPath = config.ToolboxPath;
this.LeftBrowserUrl = config.LeftBrowserDefault;
@@ -71,11 +70,12 @@ namespace Daybreak.Views
this.ShortcutFolder = config.ShortcutLocation;
this.ShortcutPlaced = config.PlaceShortcut;
this.AutoCheckUpdate = config.AutoCheckUpdate;
this.KeepLocalIconCache = config.KeepLocalIconCache;
}
private void SaveButton_Clicked(object sender, EventArgs e)
{
var currentConfig = this.configurationManager.GetConfiguration();
var currentConfig = this.liveUpdateableOptions.Value;
currentConfig.ToolboxPath = this.ToolboxPath;
currentConfig.AddressBarReadonly = this.AddressBarReadonly;
currentConfig.LeftBrowserDefault = this.LeftBrowserUrl;
@@ -88,7 +88,8 @@ namespace Daybreak.Views
currentConfig.ShortcutLocation = this.ShortcutFolder;
currentConfig.PlaceShortcut = this.ShortcutPlaced;
currentConfig.AutoCheckUpdate = this.AutoCheckUpdate;
this.configurationManager.SaveConfiguration(currentConfig);
currentConfig.KeepLocalIconCache = this.KeepLocalIconCache;
this.liveUpdateableOptions.UpdateOption();
this.viewManager.ShowView<SettingsCategoryView>();
}
+2 -1
View File
@@ -4,6 +4,7 @@ using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Extensions;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Extensions;
using Version = Daybreak.Models.Versioning.Version;
@@ -39,7 +40,7 @@ namespace Daybreak.Views
private async void LoadVersionList()
{
this.Versions.ClearAnd().AddRange(await this.applicationUpdater.GetVersions());
this.Versions.ClearAnd().AddRange((await this.applicationUpdater.GetVersions()).Reverse());
}
private void CurrentVersion_Clicked(object sender, EventArgs e)
+1
View File
@@ -5,6 +5,7 @@ Param(
Write-Output "Deleting pdb file"
Remove-item .\Publish\Daybreak.pdb
Remove-item .\Publish\Daybreak.Installer.pdb
$zipPath = "Publish\daybreakv$version.zip"
Write-Output "Compressing binaries to $zipPath"
Compress-Archive .\Publish\* $zipPath -Force