Compare commits

...
12 Commits
Author SHA1 Message Date
amacocianandGitHub b01c09491f Download and check icons at startup (#41) 2022-08-12 23:41:22 +02:00
amacocianandGitHub 54ae742899 Increment version (#40) 2022-08-12 13:22:59 +02:00
amacocianandGitHub 4c862463d7 Fix IconRetriever (#38)
Use browser to bypass header issues with http client
2022-08-12 13:15:46 +02:00
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
62 changed files with 1010 additions and 685 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>
@@ -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>();
}
}
}
@@ -3,10 +3,9 @@ using FluentAssertions;
using LiteDB;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Linq;
using WpfExtended.Logging;
using System.Logging;
namespace Daybreak.Tests.Services
{
+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,7 +37,5 @@ namespace Daybreak.Configuration
public bool PlaceShortcut { get; set; }
[JsonProperty("AutoCheckUpdate")]
public bool AutoCheckUpdate { get; set; } = true;
[JsonProperty("KeepLocalIconCache")]
public bool KeepLocalIconCache { get; set; } = true;
}
}
@@ -16,6 +16,8 @@ namespace Daybreak.Configuration
public bool LaunchGuildwarsAsCurrentUser { get; set; } = true;
[JsonProperty("CanInterceptKeys")]
public bool CanInterceptKeys { get; set; }
[JsonProperty("DownloadIcons")]
public bool DownloadIcons { get; set; }
[JsonProperty("Macros")]
public List<KeyMacro> Macros { get; set; } = new();
}
+28 -13
View File
@@ -18,9 +18,11 @@ using Microsoft.Extensions.Logging;
using Slim;
using System.Extensions;
using System.Net.Http;
using System.Windows.Extensions.Http;
using LiteDB;
using System.Windows.Extensions;
using Daybreak.Services.Options;
using Daybreak.Models;
using Microsoft.CorrelationVector;
using System.Logging;
namespace Daybreak.Configuration
{
@@ -30,26 +32,26 @@ namespace Daybreak.Configuration
{
serviceManager.ThrowIfNull(nameof(serviceManager));
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<ViewManager>();
serviceProducer.RegisterSingleton<ViewManager>(registerAllInterfaces: true);
serviceProducer.RegisterSingleton<IConfigurationManager, ConfigurationManager>();
serviceProducer.RegisterSingleton<ILiteDatabase, LiteDatabase>(sp => new LiteDatabase("Daybreak.db"));
serviceProducer.RegisterSingleton<IMutexHandler, MutexHandler>();
serviceProducer.RegisterSingleton<IShortcutManager, ShortcutManager>();
serviceProducer.RegisterSingleton<IIconBrowser, IconBrowser>();
serviceProducer.RegisterScoped<ICredentialManager, CredentialManager>();
serviceProducer.RegisterScoped<IApplicationLauncher, ApplicationLauncher>();
serviceProducer.RegisterScoped<IScreenshotProvider, ScreenshotProvider>();
@@ -59,7 +61,19 @@ namespace Daybreak.Configuration
serviceProducer.RegisterScoped<IIconRetriever, IconRetriever>();
serviceProducer.RegisterScoped<IPrivilegeManager, PrivilegeManager>();
serviceProducer.RegisterScoped<IScreenManager, ScreenManager>();
serviceProducer.RegisterLogWriter<ILogsManager, JsonLogsManager>();
serviceProducer.RegisterSingleton<ILogsManager, JsonLogsManager>();
serviceProducer.RegisterSingleton<IDebugLogsWriter, Services.Logging.DebugLogsWriter>();
serviceProducer.RegisterSingleton<ILoggerFactory, LoggerFactory>(sp =>
{
var factory = new LoggerFactory();
factory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
return factory;
});
serviceProducer.RegisterSingleton<ILogsWriter, CompositeLogsWriter>(sp => new CompositeLogsWriter(
sp.GetService<ILogsManager>(),
sp.GetService<IDebugLogsWriter>()));
serviceProducer.RegisterScoped((sp) => new ScopeMetadata(new CorrelationVector()));
}
public static void RegisterViews(IViewProducer viewProducer)
@@ -80,6 +94,7 @@ namespace Daybreak.Configuration
viewProducer.RegisterView<ScreenChoiceView>();
viewProducer.RegisterView<VersionManagementView>();
viewProducer.RegisterView<LogsView>();
viewProducer.RegisterView<IconDownloadView>();
}
}
}
+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;
@@ -31,7 +32,7 @@ namespace Daybreak.Controls
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;
@@ -80,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();
@@ -98,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;
@@ -122,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) =>
{
@@ -196,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>>();
@@ -4,11 +4,12 @@
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"
x:Name="_this"
Unloaded="BuildTemplate_Unloaded"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="Transparent" MouseLeftButtonDown="Grid_MouseLeftButtonDown">
<Grid.RowDefinitions>
@@ -1,13 +1,16 @@
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.Core.Extensions;
using System.Extensions;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
@@ -26,8 +29,10 @@ namespace Daybreak.Controls
private bool suppressBuildChanged = false;
private bool loadedProperties = false;
private IIconBrowser iconBrowser;
private BuildEntry loadedBuild;
private SkillTemplate selectingSkillTemplate;
private CancellationTokenSource cancellationTokenSource = new();
public event EventHandler BuildChanged;
@@ -59,16 +64,19 @@ namespace Daybreak.Controls
{
this.InitializeComponent();
this.InitializeProperties();
this.DataContextChanged += BuildTemplate_DataContextChanged;
this.DataContextChanged += this.BuildTemplate_DataContextChanged;
}
public void InitializeTemplate(
IIconRetriever iconRetriever,
IConfigurationManager configurationManager,
IIconBrowser iconBrowser,
ILiveOptions<ApplicationConfiguration> liveOptions,
IBuildTemplateManager buildTemplateManager,
ILogger<ChromiumBrowserWrapper> logger)
{
this.SkillBrowser.InitializeBrowser(configurationManager, buildTemplateManager, logger);
this.iconBrowser = iconBrowser.ThrowIfNull();
this.SkillBrowser.InitializeBrowser(liveOptions, buildTemplateManager, logger);
this.iconBrowser.InitializeWebView(this.SkillBrowser.WebBrowser, this.cancellationTokenSource.Token);
this.SkillTemplate0.InitializeSkillTemplate(iconRetriever);
this.SkillTemplate1.InitializeSkillTemplate(iconRetriever);
this.SkillTemplate2.InitializeSkillTemplate(iconRetriever);
@@ -97,6 +105,7 @@ namespace Daybreak.Controls
{
this.loadedBuild.Build.Secondary = this.SecondaryProfession;
}
this.LoadSkills();
this.LoadAttributes();
if (this.suppressBuildChanged is false)
@@ -129,6 +138,11 @@ namespace Daybreak.Controls
}
}
private void BuildTemplate_Unloaded(object sender, RoutedEventArgs e)
{
this.cancellationTokenSource.Cancel();
}
private void InitializeProperties()
{
this.PrimaryProfession = Profession.None;
@@ -192,55 +206,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;
@@ -307,7 +328,7 @@ namespace Daybreak.Controls
return;
}
this.BrowseToInfo(PrimaryProfession.Name);
this.BrowseToInfo(this.PrimaryProfession.Name);
if (e is RoutedEventArgs routedEventArgs)
{
routedEventArgs.Handled = true;
@@ -350,6 +371,7 @@ namespace Daybreak.Controls
{
this.BrowseToInfo(skill.Name);
}
e.Handled = true;
}
@@ -368,14 +390,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)
@@ -1,8 +1,9 @@
<UserControl x:Class="Daybreak.Controls.SkillTemplate"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:webview="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
@@ -1,10 +1,6 @@
using Daybreak.Launch;
using Daybreak.Models.Builds;
using Daybreak.Models.Builds;
using Daybreak.Services.IconRetrieve;
using System;
using System.Extensions;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
@@ -41,19 +37,17 @@ namespace Daybreak.Controls
this.iconRetriever = iconRetriever;
}
private void SkillTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
private async void SkillTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is Skill skill)
{
if (skill != Skill.NoSkill)
{
Task.Run(() => this.GetImageStream(skill)).ContinueWith((previousTask) =>
var maybeUri = await this.iconRetriever.GetIconUri(skill).ConfigureAwait(true);
if (maybeUri.ExtractValue() is Uri uri)
{
this.Dispatcher.Invoke(() =>
{
this.ImageSource = this.GetImageSource(previousTask.Result);
});
});
this.ImageSource = new BitmapImage(uri);
}
}
else if (this.ImageSource is not null)
{
@@ -90,32 +84,5 @@ namespace Daybreak.Controls
return false;
}
private async Task<Stream> GetImageStream(Skill skill)
{
if (this.iconRetriever is null)
{
return null;
}
var maybeStream = await this.iconRetriever.GetIcon(skill);
return maybeStream.ExtractValue();
}
private ImageSource GetImageSource(Stream stream)
{
if (stream is null)
{
return null;
}
return this.Dispatcher.Invoke(() =>
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = stream;
bitmapImage.CacheOption = BitmapCacheOption.OnDemand;
bitmapImage.EndInit();
return bitmapImage;
});
}
}
}
+30 -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.2.3</Version>
<Version>0.9.3.4</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.11.32" />
<PackageReference Include="LiteDB" Version="5.0.10" />
<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.5.0" />
<PackageReference Include="System.Windows.Interactivity.WPF" Version="2.0.20525" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.3.0" />
<PackageReference Include="Slim" Version="1.7.3" />
<PackageReference Include="SystemExtensions.NetCore" Version="1.0.1" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.5.0" />
<PackageReference Include="WCL" Version="1.0.2" />
<PackageReference Include="WpfExtended" Version="0.5.0" />
<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>
@@ -45,6 +45,9 @@
<Compile Update="Controls\Buttons\CancelButton.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Views\IconDownloadView.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
@@ -68,10 +71,22 @@
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Views\IconDownloadView.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
<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>
+5
View File
@@ -41,6 +41,11 @@ namespace Daybreak.Launch
return false;
}
if (this.logger is null)
{
return false;
}
if (e is FatalException fatalException)
{
this.logger.LogCritical(e, $"{nameof(FatalException)} encountered. Closing application");
+7 -15
View File
@@ -1,5 +1,5 @@
using Daybreak.Services.Bloogum;
using Daybreak.Services.Configuration;
using Daybreak.Configuration;
using Daybreak.Services.Bloogum;
using Daybreak.Services.Privilege;
using Daybreak.Services.Screenshots;
using Daybreak.Services.Updater;
@@ -7,6 +7,7 @@ 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;
@@ -31,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]
@@ -49,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)
{
@@ -177,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>();
@@ -8,6 +8,7 @@ namespace Daybreak.Models.Browser
[JsonConverter(typeof(StringEnumConverter))]
public enum PayloadKeys
{
None,
ContextMenu
}
+6 -5
View File
@@ -143,7 +143,7 @@ namespace Daybreak.Models.Builds
public static Skill Flurry { get; } = new() { Id = 344, Name = "Flurry", Profession = Profession.Warrior };
public static Skill Frenzy { get; } = new() { Id = 346, Name = "Frenzy", Profession = Profession.Warrior };
public static Skill Coward { get; } = new() { Id = 869, Name = "\"Coward!\"", Profession = Profession.Warrior };
public static Skill OnYourKnees { get; } = new() { Id = 906, Name = "On Your Knees!", Profession = Profession.Warrior };
public static Skill OnYourKnees { get; } = new() { Id = 906, Name = "\"On Your Knees!\"", Profession = Profession.Warrior };
public static Skill YoureAllAlone { get; } = new() { Id = 1412, Name = "\"You're All Alone!\"", Profession = Profession.Warrior };
public static Skill FrenziedDefense { get; } = new() { Id = 1700, Name = "Frenzied Defense", Profession = Profession.Warrior };
public static Skill Grapple { get; } = new() { Id = 2011, Name = "Grapple", Profession = Profession.Warrior };
@@ -702,7 +702,7 @@ namespace Daybreak.Models.Builds
public static Skill Echo { get; } = new() { Id = 74, Name = "Echo", Profession = Profession.Mesmer };
public static Skill ArcaneEcho { get; } = new() { Id = 75, Name = "Arcane Echo", Profession = Profession.Mesmer };
public static Skill Epidemic { get; } = new() { Id = 78, Name = "Epidemic", Profession = Profession.Mesmer };
public static Skill LyssasBalance { get; } = new() { Id = 877, Name = "Lyssa's Balance, Profession = Profession.Mesmer" };
public static Skill LyssasBalance { get; } = new() { Id = 877, Name = "Lyssa's Balance", Profession = Profession.Mesmer };
public static Skill SignetofDisenchantment { get; } = new() { Id = 882, Name = "Signet of Disenchantment", Profession = Profession.Mesmer };
public static Skill ShatterStorm { get; } = new() { Id = 933, Name = "Shatter Storm", Profession = Profession.Mesmer };
public static Skill ExpelHexes { get; } = new() { Id = 954, Name = "Expel Hexes", Profession = Profession.Mesmer };
@@ -1053,7 +1053,7 @@ namespace Daybreak.Models.Builds
public static Skill FeastofSouls { get; } = new() { Id = 980, Name = "Feast of Souls", Profession = Profession.Ritualist };
public static Skill RitualLord { get; } = new() { Id = 1217, Name = "Ritual Lord", Profession = Profession.Ritualist };
public static Skill AttunedWasSongkai { get; } = new() { Id = 1220, Name = "Attuned Was Songkai", Profession = Profession.Ritualist };
public static Skill AnguishedWasLingwah { get; } = new() { Id = 1223, Name = "Anguished Was Lingwah, Profession = Profession.Ritualist" };
public static Skill AnguishedWasLingwah { get; } = new() { Id = 1223, Name = "Anguished Was Lingwah", Profession = Profession.Ritualist };
public static Skill ExplosiveGrowth { get; } = new() { Id = 1229, Name = "Explosive Growth", Profession = Profession.Ritualist };
public static Skill BoonofCreation { get; } = new() { Id = 1230, Name = "Boon of Creation", Profession = Profession.Ritualist };
public static Skill SpiritChanneling { get; } = new() { Id = 1231, Name = "Spirit Channeling", Profession = Profession.Ritualist };
@@ -1483,8 +1483,8 @@ namespace Daybreak.Models.Builds
public static Skill VolfenBlessing { get; } = new() { Id = 2379, Name = "Volfen Blessing", Profession = Profession.None };
public static Skill TimeWard { get; } = new() { Id = 3422, Name = "Time Ward", Profession = Profession.Mesmer };
public static Skill SoulTaker { get; } = new() { Id = 3423, Name = "Soul Taker", Profession = Profession.Necromancer };
public static Skill OverTheLimit { get; } = new() { Id = 3424, Name = "Over The Limit", Profession = Profession.Elementalist };
public static Skill JudgementStrike { get; } = new() { Id = 3425, Name = "Judgement Strike", Profession = Profession.Monk };
public static Skill OverTheLimit { get; } = new() { Id = 3424, Name = "Over The Limit", AlternativeName = "Over the Limit", Profession = Profession.Elementalist };
public static Skill JudgementStrike { get; } = new() { Id = 3425, Name = "Judgement Strike", AlternativeName = "Judgment Strike", Profession = Profession.Monk };
public static Skill SevenWeaponsStance { get; } = new() { Id = 3426, Name = "Seven Weapons Stance", Profession = Profession.Warrior };
public static Skill Togetherasone { get; } = new() { Id = 3427, Name = "\"Together as one!\"", Profession = Profession.Ranger };
public static Skill ShadowTheft { get; } = new() { Id = 3428, Name = "Shadow Theft", Profession = Profession.Assassin };
@@ -3022,6 +3022,7 @@ namespace Daybreak.Models.Builds
public Profession Profession { get; private set; }
public string Name { get; private set; }
public int Id { get; private set; }
public string AlternativeName { get; private set; }
private Skill()
{
}
+8
View File
@@ -0,0 +1,8 @@
namespace Models
{
public sealed class IconPayload
{
public string SkillUrl { get; set; }
public string SkillImage { get; set; }
}
}
+11
View File
@@ -0,0 +1,11 @@
using Daybreak.Models.Builds;
namespace Models
{
public sealed class IconRequest
{
public Skill Skill { get; set; }
public string IconBase64 { get; set; }
public bool Finished { 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;
}
}
}
@@ -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 -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();
});
}
@@ -0,0 +1,16 @@
using Microsoft.Web.WebView2.Wpf;
using Models;
using System.Threading;
namespace Daybreak.Services.IconRetrieve
{
public interface IIconBrowser
{
void InitializeWebView(WebView2 webView2, CancellationToken cancellationToken);
/// <summary>
/// Queue an icon request. The browser will attempt to download the icon. Monitor the <see cref="IconRequest.Finished"/> to be notified when the request has been served.
/// </summary>
/// <param name="iconRequest">Request model.</param>
void QueueIconRequest(IconRequest iconRequest);
}
}
@@ -1,12 +1,12 @@
using Daybreak.Models.Builds;
using System;
using System.Extensions;
using System.IO;
using System.Threading.Tasks;
namespace Daybreak.Services.IconRetrieve
{
public interface IIconRetriever
{
Task<Optional<Stream>> GetIcon(Skill skill);
Task<Optional<Uri>> GetIconUri(Skill skill);
}
}
@@ -0,0 +1,163 @@
using Daybreak.Models.Builds;
using Daybreak.Utils;
using Microsoft.Extensions.Logging;
using Microsoft.Web.WebView2.Wpf;
using Models;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Core.Extensions;
using System.Extensions;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
namespace Daybreak.Services.IconRetrieve
{
public sealed class IconBrowser : IIconBrowser
{
// Sometimes due to browser issues, retrieved base64 is just a blank jpeg. This is the base64 of the image.
private const string FaultyBase64 = "/9j/4AAQSkZJRgABAQAAAQABAAD/4gIoSUNDX1BST0ZJTEUAAQEAAAIYAAAAAAQwAABtbnRyUkdCIFhZWiAAAAAAAAAAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAAHRyWFlaAAABZAAAABRnWFlaAAABeAAAABRiWFlaAAABjAAAABRyVFJDAAABoAAAAChnVFJDAAABoAAAAChiVFJDAAABoAAAACh3dHB0AAAByAAAABRjcHJ0AAAB3AAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAFgAAAAcAHMAUgBHAEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABvogAAOPUAAAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAAAA+EAAC2z3BhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABYWVogAAAAAAAA9tYAAQAAAADTLW1sdWMAAAAAAAAAAQAAAAxlblVTAAAAIAAAABwARwBvAG8AZwBsAGUAIABJAG4AYwAuACAAMgAwADEANv/bAEMAAwICAgICAwICAgMDAwMEBgQEBAQECAYGBQYJCAoKCQgJCQoMDwwKCw4LCQkNEQ0ODxAQERAKDBITEhATDxAQEP/bAEMBAwMDBAMECAQECBALCQsQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEP/AABEIAEAAQAMBIgACEQEDEQH/xAAVAAEBAAAAAAAAAAAAAAAAAAAACf/EABQQAQAAAAAAAAAAAAAAAAAAAAD/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AlUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//2Q==";
private const string LargeFaultyBase64 = "/9j/4AAQSkZJRgABAQAAAQABAAD/4gIoSUNDX1BST0ZJTEUAAQEAAAIYAAAAAAQwAABtbnRyUkdCIFhZWiAAAAAAAAAAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAAHRyWFlaAAABZAAAABRnWFlaAAABeAAAABRiWFlaAAABjAAAABRyVFJDAAABoAAAAChnVFJDAAABoAAAAChiVFJDAAABoAAAACh3dHB0AAAByAAAABRjcHJ0AAAB3AAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAFgAAAAcAHMAUgBHAEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABvogAAOPUAAAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAAAA+EAAC2z3BhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABYWVogAAAAAAAA9tYAAQAAAADTLW1sdWMAAAAAAAAAAQAAAAxlblVTAAAAIAAAABwARwBvAG8AZwBsAGUAIABJAG4AYwAuACAAMgAwADEANv/bAEMAAwICAgICAwICAgMDAwMEBgQEBAQECAYGBQYJCAoKCQgJCQoMDwwKCw4LCQkNEQ0ODxAQERAKDBITEhATDxAQEP/bAEMBAwMDBAMECAQECBALCQsQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEP/AABEIAIAAQAMBIgACEQEDEQH/xAAVAAEBAAAAAAAAAAAAAAAAAAAACf/EABQQAQAAAAAAAAAAAAAAAAAAAAD/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AlUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//2Q==";
private const string BaseUrl = "https://wiki.guildwars.com";
private const string QueryUrl = $"wiki/File:{NamePlaceholder}.jpg";
private const string NamePlaceholder = "[SKILLNAME]";
private const string IconsDirectoryName = "Icons";
private const string IconsLocation = $"{IconsDirectoryName}/{NamePlaceholder}.jpg";
private readonly ConcurrentQueue<IconRequest> iconRequests = new();
private readonly ILogger<IconBrowser> logger;
private WebView2 webView2;
private CancellationToken cancellationToken;
public IconBrowser(
ILogger<IconBrowser> logger)
{
this.logger = logger.ThrowIfNull();
}
public void InitializeWebView(WebView2 webView2, CancellationToken cancellationToken)
{
this.webView2 = webView2.ThrowIfNull();
this.cancellationToken = cancellationToken;
Task.Run(this.PeriodicallyServeRequests, cancellationToken);
}
public void QueueIconRequest(IconRequest iconRequest)
{
this.iconRequests.Enqueue(iconRequest);
}
private async Task PeriodicallyServeRequests()
{
while(true)
{
if (this.cancellationToken.IsCancellationRequested)
{
return;
}
if (this.iconRequests.TryDequeue(out var request) is false)
{
await Task.Delay(1000);
continue;
}
var logger = this.logger.CreateScopedLogger(nameof(this.PeriodicallyServeRequests), request.Skill?.Name);
logger.LogInformation($"Retrieving icon");
while(this.webView2 is null)
{
if (this.cancellationToken.IsCancellationRequested)
{
return;
}
logger.LogInformation($"Browser is not yet initialized. Waiting");
await Task.Delay(1000);
}
var curedSkillName = request.Skill.AlternativeName.IsNullOrWhiteSpace() ?
request.Skill.Name.Replace(" ", "_") :
request.Skill.AlternativeName.Replace(" ", "_");
var skillIconUrl = $"{BaseUrl}/{QueryUrl.Replace(NamePlaceholder, curedSkillName)}";
logger.LogInformation($"Looking for icon at {skillIconUrl}");
Application.Current.Dispatcher.Invoke(() =>
{
this.webView2.Source = new Uri(skillIconUrl);
});
for(var i = 0; i < 5; i++)
{
if (this.cancellationToken.IsCancellationRequested)
{
return;
}
logger.LogInformation("Executing extraction script");
var responseTask = await Application.Current.Dispatcher.InvokeAsync(async () =>
{
return await this.webView2.ExecuteScriptAsync(Scripts.GetHrefFromSkillPage);
});
var response = await responseTask;
logger.LogInformation("Parsing response");
var iconPayload = JsonConvert.DeserializeObject<IconPayload>(response);
if (iconPayload is null)
{
logger.LogInformation("Bad response");
await Task.Delay(1000);
continue;
}
if (iconPayload.SkillUrl != skillIconUrl.Replace("\"", "%22"))
{
logger.LogInformation("Retrieved icon doesn't match");
await Task.Delay(1000);
continue;
}
var potentialBase64 = iconPayload.SkillImage.Split(',').Skip(1).FirstOrDefault();
if (potentialBase64 == FaultyBase64 ||
potentialBase64 == LargeFaultyBase64)
{
logger.LogInformation("Faulty base64 retrieved");
await Task.Delay(1000);
continue;
}
byte[] bytes;
try
{
bytes = Convert.FromBase64String(potentialBase64);
}
catch
{
logger.LogError("Failed to parse base64");
await Task.Delay(1000);
continue;
}
await SaveIconLocally(request.Skill, bytes);
request.IconBase64 = potentialBase64;
request.Finished = true;
break;
}
logger.LogError($"Failed to retrieve icon");
request.Finished = true;
}
}
private static async Task<string> SaveIconLocally(Skill skill, byte[] data)
{
var curedSkillName = skill.Name
.Replace(" ", "_")
.Replace("\"", "");
await File.WriteAllBytesAsync(IconsLocation.Replace(NamePlaceholder, curedSkillName), data);
return curedSkillName;
}
}
}
+15 -94
View File
@@ -1,12 +1,12 @@
using Daybreak.Models.Builds;
using Daybreak.Services.Configuration;
using HtmlAgilityPack;
using Daybreak.Configuration;
using Daybreak.Models.Builds;
using Microsoft.Extensions.Logging;
using Models;
using System;
using System.Configuration;
using System.Core.Extensions;
using System.Extensions;
using System.Http;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Daybreak.Services.IconRetrieve
@@ -14,90 +14,33 @@ namespace Daybreak.Services.IconRetrieve
public sealed class IconRetriever : IIconRetriever
{
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 IConfigurationManager configurationManager;
public IconRetriever(
ILogger<IconRetriever> logger,
IHttpClient<IconRetriever> httpClient,
IConfigurationManager configurationManager)
ILogger<IconRetriever> logger)
{
this.logger = logger.ThrowIfNull(nameof(logger));
this.httpClient = httpClient.ThrowIfNull(nameof(httpClient));
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.httpClient.BaseAddress = new Uri(BaseUrl);
this.logger = logger.ThrowIfNull();
if (Directory.Exists(IconsDirectoryName) is false)
{
Directory.CreateDirectory(IconsDirectoryName);
}
}
public async Task<Optional<Stream>> GetIcon(Skill skill)
public Task<Optional<Uri>> GetIconUri(Skill skill)
{
if (this.configurationManager.GetConfiguration().KeepLocalIconCache)
var maybeIconUri = this.GetLocalIcon(skill);
if (maybeIconUri.ExtractValue() is Uri uri)
{
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 Task.FromResult(Optional.FromValue(uri));
}
return await this.DownloadIcon(skill);
return Task.FromResult(Optional.None<Uri>());
}
private async Task<Optional<Stream>> DownloadIcon(Skill skill)
{
var curedSkillName = skill.Name
.Replace(" ", "_");
var skillIconUrl = QueryUrl.Replace(NamePlaceholder, curedSkillName);
this.logger.LogInformation($"Looking up icon for skill '{skill.Name}' at url {skillIconUrl}");
using var response = await this.httpClient.GetAsync(skillIconUrl).ConfigureAwait(false);
if (response.IsSuccessStatusCode is false)
{
this.logger.LogError($"Client returned status code {response.StatusCode}");
return Optional.None<Stream>();
}
this.logger.LogInformation("Crawling through response for href to latest icon url");
var doc = new HtmlDocument();
doc.LoadHtml(await response.Content.ReadAsStringAsync());
var url = GetHref(doc);
if (url is null)
{
this.logger.LogError("Failed to find latest icon url");
return Optional.None<Stream>();
}
this.logger.LogInformation($"Found latest icon url at {BaseUrl + "/" + url}. Requesting stream");
using var iconResponse = await this.httpClient.GetAsync(url);
if (response.IsSuccessStatusCode)
{
this.logger.LogInformation("Retrieved latest icon stream");
var iconData = await iconResponse.Content.ReadAsByteArrayAsync();
if (this.configurationManager.GetConfiguration().KeepLocalIconCache)
{
await this.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)
private Optional<Uri> GetLocalIcon(Skill skill)
{
var curedSkillName = skill.Name
.Replace(" ", "_")
@@ -106,33 +49,11 @@ namespace Daybreak.Services.IconRetrieve
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)));
return new Uri(AppDomain.CurrentDomain.BaseDirectory + "/" + IconsLocation.Replace(NamePlaceholder, curedSkillName), UriKind.Absolute);
}
this.logger.LogWarning("No local icon cache found");
return Optional.None<Stream>();
}
private 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"))
{
var targetAttribute = child.Attributes.Where(a => a.Name == "href" && a.Value.Contains("images")).FirstOrDefault();
if (targetAttribute is not null)
{
return targetAttribute.Value;
}
}
return null;
return Optional.None<Uri>();
}
}
}
@@ -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)
@@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.Logging;
namespace Daybreak.Services.Logging
{
public sealed class CompositeLogsWriter : ILogsWriter
{
private readonly IEnumerable<ILogsWriter> logsWriters;
public CompositeLogsWriter(params ILogsWriter[] innerLogsWriters)
{
this.logsWriters = innerLogsWriters;
}
public void WriteLog(Log log)
{
foreach (var logWriter in this.logsWriters)
{
logWriter.WriteLog(log);
}
}
}
}
@@ -0,0 +1,13 @@
using System.Diagnostics;
using System.Logging;
namespace Daybreak.Services.Logging
{
public sealed class DebugLogsWriter : IDebugLogsWriter
{
public void WriteLog(Log log)
{
Debug.WriteLine($"[{log.LogTime}]\t[{log.LogLevel}]\t[{log.Category}]\n{log.Message}");
}
}
}
@@ -0,0 +1,8 @@
using System.Logging;
namespace Daybreak.Services.Logging
{
public interface IDebugLogsWriter : ILogsWriter
{
}
}
+3 -3
View File
@@ -2,14 +2,14 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using WpfExtended.Logging;
using System.Logging;
namespace Daybreak.Services.Logging
{
public interface ILogsManager : ILogsWriter
{
IEnumerable<Log> GetLogs(Expression<Func<Log, bool>> filter);
IEnumerable<Log> GetLogs();
IEnumerable<Models.Log> GetLogs(Expression<Func<Models.Log, bool>> filter);
IEnumerable<Models.Log> GetLogs();
int DeleteLogs();
}
}
+1 -1
View File
@@ -3,7 +3,7 @@ using System;
using System.Collections.Generic;
using System.Extensions;
using System.Linq.Expressions;
using WpfExtended.Models;
using System.Logging;
namespace Daybreak.Services.Logging
{
@@ -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}");
}
}
}
+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 -166
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.Configuration;
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,52 +24,32 @@ namespace Daybreak.Services.Updater
{
public sealed class ApplicationUpdater : IApplicationUpdater
{
private const string LaunchActionName = "Launch_Daybreak";
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 IConfigurationManager configurationManager;
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
private readonly IHttpClient<ApplicationUpdater> httpClient;
public Version CurrentVersion { get; }
public ApplicationUpdater(
ILogger<ApplicationUpdater> logger,
IConfigurationManager configurationManager,
ILiveOptions<ApplicationConfiguration> liveOptions,
IViewManager viewManager,
IHttpClient<ApplicationUpdater> httpClient)
{
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
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");
@@ -175,7 +154,7 @@ namespace Daybreak.Services.Updater
{
System.Extensions.TaskExtensions.RunPeriodicAsync(async () =>
{
if (this.configurationManager.GetConfiguration().AutoCheckUpdate is false)
if (this.liveOptions.Value.AutoCheckUpdate is false)
{
this.updateCancellationTokenSource.Cancel();
return;
@@ -190,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();
}
@@ -215,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");
});
}
}
@@ -244,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");
}
}
@@ -367,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);
+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()
+27
View File
@@ -31,5 +31,32 @@
};
window.chrome.webview.postMessage(jsonObject);
});";
public const string GetHrefFromSkillPage = @"
new function(){
var img = document.getElementsByClassName('fullImageLink')[0].childNodes[0].childNodes[0];
function getDataUrl(img) {
// Create canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Set width and height
canvas.width = img.width;
canvas.height = img.height;
// Draw the image
ctx.drawImage(img, 0, 0);
return canvas.toDataURL('image/jpeg');
}
console.log(img.src);
var imageBase64 = getDataUrl(img);
console.log(imageBase64);
let jsonObject =
{
skillUrl: document.URL,
skillImage: imageBase64
}
window.chrome.webview.postMessage(jsonObject);
return jsonObject;
}";
}
}
+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);
+7 -26
View File
@@ -1,8 +1,9 @@
using Daybreak.Services.Configuration;
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;
@@ -16,56 +17,36 @@ namespace Daybreak.Views
{
private readonly ILogger<AskUpdateView> logger;
private readonly IViewManager viewManager;
private readonly IConfigurationManager configurationManager;
private readonly ILiveUpdateableOptions<ApplicationConfiguration> liveOptions;
private readonly IPrivilegeManager privilegeManager;
private readonly IApplicationUpdater applicationUpdater;
public AskUpdateView(
ILogger<AskUpdateView> logger,
IViewManager viewManager,
IConfigurationManager configurationManager,
ILiveUpdateableOptions<ApplicationConfiguration> liveOptions,
IPrivilegeManager privilegeManager,
IApplicationUpdater applicationUpdater)
{
this.logger = logger.ThrowIfNull(nameof(logger));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
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");
var config = this.configurationManager.GetConfiguration();
config.AutoCheckUpdate = false;
this.configurationManager.SaveConfiguration(config);
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");
var config = this.configurationManager.GetConfiguration();
config.AutoCheckUpdate = false;
this.configurationManager.SaveConfiguration(config);
if (this.CheckIfAdmin() is false)
{
return;
}
var latestVersion = (await this.applicationUpdater.GetVersions()).Last();
this.viewManager.ShowView<UpdateView>(latestVersion);
}
+6 -5
View File
@@ -1,17 +1,17 @@
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;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Input;
namespace Daybreak.Views
{
@@ -39,7 +39,8 @@ namespace Daybreak.Views
IViewManager viewManager,
IBuildTemplateManager buildTemplateManager,
IIconRetriever iconRetriever,
IConfigurationManager configurationManager,
IIconBrowser iconBrowser,
ILiveOptions<ApplicationConfiguration> liveOptions,
ILogger<ChromiumBrowserWrapper> chromiumLogger,
ILogger<BuildTemplateView> logger)
{
@@ -47,7 +48,7 @@ namespace Daybreak.Views
this.logger = logger.ThrowIfNull(nameof(logger));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.InitializeComponent();
this.BuildTemplate.InitializeTemplate(iconRetriever, configurationManager, buildTemplateManager, chromiumLogger);
this.BuildTemplate.InitializeTemplate(iconRetriever, iconBrowser, liveOptions, buildTemplateManager, chromiumLogger);
this.DataContextChanged += (sender, contextArgs) =>
{
if (contextArgs.NewValue is BuildEntry)
+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();
@@ -92,6 +92,7 @@
<TextBlock Text="GWToolbox startup delay (in ms)" Foreground="White" FontSize="22" Height="30"></TextBlock>
<TextBlock Text="Detect build templates (in browser)" Foreground="White" FontSize="22" Height="30"></TextBlock>
<TextBlock Text="Launch gw as current user" Foreground="White" FontSize="22" Height="30"></TextBlock>
<TextBlock Text="Download icons" Foreground="White" FontSize="22" Height="30"></TextBlock>
</StackPanel>
<StackPanel Grid.Column="1">
<ToggleButton IsChecked="{Binding ElementName=_this, Path=MultiLaunch, Mode=TwoWay}" Style="{StaticResource AnimatedSwitch}"
@@ -103,6 +104,8 @@
Height="30" Width="60"></ToggleButton>
<ToggleButton IsChecked="{Binding ElementName=_this, Path=LaunchAsCurrentUser, Mode=TwoWay}" Style="{StaticResource AnimatedSwitch}"
Height="30" Width="60"></ToggleButton>
<ToggleButton IsChecked="{Binding ElementName=_this, Path=DownloadIcons, Mode=TwoWay}" Style="{StaticResource AnimatedSwitch}"
Height="30" Width="60"></ToggleButton>
</StackPanel>
</Grid>
</Grid>
+22 -43
View File
@@ -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;
@@ -15,79 +16,57 @@ namespace Daybreak.Views
/// </summary>
public partial class ExperimentalSettingsView : UserControl
{
public static readonly DependencyProperty MultiLaunchProperty =
DependencyPropertyExtensions.Register<ExperimentalSettingsView, bool>(nameof(MultiLaunch));
public static readonly DependencyProperty GWToolboxLaunchDelayProperty =
DependencyPropertyExtensions.Register<ExperimentalSettingsView, string>(nameof(GWToolboxLaunchDelay));
public static readonly DependencyProperty DynamicBuildLoadingProperty =
DependencyPropertyExtensions.Register<ExperimentalSettingsView, bool>(nameof(DynamicBuildLoading));
public static readonly DependencyProperty LaunchAsCurrentUserProperty =
DependencyPropertyExtensions.Register<ExperimentalSettingsView, bool>(nameof(LaunchAsCurrentUser));
public static readonly DependencyProperty MacrosEnabledProperty =
DependencyPropertyExtensions.Register<ExperimentalSettingsView, bool>(nameof(MacrosEnabled));
[GenerateDependencyProperty]
private bool launchAsCurrentUser;
[GenerateDependencyProperty]
private bool multiLaunch;
[GenerateDependencyProperty]
private bool dynamicBuildLoading;
[GenerateDependencyProperty]
private bool macrosEnabled;
[GenerateDependencyProperty]
public string gWToolboxLaunchDelay;
[GenerateDependencyProperty]
public bool downloadIcons;
private readonly IViewManager viewManager;
private readonly IConfigurationManager configurationManager;
public bool LaunchAsCurrentUser
{
get => this.GetTypedValue<bool>(LaunchAsCurrentUserProperty);
set => this.SetValue(LaunchAsCurrentUserProperty, value);
}
public bool MultiLaunch
{
get => this.GetTypedValue<bool>(MultiLaunchProperty);
set => this.SetValue(MultiLaunchProperty, value);
}
public string GWToolboxLaunchDelay
{
get => this.GetTypedValue<string>(GWToolboxLaunchDelayProperty);
set => this.SetValue(GWToolboxLaunchDelayProperty, value);
}
public bool DynamicBuildLoading
{
get => this.GetTypedValue<bool>(DynamicBuildLoadingProperty);
set => this.SetValue(DynamicBuildLoadingProperty, value);
}
public bool MacrosEnabled
{
get => this.GetTypedValue<bool>(MacrosEnabledProperty);
set => this.SetValue(MacrosEnabledProperty, value);
}
private readonly ILiveUpdateableOptions<ApplicationConfiguration> liveUpdateableOptions;
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;
this.LaunchAsCurrentUser = config.ExperimentalFeatures.LaunchGuildwarsAsCurrentUser;
this.MacrosEnabled = config.ExperimentalFeatures.CanInterceptKeys;
this.DownloadIcons = config.ExperimentalFeatures.DownloadIcons;
}
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;
config.ExperimentalFeatures.CanInterceptKeys = this.MacrosEnabled;
config.ExperimentalFeatures.DownloadIcons = this.DownloadIcons;
if (int.TryParse(this.GWToolboxLaunchDelay, out var gwToolboxLaunchDelay))
{
config.ExperimentalFeatures.ToolboxAutoLaunchDelay = gwToolboxLaunchDelay;
}
this.configurationManager.SaveConfiguration(config);
this.liveUpdateableOptions.UpdateOption();
}
private void SaveButton_Clicked(object sender, EventArgs e)
+35
View File
@@ -0,0 +1,35 @@
<UserControl x:Class="Daybreak.Views.IconDownloadView"
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.Views"
xmlns:controls="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
Unloaded="IconDownloadView_Unloaded"
Loaded="IconDownloadView_Loaded"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
</UserControl.Resources>
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" Background="White" MinHeight="200" MinWidth="400">
<controls:ChromiumBrowserWrapper x:Name="WebView"
ControlsEnabled="False"
AddressBarReadonly="True"
CanNavigate="False"
CanDownloadBuild="False"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Visibility="Visible"
Width="0"
Height="0"></controls:ChromiumBrowserWrapper>
<StackPanel VerticalAlignment="Center">
<TextBlock Text="{Binding ElementName=_this, Path=Description, Mode=OneWay}" Margin="10, 0, 10, 0" Foreground="Black"
TextWrapping="Wrap" HorizontalAlignment="Center" FontSize="16"></TextBlock>
<ProgressBar Minimum="0" Maximum="100" Value="{Binding ElementName=_this, Path=ProgressValue, Mode=OneWay}" Width="300" Height="20"></ProgressBar>
<controls:OpaqueButton Text="Cancel" BackgroundOpacity="0.2" TransparentBackground="Gray" HorizontalAlignment="Center" Margin="10" Width="50" Height="25"
Clicked="OpaqueButton_Clicked" Foreground="Black" FontSize="16"></controls:OpaqueButton>
</StackPanel>
</Grid>
</UserControl>
+125
View File
@@ -0,0 +1,125 @@
using Daybreak.Models.Builds;
using Daybreak.Services.IconRetrieve;
using Daybreak.Services.ViewManagement;
using Microsoft.Extensions.Logging;
using Models;
using System.Core.Extensions;
using System.Extensions;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Views
{
/// <summary>
/// Interaction logic for UpdateView.xaml
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
public partial class IconDownloadView : UserControl
{
private static bool CompleteIcons = false;
private readonly CancellationTokenSource cancellationTokenSource = new();
private readonly IIconRetriever iconRetriever;
private readonly IIconBrowser iconBrowser;
private readonly IViewManager viewManager;
private readonly ILogger<IconDownloadView> logger;
[GenerateDependencyProperty]
private string description;
[GenerateDependencyProperty]
private double progressValue;
public IconDownloadView(
IIconRetriever iconRetriever,
IIconBrowser iconBrowser,
IViewManager viewManager,
ILogger<IconDownloadView> logger)
{
this.iconRetriever = iconRetriever.ThrowIfNull();
this.iconBrowser = iconBrowser.ThrowIfNull();
this.viewManager = viewManager.ThrowIfNull();
this.logger = logger.ThrowIfNull();
this.InitializeComponent();
this.Description = "Verifying icons";
}
private async void IconDownloadView_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
await this.WebView.WebBrowser.EnsureCoreWebView2Async();
this.DownloadSkills();
}
private void IconDownloadView_Unloaded(object sender, System.Windows.RoutedEventArgs e)
{
this.cancellationTokenSource.Cancel();
}
private void OpaqueButton_Clicked(object sender, System.EventArgs e)
{
this.viewManager.ShowView<BuildsListView>();
}
private async void DownloadSkills()
{
if (CompleteIcons)
{
this.logger.LogInformation("All icons were detected. Skipping check");
this.viewManager.ShowView<BuildsListView>();
return;
}
this.logger.LogInformation("Beginning icon download");
this.iconBrowser.InitializeWebView(this.WebView.WebBrowser, this.cancellationTokenSource.Token);
var progressIncrement = 100d / Skill.Skills.Count();
var incomplete = false;
foreach(var skill in Skill.Skills.OrderBy(s => s.Name))
{
if (skill == Skill.NoSkill)
{
this.ProgressValue += progressIncrement;
continue;
}
var logger = this.logger.CreateScopedLogger(nameof(this.DownloadSkills), skill.Name);
logger.LogInformation("Verifying if icon exists");
this.Description = $"Checking [{skill.Name}] icon";
if ((await this.iconRetriever.GetIconUri(skill)).ExtractValue() is not null)
{
logger.LogInformation("Icon exists");
this.ProgressValue += progressIncrement;
await Task.Delay(1);
continue;
}
this.Description = $"Downloading [{skill.Name}] icon";
logger.LogInformation("Downloading icon");
var request = new IconRequest { Skill = skill };
this.iconBrowser.QueueIconRequest(request);
while(request.Finished is false)
{
await Task.Delay(1000);
}
if (request.IconBase64.IsNullOrWhiteSpace())
{
logger.LogWarning("Failed to download icon");
incomplete = true;
}
else
{
logger.LogInformation("Downloaded icon");
}
this.ProgressValue += progressIncrement;
}
CompleteIcons = !incomplete;
this.viewManager.ShowView<BuildsListView>();
}
}
}
+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>();
}
+16 -3
View File
@@ -1,4 +1,7 @@
using Daybreak.Services.ViewManagement;
using Daybreak.Configuration;
using Daybreak.Services.ViewManagement;
using System.Configuration;
using System.Core.Extensions;
using System.Extensions;
using System.Windows.Controls;
@@ -10,11 +13,14 @@ namespace Daybreak.Views
public partial class SettingsCategoryView : UserControl
{
private readonly IViewManager viewManager;
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
public SettingsCategoryView(
ILiveOptions<ApplicationConfiguration> liveOptions,
IViewManager viewManager)
{
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.liveOptions = liveOptions.ThrowIfNull();
this.viewManager = viewManager.ThrowIfNull();
InitializeComponent();
}
@@ -35,7 +41,14 @@ namespace Daybreak.Views
private void BuildsButton_Clicked(object sender, System.EventArgs e)
{
this.viewManager.ShowView<BuildsListView>();
if (this.liveOptions.Value.ExperimentalFeatures.DownloadIcons)
{
this.viewManager.ShowView<IconDownloadView>();
}
else
{
this.viewManager.ShowView<BuildsListView>();
}
}
private void VersionButton_Clicked(object sender, System.EventArgs e)
-3
View File
@@ -94,7 +94,6 @@
<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"
@@ -149,8 +148,6 @@
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>
+8 -15
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,14 +42,12 @@ 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();
@@ -60,7 +55,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;
@@ -73,12 +68,11 @@ 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;
@@ -91,8 +85,7 @@ namespace Daybreak.Views
currentConfig.ShortcutLocation = this.ShortcutFolder;
currentConfig.PlaceShortcut = this.ShortcutPlaced;
currentConfig.AutoCheckUpdate = this.AutoCheckUpdate;
currentConfig.KeepLocalIconCache = this.KeepLocalIconCache;
this.configurationManager.SaveConfiguration(currentConfig);
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