mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-09-16 21:35:20 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d291d5825a | ||
|
|
9d6162f65f | ||
|
|
f54ab42a92 | ||
|
|
78c8ae3e8f | ||
|
|
c64830c5b6 | ||
|
|
561c7cf7b1 | ||
|
|
2c6862de41 | ||
|
|
69842cbadf | ||
|
|
c7327e7bb2 | ||
|
|
de33ed7fc4 |
@@ -53,12 +53,12 @@ jobs:
|
||||
echo "${{ env.Changelog }}"
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v2
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '6.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.0.1
|
||||
uses: microsoft/setup-msbuild@v1.1.3
|
||||
|
||||
- name: Setup project secrets
|
||||
run: |
|
||||
|
||||
@@ -36,12 +36,12 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v2
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '6.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.0.1
|
||||
uses: microsoft/setup-msbuild@v1.1.3
|
||||
|
||||
- name: Execute Unit Tests
|
||||
run: dotnet test $env:Test_Project_Path
|
||||
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v2
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '6.x'
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0-preview-20220726-02" />
|
||||
<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="FluentAssertions" Version="6.9.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
|
||||
<PackageReference Include="Moq" Version="4.18.4" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -14,15 +14,15 @@ namespace Daybreak.Configuration
|
||||
[JsonProperty("BrowsersEnabled")]
|
||||
public bool BrowsersEnabled { get; set; } = true;
|
||||
[JsonProperty("ToolboxPath")]
|
||||
public string ToolboxPath { get; set; }
|
||||
public string? ToolboxPath { get; set; }
|
||||
[JsonProperty("TexmodPath")]
|
||||
public string TexmodPath { get; set; }
|
||||
public string? TexmodPath { get; set; }
|
||||
[JsonProperty("ToolboxAutoLaunch")]
|
||||
public bool ToolboxAutoLaunch { get; set; }
|
||||
[JsonProperty("LeftBrowserDefault")]
|
||||
public string LeftBrowserDefault { get; set; } = "https://gwpvx.fandom.com/wiki/PvX_wiki";
|
||||
public string? LeftBrowserDefault { get; set; } = "https://gwpvx.fandom.com/wiki/PvX_wiki";
|
||||
[JsonProperty("RightBrowserDefault")]
|
||||
public string RightBrowserDefault { get; set; } = "https://wiki.guildwars.com/wiki/Quick_access_links";
|
||||
public string? RightBrowserDefault { get; set; } = "https://wiki.guildwars.com/wiki/Quick_access_links";
|
||||
[JsonProperty("GuildwarsPaths")]
|
||||
public List<GuildwarsPath> GuildwarsPaths { get; set; } = new();
|
||||
[JsonProperty("ProtectedLoginCredentials")]
|
||||
@@ -32,14 +32,14 @@ namespace Daybreak.Configuration
|
||||
[JsonProperty("ExperimentalFeatures")]
|
||||
public ExperimentalFeatures ExperimentalFeatures { get; set; } = new();
|
||||
[JsonProperty("ShortcutLocation")]
|
||||
public string ShortcutLocation { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
public string? ShortcutLocation { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
[JsonProperty("PlaceShortcut")]
|
||||
public bool PlaceShortcut { get; set; }
|
||||
[JsonProperty("AutoCheckUpdate")]
|
||||
public bool AutoCheckUpdate { get; set; } = true;
|
||||
[JsonProperty("ProtectedGraphAccessToken")]
|
||||
public string ProtectedGraphAccessToken { get; set; }
|
||||
public string? ProtectedGraphAccessToken { get; set; }
|
||||
[JsonProperty("ProtectedGraphRefreshToken")]
|
||||
public string ProtectedGraphRefreshToken { get; set; }
|
||||
public string? ProtectedGraphRefreshToken { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ using Daybreak.Services.Updater.PostUpdate.Actions;
|
||||
using Daybreak.Services.Graph;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Daybreak.Services.Navigation;
|
||||
using Daybreak.Services.Onboarding;
|
||||
using Daybreak.Services.Menu;
|
||||
|
||||
namespace Daybreak.Configuration;
|
||||
|
||||
@@ -44,21 +46,21 @@ public static class ProjectConfiguration
|
||||
.WithMessageHandler(sp =>
|
||||
{
|
||||
var logger = sp.GetService<ILogger<ApplicationUpdater>>();
|
||||
return new LoggingHttpMessageHandler(logger) { InnerHandler = new HttpClientHandler() };
|
||||
return new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() };
|
||||
})
|
||||
.Build()
|
||||
.RegisterHttpClient<BloogumClient>()
|
||||
.WithMessageHandler(sp =>
|
||||
{
|
||||
var logger = sp.GetService<ILogger<BloogumClient>>();
|
||||
return new LoggingHttpMessageHandler(logger) { InnerHandler = new HttpClientHandler() };
|
||||
return new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() };
|
||||
})
|
||||
.Build()
|
||||
.RegisterHttpClient<GraphClient>()
|
||||
.WithMessageHandler(sp =>
|
||||
{
|
||||
var logger = sp.GetService<ILogger<GraphClient>>();
|
||||
return new LoggingHttpMessageHandler(logger) { InnerHandler = new HttpClientHandler() };
|
||||
return new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() };
|
||||
})
|
||||
.Build();
|
||||
}
|
||||
@@ -69,6 +71,7 @@ public static class ProjectConfiguration
|
||||
|
||||
services.AddSingleton<ILogsManager, JsonLogsManager>();
|
||||
services.AddSingleton<IDebugLogsWriter, Services.Logging.DebugLogsWriter>();
|
||||
services.AddSingleton<IEventViewerLogsWriter, EventViewerLogsWriter>();
|
||||
services.AddSingleton<ILoggerFactory, LoggerFactory>(sp =>
|
||||
{
|
||||
var factory = new LoggerFactory();
|
||||
@@ -76,8 +79,9 @@ public static class ProjectConfiguration
|
||||
return factory;
|
||||
});
|
||||
services.AddSingleton<ILogsWriter, CompositeLogsWriter>(sp => new CompositeLogsWriter(
|
||||
sp.GetService<ILogsManager>(),
|
||||
sp.GetService<IDebugLogsWriter>()));
|
||||
sp.GetService<ILogsManager>()!,
|
||||
sp.GetService<IDebugLogsWriter>()!,
|
||||
sp.GetService<IEventViewerLogsWriter>()!));
|
||||
|
||||
services.AddScoped((sp) => new ScopeMetadata(new CorrelationVector()));
|
||||
services.AddSingleton<ViewManager>();
|
||||
@@ -87,6 +91,8 @@ public static class ProjectConfiguration
|
||||
services.AddSingleton<IPostUpdateActionManager>(sp => sp.GetRequiredService<PostUpdateActionManager>());
|
||||
services.AddSingleton<IPostUpdateActionProducer>(sp => sp.GetRequiredService<PostUpdateActionManager>());
|
||||
services.AddSingleton<IPostUpdateActionProvider>(sp => sp.GetRequiredService<PostUpdateActionManager>());
|
||||
services.AddSingleton<IMenuService, MenuService>();
|
||||
services.AddSingleton<IMenuServiceInitializer, MenuService>(sp => sp.GetRequiredService<IMenuService>().As<MenuService>());
|
||||
services.AddSingleton<IConfigurationManager, ConfigurationManager>();
|
||||
services.AddSingleton<ILiteDatabase, LiteDatabase>(sp => new LiteDatabase("Daybreak.db"));
|
||||
services.AddSingleton<IMutexHandler, MutexHandler>();
|
||||
@@ -103,6 +109,7 @@ public static class ProjectConfiguration
|
||||
services.AddScoped<IPrivilegeManager, PrivilegeManager>();
|
||||
services.AddScoped<IScreenManager, ScreenManager>();
|
||||
services.AddScoped<IGraphClient, GraphClient>();
|
||||
services.AddScoped<IOnboardingService, OnboardingService>();
|
||||
}
|
||||
|
||||
public static void RegisterViews(IViewProducer viewProducer)
|
||||
@@ -125,6 +132,7 @@ public static class ProjectConfiguration
|
||||
viewProducer.RegisterView<IconDownloadView>();
|
||||
viewProducer.RegisterView<GraphAuthorizationView>();
|
||||
viewProducer.RegisterView<BuildsSynchronizationView>();
|
||||
viewProducer.RegisterView<OnboardingView>();
|
||||
}
|
||||
|
||||
public static void RegisterPostUpdateActions(IPostUpdateActionProducer postUpdateActionProducer)
|
||||
|
||||
@@ -5,7 +5,7 @@ public class SecretKeys
|
||||
public static readonly SecretKeys AadApplicationId = new() { Key = "AadApplicationId" };
|
||||
public static readonly SecretKeys AadTenantId = new() { Key = "AadTenantId" };
|
||||
|
||||
public string Key { get; private set; }
|
||||
public string Key { get; private set; } = string.Empty;
|
||||
private SecretKeys()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Daybreak.Configuration;
|
||||
|
||||
public static class SecretManager
|
||||
{
|
||||
private static JObject SecretsHolder;
|
||||
private static JObject? SecretsHolder;
|
||||
|
||||
public static string GetSecret(SecretKeys secretKey)
|
||||
{
|
||||
@@ -16,7 +16,7 @@ public static class SecretManager
|
||||
LoadSecrets();
|
||||
}
|
||||
|
||||
return SecretsHolder.Value<string>(secretKey.Key);
|
||||
return SecretsHolder!.Value<string>(secretKey.Key)!;
|
||||
}
|
||||
|
||||
public static T GetSecret<T>(SecretKeys secretKey)
|
||||
@@ -26,7 +26,7 @@ public static class SecretManager
|
||||
LoadSecrets();
|
||||
}
|
||||
|
||||
return SecretsHolder.Value<T>(secretKey.Key);
|
||||
return SecretsHolder!.Value<T>(secretKey.Key)!;
|
||||
}
|
||||
|
||||
private static void LoadSecrets()
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class AddButton : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
public AddButton()
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class BackButton : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
public BackButton()
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class BinButton : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
public BinButton()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class CancelButton : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
public CancelButton()
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class FilePickerGlyph : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
public FilePickerGlyph()
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class HelpButton : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
public HelpButton()
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class HomeButton : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
public HomeButton()
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class MaximizeButton : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
public MaximizeButton()
|
||||
{
|
||||
|
||||
@@ -11,16 +11,16 @@ namespace Daybreak.Controls.Buttons;
|
||||
/// </summary>
|
||||
public partial class MenuButton : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private bool highlighted;
|
||||
[GenerateDependencyProperty]
|
||||
private Brush highlightColor;
|
||||
private Brush highlightColor = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private FrameworkElement innerContent;
|
||||
[GenerateDependencyProperty]
|
||||
private string title;
|
||||
private FrameworkElement innerContent = default!;
|
||||
[GenerateDependencyProperty(InitialValue = "")]
|
||||
private string title = string.Empty;
|
||||
|
||||
public MenuButton()
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class MinusButton : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
public MinusButton()
|
||||
{
|
||||
|
||||
@@ -12,61 +12,20 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class OpaqueButton : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty TextProperty =
|
||||
DependencyPropertyExtensions.Register<OpaqueButton, string>(nameof(Text));
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
public static readonly DependencyProperty TransparentBackgroundProperty =
|
||||
DependencyPropertyExtensions.Register<OpaqueButton, Brush>(nameof(TransparentBackground));
|
||||
|
||||
public static readonly DependencyProperty HighlightProperty =
|
||||
DependencyPropertyExtensions.Register<OpaqueButton, Brush>(nameof(Highlight));
|
||||
|
||||
public static readonly DependencyProperty BackgroundOpacityProperty =
|
||||
DependencyPropertyExtensions.Register<OpaqueButton, double>(nameof(BackgroundOpacity));
|
||||
|
||||
public static readonly DependencyProperty HighlightOpacityProperty =
|
||||
DependencyPropertyExtensions.Register<OpaqueButton, double>(nameof(HighlightOpacity));
|
||||
|
||||
public static readonly DependencyProperty HighlightVisibleProperty =
|
||||
DependencyPropertyExtensions.Register<OpaqueButton, bool>(nameof(HighlightVisible));
|
||||
|
||||
public event EventHandler Clicked;
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => this.GetTypedValue<string>(TextProperty);
|
||||
set => this.SetTypedValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public Brush TransparentBackground
|
||||
{
|
||||
get => this.GetTypedValue<Brush>(TransparentBackgroundProperty);
|
||||
set => this.SetTypedValue(TransparentBackgroundProperty, value);
|
||||
}
|
||||
|
||||
public Brush Highlight
|
||||
{
|
||||
get => this.GetTypedValue<Brush>(HighlightProperty);
|
||||
set => this.SetTypedValue(HighlightProperty, value);
|
||||
}
|
||||
|
||||
public double BackgroundOpacity
|
||||
{
|
||||
get => this.GetTypedValue<double>(BackgroundOpacityProperty);
|
||||
set => this.SetTypedValue(BackgroundOpacityProperty, value);
|
||||
}
|
||||
|
||||
public double HighlightOpacity
|
||||
{
|
||||
get => this.GetTypedValue<double>(HighlightOpacityProperty);
|
||||
set => this.SetTypedValue(HighlightOpacityProperty, value);
|
||||
}
|
||||
|
||||
public bool HighlightVisible
|
||||
{
|
||||
get => this.GetTypedValue<bool>(HighlightVisibleProperty);
|
||||
set => this.SetTypedValue(HighlightVisibleProperty, value);
|
||||
}
|
||||
[GenerateDependencyProperty(InitialValue = "")]
|
||||
private string text = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
private Brush transparentBackground = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Brush highlight = default!;
|
||||
[GenerateDependencyProperty]
|
||||
public double backgroundOpacity;
|
||||
[GenerateDependencyProperty]
|
||||
public double highlightOpacity;
|
||||
[GenerateDependencyProperty]
|
||||
public bool highlightVisible;
|
||||
|
||||
public OpaqueButton()
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class SaveButton : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
public SaveButton()
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Controls;
|
||||
/// </summary>
|
||||
public partial class SynchronizeButton : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
public SynchronizeButton()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
@@ -10,46 +11,22 @@ namespace Daybreak.Controls;
|
||||
/// </summary>
|
||||
public partial class TileButton : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
public static readonly DependencyProperty HighlightedProperty =
|
||||
DependencyProperty.Register("Highlighted", typeof(bool), typeof(TileButton), null);
|
||||
public static readonly DependencyProperty HighlightColorProperty =
|
||||
DependencyProperty.Register("HighlightColor", typeof(Brush), typeof(TileButton), null);
|
||||
public static readonly DependencyProperty InnerContentProperty =
|
||||
DependencyProperty.Register("InnerContent", typeof(FrameworkElement), typeof(TileButton), null);
|
||||
public static readonly DependencyProperty TitleProperty =
|
||||
DependencyProperty.Register("Title", typeof(string), typeof(TileButton), null);
|
||||
[GenerateDependencyProperty]
|
||||
public bool highlighted;
|
||||
[GenerateDependencyProperty(InitialValue = "")]
|
||||
public string title = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
public FrameworkElement InnerContent = default!;
|
||||
[GenerateDependencyProperty]
|
||||
public Brush HighlightColor = default!;
|
||||
|
||||
public TileButton()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
public bool Highlighted
|
||||
{
|
||||
get => (bool)this.GetValue(HighlightedProperty);
|
||||
set => this.SetValue(HighlightedProperty, value);
|
||||
}
|
||||
|
||||
public string Title
|
||||
{
|
||||
get => this.GetValue(TitleProperty) as string;
|
||||
set => this.SetValue(TitleProperty, value);
|
||||
}
|
||||
|
||||
public FrameworkElement InnerContent
|
||||
{
|
||||
get => this.GetValue(InnerContentProperty) as FrameworkElement;
|
||||
set => this.SetValue(InnerContentProperty, value);
|
||||
}
|
||||
|
||||
public Brush HighlightColor
|
||||
{
|
||||
get => this.GetValue(HighlightColorProperty) as Brush;
|
||||
set => this.SetValue(HighlightColorProperty, value);
|
||||
}
|
||||
|
||||
private void Grid_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
|
||||
{
|
||||
this.Highlighted = true;
|
||||
|
||||
@@ -29,15 +29,15 @@ namespace Daybreak.Controls
|
||||
|
||||
private const string BrowserDownloadLink = "https://developer.microsoft.com/en-us/microsoft-edge/webview2/";
|
||||
|
||||
private static CoreWebView2Environment coreWebView2Environment;
|
||||
private static CoreWebView2Environment? coreWebView2Environment;
|
||||
|
||||
public event EventHandler<string> FavoriteUriChanged;
|
||||
public event EventHandler MaximizeClicked;
|
||||
public event EventHandler<Build> BuildDecoded;
|
||||
public event EventHandler<string>? FavoriteUriChanged;
|
||||
public event EventHandler? MaximizeClicked;
|
||||
public event EventHandler<Build>? BuildDecoded;
|
||||
|
||||
private ILiveOptions<ApplicationConfiguration> liveOptions;
|
||||
private ILogger<ChromiumBrowserWrapper> logger;
|
||||
private IBuildTemplateManager buildTemplateManager;
|
||||
private ILiveOptions<ApplicationConfiguration>? liveOptions;
|
||||
private ILogger<ChromiumBrowserWrapper>? logger;
|
||||
private IBuildTemplateManager? buildTemplateManager;
|
||||
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool canDownloadBuild;
|
||||
@@ -54,7 +54,7 @@ namespace Daybreak.Controls
|
||||
[GenerateDependencyProperty]
|
||||
private bool navigating;
|
||||
[GenerateDependencyProperty]
|
||||
private string favoriteAddress;
|
||||
private string favoriteAddress = string.Empty;
|
||||
[GenerateDependencyProperty(InitialValue = false)]
|
||||
private bool preventDispose;
|
||||
public string Address
|
||||
@@ -112,7 +112,7 @@ namespace Daybreak.Controls
|
||||
|
||||
private void InitializeEnvironment()
|
||||
{
|
||||
if (this.liveOptions.Value.BrowsersEnabled is false)
|
||||
if (this.liveOptions!.Value.BrowsersEnabled is false)
|
||||
{
|
||||
this.BrowserSupported = false;
|
||||
return;
|
||||
@@ -120,16 +120,13 @@ namespace Daybreak.Controls
|
||||
|
||||
try
|
||||
{
|
||||
if (coreWebView2Environment is null)
|
||||
{
|
||||
coreWebView2Environment = System.Extensions.TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", null));
|
||||
}
|
||||
coreWebView2Environment ??= System.Extensions.TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", null));
|
||||
|
||||
this.BrowserSupported = true;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
this.logger.LogWarning($"Browser initialization failed. Details: {e}");
|
||||
this.logger!.LogWarning($"Browser initialization failed. Details: {e}");
|
||||
this.BrowserSupported = false;
|
||||
}
|
||||
}
|
||||
@@ -141,7 +138,7 @@ namespace Daybreak.Controls
|
||||
this.WebBrowser.IsEnabled = true;
|
||||
this.BrowserEnabled = true;
|
||||
await this.WebBrowser.EnsureCoreWebView2Async(coreWebView2Environment);
|
||||
this.AddressBarReadonly = this.liveOptions.Value.AddressBarReadonly;
|
||||
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) =>
|
||||
@@ -156,7 +153,7 @@ namespace Daybreak.Controls
|
||||
}
|
||||
};
|
||||
this.WebBrowser.NavigationCompleted += (browser, args) => this.Navigating = false;
|
||||
this.WebBrowser.WebMessageReceived += this.CoreWebView2_WebMessageReceived;
|
||||
this.WebBrowser.WebMessageReceived += this.CoreWebView2_WebMessageReceived!;
|
||||
this.WebBrowser.CoreWebView2.Settings.AreDevToolsEnabled = false;
|
||||
this.WebBrowser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
|
||||
if (this.CanDownloadBuild)
|
||||
@@ -193,7 +190,7 @@ namespace Daybreak.Controls
|
||||
{
|
||||
var newAddress = sender.As<TextBox>().Text;
|
||||
newAddress = SanitizeAddress(newAddress);
|
||||
if (newAddress is null)
|
||||
if (newAddress.IsNullOrWhiteSpace())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -206,20 +203,20 @@ namespace Daybreak.Controls
|
||||
|
||||
private void CoreWebView2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs args)
|
||||
{
|
||||
BrowserPayload payload = default;
|
||||
BrowserPayload payload = default!;
|
||||
try
|
||||
{
|
||||
payload = args.WebMessageAsJson.Deserialize<BrowserPayload>();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
this.logger.LogError(e, $"Exception encountered when deserializing {nameof(BrowserPayload)}");
|
||||
this.logger!.LogError(e, $"Exception encountered when deserializing {nameof(BrowserPayload)}");
|
||||
}
|
||||
|
||||
if (payload?.Key == BrowserPayload.PayloadKeys.ContextMenu)
|
||||
{
|
||||
var contextMenuPayload = args.WebMessageAsJson.Deserialize<BrowserPayload<OnContextMenuPayload>>();
|
||||
var maybeTemplate = contextMenuPayload.Value.Selection;
|
||||
var maybeTemplate = contextMenuPayload.Value!.Selection;
|
||||
if (string.IsNullOrWhiteSpace(maybeTemplate))
|
||||
{
|
||||
return;
|
||||
@@ -248,7 +245,7 @@ namespace Daybreak.Controls
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
this.logger.LogWarning($"Exception when decoding template {maybeTemplate}. Details {e}");
|
||||
this.logger!.LogWarning($"Exception when decoding template {maybeTemplate}. Details {e}");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -326,7 +323,7 @@ namespace Daybreak.Controls
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(address))
|
||||
{
|
||||
return null;
|
||||
return default!;
|
||||
}
|
||||
|
||||
if (address.StartsWith("www") is false &&
|
||||
@@ -340,7 +337,7 @@ namespace Daybreak.Controls
|
||||
}
|
||||
|
||||
Uri.TryCreate(address, UriKind.Absolute, out var uri);
|
||||
return uri?.ToString();
|
||||
return uri?.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class RefreshGlyph : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
public RefreshGlyph()
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class StarGlyph : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler? Clicked;
|
||||
|
||||
public StarGlyph()
|
||||
{
|
||||
|
||||
@@ -11,12 +11,12 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class SearchTextBox : UserControl
|
||||
{
|
||||
public event EventHandler<string> TextChanged;
|
||||
public event EventHandler<string>? TextChanged;
|
||||
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool placeholderVisibility;
|
||||
[GenerateDependencyProperty]
|
||||
private string searchText;
|
||||
private string searchText = default!;
|
||||
|
||||
public SearchTextBox()
|
||||
{
|
||||
|
||||
@@ -14,15 +14,15 @@ namespace Daybreak.Controls
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class AccountTemplate : UserControl
|
||||
{
|
||||
public event EventHandler RemoveClicked;
|
||||
public event EventHandler DefaultClicked;
|
||||
public event EventHandler? RemoveClicked;
|
||||
public event EventHandler? DefaultClicked;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private string username;
|
||||
private string username = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
private string password;
|
||||
private string password = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
private string characterName;
|
||||
private string characterName = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
private bool isDefault;
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace Daybreak.Controls
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class AttributeTemplate : UserControl
|
||||
{
|
||||
public event EventHandler<AttributeEntry> HelpClicked;
|
||||
public event EventHandler<AttributeEntry> AttributeChanged;
|
||||
public event EventHandler<AttributeEntry>? HelpClicked;
|
||||
public event EventHandler<AttributeEntry>? AttributeChanged;
|
||||
|
||||
[GenerateDependencyProperty(InitialValue = false)]
|
||||
private bool canAdd;
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Controls
|
||||
/// </summary>
|
||||
public partial class BuildEntryTemplate : UserControl
|
||||
{
|
||||
public event EventHandler<BuildEntry> RemoveClicked;
|
||||
public event EventHandler<BuildEntry>? RemoveClicked;
|
||||
|
||||
public BuildEntryTemplate()
|
||||
{
|
||||
|
||||
@@ -31,35 +31,35 @@ namespace Daybreak.Controls
|
||||
|
||||
private bool suppressBuildChanged = false;
|
||||
private bool loadedProperties = false;
|
||||
private IIconBrowser iconBrowser;
|
||||
private BuildEntry loadedBuild;
|
||||
private SkillTemplate selectingSkillTemplate;
|
||||
private CancellationTokenSource cancellationTokenSource = new();
|
||||
private IIconBrowser? iconBrowser;
|
||||
private BuildEntry? loadedBuild;
|
||||
private SkillTemplate? selectingSkillTemplate;
|
||||
private CancellationTokenSource? cancellationTokenSource = new();
|
||||
|
||||
public event EventHandler BuildChanged;
|
||||
public event EventHandler? BuildChanged;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private string skillSearchText;
|
||||
private string skillSearchText = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
private Profession primaryProfession;
|
||||
private Profession primaryProfession = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Profession secondaryProfession;
|
||||
private Profession secondaryProfession = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill0;
|
||||
private Skill skill0 = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill1;
|
||||
private Skill skill1 = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill2;
|
||||
private Skill skill2 = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill3;
|
||||
private Skill skill3 = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill4;
|
||||
private Skill skill4 = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill5;
|
||||
private Skill skill5 = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill6;
|
||||
private Skill skill6 = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill7;
|
||||
private Skill skill7 = default!;
|
||||
public ObservableCollection<Skill> AvailableSkills { get; } = new ObservableCollection<Skill>();
|
||||
public ObservableCollection<AttributeEntry> Attributes { get; } = new ObservableCollection<AttributeEntry>();
|
||||
public ObservableCollection<Profession> Professions { get; } = new ObservableCollection<Profession>(Profession.Professions);
|
||||
@@ -105,11 +105,11 @@ namespace Daybreak.Controls
|
||||
{
|
||||
if (e.Property == PrimaryProfessionProperty)
|
||||
{
|
||||
this.loadedBuild.Build.Primary = this.PrimaryProfession;
|
||||
this.loadedBuild!.Build!.Primary = this.PrimaryProfession;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.loadedBuild.Build.Secondary = this.SecondaryProfession;
|
||||
this.loadedBuild!.Build!.Secondary = this.SecondaryProfession;
|
||||
}
|
||||
|
||||
this.LoadSkills();
|
||||
@@ -131,14 +131,14 @@ namespace Daybreak.Controls
|
||||
{
|
||||
if (this.suppressBuildChanged is false)
|
||||
{
|
||||
this.loadedBuild.Build.Skills[0] = this.Skill0;
|
||||
this.loadedBuild.Build.Skills[1] = this.Skill1;
|
||||
this.loadedBuild.Build.Skills[2] = this.Skill2;
|
||||
this.loadedBuild.Build.Skills[3] = this.Skill3;
|
||||
this.loadedBuild.Build.Skills[4] = this.Skill4;
|
||||
this.loadedBuild.Build.Skills[5] = this.Skill5;
|
||||
this.loadedBuild.Build.Skills[6] = this.Skill6;
|
||||
this.loadedBuild.Build.Skills[7] = this.Skill7;
|
||||
this.loadedBuild!.Build!.Skills[0] = this.Skill0;
|
||||
this.loadedBuild!.Build!.Skills[1] = this.Skill1;
|
||||
this.loadedBuild!.Build!.Skills[2] = this.Skill2;
|
||||
this.loadedBuild!.Build!.Skills[3] = this.Skill3;
|
||||
this.loadedBuild!.Build!.Skills[4] = this.Skill4;
|
||||
this.loadedBuild!.Build!.Skills[5] = this.Skill5;
|
||||
this.loadedBuild!.Build!.Skills[6] = this.Skill6;
|
||||
this.loadedBuild!.Build!.Skills[7] = this.Skill7;
|
||||
this.BuildChanged?.Invoke(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
@@ -146,7 +146,7 @@ namespace Daybreak.Controls
|
||||
|
||||
private void BuildTemplate_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.cancellationTokenSource.Cancel();
|
||||
this.cancellationTokenSource?.Cancel();
|
||||
}
|
||||
|
||||
private void InitializeProperties()
|
||||
@@ -186,17 +186,17 @@ namespace Daybreak.Controls
|
||||
if (this.PrimaryProfession != Profession.None)
|
||||
{
|
||||
possibleAttributes.Add(new AttributeEntry { Attribute = this.PrimaryProfession.PrimaryAttribute });
|
||||
possibleAttributes.AddRange(this.PrimaryProfession.Attributes.Select(a => new AttributeEntry { Attribute = a }));
|
||||
possibleAttributes.AddRange(this.PrimaryProfession.Attributes!.Select(a => new AttributeEntry { Attribute = a }));
|
||||
}
|
||||
|
||||
if (this.SecondaryProfession != Profession.None && this.SecondaryProfession != this.PrimaryProfession)
|
||||
{
|
||||
possibleAttributes.AddRange(this.SecondaryProfession.Attributes.Select(a => new AttributeEntry { Attribute = a }));
|
||||
possibleAttributes.AddRange(this.SecondaryProfession.Attributes!.Select(a => new AttributeEntry { Attribute = a }));
|
||||
}
|
||||
|
||||
this.Attributes.ClearAnd().AddRange(possibleAttributes.Select(entry =>
|
||||
{
|
||||
var maybePresentAttribute = this.loadedBuild.Build.Attributes.Where(buildEntry => entry.Attribute == buildEntry.Attribute).FirstOrDefault();
|
||||
var maybePresentAttribute = this.loadedBuild!.Build!.Attributes.Where(buildEntry => entry.Attribute == buildEntry.Attribute).FirstOrDefault();
|
||||
if (maybePresentAttribute is null)
|
||||
{
|
||||
return entry;
|
||||
@@ -206,7 +206,7 @@ namespace Daybreak.Controls
|
||||
return entry;
|
||||
}));
|
||||
|
||||
this.loadedBuild.Build.Attributes = this.Attributes.ToList();
|
||||
this.loadedBuild!.Build!.Attributes = this.Attributes.ToList();
|
||||
}
|
||||
|
||||
private async void LoadSkills()
|
||||
@@ -277,7 +277,7 @@ namespace Daybreak.Controls
|
||||
this.suppressBuildChanged = true;
|
||||
var build = this.DataContext.As<BuildEntry>();
|
||||
this.loadedBuild = build;
|
||||
this.PrimaryProfession = build.Build.Primary;
|
||||
this.PrimaryProfession = build.Build!.Primary;
|
||||
this.SecondaryProfession = build.Build.Secondary;
|
||||
this.Skill0 = build.Build.Skills[0];
|
||||
this.Skill1 = build.Build.Skills[1];
|
||||
@@ -332,7 +332,7 @@ namespace Daybreak.Controls
|
||||
return;
|
||||
}
|
||||
|
||||
this.BrowseToInfo(this.PrimaryProfession.Name);
|
||||
this.BrowseToInfo(this.PrimaryProfession.Name!);
|
||||
if (e is RoutedEventArgs routedEventArgs)
|
||||
{
|
||||
routedEventArgs.Handled = true;
|
||||
@@ -346,7 +346,7 @@ namespace Daybreak.Controls
|
||||
return;
|
||||
}
|
||||
|
||||
this.BrowseToInfo(this.SecondaryProfession.Name);
|
||||
this.BrowseToInfo(this.SecondaryProfession.Name!);
|
||||
if (e is RoutedEventArgs routedEventArgs)
|
||||
{
|
||||
routedEventArgs.Handled = true;
|
||||
@@ -355,7 +355,7 @@ namespace Daybreak.Controls
|
||||
|
||||
private void AttributeTemplate_HelpClicked(object _, AttributeEntry e)
|
||||
{
|
||||
this.BrowseToInfo(e.Attribute.Name);
|
||||
this.BrowseToInfo(e.Attribute?.Name!);
|
||||
}
|
||||
|
||||
private void AttributeTemplate_AttributeChanged(object _, AttributeEntry e)
|
||||
@@ -375,7 +375,7 @@ namespace Daybreak.Controls
|
||||
}
|
||||
else
|
||||
{
|
||||
this.BrowseToInfo(skill.Name);
|
||||
this.BrowseToInfo(skill.Name!);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
@@ -402,14 +402,14 @@ namespace Daybreak.Controls
|
||||
|
||||
this.selectingSkillTemplate.DataContext = sender.As<ListView>().SelectedItem;
|
||||
this.HideSkillListView();
|
||||
this.loadedBuild.Build.Skills[0] = this.Skill0;
|
||||
this.loadedBuild.Build.Skills[1] = this.Skill1;
|
||||
this.loadedBuild.Build.Skills[2] = this.Skill2;
|
||||
this.loadedBuild.Build.Skills[3] = this.Skill3;
|
||||
this.loadedBuild.Build.Skills[4] = this.Skill4;
|
||||
this.loadedBuild.Build.Skills[5] = this.Skill5;
|
||||
this.loadedBuild.Build.Skills[6] = this.Skill6;
|
||||
this.loadedBuild.Build.Skills[7] = this.Skill7;
|
||||
this.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)
|
||||
@@ -443,7 +443,7 @@ namespace Daybreak.Controls
|
||||
private async IAsyncEnumerable<Skill> FilterSkills(string searchTerm)
|
||||
{
|
||||
// Replace symbols to ease search
|
||||
searchTerm = searchTerm?.Replace("\"", "").Replace("!", "");
|
||||
searchTerm = searchTerm?.Replace("\"", "").Replace("!", "")!;
|
||||
|
||||
foreach (var skill in Skill.Skills)
|
||||
{
|
||||
@@ -465,7 +465,7 @@ namespace Daybreak.Controls
|
||||
continue;
|
||||
}
|
||||
|
||||
var matchesName = await Task.Run(() => StringUtils.MatchesSearchString(skill.Name.Replace("\"", "").Replace("!", ""), searchTerm));
|
||||
var matchesName = await Task.Run(() => StringUtils.MatchesSearchString(skill.Name!.Replace("\"", "").Replace("!", ""), searchTerm!));
|
||||
if (matchesName)
|
||||
{
|
||||
yield return skill;
|
||||
|
||||
@@ -15,11 +15,11 @@ namespace Daybreak.Controls
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class GuildwarsPathTemplate : UserControl
|
||||
{
|
||||
public event EventHandler RemoveClicked;
|
||||
public event EventHandler DefaultClicked;
|
||||
public event EventHandler? RemoveClicked;
|
||||
public event EventHandler? DefaultClicked;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private string path;
|
||||
private string path = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
private bool isDefault;
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Daybreak.Controls
|
||||
private bool expanded;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private string message;
|
||||
private string message = string.Empty;
|
||||
|
||||
public LogMessageTemplate()
|
||||
{
|
||||
|
||||
@@ -15,12 +15,12 @@ namespace Daybreak.Controls.Templates
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class ScreenTemplate : UserControl
|
||||
{
|
||||
public event EventHandler<Screen> Clicked;
|
||||
public event EventHandler<Screen>? Clicked;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private string screenId;
|
||||
private string screenId = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
private Brush highlight;
|
||||
private Brush highlight = default!;
|
||||
|
||||
public ScreenTemplate()
|
||||
{
|
||||
|
||||
@@ -16,13 +16,13 @@ namespace Daybreak.Controls
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class SkillTemplate : UserControl
|
||||
{
|
||||
public event EventHandler<RoutedEventArgs> Clicked;
|
||||
public event EventHandler RemoveClicked;
|
||||
public event EventHandler<RoutedEventArgs>? Clicked;
|
||||
public event EventHandler? RemoveClicked;
|
||||
|
||||
private IIconCache iconRetriever;
|
||||
private IIconCache? iconRetriever;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private ImageSource imageSource;
|
||||
private ImageSource imageSource = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private double borderOpacity;
|
||||
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
<RootNamespace>Daybreak</RootNamespace>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
|
||||
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
|
||||
<Version>0.9.7.2</Version>
|
||||
<Version>0.9.7.7</Version>
|
||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||
<UserSecretsId>cfb2a489-db80-448d-a969-80270f314c46</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
@@ -35,14 +36,14 @@
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LiteDB" Version="5.0.12" />
|
||||
<PackageReference Include="LiteDB" Version="5.0.15" />
|
||||
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.2" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1370.28" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1518.46" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="NReco.Logging.File" Version="1.1.5" />
|
||||
<PackageReference Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageReference Include="Slim" Version="1.9.2" />
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Daybreak.Launch
|
||||
{
|
||||
public readonly static Launcher Instance = new();
|
||||
|
||||
private ILogger logger;
|
||||
private ILogger? logger;
|
||||
|
||||
public System.IServiceProvider ApplicationServiceProvider => this.ServiceProvider;
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace Daybreak.Launch
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (e.Message.Contains("Invalid window handle.") && e.StackTrace.Contains("CoreWebView2Environment.CreateCoreWebView2ControllerAsync"))
|
||||
else if (e.Message.Contains("Invalid window handle.") && e.StackTrace?.Contains("CoreWebView2Environment.CreateCoreWebView2ControllerAsync") is true)
|
||||
{
|
||||
/*
|
||||
* Ignore exception caused by browser failing to initialize due to missing window.
|
||||
@@ -95,8 +95,8 @@ namespace Daybreak.Launch
|
||||
}
|
||||
protected override void ApplicationStarting()
|
||||
{
|
||||
ProjectConfiguration.RegisterViews(this.ServiceProvider.GetService<IViewManager>());
|
||||
ProjectConfiguration.RegisterPostUpdateActions(this.ServiceProvider.GetService<IPostUpdateActionProducer>());
|
||||
ProjectConfiguration.RegisterViews(this.ServiceProvider.GetService<IViewManager>()!);
|
||||
ProjectConfiguration.RegisterPostUpdateActions(this.ServiceProvider.GetService<IPostUpdateActionProducer>()!);
|
||||
|
||||
this.logger = this.ServiceProvider.GetRequiredService<ILogger<Launcher>>();
|
||||
this.RegisterViewContainer();
|
||||
|
||||
@@ -121,7 +121,8 @@
|
||||
Background="#A0202020">
|
||||
<controls:MenuList Margin="0, 30, 0, 0"/>
|
||||
</Grid>
|
||||
<ToggleButton Style="{StaticResource Window_SettingsButton}"
|
||||
<ToggleButton x:Name="OpeningSettingsButton"
|
||||
Style="{StaticResource Window_SettingsButton}"
|
||||
Width="50"
|
||||
Height="30"
|
||||
HorizontalAlignment="Left"
|
||||
@@ -129,7 +130,8 @@
|
||||
Grid.ColumnSpan="2"
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Click="SettingsButton_Clicked"></ToggleButton>
|
||||
<ToggleButton Style="{StaticResource Window_SettingsButton}"
|
||||
<ToggleButton x:Name="ClosingSettingsButton"
|
||||
Style="{StaticResource Window_SettingsButton}"
|
||||
Width="50"
|
||||
Height="30"
|
||||
HorizontalAlignment="Left"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Daybreak.Configuration;
|
||||
using Daybreak.Services.Bloogum;
|
||||
using Daybreak.Services.IconRetrieve;
|
||||
using Daybreak.Services.Menu;
|
||||
using Daybreak.Services.Navigation;
|
||||
using Daybreak.Services.Privilege;
|
||||
using Daybreak.Services.Screenshots;
|
||||
@@ -32,6 +33,7 @@ namespace Daybreak.Launch
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private readonly IMenuServiceInitializer menuServiceInitializer;
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly IScreenshotProvider screenshotProvider;
|
||||
private readonly IBloogumClient bloogumClient;
|
||||
@@ -42,15 +44,16 @@ namespace Daybreak.Launch
|
||||
private readonly CancellationTokenSource cancellationToken = new();
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private string creditText;
|
||||
private string creditText = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
private string currentVersionText;
|
||||
private string currentVersionText = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
private bool isRunningAsAdmin;
|
||||
[GenerateDependencyProperty]
|
||||
private bool isShowingDropdown;
|
||||
|
||||
public MainWindow(
|
||||
IMenuServiceInitializer menuServiceInitializer,
|
||||
IViewManager viewManager,
|
||||
IScreenshotProvider screenshotProvider,
|
||||
IBloogumClient bloogumClient,
|
||||
@@ -59,6 +62,7 @@ namespace Daybreak.Launch
|
||||
IIconDownloader iconDownloader,
|
||||
ILiveOptions<ApplicationConfiguration> liveOptions)
|
||||
{
|
||||
this.menuServiceInitializer = menuServiceInitializer.ThrowIfNull();
|
||||
this.viewManager = viewManager.ThrowIfNull();
|
||||
this.screenshotProvider = screenshotProvider.ThrowIfNull();
|
||||
this.bloogumClient = bloogumClient.ThrowIfNull();
|
||||
@@ -69,6 +73,7 @@ namespace Daybreak.Launch
|
||||
this.InitializeComponent();
|
||||
this.CurrentVersionText = this.applicationUpdater.CurrentVersion.ToString();
|
||||
this.IsRunningAsAdmin = this.privilegeManager.AdminPrivileges;
|
||||
this.SetupMenuService();
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +160,35 @@ namespace Daybreak.Launch
|
||||
|
||||
private void SettingsButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
sender.As<ToggleButton>().IsEnabled = false;
|
||||
this.ToggleDropdownMenu();
|
||||
}
|
||||
|
||||
private void OpenDropdownMenu()
|
||||
{
|
||||
if (this.IsShowingDropdown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.ToggleDropdownMenu();
|
||||
}
|
||||
|
||||
private void CloseDropdownMenu()
|
||||
{
|
||||
if (!this.IsShowingDropdown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.ToggleDropdownMenu();
|
||||
}
|
||||
|
||||
private void ToggleDropdownMenu()
|
||||
{
|
||||
var button = this.IsShowingDropdown ?
|
||||
this.ClosingSettingsButton :
|
||||
this.OpeningSettingsButton;
|
||||
button.IsEnabled = false;
|
||||
var widthAnimation = new DoubleAnimation
|
||||
{
|
||||
From = this.IsShowingDropdown ?
|
||||
@@ -190,7 +223,7 @@ namespace Daybreak.Launch
|
||||
|
||||
storyBoard.Completed += (_, _) =>
|
||||
{
|
||||
sender.As<ToggleButton>().IsEnabled = true;
|
||||
button.IsEnabled = true;
|
||||
this.IsShowingDropdown = !this.IsShowingDropdown;
|
||||
};
|
||||
|
||||
@@ -247,6 +280,11 @@ namespace Daybreak.Launch
|
||||
this.applicationUpdater.PeriodicallyCheckForUpdates();
|
||||
}
|
||||
|
||||
private void SetupMenuService()
|
||||
{
|
||||
this.menuServiceInitializer.InitializeMenuService(this.OpenDropdownMenu, this.CloseDropdownMenu, this.ToggleDropdownMenu);
|
||||
}
|
||||
|
||||
private static Color GetAverageColor(BitmapSource bitmap)
|
||||
{
|
||||
var format = bitmap.Format;
|
||||
|
||||
@@ -19,6 +19,6 @@ namespace Daybreak.Models.Browser
|
||||
public sealed class BrowserPayload<T> : BrowserPayload
|
||||
{
|
||||
[JsonProperty("Value")]
|
||||
public T Value { get; set; }
|
||||
public T? Value { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@ namespace Daybreak.Models.Browser
|
||||
[JsonProperty("Y")]
|
||||
public double Y { get; set; }
|
||||
[JsonProperty("Selection")]
|
||||
public string Selection { get; set; }
|
||||
public string? Selection { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,6 @@ namespace Daybreak.Models;
|
||||
|
||||
public sealed class BuildWithTemplateCode
|
||||
{
|
||||
public BuildEntry Build { get; set; }
|
||||
public string TemplateCode { get; set; }
|
||||
public BuildEntry? Build { get; set; }
|
||||
public string? TemplateCode { get; set; }
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace Daybreak.Models.Builds
|
||||
|
||||
public static bool TryParse(int id, out Attribute attribute)
|
||||
{
|
||||
attribute = Attributes.Where(attr => attr.Id == id).FirstOrDefault();
|
||||
attribute = Attributes.Where(attr => attr.Id == id).FirstOrDefault()!;
|
||||
if (attribute is null)
|
||||
{
|
||||
return false;
|
||||
@@ -107,7 +107,7 @@ namespace Daybreak.Models.Builds
|
||||
}
|
||||
public static bool TryParse(string name, out Attribute attribute)
|
||||
{
|
||||
attribute = Attributes.Where(attr => attr.Name == name).FirstOrDefault();
|
||||
attribute = Attributes.Where(attr => attr.Name == name).FirstOrDefault()!;
|
||||
if (attribute is null)
|
||||
{
|
||||
return false;
|
||||
@@ -135,7 +135,7 @@ namespace Daybreak.Models.Builds
|
||||
}
|
||||
|
||||
public int Id { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public string? Name { get; private set; }
|
||||
private Attribute()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ namespace Daybreak.Models.Builds
|
||||
{
|
||||
public sealed class AttributeEntry : INotifyPropertyChanged
|
||||
{
|
||||
private Attribute attribute;
|
||||
private Attribute? attribute;
|
||||
private int points;
|
||||
|
||||
public Attribute Attribute
|
||||
public Attribute? Attribute
|
||||
{
|
||||
get => this.attribute;
|
||||
set
|
||||
@@ -26,6 +26,6 @@ namespace Daybreak.Models.Builds
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Daybreak.Models.Builds
|
||||
{
|
||||
public sealed class Build
|
||||
{
|
||||
public BuildMetadata BuildMetadata { get; set; }
|
||||
public BuildMetadata? BuildMetadata { get; set; }
|
||||
public Profession Primary { get; set; } = Profession.None;
|
||||
public Profession Secondary { get; set; } = Profession.None;
|
||||
public List<AttributeEntry> Attributes { get; set; } = new();
|
||||
|
||||
@@ -4,12 +4,12 @@ namespace Daybreak.Models.Builds
|
||||
{
|
||||
public sealed class BuildEntry : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
private string name;
|
||||
private Build build;
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
private string? name;
|
||||
private Build? build;
|
||||
|
||||
public string PreviousName { get; set; }
|
||||
public string Name
|
||||
public string? PreviousName { get; set; }
|
||||
public string? Name
|
||||
{
|
||||
get => this.name;
|
||||
set
|
||||
@@ -18,7 +18,7 @@ namespace Daybreak.Models.Builds
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Name)));
|
||||
}
|
||||
}
|
||||
public Build Build
|
||||
public Build? Build
|
||||
{
|
||||
get => this.build;
|
||||
set
|
||||
|
||||
@@ -4,8 +4,8 @@ namespace Daybreak.Models.Builds
|
||||
{
|
||||
public sealed class BuildMetadata
|
||||
{
|
||||
public List<int> Base64Decoded { get; set; }
|
||||
public List<string> BinaryDecoded { get; set; }
|
||||
public List<int>? Base64Decoded { get; set; }
|
||||
public List<string>? BinaryDecoded { get; set; }
|
||||
public int Header { get; set; }
|
||||
public int VersionNumber { get; set; }
|
||||
public int ProfessionIdLength { get; set; }
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Daybreak.Models.Builds
|
||||
};
|
||||
public static bool TryParse(int id, out Profession profession)
|
||||
{
|
||||
profession = Professions.Where(prof => prof.Id == id).FirstOrDefault();
|
||||
profession = Professions.Where(prof => prof.Id == id).FirstOrDefault()!;
|
||||
if (profession is null)
|
||||
{
|
||||
return false;
|
||||
@@ -43,7 +43,7 @@ namespace Daybreak.Models.Builds
|
||||
}
|
||||
public static bool TryParse(string name, out Profession profession)
|
||||
{
|
||||
profession = Professions.Where(prof => prof.Name == name).FirstOrDefault();
|
||||
profession = Professions.Where(prof => prof.Name == name).FirstOrDefault()!;
|
||||
if (profession is null)
|
||||
{
|
||||
return false;
|
||||
@@ -70,10 +70,10 @@ namespace Daybreak.Models.Builds
|
||||
return profession;
|
||||
}
|
||||
|
||||
public string Name { get; private set; }
|
||||
public string? Name { get; private set; }
|
||||
public int Id { get; set; }
|
||||
public Attribute PrimaryAttribute { get; private set; }
|
||||
public List<Attribute> Attributes { get; private set; }
|
||||
public Attribute? PrimaryAttribute { get; private set; }
|
||||
public List<Attribute>? Attributes { get; private set; }
|
||||
private Profession()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -2982,7 +2982,7 @@ namespace Daybreak.Models.Builds
|
||||
|
||||
public static bool TryParse(int id, out Skill skill)
|
||||
{
|
||||
skill = Skills.Where(skill => skill.Id == id).FirstOrDefault();
|
||||
skill = Skills.Where(skill => skill.Id == id).FirstOrDefault()!;
|
||||
if (skill is null)
|
||||
{
|
||||
return false;
|
||||
@@ -2992,7 +2992,7 @@ namespace Daybreak.Models.Builds
|
||||
}
|
||||
public static bool TryParse(string name, out Skill skill)
|
||||
{
|
||||
skill = Skills.Where(skill => skill.Name == name).FirstOrDefault();
|
||||
skill = Skills.Where(skill => skill.Name == name).FirstOrDefault()!;
|
||||
if (skill is null)
|
||||
{
|
||||
return false;
|
||||
@@ -3019,10 +3019,10 @@ namespace Daybreak.Models.Builds
|
||||
return skill;
|
||||
}
|
||||
|
||||
public Profession Profession { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public int Id { get; private set; }
|
||||
public string AlternativeName { get; private set; }
|
||||
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()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ namespace Daybreak.Models
|
||||
{
|
||||
public sealed class ElevationRequest
|
||||
{
|
||||
public object DataContext { get; set; }
|
||||
public Type View { get; set; }
|
||||
public string MessageToUser { get; set; }
|
||||
public object? DataContext { get; set; }
|
||||
public Type? View { get; set; }
|
||||
public string? MessageToUser { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@ namespace Daybreak.Models.Github
|
||||
public sealed class GithubRefTag
|
||||
{
|
||||
[JsonProperty("ref")]
|
||||
public string Ref;
|
||||
public string? Ref;
|
||||
[JsonProperty("node_id")]
|
||||
public string NodeId;
|
||||
public string? NodeId;
|
||||
[JsonProperty("url")]
|
||||
public string Url;
|
||||
public string? Url;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Daybreak.Models
|
||||
public sealed class GuildwarsPath
|
||||
{
|
||||
[JsonProperty("path")]
|
||||
public string Path { get; set; }
|
||||
public string? Path { get; set; }
|
||||
[JsonProperty("default")]
|
||||
public bool Default { get; set; }
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
public sealed class IconPayload
|
||||
{
|
||||
public string SkillUrl { get; set; }
|
||||
public string SkillImage { get; set; }
|
||||
public string? SkillUrl { get; set; }
|
||||
public string? SkillImage { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ namespace Daybreak.Models
|
||||
{
|
||||
public sealed class IconRequest
|
||||
{
|
||||
public Skill Skill { get; set; }
|
||||
public string IconBase64 { get; set; }
|
||||
public Skill? Skill { get; set; }
|
||||
public string? IconBase64 { get; set; }
|
||||
public bool Finished { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Daybreak.Models
|
||||
{
|
||||
public sealed class KeyMacro
|
||||
{
|
||||
public List<Keys> Keys { get; set; }
|
||||
public List<Keys>? Keys { get; set; }
|
||||
public Keys TargetKey { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ namespace Daybreak.Models
|
||||
{
|
||||
public sealed class Log
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public string Category { get; set; }
|
||||
public string? Message { get; set; }
|
||||
public string? Category { get; set; }
|
||||
public LogLevel LogLevel { get; set; }
|
||||
public string CorrelationVector { get; set; }
|
||||
public string EventId { get; set; }
|
||||
public string? CorrelationVector { get; set; }
|
||||
public string? EventId { get; set; }
|
||||
public DateTime LogTime { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
{
|
||||
public sealed class LoginCredentials
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string CharacterName { get; set; }
|
||||
public string? Username { get; set; }
|
||||
public string? Password { get; set; }
|
||||
public string? CharacterName { get; set; }
|
||||
public bool Default { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Daybreak.Models
|
||||
{
|
||||
public enum OnboardingStage
|
||||
{
|
||||
Default,
|
||||
NeedsCredentials,
|
||||
NeedsExecutable,
|
||||
Complete
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace Daybreak.Models.Progress
|
||||
|
||||
private IconDownloadStep currentStep = StartingStep;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public IconDownloadStep CurrentStep
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Daybreak.Models.Progress
|
||||
|
||||
private UpdateStep currentStep = StartingStep;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public UpdateStep CurrentStep
|
||||
{
|
||||
|
||||
@@ -5,11 +5,11 @@ namespace Daybreak.Models
|
||||
public sealed class ProtectedLoginCredentials
|
||||
{
|
||||
[JsonProperty("ProtectedUsername")]
|
||||
public string ProtectedUsername { get; set; }
|
||||
public string? ProtectedUsername { get; set; }
|
||||
[JsonProperty("ProtectedPassword")]
|
||||
public string ProtectedPassword { get; set; }
|
||||
public string? ProtectedPassword { get; set; }
|
||||
[JsonProperty("CharacterName")]
|
||||
public string CharacterName { get; set; }
|
||||
public string? CharacterName { get; set; }
|
||||
[JsonProperty("Default")]
|
||||
public bool Default { get; set; }
|
||||
}
|
||||
|
||||
@@ -11,24 +11,24 @@ namespace Daybreak.Models
|
||||
{
|
||||
public static SecureString Empty { get => new(string.Empty); }
|
||||
|
||||
private byte[] encryptedBytes;
|
||||
private byte[]? encryptedBytes;
|
||||
private readonly byte[] key;
|
||||
|
||||
private byte[] DecryptedValue
|
||||
private byte[]? DecryptedValue
|
||||
{
|
||||
get => this.encryptedBytes.DecryptBytes(this.key);
|
||||
set => this.encryptedBytes = value.EncryptBytes(this.key);
|
||||
get => this.encryptedBytes?.DecryptBytes(this.key);
|
||||
set => this.encryptedBytes = value?.EncryptBytes(this.key);
|
||||
}
|
||||
[JsonProperty("value")]
|
||||
public string Value
|
||||
public string? Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.encryptedBytes.DecryptBytes(this.key).AsString();
|
||||
return this.encryptedBytes?.DecryptBytes(this.key).AsString();
|
||||
}
|
||||
set
|
||||
{
|
||||
this.encryptedBytes = value.AsBytes().EncryptBytes(this.key);
|
||||
this.encryptedBytes = value?.AsBytes().EncryptBytes(this.key);
|
||||
}
|
||||
}
|
||||
private SecureString(byte[] value)
|
||||
@@ -46,26 +46,26 @@ namespace Daybreak.Models
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public static implicit operator string(SecureString ss) => ss is null ? string.Empty : ss.Value;
|
||||
public static implicit operator string?(SecureString ss) => ss is null ? string.Empty : ss.Value;
|
||||
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));
|
||||
if (ss2 is null) throw new ArgumentNullException(nameof(ss2));
|
||||
|
||||
return new SecureString(ss1.DecryptedValue.Concat(ss2.DecryptedValue).ToArray());
|
||||
return new SecureString(ss1.DecryptedValue!.Concat(ss2.DecryptedValue!).ToArray());
|
||||
}
|
||||
public static SecureString operator +(SecureString ss1, string s2)
|
||||
{
|
||||
if (ss1 is null) throw new ArgumentNullException(nameof(ss1));
|
||||
|
||||
return new SecureString(ss1.DecryptedValue.Concat(s2.AsBytes()).ToArray());
|
||||
return new SecureString(ss1.DecryptedValue!.Concat(s2.AsBytes()).ToArray());
|
||||
}
|
||||
public static SecureString operator +(SecureString ss1, char c)
|
||||
{
|
||||
if (ss1 is null) throw new ArgumentNullException(nameof(ss1));
|
||||
|
||||
return new SecureString(ss1.DecryptedValue.Append(Convert.ToByte(c)).ToArray());
|
||||
|
||||
return new SecureString(ss1.DecryptedValue!.Append(Convert.ToByte(c)).ToArray());
|
||||
}
|
||||
public static bool operator ==(SecureString ss1, SecureString ss2)
|
||||
{
|
||||
@@ -76,12 +76,13 @@ namespace Daybreak.Models
|
||||
var ss1Value = ss1.DecryptedValue;
|
||||
var ss2Value = ss2.DecryptedValue;
|
||||
|
||||
if (ss1Value.Length != ss2Value.Length) return false;
|
||||
if (ss1Value!.Length != ss2Value!.Length) return false;
|
||||
|
||||
for (int i = 0; i < ss1Value.Length; i++)
|
||||
{
|
||||
if (ss1Value[i] != ss2Value[i]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public static bool operator !=(SecureString ss1, SecureString ss2)
|
||||
@@ -101,15 +102,15 @@ namespace Daybreak.Models
|
||||
return !(ss1.Value == s2);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is string)
|
||||
{
|
||||
return this == (obj as string);
|
||||
return this == (obj as string)!;
|
||||
}
|
||||
else if (obj is SecureString)
|
||||
{
|
||||
return this == (obj as SecureString);
|
||||
return this == (obj as SecureString)!;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -119,12 +120,12 @@ namespace Daybreak.Models
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.Value.GetHashCode();
|
||||
return this.Value!.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.Value;
|
||||
return this.Value!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Daybreak.Models;
|
||||
|
||||
public sealed class SynchronizationBuild
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
public string? TemplateCode { get; set; }
|
||||
public bool Changed { get; set; }
|
||||
}
|
||||
@@ -58,7 +58,7 @@ namespace Daybreak.Models.Versioning
|
||||
{
|
||||
if (TryParseParts(version, out var parts, out var hasPrefix) is false)
|
||||
{
|
||||
parsedVersion = null;
|
||||
parsedVersion = default!;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace Daybreak.Models.Versioning
|
||||
private static bool TryParseParts(string version, out List<VersionToken> parts, out bool hasPrefix)
|
||||
{
|
||||
hasPrefix = false;
|
||||
parts = null;
|
||||
parts = default!;
|
||||
if (version.IsNullOrWhiteSpace())
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Daybreak.Services.ApplicationLauncher
|
||||
this.ClearGwLocks();
|
||||
}
|
||||
|
||||
return await this.LaunchGuildwarsProcess(credentials.Username, credentials.Password, credentials.CharacterName);
|
||||
return await this.LaunchGuildwarsProcess(credentials.Username!, credentials.Password!, credentials.CharacterName!);
|
||||
},
|
||||
onNone: () =>
|
||||
{
|
||||
@@ -162,12 +162,12 @@ namespace Daybreak.Services.ApplicationLauncher
|
||||
"-email",
|
||||
email,
|
||||
"-password",
|
||||
password
|
||||
password!
|
||||
};
|
||||
if (!string.IsNullOrWhiteSpace(character))
|
||||
{
|
||||
args.Add("-character");
|
||||
args.Add(character);
|
||||
args.Add($"\"character\"");
|
||||
}
|
||||
|
||||
var identity = this.liveOptions.Value.ExperimentalFeatures.LaunchGuildwarsAsCurrentUser ?
|
||||
@@ -202,7 +202,7 @@ namespace Daybreak.Services.ApplicationLauncher
|
||||
throw new InvalidOperationException("Newly launched gw process not detected");
|
||||
}
|
||||
|
||||
if (gwProcess.MainWindowHandle == IntPtr.Zero)
|
||||
if (gwProcess!.MainWindowHandle == IntPtr.Zero)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -232,7 +232,7 @@ namespace Daybreak.Services.ApplicationLauncher
|
||||
return false;
|
||||
}
|
||||
|
||||
return Process.GetProcessesByName(ProcessName).Where(process => string.Equals(path.Path, process.MainModule.FileName, StringComparison.Ordinal)).Any();
|
||||
return Process.GetProcessesByName(ProcessName).Where(process => string.Equals(path.Path, process.MainModule!.FileName, StringComparison.Ordinal)).Any();
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -264,8 +264,8 @@ namespace Daybreak.Services.ApplicationLauncher
|
||||
try
|
||||
{
|
||||
var registryKey = GetGuildwarsRegistryKey(true);
|
||||
registryKey.SetValue("Path", gamePath);
|
||||
registryKey.SetValue("Src", gamePath);
|
||||
registryKey.SetValue("Path", gamePath!);
|
||||
registryKey.SetValue("Src", gamePath!);
|
||||
registryKey.Close();
|
||||
}
|
||||
catch (SecurityException ex)
|
||||
|
||||
@@ -44,7 +44,6 @@ namespace Daybreak.Services.BuildTemplates
|
||||
var emptyBuild = new Build();
|
||||
var name = Guid.NewGuid().ToString();
|
||||
var entry = new BuildEntry { Build = emptyBuild, Name = name, PreviousName = string.Empty };
|
||||
this.SaveBuild(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -52,19 +51,24 @@ namespace Daybreak.Services.BuildTemplates
|
||||
{
|
||||
var emptyBuild = new Build();
|
||||
var entry = new BuildEntry { Build = emptyBuild, Name = name, PreviousName = string.Empty };
|
||||
this.SaveBuild(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void SaveBuild(BuildEntry buildEntry)
|
||||
{
|
||||
var encodedBuild = this.EncodeTemplate(buildEntry.Build);
|
||||
if (string.IsNullOrWhiteSpace(buildEntry.PreviousName))
|
||||
var encodedBuild = this.EncodeTemplate(buildEntry.Build!);
|
||||
var newPath = Path.Combine(BuildsPath, $"{buildEntry.Name}.txt");
|
||||
if (string.IsNullOrWhiteSpace(buildEntry.PreviousName) is false)
|
||||
{
|
||||
File.Delete($"{BuildsPath}\\{buildEntry.PreviousName}.txt");
|
||||
var oldPath = Path.GetFullPath(Path.Combine(BuildsPath, $"{buildEntry.PreviousName}.txt"));
|
||||
if (File.Exists(oldPath))
|
||||
{
|
||||
File.Delete(oldPath);
|
||||
}
|
||||
}
|
||||
|
||||
File.WriteAllText($"{BuildsPath}\\{buildEntry.Name}.txt", encodedBuild);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(newPath)!);
|
||||
File.WriteAllText(newPath, encodedBuild);
|
||||
}
|
||||
|
||||
public void RemoveBuild(BuildEntry buildEntry)
|
||||
@@ -82,12 +86,13 @@ namespace Daybreak.Services.BuildTemplates
|
||||
|
||||
public async Task<Result<BuildEntry, Exception>> GetBuild(string name)
|
||||
{
|
||||
if (File.Exists($"{BuildsPath}/{name}.txt") is false)
|
||||
var path = Path.Combine(BuildsPath, $"{name}.txt");
|
||||
if (File.Exists(path) is false)
|
||||
{
|
||||
return new InvalidOperationException("Unable to find build file");
|
||||
}
|
||||
|
||||
var content = await File.ReadAllTextAsync($"{BuildsPath}/{name}.txt");
|
||||
var content = await File.ReadAllTextAsync(path);
|
||||
if (this.TryDecodeTemplate(content, out var build) is false)
|
||||
{
|
||||
return new InvalidOperationException("Unable to parse build file");
|
||||
@@ -98,7 +103,7 @@ namespace Daybreak.Services.BuildTemplates
|
||||
|
||||
public void ClearBuilds()
|
||||
{
|
||||
foreach(var file in Directory.GetFiles(BuildsPath))
|
||||
foreach(var file in Directory.GetFiles(BuildsPath, "*.txt", SearchOption.AllDirectories))
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
@@ -106,7 +111,12 @@ namespace Daybreak.Services.BuildTemplates
|
||||
|
||||
public async IAsyncEnumerable<BuildEntry> GetBuilds()
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(BuildsPath))
|
||||
if (Directory.Exists(BuildsPath) is false)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var file in Directory.GetFiles(BuildsPath, "*.txt", SearchOption.AllDirectories))
|
||||
{
|
||||
var maybeBuild = this.DecodeTemplateInner(await File.ReadAllTextAsync(file));
|
||||
var build = maybeBuild.Switch(
|
||||
@@ -114,12 +124,12 @@ namespace Daybreak.Services.BuildTemplates
|
||||
onFailure: exception =>
|
||||
{
|
||||
this.logger.LogError(exception, "Failed to parse build");
|
||||
return default;
|
||||
return default!;
|
||||
});
|
||||
|
||||
if (build is not null)
|
||||
{
|
||||
yield return new BuildEntry { Build = build, Name = Path.GetFileNameWithoutExtension(file), PreviousName = Path.GetFileNameWithoutExtension(file) };
|
||||
yield return new BuildEntry { Build = build, Name = Path.GetRelativePath(BuildsPath, file).Replace(".txt", string.Empty), PreviousName = Path.GetRelativePath(BuildsPath, file).Replace(".txt", string.Empty) };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,7 +147,7 @@ namespace Daybreak.Services.BuildTemplates
|
||||
var maybeBuild = this.DecodeTemplateInner(template);
|
||||
(var result, var parsedBuild) = maybeBuild.Switch(
|
||||
onSuccess: parsedBuild => (true, parsedBuild),
|
||||
onFailure: _ => (false, null));
|
||||
onFailure: _ => (false, default!));
|
||||
|
||||
build = parsedBuild;
|
||||
return result;
|
||||
@@ -215,9 +225,9 @@ namespace Daybreak.Services.BuildTemplates
|
||||
PrimaryProfessionId = build.Primary.Id,
|
||||
SecondaryProfessionId = build.Secondary.Id,
|
||||
AttributeCount = build.Attributes.Count,
|
||||
AttributesIds = build.Attributes.Select(attrEntry => attrEntry.Attribute.Id).ToList(),
|
||||
AttributesIds = build.Attributes.Select(attrEntry => attrEntry.Attribute!.Id).ToList(),
|
||||
AttributePoints = build.Attributes.Select(attrEntry => attrEntry.Points).ToList(),
|
||||
SkillIds = build.Skills.Select(skill => skill.Id).ToList(),
|
||||
SkillIds = build.Skills.Select(skill => skill.Id!.Value).ToList(),
|
||||
TailPresent = true
|
||||
};
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Daybreak.Services.Configuration
|
||||
private ApplicationConfiguration applicationConfiguration;
|
||||
private readonly ILogger<ConfigurationManager> logger;
|
||||
|
||||
public event EventHandler ConfigurationChanged;
|
||||
public event EventHandler? ConfigurationChanged;
|
||||
|
||||
public ConfigurationManager(ILogger<ConfigurationManager> logger)
|
||||
{
|
||||
|
||||
@@ -87,8 +87,8 @@ namespace Daybreak.Services.Credentials
|
||||
{
|
||||
try
|
||||
{
|
||||
var usrbytes = Convert.FromBase64String(protectedLoginCredentials.ProtectedUsername);
|
||||
var psdBytes = Convert.FromBase64String(protectedLoginCredentials.ProtectedPassword);
|
||||
var usrbytes = Convert.FromBase64String(protectedLoginCredentials.ProtectedUsername!);
|
||||
var psdBytes = Convert.FromBase64String(protectedLoginCredentials.ProtectedPassword!);
|
||||
return new LoginCredentials
|
||||
{
|
||||
Username = Encoding.UTF8.GetString(ProtectedData.Unprotect(usrbytes, Entropy, DataProtectionScope.LocalMachine)),
|
||||
@@ -107,8 +107,8 @@ namespace Daybreak.Services.Credentials
|
||||
{
|
||||
try
|
||||
{
|
||||
var usrBytes = Encoding.UTF8.GetBytes(loginCredentials.Username);
|
||||
var psdBytes = Encoding.UTF8.GetBytes(loginCredentials.Password);
|
||||
var usrBytes = Encoding.UTF8.GetBytes(loginCredentials.Username!);
|
||||
var psdBytes = Encoding.UTF8.GetBytes(loginCredentials.Password!);
|
||||
return new ProtectedLoginCredentials
|
||||
{
|
||||
ProtectedUsername = Convert.ToBase64String(ProtectedData.Protect(usrBytes, Entropy, DataProtectionScope.LocalMachine)),
|
||||
|
||||
@@ -54,7 +54,7 @@ public sealed class GraphClient : IGraphClient
|
||||
private readonly IHttpClient<GraphClient> httpClient;
|
||||
private readonly ILogger<GraphClient> logger;
|
||||
|
||||
private List<BuildFile> buildsCache;
|
||||
private List<BuildFile>? buildsCache;
|
||||
|
||||
public GraphClient(
|
||||
IBuildTemplateManager buildTemplateManager,
|
||||
@@ -138,7 +138,7 @@ public sealed class GraphClient : IGraphClient
|
||||
try
|
||||
{
|
||||
var profile = JsonConvert.DeserializeObject<User>(await response.Content.ReadAsStringAsync());
|
||||
return profile;
|
||||
return profile!;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@@ -168,9 +168,9 @@ public sealed class GraphClient : IGraphClient
|
||||
}
|
||||
|
||||
this.buildTemplateManager.ClearBuilds();
|
||||
var compiledBuilds = this.buildsCache.Select(buildFile =>
|
||||
var compiledBuilds = this.buildsCache?.Select(buildFile =>
|
||||
{
|
||||
if (this.buildTemplateManager.TryDecodeTemplate(buildFile.TemplateCode, out var build) is false)
|
||||
if (this.buildTemplateManager.TryDecodeTemplate(buildFile.TemplateCode!, out var build) is false)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -182,7 +182,7 @@ public sealed class GraphClient : IGraphClient
|
||||
PreviousName = buildFile.FileName
|
||||
};
|
||||
}).Where(entry => entry is not null).ToList();
|
||||
_ = compiledBuilds.Do(this.buildTemplateManager.SaveBuild).ToList();
|
||||
_ = compiledBuilds.Do(this.buildTemplateManager.SaveBuild!).ToList();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -202,11 +202,11 @@ public sealed class GraphClient : IGraphClient
|
||||
return false;
|
||||
}
|
||||
|
||||
var compiledBuilds = this.buildsCache
|
||||
var compiledBuilds = this.buildsCache?
|
||||
.Where(b => b.FileName == buildName)
|
||||
.Select(buildFile =>
|
||||
{
|
||||
if (this.buildTemplateManager.TryDecodeTemplate(buildFile.TemplateCode, out var build) is false)
|
||||
if (this.buildTemplateManager.TryDecodeTemplate(buildFile.TemplateCode!, out var build) is false)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -218,7 +218,7 @@ public sealed class GraphClient : IGraphClient
|
||||
PreviousName = buildFile.FileName
|
||||
};
|
||||
}).Where(entry => entry is not null).ToList();
|
||||
_ = compiledBuilds.Do(this.buildTemplateManager.SaveBuild).ToList();
|
||||
_ = compiledBuilds.Do(this.buildTemplateManager.SaveBuild!).ToList();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -260,7 +260,7 @@ public sealed class GraphClient : IGraphClient
|
||||
using var httpContent = new FormUrlEncodedContent(new Dictionary<string, string>
|
||||
{
|
||||
{ "client_id", ApplicationId },
|
||||
{ "refresh_token", refreshToken.Token },
|
||||
{ "refresh_token", refreshToken.Token! },
|
||||
{ "grant_type", "refresh_token" }
|
||||
});
|
||||
using var response = await this.httpClient.PostAsync(TokenUrlPlaceholder, httpContent);
|
||||
@@ -269,7 +269,7 @@ public sealed class GraphClient : IGraphClient
|
||||
return Optional.None<TokenResponse>();
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<TokenResponse>(await response.Content.ReadAsStringAsync());
|
||||
return JsonConvert.DeserializeObject<TokenResponse>(await response.Content.ReadAsStringAsync())!;
|
||||
}
|
||||
|
||||
private async Task<bool> PutBuild(BuildEntry buildEntry)
|
||||
@@ -282,7 +282,7 @@ public sealed class GraphClient : IGraphClient
|
||||
var buildFile = new BuildFile
|
||||
{
|
||||
FileName = buildEntry.Name,
|
||||
TemplateCode = this.buildTemplateManager.EncodeTemplate(buildEntry.Build)
|
||||
TemplateCode = this.buildTemplateManager.EncodeTemplate(buildEntry.Build!)
|
||||
};
|
||||
|
||||
var buildList = this.buildsCache ?? new List<BuildFile>();
|
||||
@@ -309,7 +309,7 @@ public sealed class GraphClient : IGraphClient
|
||||
var buildFiles = buildEntries.Select(buildEntry => new BuildFile
|
||||
{
|
||||
FileName = buildEntry.Name,
|
||||
TemplateCode = this.buildTemplateManager.EncodeTemplate(buildEntry.Build)
|
||||
TemplateCode = this.buildTemplateManager.EncodeTemplate(buildEntry.Build!)
|
||||
});
|
||||
|
||||
var buildList = new List<BuildFile>();
|
||||
@@ -363,13 +363,13 @@ public sealed class GraphClient : IGraphClient
|
||||
.Replace(' ', '+'))
|
||||
.Replace(StatePlaceholder, state);
|
||||
|
||||
NameValueCollection query = null;
|
||||
NameValueCollection query = default!;
|
||||
bool finished = false;
|
||||
chromiumBrowserWrapper.WebBrowser.CoreWebView2.SourceChanged += (_, sourceArgs) =>
|
||||
{
|
||||
if (chromiumBrowserWrapper.Address.StartsWith(RedirectUri))
|
||||
{
|
||||
query = HttpUtility.ParseQueryString(chromiumBrowserWrapper.Address.Split('?').Skip(1).FirstOrDefault());
|
||||
query = HttpUtility.ParseQueryString(chromiumBrowserWrapper.Address.Split('?').Skip(1).FirstOrDefault()!);
|
||||
finished = true;
|
||||
chromiumBrowserWrapper.WebBrowser.CoreWebView2.NavigateToString(string.Empty);
|
||||
}
|
||||
@@ -439,7 +439,7 @@ public sealed class GraphClient : IGraphClient
|
||||
return new InvalidOperationException($"Invalid access token response. Status code [{response.StatusCode}]");
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<TokenResponse>(await response.Content.ReadAsStringAsync());
|
||||
return JsonConvert.DeserializeObject<TokenResponse>(await response.Content.ReadAsStringAsync())!;
|
||||
}
|
||||
|
||||
private (AccessToken, RefreshToken) SaveTokenResponse(TokenResponse token)
|
||||
@@ -486,10 +486,10 @@ public sealed class GraphClient : IGraphClient
|
||||
return Optional.None<AccessToken>();
|
||||
}
|
||||
|
||||
var codeBytes = ProtectedData.Unprotect(Convert.FromBase64String(protectedCode), Entropy, DataProtectionScope.CurrentUser);
|
||||
var codeBytes = ProtectedData.Unprotect(Convert.FromBase64String(protectedCode!), Entropy, DataProtectionScope.CurrentUser);
|
||||
try
|
||||
{
|
||||
return JsonConvert.DeserializeObject<AccessToken>(Encoding.UTF8.GetString(codeBytes));
|
||||
return JsonConvert.DeserializeObject<AccessToken>(Encoding.UTF8.GetString(codeBytes))!;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@@ -507,10 +507,10 @@ public sealed class GraphClient : IGraphClient
|
||||
return Optional.None<RefreshToken>();
|
||||
}
|
||||
|
||||
var codeBytes = ProtectedData.Unprotect(Convert.FromBase64String(protectedCode), Entropy, DataProtectionScope.CurrentUser);
|
||||
var codeBytes = ProtectedData.Unprotect(Convert.FromBase64String(protectedCode!), Entropy, DataProtectionScope.CurrentUser);
|
||||
try
|
||||
{
|
||||
return JsonConvert.DeserializeObject<RefreshToken>(Encoding.UTF8.GetString(codeBytes));
|
||||
return JsonConvert.DeserializeObject<RefreshToken>(Encoding.UTF8.GetString(codeBytes))!;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Daybreak.Services.Graph.Models;
|
||||
|
||||
public sealed class AccessToken
|
||||
{
|
||||
public string Token { get; set; }
|
||||
public string? Token { get; set; }
|
||||
public DateTime ExpirationDate { get; set; }
|
||||
|
||||
public static AccessToken FromTokenResponse(TokenResponse tokenResponse)
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
public sealed class BuildFile
|
||||
{
|
||||
public string TemplateCode { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public string? TemplateCode { get; set; }
|
||||
public string? FileName { get; set; }
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ namespace Daybreak.Services.Graph.Models;
|
||||
public sealed class FileItem
|
||||
{
|
||||
[JsonProperty("@microsoft.graph.downloadUrl")]
|
||||
public string DownloadUrl { get; set; }
|
||||
public string? DownloadUrl { get; set; }
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
public string? Name { get; set; }
|
||||
[JsonProperty("lastModifiedDateTime")]
|
||||
public DateTime LastModifiedDateTime { get; set; }
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@ namespace Daybreak.Services.Graph.Models;
|
||||
public sealed class FolderItem
|
||||
{
|
||||
[JsonProperty("value")]
|
||||
public List<FileItem> Files { get; set; }
|
||||
public List<FileItem>? Files { get; set; }
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
public sealed class RefreshToken
|
||||
{
|
||||
public string Token { get; set; }
|
||||
public string? Token { get; set; }
|
||||
|
||||
public static RefreshToken FromTokenResponse(TokenResponse tokenResponse)
|
||||
{
|
||||
|
||||
@@ -5,13 +5,13 @@ namespace Daybreak.Services.Graph.Models;
|
||||
public sealed class TokenResponse
|
||||
{
|
||||
[JsonProperty("token_type")]
|
||||
public string TokenType { get; set; }
|
||||
public string? TokenType { get; set; }
|
||||
[JsonProperty("scope")]
|
||||
public string Scope { get; set; }
|
||||
public string? Scope { get; set; }
|
||||
[JsonProperty("expires_in")]
|
||||
public int ExpiresIn { get; set; }
|
||||
[JsonProperty("access_token")]
|
||||
public string AccessToken { get; set; }
|
||||
public string? AccessToken { get; set; }
|
||||
[JsonProperty("refresh_token")]
|
||||
public string RefreshToken { get; set; }
|
||||
public string? RefreshToken { get; set; }
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ namespace Daybreak.Services.Graph.Models;
|
||||
public sealed class User
|
||||
{
|
||||
[JsonProperty("displayName")]
|
||||
public string DisplayName { get; set; }
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
[JsonProperty("mail")]
|
||||
public string Email { get; set; }
|
||||
public string? Email { get; set; }
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ namespace Daybreak.Services.Graph.Models;
|
||||
|
||||
public sealed class ViewRedirectContext
|
||||
{
|
||||
public Type CallingView { get; set; }
|
||||
public Type? CallingView { get; set; }
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Daybreak.Services.IconRetrieve
|
||||
private readonly ConcurrentQueue<IconRequest> iconRequests = new();
|
||||
private readonly ILogger<IconBrowser> logger;
|
||||
|
||||
private ChromiumBrowserWrapper browserWrapper;
|
||||
private ChromiumBrowserWrapper? browserWrapper;
|
||||
private CancellationToken cancellationToken;
|
||||
|
||||
public IconBrowser(
|
||||
@@ -101,9 +101,9 @@ namespace Daybreak.Services.IconRetrieve
|
||||
this.logger.LogError(e, "Encountered error when initializing browser");
|
||||
}
|
||||
|
||||
var curedSkillName = request.Skill.AlternativeName.IsNullOrWhiteSpace() ?
|
||||
request.Skill.Name.Replace(" ", "_") :
|
||||
request.Skill.AlternativeName.Replace(" ", "_");
|
||||
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}");
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace Daybreak.Services.IconRetrieve
|
||||
continue;
|
||||
}
|
||||
|
||||
var potentialBase64 = iconPayload.SkillImage.Split(',').Skip(1).FirstOrDefault();
|
||||
var potentialBase64 = iconPayload.SkillImage!.Split(',').Skip(1).FirstOrDefault();
|
||||
if (potentialBase64 == FaultyBase64 ||
|
||||
potentialBase64 == LargeFaultyBase64)
|
||||
{
|
||||
@@ -150,7 +150,7 @@ namespace Daybreak.Services.IconRetrieve
|
||||
byte[] bytes;
|
||||
try
|
||||
{
|
||||
bytes = Convert.FromBase64String(potentialBase64);
|
||||
bytes = Convert.FromBase64String(potentialBase64!);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -160,7 +160,7 @@ namespace Daybreak.Services.IconRetrieve
|
||||
}
|
||||
|
||||
await SaveIconLocally(request.Skill, bytes);
|
||||
request.IconBase64 = potentialBase64;
|
||||
request.IconBase64 = potentialBase64!;
|
||||
request.Finished = true;
|
||||
break;
|
||||
}
|
||||
@@ -171,11 +171,11 @@ namespace Daybreak.Services.IconRetrieve
|
||||
|
||||
private static async Task<string> SaveIconLocally(Skill skill, byte[] data)
|
||||
{
|
||||
var curedSkillName = skill.Name
|
||||
var curedSkillName = skill.Name?
|
||||
.Replace(" ", "_")
|
||||
.Replace("\"", "");
|
||||
await File.WriteAllBytesAsync(IconsLocation.Replace(NamePlaceholder, curedSkillName), data);
|
||||
return curedSkillName;
|
||||
return curedSkillName!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Daybreak.Services.IconRetrieve
|
||||
|
||||
private Optional<Uri> GetLocalIcon(Skill skill)
|
||||
{
|
||||
var curedSkillName = skill.Name
|
||||
var curedSkillName = skill.Name?
|
||||
.Replace(" ", "_")
|
||||
.Replace("\"", "");
|
||||
this.logger.LogInformation("Checking local icon cache");
|
||||
|
||||
@@ -28,9 +28,9 @@ namespace Daybreak.Services.IconRetrieve
|
||||
private readonly ILogger<IconDownloader> logger;
|
||||
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
|
||||
private readonly ILogger<ChromiumBrowserWrapper> browserLogger;
|
||||
private ChromiumBrowserWrapper browserWrapper;
|
||||
private CancellationTokenSource cancellationTokenSource;
|
||||
private IconDownloadStatus iconDownloadStatus;
|
||||
private ChromiumBrowserWrapper? browserWrapper;
|
||||
private CancellationTokenSource? cancellationTokenSource;
|
||||
private IconDownloadStatus? iconDownloadStatus;
|
||||
|
||||
public bool DownloadComplete { get; private set; }
|
||||
public bool Downloading => this.cancellationTokenSource is not null;
|
||||
@@ -73,7 +73,7 @@ namespace Daybreak.Services.IconRetrieve
|
||||
if (this.Downloading)
|
||||
{
|
||||
this.logger.LogInformation("Download already running");
|
||||
return this.iconDownloadStatus;
|
||||
return this.iconDownloadStatus!;
|
||||
}
|
||||
|
||||
this.cancellationTokenSource = new();
|
||||
@@ -86,7 +86,7 @@ namespace Daybreak.Services.IconRetrieve
|
||||
{
|
||||
this.cancellationTokenSource?.Cancel();
|
||||
this.cancellationTokenSource?.Dispose();
|
||||
this.cancellationTokenSource = null;
|
||||
this.cancellationTokenSource = default!;
|
||||
}
|
||||
|
||||
private async Task DownloadIcons()
|
||||
@@ -95,7 +95,7 @@ namespace Daybreak.Services.IconRetrieve
|
||||
if (await TestBrowserSupported() is false)
|
||||
{
|
||||
this.logger.LogError("Browser not supported. Icon downloading stopped");
|
||||
this.iconDownloadStatus.CurrentStep = IconDownloadStatus.BrowserNotSupported;
|
||||
this.iconDownloadStatus!.CurrentStep = IconDownloadStatus.BrowserNotSupported;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace Daybreak.Services.IconRetrieve
|
||||
|
||||
var logger = this.logger.CreateScopedLogger(nameof(this.DownloadIcons), skill.Name);
|
||||
logger.LogInformation("Verifying if icon exists");
|
||||
this.iconDownloadStatus.CurrentStep = IconDownloadStatus.Checking(skill.Name, progressValue);
|
||||
this.iconDownloadStatus!.CurrentStep = IconDownloadStatus.Checking(skill.Name!, progressValue);
|
||||
if ((await this.iconCache.GetIconUri(skill)).ExtractValue() is not null)
|
||||
{
|
||||
progressValue += progressIncrement;
|
||||
@@ -125,18 +125,18 @@ namespace Daybreak.Services.IconRetrieve
|
||||
if (skillsToDownload.Count == 0)
|
||||
{
|
||||
this.logger.LogInformation("No icons missing. Stopping download");
|
||||
this.iconDownloadStatus.CurrentStep = IconDownloadStatus.Finished;
|
||||
this.iconDownloadStatus!.CurrentStep = IconDownloadStatus.Finished;
|
||||
return;
|
||||
}
|
||||
|
||||
this.iconBrowser.InitializeWebView(this.browserWrapper, this.cancellationTokenSource.Token);
|
||||
this.iconBrowser.InitializeWebView(this.browserWrapper!, this.cancellationTokenSource!.Token);
|
||||
|
||||
var incomplete = false;
|
||||
foreach (var skill in skillsToDownload)
|
||||
{
|
||||
if (this.cancellationTokenSource?.IsCancellationRequested is null or true)
|
||||
{
|
||||
this.iconDownloadStatus.CurrentStep = IconDownloadStatus.Stopped(progressValue);
|
||||
this.iconDownloadStatus!.CurrentStep = IconDownloadStatus.Stopped(progressValue);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ namespace Daybreak.Services.IconRetrieve
|
||||
}
|
||||
|
||||
this.logger.LogInformation("Downloading icon");
|
||||
this.iconDownloadStatus.CurrentStep = IconDownloadStatus.Downloading(skill.Name, progressValue);
|
||||
this.iconDownloadStatus!.CurrentStep = IconDownloadStatus.Downloading(skill.Name!, progressValue);
|
||||
var request = new IconRequest { Skill = skill };
|
||||
this.iconBrowser.QueueIconRequest(request);
|
||||
|
||||
@@ -178,10 +178,10 @@ namespace Daybreak.Services.IconRetrieve
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
this.browserWrapper.IsEnabled = false;
|
||||
this.browserWrapper!.IsEnabled = false;
|
||||
this.browserWrapper.WebBrowser.Dispose();
|
||||
});
|
||||
this.iconDownloadStatus.CurrentStep = IconDownloadStatus.Finished;
|
||||
this.iconDownloadStatus!.CurrentStep = IconDownloadStatus.Finished;
|
||||
this.DownloadComplete = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
using Daybreak.Models;
|
||||
using System;
|
||||
using System.Windows.Extensions.Services;
|
||||
|
||||
namespace Daybreak.Services.KeyboardHook
|
||||
{
|
||||
public interface IKeyboardHookService : IApplicationLifetimeService
|
||||
{
|
||||
event EventHandler<KeyboardHookEventArgs> KeyboardPressed;
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Utils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Extensions;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Daybreak.Services.KeyboardHook
|
||||
{
|
||||
// Based on https://gist.github.com/Stasonix
|
||||
// https://stackoverflow.com/questions/604410/global-keyboard-capture-in-c-sharp-application
|
||||
public sealed class KeyboardHookService : IKeyboardHookService, IDisposable
|
||||
{
|
||||
private readonly ILogger<KeyboardHookService> logger;
|
||||
private IntPtr windowsHookHandle;
|
||||
private IntPtr user32LibraryHandle;
|
||||
private NativeMethods.HookProc hookProc;
|
||||
|
||||
public event EventHandler<KeyboardHookEventArgs> KeyboardPressed;
|
||||
|
||||
public KeyboardHookService(
|
||||
ILogger<KeyboardHookService> logger)
|
||||
{
|
||||
this.logger = logger.ThrowIfNull(nameof(logger));
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
public void OnStartup()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnClosing()
|
||||
{
|
||||
this.Dispose();
|
||||
}
|
||||
|
||||
private void Setup()
|
||||
{
|
||||
this.windowsHookHandle = IntPtr.Zero;
|
||||
this.hookProc = this.LowLevelKeyboardProc; // we must keep alive _hookProc, because GC is not aware about SetWindowsHookEx behaviour.
|
||||
|
||||
this.user32LibraryHandle = NativeMethods.LoadLibrary("User32");
|
||||
if (this.user32LibraryHandle == IntPtr.Zero)
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
this.logger.LogError($"Failed to load library 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
|
||||
}
|
||||
|
||||
this.windowsHookHandle = NativeMethods.SetWindowsHookEx(NativeMethods.WH_KEYBOARD_LL, this.hookProc, this.user32LibraryHandle, 0);
|
||||
if (this.windowsHookHandle == IntPtr.Zero)
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
this.logger.LogError($"Failed to adjust keyboard hooks for '{Process.GetCurrentProcess().ProcessName}'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
|
||||
}
|
||||
}
|
||||
|
||||
private IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
var handled = false;
|
||||
var wparamTyped = wParam.ToInt32();
|
||||
if (Enum.IsDefined(typeof(KeyboardState), wparamTyped))
|
||||
{
|
||||
var p = Marshal.PtrToStructure(lParam, typeof(KeyboardInput)).Cast<KeyboardInput>();
|
||||
var eventArguments = new KeyboardHookEventArgs(wparamTyped.Cast<KeyboardState>(), p);
|
||||
this.KeyboardPressed?.Invoke(this, eventArguments);
|
||||
handled = eventArguments.Handled;
|
||||
}
|
||||
|
||||
return handled ? (IntPtr)1 : NativeMethods.CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// because we can unhook only in the same thread, not in garbage collector thread
|
||||
if (this.windowsHookHandle != IntPtr.Zero)
|
||||
{
|
||||
if (NativeMethods.UnhookWindowsHookEx(this.windowsHookHandle) is false)
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
this.logger.LogCritical($"Failed to remove keyboard hooks for '{Process.GetCurrentProcess().ProcessName}'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
|
||||
}
|
||||
|
||||
this.windowsHookHandle = IntPtr.Zero;
|
||||
this.hookProc -= this.LowLevelKeyboardProc;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.user32LibraryHandle != IntPtr.Zero)
|
||||
{
|
||||
if (NativeMethods.FreeLibrary(this.user32LibraryHandle) is false) // reduces reference to library by 1.
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
this.logger.LogCritical($"Failed to unload library 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
|
||||
}
|
||||
|
||||
this.user32LibraryHandle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
~KeyboardHookService()
|
||||
{
|
||||
this.Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using System.Windows.Extensions.Services;
|
||||
|
||||
namespace Daybreak.Services.KeyboardMacros
|
||||
{
|
||||
public interface IMacroService : IApplicationLifetimeService
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
using Daybreak.Configuration;
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Services.KeyboardHook;
|
||||
using Daybreak.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Extensions;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Daybreak.Services.KeyboardMacros
|
||||
{
|
||||
public sealed class MacroService : IMacroService
|
||||
{
|
||||
private readonly CancellationTokenSource cancellationTokenSource = new();
|
||||
private readonly IKeyboardHookService keyboardHookService;
|
||||
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
|
||||
private readonly HashSet<Keys> KeysDown = new();
|
||||
|
||||
private bool gameActive;
|
||||
private IntPtr gwWindowHwnd;
|
||||
|
||||
public MacroService(
|
||||
IKeyboardHookService keyboardHookService,
|
||||
ILiveOptions<ApplicationConfiguration> liveOptions)
|
||||
{
|
||||
this.keyboardHookService = keyboardHookService.ThrowIfNull(nameof(keyboardHookService));
|
||||
this.liveOptions = liveOptions.ThrowIfNull(nameof(liveOptions));
|
||||
|
||||
this.keyboardHookService.KeyboardPressed += this.KeyboardHookService_KeyboardPressed;
|
||||
this.SetupGameActiveChecker();
|
||||
}
|
||||
|
||||
private void SetupGameActiveChecker()
|
||||
{
|
||||
TaskExtensions.RunPeriodicAsync(() =>
|
||||
{
|
||||
var windowHandle = NativeMethods.GetForegroundWindow();
|
||||
var windowNameLength = NativeMethods.GetWindowTextLength(windowHandle);
|
||||
var sb = new StringBuilder(windowNameLength);
|
||||
_ = NativeMethods.GetWindowText(windowHandle, sb, windowNameLength + 1);
|
||||
if (sb.ToString() != "Guild Wars")
|
||||
{
|
||||
this.gameActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.gwWindowHwnd = windowHandle;
|
||||
this.gameActive = true;
|
||||
},
|
||||
TimeSpan.Zero,
|
||||
TimeSpan.FromMilliseconds(33),
|
||||
this.cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
private void KeyboardHookService_KeyboardPressed(object sender, KeyboardHookEventArgs e)
|
||||
{
|
||||
if (this.gameActive && this.liveOptions.Value.ExperimentalFeatures.CanInterceptKeys)
|
||||
{
|
||||
if (e.KeyboardState == KeyboardState.KeyDown)
|
||||
{
|
||||
this.KeysDown.Add(e.KeyboardInput.Key);
|
||||
}
|
||||
else if (e.KeyboardState == KeyboardState.KeyUp)
|
||||
{
|
||||
this.KeysDown.Remove(e.KeyboardInput.Key);
|
||||
return;
|
||||
}
|
||||
|
||||
e.Handled = this.liveOptions.Value.ExperimentalFeatures.Macros
|
||||
.Where(keyMacro => MacroContainsKey(keyMacro, e.KeyboardInput.Key))
|
||||
.Where(this.MacroHit)
|
||||
.Do(this.HandleMacro)
|
||||
.Any();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnClosing()
|
||||
{
|
||||
this.cancellationTokenSource.Cancel();
|
||||
}
|
||||
|
||||
public void OnStartup()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private bool MacroHit(KeyMacro keyMacro)
|
||||
{
|
||||
return this.KeysDown.Intersect(keyMacro.Keys).OrderBy(key => key).SequenceEqual(keyMacro.Keys.OrderBy(key => key));
|
||||
}
|
||||
|
||||
private void HandleMacro(KeyMacro keyMacro)
|
||||
{
|
||||
// TODO: Propagate key to guildwars executable.
|
||||
}
|
||||
|
||||
private static bool MacroContainsKey(KeyMacro keyMacro, Keys lastKey)
|
||||
{
|
||||
return keyMacro.Keys.Contains(lastKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Diagnostics;
|
||||
using System.Logging;
|
||||
|
||||
namespace Daybreak.Services.Logging;
|
||||
|
||||
public sealed class EventViewerLogsWriter : IEventViewerLogsWriter
|
||||
{
|
||||
private const string AppName = "Daybreak";
|
||||
private const string LogType = "Application";
|
||||
|
||||
public EventViewerLogsWriter()
|
||||
{
|
||||
if (EventLog.SourceExists(AppName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EventLog.CreateEventSource(AppName, LogType);
|
||||
}
|
||||
|
||||
public void WriteLog(Log log)
|
||||
{
|
||||
if (log.LogLevel is not LogLevel.Critical)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EventLog.WriteEntry(AppName, $"[{log.LogTime}]\t[{log.LogLevel}]\t[{log.Category}]\n{log.Message}", GetFromLogLevel(log.LogLevel));
|
||||
}
|
||||
|
||||
private static EventLogEntryType GetFromLogLevel(LogLevel logLevel)
|
||||
{
|
||||
return logLevel switch
|
||||
{
|
||||
LogLevel.Debug => EventLogEntryType.Information,
|
||||
LogLevel.Information => EventLogEntryType.Information,
|
||||
LogLevel.Warning => EventLogEntryType.Warning,
|
||||
LogLevel.Error => EventLogEntryType.Error,
|
||||
LogLevel.Critical => EventLogEntryType.Error,
|
||||
_ => EventLogEntryType.Information
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using System.Logging;
|
||||
|
||||
namespace Daybreak.Services.Logging;
|
||||
|
||||
public interface IEventViewerLogsWriter : ILogsWriter
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Daybreak.Services.Menu;
|
||||
|
||||
public interface IMenuService
|
||||
{
|
||||
void OpenMenu();
|
||||
void CloseMenu();
|
||||
void ToggleMenu();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Services.Menu;
|
||||
|
||||
public interface IMenuServiceInitializer
|
||||
{
|
||||
void InitializeMenuService(Action openMenuAction, Action closeMenuAction, Action toggleMenuAction);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Core.Extensions;
|
||||
|
||||
namespace Daybreak.Services.Menu;
|
||||
|
||||
public sealed class MenuService : IMenuService, IMenuServiceInitializer
|
||||
{
|
||||
private readonly ILogger<MenuService> logger;
|
||||
|
||||
private Action? openMenuAction, closeMenuAction, toggleMenuAction;
|
||||
private bool initialized;
|
||||
|
||||
public MenuService(
|
||||
ILogger<MenuService> logger)
|
||||
{
|
||||
this.logger = logger.ThrowIfNull();
|
||||
}
|
||||
|
||||
public void InitializeMenuService(Action openMenuAction, Action closeMenuAction, Action toggleMenuAction)
|
||||
{
|
||||
this.openMenuAction = openMenuAction.ThrowIfNull();
|
||||
this.closeMenuAction = closeMenuAction.ThrowIfNull();
|
||||
this.toggleMenuAction = toggleMenuAction.ThrowIfNull();
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
public void CloseMenu()
|
||||
{
|
||||
if (this.initialized is false)
|
||||
{
|
||||
this.logger.LogError($"Called {nameof(this.CloseMenu)} before initializing {nameof(MenuService)}");
|
||||
}
|
||||
|
||||
this.closeMenuAction?.Invoke();
|
||||
}
|
||||
|
||||
public void OpenMenu()
|
||||
{
|
||||
if (this.initialized is false)
|
||||
{
|
||||
this.logger.LogError($"Called {nameof(this.OpenMenu)} before initializing {nameof(MenuService)}");
|
||||
}
|
||||
|
||||
this.openMenuAction?.Invoke();
|
||||
}
|
||||
|
||||
public void ToggleMenu()
|
||||
{
|
||||
if (this.initialized is false)
|
||||
{
|
||||
this.logger.LogError($"Called {nameof(this.ToggleMenu)} before initializing {nameof(MenuService)}");
|
||||
}
|
||||
|
||||
this.toggleMenuAction?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ namespace Daybreak.Services.Mutex
|
||||
for (int i = 0; i < Marshal.ReadInt32(systemHandle); i++)
|
||||
{
|
||||
var currentOffset = IntPtr.Size + i * Marshal.SizeOf(typeof(NativeMethods.SystemHandleInformation));
|
||||
currentHandleInfo = (NativeMethods.SystemHandleInformation)Marshal.PtrToStructure(new IntPtr(basePointer + currentOffset), typeof(NativeMethods.SystemHandleInformation));
|
||||
currentHandleInfo = (NativeMethods.SystemHandleInformation)Marshal.PtrToStructure(new IntPtr(basePointer + currentOffset), typeof(NativeMethods.SystemHandleInformation))!;
|
||||
if (currentHandleInfo.OwnerPID == (uint)targetProcess.Id)
|
||||
{
|
||||
processHandles.Add(currentHandleInfo);
|
||||
@@ -108,7 +108,7 @@ namespace Daybreak.Services.Mutex
|
||||
var infoBufferSize = Marshal.SizeOf(typeof(NativeMethods.ObjectBasicInformation));
|
||||
var pInfoBuffer = Marshal.AllocHGlobal(infoBufferSize);
|
||||
NativeMethods.NtQueryObject(handle, NativeMethods.ObjectInformationClass.ObjectBasicInformation, pInfoBuffer, infoBufferSize, out _);
|
||||
NativeMethods.ObjectBasicInformation objInfo = (NativeMethods.ObjectBasicInformation)Marshal.PtrToStructure(pInfoBuffer, typeof(NativeMethods.ObjectBasicInformation));
|
||||
NativeMethods.ObjectBasicInformation objInfo = (NativeMethods.ObjectBasicInformation)Marshal.PtrToStructure(pInfoBuffer, typeof(NativeMethods.ObjectBasicInformation))!;
|
||||
Marshal.FreeHGlobal(pInfoBuffer);
|
||||
if (objInfo.NameInformationLength == 0)
|
||||
{
|
||||
@@ -125,7 +125,7 @@ namespace Daybreak.Services.Mutex
|
||||
var baseAddress = stringBuffer.ToInt64();
|
||||
var offset = IntPtr.Size * 2;
|
||||
var handleName = Marshal.PtrToStringUni(new IntPtr(baseAddress + offset));
|
||||
return handleName;
|
||||
return handleName!;
|
||||
}
|
||||
|
||||
private static bool CloseOwnedHandle(uint processId, IntPtr handleToClose)
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Daybreak.Services.Navigation
|
||||
public sealed class ViewManager : IViewManager
|
||||
{
|
||||
private readonly IServiceManager serviceManager;
|
||||
private Panel container;
|
||||
private Panel? container;
|
||||
|
||||
public ViewManager(IServiceManager serviceManager)
|
||||
{
|
||||
@@ -50,7 +50,7 @@ namespace Daybreak.Services.Navigation
|
||||
|
||||
public void ShowView(Type type)
|
||||
{
|
||||
this.ShowViewInner(type, null);
|
||||
this.ShowViewInner(type, default);
|
||||
}
|
||||
|
||||
public void ShowView(Type type, object dataContext)
|
||||
@@ -58,11 +58,16 @@ namespace Daybreak.Services.Navigation
|
||||
this.ShowViewInner(type, dataContext);
|
||||
}
|
||||
|
||||
private void ShowViewInner(Type viewType, object dataContext)
|
||||
private void ShowViewInner(Type viewType, object? dataContext)
|
||||
{
|
||||
var scopedManager = this.serviceManager.CreateScope();
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (this.container is null)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot show a view without a registered container");
|
||||
}
|
||||
|
||||
var view = scopedManager.GetService(viewType).As<UserControl>();
|
||||
this.container.Children.Clear();
|
||||
this.container.Children.Add(view);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using Daybreak.Models;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Daybreak.Services.Onboarding;
|
||||
|
||||
public interface IOnboardingService
|
||||
{
|
||||
Task<OnboardingStage> CheckOnboardingStage();
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using Daybreak.Configuration;
|
||||
using Daybreak.Exceptions;
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Services.Credentials;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Core.Extensions;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Daybreak.Services.Onboarding;
|
||||
|
||||
public sealed class OnboardingService : IOnboardingService
|
||||
{
|
||||
private readonly ICredentialManager credentialManager;
|
||||
private readonly ILiveOptions<ApplicationConfiguration> options;
|
||||
private readonly ILogger<OnboardingService> logger;
|
||||
|
||||
public OnboardingService(
|
||||
ICredentialManager credentialManager,
|
||||
ILiveOptions<ApplicationConfiguration> liveOptions,
|
||||
ILogger<OnboardingService> logger)
|
||||
{
|
||||
this.credentialManager = credentialManager.ThrowIfNull();
|
||||
this.options = liveOptions.ThrowIfNull();
|
||||
this.logger = logger.ThrowIfNull();
|
||||
}
|
||||
|
||||
public async Task<OnboardingStage> CheckOnboardingStage()
|
||||
{
|
||||
this.logger.LogInformation("Verifying if user is completely onboarded");
|
||||
var maybeCredentials = await this.credentialManager.GetDefaultCredentials();
|
||||
var credentials = maybeCredentials.ExtractValue();
|
||||
if (credentials is null)
|
||||
{
|
||||
this.logger.LogError("No default credentials found. User needs to set default credentials");
|
||||
return OnboardingStage.NeedsCredentials;
|
||||
}
|
||||
|
||||
var config = this.options.Value;
|
||||
var executable = config.GuildwarsPaths.Where(path => path.Default).FirstOrDefault();
|
||||
if (executable is null)
|
||||
{
|
||||
this.logger.LogError("No default Guildwars executable found. User needs to set default Guildwars executable");
|
||||
return OnboardingStage.NeedsExecutable;
|
||||
}
|
||||
|
||||
if (File.Exists(executable.Path) is false)
|
||||
{
|
||||
this.logger.LogError("Default Guildwars executable does not exist. User needs to set default Guildwars executable");
|
||||
return OnboardingStage.NeedsExecutable;
|
||||
}
|
||||
|
||||
this.logger.LogInformation("User is onboarded");
|
||||
return OnboardingStage.Complete;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace Daybreak.Services.Privilege
|
||||
{
|
||||
bool AdminPrivileges { get; }
|
||||
|
||||
void RequestAdminPrivileges<TCancelView>(string messageToUser, object dataContextOfCancelView = null)
|
||||
void RequestAdminPrivileges<TCancelView>(string messageToUser, object? dataContextOfCancelView = null)
|
||||
where TCancelView : UserControl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ namespace Daybreak.Services.Privilege
|
||||
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
|
||||
}
|
||||
|
||||
public void RequestAdminPrivileges<TCancelView>(string messageToUser, object dataContextOfCancelView = null)
|
||||
public void RequestAdminPrivileges<TCancelView>(string messageToUser, object? dataContextOfCancelView = default)
|
||||
where TCancelView : UserControl
|
||||
{
|
||||
this.logger.LogInformation("Requesting admin privileges");
|
||||
this.viewManager.ShowView<RequestElevationView>(new ElevationRequest { View = typeof(TCancelView), DataContext = dataContextOfCancelView, MessageToUser = messageToUser });
|
||||
this.viewManager.ShowView<RequestElevationView>(new ElevationRequest { View = typeof(TCancelView), DataContext = dataContextOfCancelView!, MessageToUser = messageToUser });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace Daybreak.Services.Updater
|
||||
|
||||
this.httpClient.DefaultRequestHeaders.Add("user-agent", "Daybreak Client");
|
||||
|
||||
if (Version.TryParse(Assembly.GetExecutingAssembly().GetName().Version.ToString(), out var currentVersion))
|
||||
if (Version.TryParse(Assembly.GetExecutingAssembly()!.GetName()!.Version!.ToString(), out var currentVersion))
|
||||
{
|
||||
if (currentVersion.HasPrefix is false)
|
||||
{
|
||||
@@ -91,7 +91,7 @@ namespace Daybreak.Services.Updater
|
||||
using var downloadStream = await this.httpClient.GetStreamAsync(uri);
|
||||
this.logger.LogInformation("Beginning update download");
|
||||
var fileStream = File.OpenWrite(TempFile);
|
||||
var downloadSize = (double)response.Content.Headers.ContentLength;
|
||||
var downloadSize = (double)response.Content!.Headers!.ContentLength!;
|
||||
var buffer = new byte[1024];
|
||||
var length = 0;
|
||||
double downloaded = 0;
|
||||
@@ -152,7 +152,7 @@ namespace Daybreak.Services.Updater
|
||||
{
|
||||
var serializedList = await response.Content.ReadAsStringAsync();
|
||||
var versionList = serializedList.Deserialize<GithubRefTag[]>();
|
||||
return versionList.Select(v => v.Ref.Remove(0, RefTagPrefix.Length)).Select(v => new Version(v));
|
||||
return versionList.Select(v => v.Ref!.Remove(0, RefTagPrefix.Length)).Select(v => new Version(v));
|
||||
}
|
||||
|
||||
return new List<Version>();
|
||||
@@ -199,7 +199,7 @@ namespace Daybreak.Services.Updater
|
||||
using var response = await this.httpClient.GetAsync(Url);
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var versionTag = response.RequestMessage.RequestUri.ToString().Split('/').Last().TrimStart('v');
|
||||
var versionTag = response.RequestMessage!.RequestUri!.ToString().Split('/').Last().TrimStart('v');
|
||||
return versionTag;
|
||||
}
|
||||
|
||||
@@ -270,11 +270,8 @@ namespace Daybreak.Services.Updater
|
||||
|
||||
private static RegistryKey GetOrCreateHomeKey()
|
||||
{
|
||||
var homeRegistryKey = Registry.CurrentUser.OpenSubKey("Software", true).OpenSubKey(RegistryKey, true);
|
||||
if (homeRegistryKey is null)
|
||||
{
|
||||
homeRegistryKey = Registry.CurrentUser.OpenSubKey("Software", true).CreateSubKey(RegistryKey, true);
|
||||
}
|
||||
var homeRegistryKey = Registry.CurrentUser.OpenSubKey("Software", true)?.OpenSubKey(RegistryKey, true);
|
||||
homeRegistryKey ??= Registry.CurrentUser.OpenSubKey("Software", true)!.CreateSubKey(RegistryKey, true);
|
||||
|
||||
return homeRegistryKey;
|
||||
}
|
||||
|
||||
@@ -6,19 +6,20 @@ namespace Daybreak.Utils
|
||||
{
|
||||
internal static class EncryptionHelper
|
||||
{
|
||||
private static Aes aesAlgorithm;
|
||||
private static Aes? AesAlgorithm;
|
||||
private static Aes Aes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (aesAlgorithm is null)
|
||||
if (AesAlgorithm is null)
|
||||
{
|
||||
aesAlgorithm = Aes.Create();
|
||||
aesAlgorithm.Mode = CipherMode.CBC;
|
||||
aesAlgorithm.BlockSize = 128;
|
||||
aesAlgorithm.Padding = PaddingMode.PKCS7;
|
||||
AesAlgorithm = Aes.Create();
|
||||
AesAlgorithm.Mode = CipherMode.CBC;
|
||||
AesAlgorithm.BlockSize = 128;
|
||||
AesAlgorithm.Padding = PaddingMode.PKCS7;
|
||||
}
|
||||
return aesAlgorithm;
|
||||
|
||||
return AesAlgorithm;
|
||||
}
|
||||
}
|
||||
private static int Iterations { get; } = 10000;
|
||||
@@ -31,7 +32,7 @@ namespace Daybreak.Utils
|
||||
var saltBytes = Generate128BitsOfRandomEntropy();
|
||||
var ivBytes = Generate128BitsOfRandomEntropy();
|
||||
|
||||
using var password = new Rfc2898DeriveBytes(key, saltBytes, Iterations);
|
||||
using var password = new Rfc2898DeriveBytes(key, saltBytes, Iterations, HashAlgorithmName.SHA512);
|
||||
var keyBytes = password.GetBytes(Aes.KeySize / 8);
|
||||
using var encryptor = Aes.CreateEncryptor(keyBytes, ivBytes);
|
||||
using var memoryStream = new MemoryStream();
|
||||
@@ -57,7 +58,7 @@ namespace Daybreak.Utils
|
||||
encryptedStream.Read(ivBytes, 0, ivBytes.Length);
|
||||
encryptedStream.Read(cipherBytes, 0, cipherBytes.Length);
|
||||
|
||||
using var password = new Rfc2898DeriveBytes(key, saltBytes, Iterations);
|
||||
using var password = new Rfc2898DeriveBytes(key, saltBytes, Iterations, HashAlgorithmName.SHA512);
|
||||
var keyBytes = password.GetBytes(Aes.KeySize / 8);
|
||||
using var decryptor = Aes.CreateDecryptor(keyBytes, ivBytes);
|
||||
using var memoryStream = new MemoryStream(cipherBytes);
|
||||
|
||||
@@ -51,6 +51,11 @@ namespace Daybreak.Views
|
||||
private void AccountTemplate_RemoveClicked(object sender, EventArgs e)
|
||||
{
|
||||
var creds = sender.As<AccountTemplate>()?.DataContext?.As<LoginCredentials>();
|
||||
if (creds is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Accounts.Remove(creds);
|
||||
if (this.Accounts.Count > 0 && creds.Default is true)
|
||||
{
|
||||
@@ -61,6 +66,11 @@ namespace Daybreak.Views
|
||||
private void AccountTemplate_DefaultClicked(object sender, EventArgs e)
|
||||
{
|
||||
var creds = sender.As<AccountTemplate>()?.DataContext?.As<LoginCredentials>();
|
||||
if (creds is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.SetAccountAsDefault(creds);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Daybreak.Views
|
||||
/// </summary>
|
||||
public partial class BuildTemplateView : UserControl
|
||||
{
|
||||
private const string DisallowedChars = "\r\n\\/.";
|
||||
private const string DisallowedChars = "\r\n/.";
|
||||
|
||||
private bool supressDecode = false;
|
||||
|
||||
@@ -31,9 +31,9 @@ namespace Daybreak.Views
|
||||
[GenerateDependencyProperty(InitialValue = false)]
|
||||
private bool saveButtonEnabled;
|
||||
[GenerateDependencyProperty]
|
||||
private BuildEntry currentBuild;
|
||||
private BuildEntry currentBuild = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private string currentBuildCode;
|
||||
private string currentBuildCode = string.Empty;
|
||||
|
||||
public BuildTemplateView(
|
||||
IViewManager viewManager,
|
||||
@@ -55,7 +55,7 @@ namespace Daybreak.Views
|
||||
{
|
||||
this.logger.LogInformation("Received data context. Setting current build");
|
||||
this.CurrentBuild = contextArgs.NewValue.As<BuildEntry>();
|
||||
this.CurrentBuildCode = this.buildTemplateManager.EncodeTemplate(this.CurrentBuild.Build);
|
||||
this.CurrentBuildCode = this.buildTemplateManager.EncodeTemplate(this.CurrentBuild.Build!);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -95,7 +95,7 @@ namespace Daybreak.Views
|
||||
try
|
||||
{
|
||||
this.supressDecode = true;
|
||||
this.CurrentBuildCode = this.buildTemplateManager.EncodeTemplate(this.CurrentBuild.Build);
|
||||
this.CurrentBuildCode = this.buildTemplateManager.EncodeTemplate(this.CurrentBuild.Build!);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Daybreak.Views
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly IBuildTemplateManager buildTemplateManager;
|
||||
|
||||
private IEnumerable<BuildEntry> buildEntries;
|
||||
private IEnumerable<BuildEntry>? buildEntries;
|
||||
|
||||
public ObservableCollection<BuildEntry> BuildEntries { get; } = new ObservableCollection<BuildEntry>();
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Daybreak.Views
|
||||
private async void LoadBuilds()
|
||||
{
|
||||
this.buildEntries = await this.buildTemplateManager.GetBuilds().ToListAsync();
|
||||
this.BuildEntries.ClearAnd().AddRange(this.buildEntries);
|
||||
this.BuildEntries.ClearAnd().AddRange(this.buildEntries.OrderBy(b => b.Name));
|
||||
}
|
||||
|
||||
private void ListView_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
@@ -60,7 +60,7 @@ namespace Daybreak.Views
|
||||
{
|
||||
this.BuildEntries.Clear();
|
||||
this.BuildEntries.AddRange(
|
||||
this.buildEntries.Where(b => StringUtils.MatchesSearchString(b.Name, e)));
|
||||
this.buildEntries!.Where(b => StringUtils.MatchesSearchString(b.Name!, e)));
|
||||
}
|
||||
|
||||
private void SynchronizeButton_Clicked(object sender, EventArgs e)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<UserControl.Resources>
|
||||
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" TriggerValue="False"></converters:BooleanToVisibilityConverter>
|
||||
<converters:BooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter" TriggerValue="True"></converters:BooleanToVisibilityConverter>
|
||||
<BooleanToVisibilityConverter x:Key="BaseBooleanToVisibilityConverter"></BooleanToVisibilityConverter>
|
||||
</UserControl.Resources>
|
||||
<Grid
|
||||
Background="#A0202020">
|
||||
@@ -96,9 +97,12 @@
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Rectangle Fill="LawnGreen"
|
||||
Opacity="0.2"
|
||||
Visibility="{Binding Changed, Converter={StaticResource BooleanToVisibilityConverter}}"></Rectangle>
|
||||
<TextBlock FontSize="14"
|
||||
Foreground="White"
|
||||
Text="{Binding Build.Name}"
|
||||
Text="{Binding Name}"
|
||||
HorizontalAlignment="Left"></TextBlock>
|
||||
<TextBlock FontSize="14"
|
||||
Foreground="White"
|
||||
@@ -134,13 +138,16 @@
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Rectangle Fill="Red"
|
||||
Visibility="{Binding Changed, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
Opacity="0.2"></Rectangle>
|
||||
<TextBlock FontSize="14"
|
||||
Foreground="White"
|
||||
Text="{Binding TemplateCode}"
|
||||
HorizontalAlignment="Left"></TextBlock>
|
||||
<TextBlock FontSize="14"
|
||||
Foreground="White"
|
||||
Text="{Binding FileName}"
|
||||
Text="{Binding Name}"
|
||||
HorizontalAlignment="Right"></TextBlock>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user