Compare commits

...
14 Commits
Author SHA1 Message Date
Alexandru Macocian bc66ca9948 Feature flag to disable dynamic build loading in experimental settings. 2021-04-22 17:53:04 +02:00
amacocianandGitHub 524cd21fd4 Update README.md 2021-04-22 17:39:51 +02:00
amacocianandGitHub 132cb0e1f4 Update README.md 2021-04-22 17:32:35 +02:00
amacocianandGitHub 09c99e7731 Update README.md 2021-04-22 17:29:49 +02:00
Alexandru Macocian c9d0be1117 Update to 0.7.0 2021-04-22 17:02:48 +02:00
Alexandru Macocian 965055c8d7 Build management implementation.
Load build from browser when selection is detected to be a build template.
Load skill images from internet on demand.
Load skill details page when a skill is selected.
Separate skills on professions.
2021-04-22 17:02:28 +02:00
Alexandru Macocian f6bb21d0ef Build template parser and encoder.
Unit test project.
2021-04-20 20:06:15 +02:00
Alexandru Macocian 465e0a4ce0 Fix buttons while browser is fullscreen. 2021-04-20 12:51:26 +02:00
Alexandru Macocian 55f304b885 Update to wpfextended 0.2 2021-04-19 21:37:15 +02:00
Alexandru Macocian 0cb1d97332 Remove hyperlink from version text. 2021-04-17 20:04:20 +02:00
Alexandru Macocian e2091cd82f Home button for browsers.
Stop asking for updates if user already answered no.
2021-04-17 19:39:56 +02:00
Alexandru Macocian d2bada4159 Button to disable browsers. 2021-04-17 10:21:06 +02:00
Alexandru Macocian b27998d7f2 Basic support for texmod/umod. 2021-04-15 11:15:36 +02:00
amacocianandGitHub 98d3e21db9 Update README.md 2021-04-15 10:17:24 +02:00
102 changed files with 6305 additions and 65 deletions
+22
View File
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0-windows</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.0.0-alpha0002" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Daybreak\Daybreak.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,96 @@
using Daybreak.Models.Builds;
using Daybreak.Services.BuildTemplates;
using Daybreak.Services.Logging;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System.Collections.Generic;
namespace Daybreak.Tests.Services
{
[TestClass]
public class BuildTemplateManagerTests
{
private const string EncodedTemplate = "OwBk0texXNu0Dj/z+TDzBj+TN4AE";
private IBuildTemplateManager buildTemplateManager;
[TestInitialize]
public void Initialize()
{
buildTemplateManager = new BuildTemplateManager(new Mock<ILogger>().Object);
}
[TestMethod]
public void TestDecode()
{
var build = this.buildTemplateManager.DecodeTemplate(EncodedTemplate);
build.Primary.Should().Be(Profession.Assassin);
build.Secondary.Should().Be(Profession.None);
build.Attributes.Count.Should().Be(4);
build.Attributes[0].Attribute.Should().Be(Attribute.DaggerMastery);
build.Attributes[0].Points.Should().Be(11);
build.Attributes[1].Attribute.Should().Be(Attribute.DeadlyArts);
build.Attributes[1].Points.Should().Be(1);
build.Attributes[2].Attribute.Should().Be(Attribute.ShadowArts);
build.Attributes[2].Points.Should().Be(5);
build.Attributes[3].Attribute.Should().Be(Attribute.CriticalStrikes);
build.Attributes[3].Points.Should().Be(11);
build.Skills.Count.Should().Be(8);
build.Skills[0].Should().Be(Skill.UnsuspectingStrike);
build.Skills[1].Should().Be(Skill.WildStrike);
build.Skills[2].Should().Be(Skill.CriticalStrike);
build.Skills[3].Should().Be(Skill.MoebiusStrike);
build.Skills[4].Should().Be(Skill.DeathBlossom);
build.Skills[5].Should().Be(Skill.CriticalEye);
build.Skills[6].Should().Be(Skill.CriticalAgility);
build.Skills[7].Should().Be(Skill.CriticalDefenses);
}
[TestMethod]
public void TestEncode()
{
var build = new Build()
{
Primary = Profession.Assassin,
Secondary = Profession.None,
Attributes = new List<AttributeEntry>
{
new AttributeEntry
{
Attribute = Attribute.DaggerMastery,
Points = 11
},
new AttributeEntry
{
Attribute = Attribute.DeadlyArts,
Points = 1
},
new AttributeEntry
{
Attribute = Attribute.ShadowArts,
Points = 5
},
new AttributeEntry
{
Attribute = Attribute.CriticalStrikes,
Points = 11
}
},
Skills = new List<Skill>
{
Skill.UnsuspectingStrike,
Skill.WildStrike,
Skill.CriticalStrike,
Skill.MoebiusStrike,
Skill.DeathBlossom,
Skill.CriticalEye,
Skill.CriticalAgility,
Skill.CriticalDefenses
}
};
var encoded = this.buildTemplateManager.EncodeTemplate(build);
encoded.Should().Be(EncodedTemplate);
}
}
}
+10
View File
@@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.31005.135
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Daybreak", "Daybreak\Daybreak.csproj", "{AA45C2B1-8BD0-466C-9271-699F168905AF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Daybreak.Tests", "Daybreak.Tests\Daybreak.Tests.csproj", "{C911C1C2-6566-419C-89C7-F802EB3FE709}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -21,6 +23,14 @@ Global
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Release|Any CPU.Build.0 = Release|Any CPU
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Release|x64.ActiveCfg = Release|x64
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Release|x64.Build.0 = Release|x64
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Debug|x64.ActiveCfg = Debug|Any CPU
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Debug|x64.Build.0 = Debug|Any CPU
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|Any CPU.Build.0 = Release|Any CPU
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x64.ActiveCfg = Release|Any CPU
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+55
View File
@@ -0,0 +1,55 @@
using System;
using System.Extensions;
using System.Windows.Controls;
using System.Windows.Interactivity;
namespace Daybreak.Behaviors
{
public class ScrollIntoView : Behavior<ListView>
{
/// <summary>
/// When Beahvior is attached
/// </summary>
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
}
/// <summary>
/// On Selection Changed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void AssociatedObject_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
if (sender is ListView)
{
var listView = sender.As<ListView>();
if (listView.SelectedItem != null)
{
listView.Dispatcher.BeginInvoke(
(Action)(() =>
{
listView.UpdateLayout();
if (listView.SelectedItem !=
null)
listView.ScrollIntoView(
listView.SelectedItem);
}));
}
}
}
/// <summary>
/// When behavior is detached
/// </summary>
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.SelectionChanged -=
AssociatedObject_SelectionChanged;
}
}
}
@@ -6,8 +6,12 @@ namespace Daybreak.Configuration
{
public sealed class ApplicationConfiguration
{
[JsonProperty("BrowsersEnabled")]
public bool BrowsersEnabled { get; set; } = true;
[JsonProperty("ToolboxPath")]
public string ToolboxPath { get; set; }
[JsonProperty("TexmodPath")]
public string TexmodPath { get; set; }
[JsonProperty("ToolboxAutoLaunch")]
public bool ToolboxAutoLaunch { get; set; }
[JsonProperty("LeftBrowserDefault")]
@@ -8,5 +8,7 @@ namespace Daybreak.Configuration
public bool MultiLaunchSupport { get; set; }
[JsonProperty("ToolboxAutoLaunchDelay")]
public int ToolboxAutoLaunchDelay { get; set; } = 5000;
[JsonProperty("DynamicBuildLoading")]
public bool DynamicBuildLoading { get; set; } = true;
}
}
@@ -1,10 +1,13 @@
using Daybreak.Services.ApplicationLauncher;
using Daybreak.Services.ApplicationLifetime;
using Daybreak.Services.Bloogum;
using Daybreak.Services.BuildTemplates;
using Daybreak.Services.Configuration;
using Daybreak.Services.Credentials;
using Daybreak.Services.IconRetrieve;
using Daybreak.Services.Logging;
using Daybreak.Services.Mutex;
using Daybreak.Services.Runtime;
using Daybreak.Services.Screenshots;
using Daybreak.Services.Updater;
using Daybreak.Services.ViewManagement;
@@ -14,7 +17,6 @@ using System.Extensions;
namespace Daybreak.Configuration
{
// TODO: Credit http://bloogum.net/guildwars/
public static class ProjectConfiguration
{
public static void RegisterServices(IServiceProducer serviceProducer)
@@ -32,6 +34,9 @@ namespace Daybreak.Configuration
serviceProducer.RegisterSingleton<IBloogumClient, BloogumClient>();
serviceProducer.RegisterSingleton<IApplicationUpdater, ApplicationUpdater>();
serviceProducer.RegisterSingleton<IMutexHandler, MutexHandler>();
serviceProducer.RegisterSingleton<IRuntimeStore, RuntimeStore>();
serviceProducer.RegisterSingleton<IBuildTemplateManager, BuildTemplateManager>();
serviceProducer.RegisterSingleton<IIconRetriever, IconRetriever>();
}
public static void RegisterLifetimeServices(IApplicationLifetimeProducer applicationLifetimeProducer)
{
@@ -53,6 +58,8 @@ namespace Daybreak.Configuration
viewProducer.RegisterView<AccountsView>();
viewProducer.RegisterView<ExperimentalSettingsView>();
viewProducer.RegisterView<ExecutablesView>();
viewProducer.RegisterView<BuildTemplateView>();
viewProducer.RegisterView<BuildsListView>();
}
}
}
+25
View File
@@ -0,0 +1,25 @@
<UserControl x:Class="Daybreak.Controls.HomeButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" StrokeThickness="3" Width="60" Height="60"></Ellipse>
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Path Data="m42,45.384l-14,0l0,-13l-8,0l0,13l-14,0l0,-21c0,-0.552 0.447,-1 1,-1s1,0.448 1,1l0,19l10,0l0,-13l12,0l0,13l10,0l0,-18c0,-0.552 0.447,-1 1,-1s1,0.448 1,1l0,20z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Path Data="m47,24.384c-0.249,0 -0.497,-0.092 -0.691,-0.277l-22.309,-21.339l-22.309,21.339c-0.399,0.381 -1.032,0.368 -1.414,-0.031c-0.382,-0.399 -0.367,-1.032 0.031,-1.414l23.692,-22.662l23.691,22.661c0.398,0.382 0.413,1.015 0.031,1.414c-0.196,0.205 -0.458,0.309 -0.722,0.309z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Path Data="m39,12.384c-0.553,0 -1,-0.448 -1,-1l0,-6l-6,0c-0.553,0 -1,-0.448 -1,-1s0.447,-1 1,-1l8,0l0,8c0,0.552 -0.447,1 -1,1z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
</Grid>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
</UserControl>
@@ -0,0 +1,37 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for HomeButton.xaml
/// </summary>
public partial class HomeButton : UserControl
{
public event EventHandler Clicked;
public HomeButton()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
}
}
}
@@ -0,0 +1,20 @@
<UserControl x:Class="Daybreak.Controls.MinusButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
<Path Data="m13,26a13,13 0 1 1 13,-13a13,13 0 0 1 -13,13zm0,-24a11,11 0 1 0 11,11a11,11 0 0 0 -11,-11z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Path Data="m19,14l-12,0a1,1 0 0 1 0,-2l12,0a1,1 0 0 1 0,2z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
</UserControl>
@@ -0,0 +1,37 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for AddButton.xaml
/// </summary>
public partial class MinusButton : UserControl
{
public event EventHandler Clicked;
public MinusButton()
{
InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
}
}
}
+18 -1
View File
@@ -14,6 +14,18 @@
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" TriggerValue="True"></converters:BooleanToVisibilityConverter>
<converters:BooleanToVisibilityConverter x:Key="ReverseBooleanToVisibilityConverter" TriggerValue="False"></converters:BooleanToVisibilityConverter>
</UserControl.Resources>
<UserControl.ContextMenu>
<ContextMenu>
<ContextMenu.Template>
<ControlTemplate>
<StackPanel Margin="10">
<local:OpaqueButton Text="Load build template" Foreground="White" Background="#F0202020" BackgroundOpacity="0.4"
Clicked="LoadBuildTemplateButton_Click" FontSize="16" Height="40" Width="200"></local:OpaqueButton>
</StackPanel>
</ControlTemplate>
</ContextMenu.Template>
</ContextMenu>
</UserControl.ContextMenu>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
@@ -21,7 +33,8 @@
</Grid.RowDefinitions>
<wv2:WebView2 x:Name="WebBrowser" Source="{Binding ElementName=_this, Path=Address, Mode=TwoWay}"
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"></wv2:WebView2>
<Grid Grid.Row="1" Background="#80808080" IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}">
<Grid Grid.Row="1" Background="#80808080" IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
Visibility="{Binding ElementName=_this, Path=ControlsEnabled, Mode=OneWay, Converter={StaticResource ReverseBooleanToVisibilityConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
@@ -55,6 +68,10 @@
PreviewKeyDown="TextBox_PreviewKeyDown"
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"></TextBox>
<StackPanel Grid.Column="2" Orientation="Horizontal">
<local:HomeButton Width="30" Height="30" Margin="5"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
Clicked="HomeButton_Clicked"></local:HomeButton>
<local:StarGlyph Height="30" Width="30" Margin="5"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
@@ -1,4 +1,7 @@
using Daybreak.Launch;
using Daybreak.Models.Browser;
using Daybreak.Models.Builds;
using Daybreak.Services.BuildTemplates;
using Daybreak.Services.Configuration;
using Daybreak.Services.Logging;
using Daybreak.Utils;
@@ -23,16 +26,32 @@ namespace Daybreak.Controls
public readonly static DependencyProperty AddressProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, string>(nameof(Address));
public readonly static DependencyProperty FavoriteAddressProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, string>(nameof(FavoriteAddress));
public readonly static DependencyProperty NavigatingProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(Navigating));
public readonly static DependencyProperty BrowserEnabledProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(BrowserEnabled));
public readonly static DependencyProperty AddressBarReadonlyProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(AddressBarReadonly));
public readonly static DependencyProperty BrowserSupportedProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(BrowserSupported), new PropertyMetadata(true));
public readonly static DependencyProperty ControlsEnabledProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(ControlsEnabled), new PropertyMetadata(true));
public readonly static DependencyProperty CanNavigateProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(CanNavigate), new PropertyMetadata(true));
public readonly static DependencyProperty CanDownloadBuildProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(CanDownloadBuild), new PropertyMetadata(false));
public event EventHandler<string> FavoriteUriChanged;
public event EventHandler MaximizeClicked;
public event EventHandler<Build> BuildDecoded;
private readonly IConfigurationManager configurationManager;
private readonly ILogger logger;
private readonly IBuildTemplateManager buildTemplateManager;
private CoreWebView2Environment coreWebView2Environment;
public bool CanDownloadBuild
{
get => this.GetTypedValue<bool>(CanDownloadBuildProperty);
set => this.SetTypedValue<bool>(CanDownloadBuildProperty, value);
}
public bool CanNavigate
{
get => this.GetTypedValue<bool>(CanNavigateProperty);
set => this.SetTypedValue<bool>(CanNavigateProperty, value);
}
public string Address
{
get => this.GetTypedValue<string>(AddressProperty);
@@ -51,18 +70,29 @@ namespace Daybreak.Controls
public bool AddressBarReadonly
{
get => this.GetTypedValue<bool>(AddressBarReadonlyProperty);
private set => this.SetTypedValue<bool>(AddressBarReadonlyProperty, value);
set => this.SetTypedValue<bool>(AddressBarReadonlyProperty, value);
}
public bool BrowserEnabled
{
get => this.GetTypedValue<bool>(BrowserEnabledProperty);
private set => this.SetTypedValue<bool>(BrowserEnabledProperty, value);
}
public bool BrowserSupported
{
get => this.GetTypedValue<bool>(BrowserSupportedProperty);
private set => this.SetTypedValue<bool>(BrowserSupportedProperty, value);
}
public bool ControlsEnabled
{
get => this.GetTypedValue<bool>(ControlsEnabledProperty);
set => this.SetTypedValue<bool>(ControlsEnabledProperty, value);
}
public ChromiumBrowserWrapper()
{
this.configurationManager = Launcher.ApplicationServiceManager.GetService<IConfigurationManager>();
this.logger = Launcher.ApplicationServiceManager.GetService<ILogger>();
this.buildTemplateManager = Launcher.ApplicationServiceManager.GetService<IBuildTemplateManager>();
this.InitializeComponent();
this.InitializeEnvironment();
this.InitializeBrowser();
@@ -77,13 +107,19 @@ namespace Daybreak.Controls
}
}
public void ReinitializeBrowser()
public async void ReinitializeBrowser()
{
this.InitializeBrowser();
await this.InitializeBrowser();
}
private void InitializeEnvironment()
{
if (this.configurationManager.GetConfiguration().BrowsersEnabled is false)
{
this.BrowserSupported = false;
return;
}
try
{
this.coreWebView2Environment = System.Extensions.TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", null));
@@ -102,9 +138,24 @@ namespace Daybreak.Controls
{
await this.WebBrowser.EnsureCoreWebView2Async(this.coreWebView2Environment);
this.AddressBarReadonly = this.configurationManager.GetConfiguration().AddressBarReadonly;
this.CanDownloadBuild = this.configurationManager.GetConfiguration().ExperimentalFeatures.DynamicBuildLoading;
this.WebBrowser.CoreWebView2.NewWindowRequested += (browser, args) => args.Handled = true;
this.WebBrowser.NavigationStarting += (browser, args) => this.Navigating = true;
this.WebBrowser.NavigationStarting += (browser, args) =>
{
if (this.CanNavigate is false && args.Uri != this.Address)
{
args.Cancel = true;
}
else
{
this.Navigating = true;
}
};
this.WebBrowser.NavigationCompleted += (browser, args) => this.Navigating = false;
this.WebBrowser.WebMessageReceived += this.CoreWebView2_WebMessageReceived;
this.WebBrowser.CoreWebView2.Settings.AreDevToolsEnabled = false;
this.WebBrowser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
await this.WebBrowser.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(Scripts.AlterContextMenu);
}
}
@@ -146,9 +197,55 @@ namespace Daybreak.Controls
}
}
private void CoreWebView2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs args)
{
BrowserPayload payload = default;
try
{
payload = args.WebMessageAsJson.Deserialize<BrowserPayload>();
}
catch(Exception e)
{
this.logger.LogError(e);
}
if (payload?.Key == BrowserPayload.PayloadKeys.ContextMenu)
{
var contextMenuPayload = args.WebMessageAsJson.Deserialize<BrowserPayload<OnContextMenuPayload>>();
if (this.CanDownloadBuild is false)
{
return;
}
var maybeTemplate = contextMenuPayload.Value.Selection;
Task.Run(() =>
{
try
{
var build = this.buildTemplateManager.DecodeTemplate(maybeTemplate);
this.Dispatcher.Invoke(() =>
{
this.ContextMenu.DataContext = build;
this.ContextMenu.IsOpen = true;
});
}
catch(Exception e)
{
this.logger.LogWarning($"Exception when decoding template {maybeTemplate}. Details {e}");
}
});
}
}
private void LoadBuildTemplateButton_Click(object sender, EventArgs e)
{
var build = this.ContextMenu.DataContext.As<Build>();
this.ContextMenu.IsOpen = false;
this.BuildDecoded?.Invoke(this, build);
}
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
{
this.WebBrowser.Dispose();
this.WebBrowser?.Dispose();
}
private void BackButton_Clicked(object sender, EventArgs e)
@@ -180,6 +277,11 @@ namespace Daybreak.Controls
this.FavoriteUriChanged?.Invoke(this, this.FavoriteAddress);
}
private void HomeButton_Clicked(object sender, EventArgs e)
{
this.WebBrowser.CoreWebView2.Navigate(this.FavoriteAddress);
}
private void MaximizeButton_Clicked(object sender, EventArgs e)
{
this.MaximizeClicked?.Invoke(this, e);
@@ -0,0 +1,553 @@
<UserControl x:Class="Daybreak.Controls.CircularLoadingWidget"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Daybreak.Controls"
Height="Auto" Width="Auto">
<UserControl.Resources>
<Storyboard x:Key="ProgressAnimation" RepeatBehavior="Forever">
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#8E000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#00000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block17" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#8E000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="Black"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block16" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#8E000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#EF000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block15" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#8E000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#E2000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block14" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#8E000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#D3000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block13" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#8E000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#C6000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block12" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#8E000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#B7000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block11" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#8E000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#AA000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block10" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#8E000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#23000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#9B000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block9" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#91000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block8" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#91000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#7F000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block7" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#91000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#72000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block6" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#91000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#63000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block5" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#91000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#56000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block4" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#91000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#3D000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block3" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#91000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#26000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block2" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#0C000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#91000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#19000000"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block1" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#00000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="Black"/>
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#EF000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#E2000000"/>
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#D3000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#C6000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#B7000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#AA000000"/>
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#9B000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#8E000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#7F000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#72000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#63000000"/>
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#56000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#3D000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#26000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#19000000"/>
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#0C000000"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<UserControl.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard x:Name="ProgressAnimation_BeginStoryboard" Storyboard="{StaticResource ProgressAnimation}"/>
</EventTrigger>
</UserControl.Triggers>
<Viewbox>
<Canvas x:Name="LayoutRoot" VerticalAlignment="Top" Height="88" Width="88">
<Grid Width="10.734" Height="10.004" Canvas.Left="38.614" Canvas.Top="0.331">
<Rectangle Fill="White" x:Name="block" RenderTransformOrigin="0.5,4.3689" OpacityMask="#00000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="180"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block1" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#0C000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
<SkewTransform/>
<RotateTransform Angle="-160"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block2" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#19000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-140"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block3" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#26000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
<SkewTransform/>
<RotateTransform Angle="-119.99999999999999"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block4" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#3D000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
<SkewTransform/>
<RotateTransform Angle="-100"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block5" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#56000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
<SkewTransform/>
<RotateTransform Angle="-80"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block6" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#64000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-59.999999999999993"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block7" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#72000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
<SkewTransform/>
<RotateTransform Angle="-40"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block8" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#80000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-19.999999999999996"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block9" Fill="White" OpacityMask="#8E000000" RenderTransformOrigin="0.5,4.3689" VerticalAlignment="Top" Height="10.004"/>
<Rectangle x:Name="block10" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#9C000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="19.999999999999996"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block11" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#AA000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
<SkewTransform/>
<RotateTransform Angle="40"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block12" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#B8000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="59.999999999999993"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block13" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#C6000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
<SkewTransform/>
<RotateTransform Angle="80"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block14" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#D4000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
<SkewTransform/>
<RotateTransform Angle="100"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block15" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#E2000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
<SkewTransform/>
<RotateTransform Angle="119.99999999999999"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block16" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#F0000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="140"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block17" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="Black" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
<SkewTransform/>
<RotateTransform Angle="160"/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
</Canvas>
</Viewbox>
</UserControl>
@@ -0,0 +1,32 @@
using System.Windows;
using System.Windows.Controls;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for CircularLoadingWidget.xaml
/// </summary>
public partial class CircularLoadingWidget : UserControl
{
public CircularLoadingWidget()
{
InitializeComponent();
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == IsEnabledProperty)
{
if (e.NewValue is true)
{
this.ProgressAnimation_BeginStoryboard.Storyboard.Pause();
}
else
{
this.ProgressAnimation_BeginStoryboard.Storyboard.Resume();
}
}
}
}
}
@@ -0,0 +1,21 @@
<UserControl x:Class="Daybreak.Controls.FireballGlyph"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Line Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
X1="15" X2="26" Y1="11" Y2="0"></Line>
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Width="4" Height="4"
Margin="8,13,13,8"></Ellipse>
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m15.025,0l-12.7,11.3c-3.1,3.1 -3.1,8.2 0,11.3s8.2,3.1 11.3,0l12.4,-11.6"></Path>
</Grid>
</Viewbox>
</UserControl>
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for FireballGlyph.xaml
/// </summary>
public partial class FireballGlyph : UserControl
{
public FireballGlyph()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,20 @@
<UserControl x:Class="Daybreak.Controls.AttributeTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="10, 0, 10, 0">
<TextBlock Text="{Binding Attribute.Name}" FontSize="16" Foreground="White"></TextBlock>
</WrapPanel>
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="10, 0, 10, 0">
<local:MinusButton Foreground="White" Height="20" Clicked="MinusButton_Clicked"></local:MinusButton>
<TextBox Background="Transparent" Foreground="White" FontSize="16" IsReadOnly="True" Width="30"
Text="{Binding Points}"></TextBox>
<local:AddButton Foreground="White" Height="20" Clicked="AddButton_Clicked"></local:AddButton>
</WrapPanel>
</Grid>
</UserControl>
@@ -0,0 +1,33 @@
using Daybreak.Models.Builds;
using System.Extensions;
using System.Windows.Controls;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for AttributeTemplate.xaml
/// </summary>
public partial class AttributeTemplate : UserControl
{
public AttributeTemplate()
{
InitializeComponent();
}
private void MinusButton_Clicked(object sender, System.EventArgs e)
{
if (this.DataContext.As<AttributeEntry>().Points > 0)
{
this.DataContext.As<AttributeEntry>().Points--;
}
}
private void AddButton_Clicked(object sender, System.EventArgs e)
{
if (this.DataContext.As<AttributeEntry>().Points < 12)
{
this.DataContext.As<AttributeEntry>().Points++;
}
}
}
}
@@ -0,0 +1,14 @@
<UserControl x:Class="Daybreak.Controls.BuildEntryTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
xmlns:controls="clr-namespace:Daybreak.Controls"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock FontSize="16" Foreground="White" Text="{Binding Name}" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
<controls:BinButton Width="30" Height="30" Foreground="White" HorizontalAlignment="Right" Clicked="BinButton_Clicked"></controls:BinButton>
</Grid>
</UserControl>
@@ -0,0 +1,27 @@
using Daybreak.Models.Builds;
using System;
using System.Windows.Controls;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for BuildEntryTemplate.xaml
/// </summary>
public partial class BuildEntryTemplate : UserControl
{
public event EventHandler<BuildEntry> RemoveClicked;
public BuildEntryTemplate()
{
InitializeComponent();
}
private void BinButton_Clicked(object sender, EventArgs e)
{
if (this.DataContext is BuildEntry buildEntry)
{
this.RemoveClicked?.Invoke(this, buildEntry);
}
}
}
}
@@ -0,0 +1,163 @@
<UserControl x:Class="Daybreak.Controls.BuildTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
xmlns:interactivity="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
xmlns:converters="clr-namespace:Daybreak.Converters"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="Transparent" MouseLeftButtonDown="Grid_MouseLeftButtonDown">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="Primary Profession: " FontSize="16" Foreground="White"></TextBlock>
<ListView FontSize="16" Foreground="White" Grid.Column="1"
Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Professions, Mode=OneWay}"
SelectedItem="{Binding ElementName=_this, Path=PrimaryProfession, Mode=TwoWay}" Height="25"
SelectionMode="Single" ScrollViewer.VerticalScrollBarVisibility="Disabled"
PreviewMouseWheel="ListView_DisableMouseWheel">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name, Mode=OneWay}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
<interactivity:Interaction.Behaviors>
<behaviors:ScrollIntoView></behaviors:ScrollIntoView>
</interactivity:Interaction.Behaviors>
</ListView>
</Grid>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="Secondary Profession: " FontSize="16" Foreground="White"></TextBlock>
<ListView FontSize="16" Foreground="White" Grid.Column="1"
Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Professions, Mode=OneWay}"
SelectedItem="{Binding ElementName=_this, Path=SecondaryProfession, Mode=TwoWay}" Height="25"
SelectionMode="Single" ScrollViewer.VerticalScrollBarVisibility="Disabled"
PreviewMouseWheel="ListView_DisableMouseWheel">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name, Mode=OneWay}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
<interactivity:Interaction.Behaviors>
<behaviors:ScrollIntoView></behaviors:ScrollIntoView>
</interactivity:Interaction.Behaviors>
</ListView>
</Grid>
<Grid Grid.Row="3">
<ListBox Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Attributes, Mode=OneWay}"
HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<local:AttributeTemplate></local:AttributeTemplate>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
<Grid Grid.Row="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<local:SkillTemplate Grid.Column="0"
Foreground="White"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill0, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<local:SkillTemplate Grid.Column="1"
Foreground="White"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill1, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<local:SkillTemplate Grid.Column="2"
Foreground="White"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill2, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<local:SkillTemplate Grid.Column="3"
Foreground="White"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill3, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<local:SkillTemplate Grid.Column="4"
Foreground="White"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill4, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<local:SkillTemplate Grid.Column="5"
Foreground="White"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill5, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<local:SkillTemplate Grid.Column="6"
Foreground="White"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill6, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<local:SkillTemplate Grid.Column="7"
Foreground="White"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill7, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<TextBlock Grid.Column="0" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill0.Name, Mode=OneWay}"></TextBlock>
<TextBlock Grid.Column="1" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill1.Name, Mode=OneWay}"></TextBlock>
<TextBlock Grid.Column="2" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill2.Name, Mode=OneWay}"></TextBlock>
<TextBlock Grid.Column="3" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill3.Name, Mode=OneWay}"></TextBlock>
<TextBlock Grid.Column="4" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill4.Name, Mode=OneWay}"></TextBlock>
<TextBlock Grid.Column="5" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill5.Name, Mode=OneWay}"></TextBlock>
<TextBlock Grid.Column="6" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill6.Name, Mode=OneWay}"></TextBlock>
<TextBlock Grid.Column="7" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill7.Name, Mode=OneWay}"></TextBlock>
</Grid>
<Grid Grid.Column="1" Grid.RowSpan="6">
<local:ChromiumBrowserWrapper x:Name="SkillBrowser" ControlsEnabled="False" Width="0" AddressBarReadonly="True" CanNavigate="True"></local:ChromiumBrowserWrapper>
</Grid>
<Grid Grid.Column="1" Grid.RowSpan="6">
<ListView x:Name="SkillsListView" Background="Transparent" Width="0"
ItemsSource="{Binding ElementName=_this, Path=AvailableSkills, Mode=OneWay}" MouseDoubleClick="ListView_MouseDoubleClick">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock FontSize="16" Foreground="White" TextWrapping="Wrap" Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Grid>
</UserControl>
@@ -0,0 +1,296 @@
using Daybreak.Launch;
using Daybreak.Models.Builds;
using Daybreak.Services.IconRetrieve;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Extensions;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for BuildTemplate.xaml
/// </summary>
public partial class BuildTemplate : UserControl
{
private const string SkillNamePlaceholder = "[NAME]";
private const string BaseAddress = $"https://wiki.guildwars.com/wiki/{SkillNamePlaceholder}";
public readonly static DependencyProperty PrimaryProfessionProperty =
DependencyPropertyExtensions.Register<BuildTemplate, Profession>(nameof(PrimaryProfession), new PropertyMetadata(Profession.None));
public readonly static DependencyProperty SecondaryProfessionProperty =
DependencyPropertyExtensions.Register<BuildTemplate, Profession>(nameof(SecondaryProfession), new PropertyMetadata(Profession.None));
public readonly static DependencyProperty Skill0Property =
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill0), new PropertyMetadata(Skill.NoSkill));
public readonly static DependencyProperty Skill1Property =
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill1), new PropertyMetadata(Skill.NoSkill));
public readonly static DependencyProperty Skill2Property =
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill2), new PropertyMetadata(Skill.NoSkill));
public readonly static DependencyProperty Skill3Property =
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill3), new PropertyMetadata(Skill.NoSkill));
public readonly static DependencyProperty Skill4Property =
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill4), new PropertyMetadata(Skill.NoSkill));
public readonly static DependencyProperty Skill5Property =
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill5), new PropertyMetadata(Skill.NoSkill));
public readonly static DependencyProperty Skill6Property =
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill6), new PropertyMetadata(Skill.NoSkill));
public readonly static DependencyProperty Skill7Property =
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill7), new PropertyMetadata(Skill.NoSkill));
private BuildEntry loadedBuild;
private SkillTemplate selectingSkillTemplate;
public Profession PrimaryProfession
{
get => this.GetTypedValue<Profession>(PrimaryProfessionProperty);
set => this.SetValue(PrimaryProfessionProperty, value);
}
public Profession SecondaryProfession
{
get => this.GetTypedValue<Profession>(SecondaryProfessionProperty);
set => this.SetValue(SecondaryProfessionProperty, value);
}
public Skill Skill0
{
get => this.GetTypedValue<Skill>(Skill0Property);
set => this.SetValue(Skill0Property, value);
}
public Skill Skill1
{
get => this.GetTypedValue<Skill>(Skill1Property);
set => this.SetValue(Skill1Property, value);
}
public Skill Skill2
{
get => this.GetTypedValue<Skill>(Skill2Property);
set => this.SetValue(Skill2Property, value);
}
public Skill Skill3
{
get => this.GetTypedValue<Skill>(Skill3Property);
set => this.SetValue(Skill3Property, value);
}
public Skill Skill4
{
get => this.GetTypedValue<Skill>(Skill4Property);
set => this.SetValue(Skill4Property, value);
}
public Skill Skill5
{
get => this.GetTypedValue<Skill>(Skill5Property);
set => this.SetValue(Skill5Property, value);
}
public Skill Skill6
{
get => this.GetTypedValue<Skill>(Skill6Property);
set => this.SetValue(Skill6Property, value);
}
public Skill Skill7
{
get => this.GetTypedValue<Skill>(Skill7Property);
set => this.SetValue(Skill7Property, value);
}
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);
public BuildTemplate()
{
this.InitializeComponent();
this.DataContextChanged += BuildTemplate_DataContextChanged;
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == PrimaryProfessionProperty || e.Property == SecondaryProfessionProperty)
{
if (e.Property == PrimaryProfessionProperty)
{
this.loadedBuild.Build.Primary = this.PrimaryProfession;
}
else
{
this.loadedBuild.Build.Secondary = this.SecondaryProfession;
}
this.LoadSkills();
this.LoadAttributes();
}
}
private void BuildTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if(e.NewValue is BuildEntry)
{
this.LoadBuild();
this.LoadSkills();
this.LoadAttributes();
}
}
private void Grid_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
this.SkillBrowser.Width = 0;
this.SkillsListView.Width = 0;
}
private void LoadAttributes()
{
var possibleAttributes = new List<AttributeEntry>();
if (this.PrimaryProfession != Profession.None)
{
possibleAttributes.Add(new AttributeEntry { Attribute = this.PrimaryProfession.PrimaryAttribute });
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 }));
}
this.Attributes.ClearAnd().AddRange(possibleAttributes.Select(entry =>
{
var maybePresentAttribute = this.loadedBuild.Build.Attributes.Where(buildEntry => entry.Attribute == buildEntry.Attribute).FirstOrDefault();
if (maybePresentAttribute is null)
{
return entry;
}
entry.Points = maybePresentAttribute.Points;
return entry;
}));
this.loadedBuild.Build.Attributes = this.Attributes.ToList();
}
private void LoadSkills()
{
var possibleSkills = Skill.Skills
.Where(s => s.Profession == PrimaryProfession || s.Profession == SecondaryProfession || s.Profession == Profession.None)
.Where(s => s != Skill.NoSkill)
.OrderBy(s => s.Name);
this.AvailableSkills.ClearAnd().AddRange(possibleSkills);
if (this.Skill0.Profession != PrimaryProfession &&
this.Skill0.Profession != SecondaryProfession &&
this.Skill0.Profession != Profession.None)
{
this.Skill0 = Skill.NoSkill;
}
if (this.Skill1.Profession != PrimaryProfession &&
this.Skill1.Profession != SecondaryProfession &&
this.Skill1.Profession != Profession.None)
{
this.Skill1 = Skill.NoSkill;
}
if (this.Skill2.Profession != PrimaryProfession &&
this.Skill2.Profession != SecondaryProfession &&
this.Skill2.Profession != Profession.None)
{
this.Skill2 = Skill.NoSkill;
}
if (this.Skill3.Profession != PrimaryProfession &&
this.Skill3.Profession != SecondaryProfession &&
this.Skill3.Profession != Profession.None)
{
this.Skill3 = Skill.NoSkill;
}
if (this.Skill4.Profession != PrimaryProfession &&
this.Skill4.Profession != SecondaryProfession &&
this.Skill4.Profession != Profession.None)
{
this.Skill4 = Skill.NoSkill;
}
if (this.Skill5.Profession != PrimaryProfession &&
this.Skill5.Profession != SecondaryProfession &&
this.Skill5.Profession != Profession.None)
{
this.Skill5 = Skill.NoSkill;
}
if (this.Skill6.Profession != PrimaryProfession &&
this.Skill6.Profession != SecondaryProfession &&
this.Skill6.Profession != Profession.None)
{
this.Skill6 = Skill.NoSkill;
}
if (this.Skill7.Profession != PrimaryProfession &&
this.Skill7.Profession != SecondaryProfession &&
this.Skill7.Profession != Profession.None)
{
this.Skill7 = Skill.NoSkill;
}
}
private void LoadBuild()
{
var build = this.DataContext.As<BuildEntry>();
this.loadedBuild = build;
this.PrimaryProfession = build.Build.Primary;
this.SecondaryProfession = build.Build.Secondary;
this.Skill0 = build.Build.Skills[0];
this.Skill1 = build.Build.Skills[1];
this.Skill2 = build.Build.Skills[2];
this.Skill3 = build.Build.Skills[3];
this.Skill4 = build.Build.Skills[4];
this.Skill5 = build.Build.Skills[5];
this.Skill6 = build.Build.Skills[6];
this.Skill7 = build.Build.Skills[7];
}
private void SkillTemplate_Clicked(object sender, RoutedEventArgs e)
{
var skill = sender.As<SkillTemplate>().DataContext.As<Skill>();
if (skill == Skill.NoSkill)
{
this.SkillsListView.Width = 400;
this.SkillBrowser.Width = 0;
this.selectingSkillTemplate = sender.As<SkillTemplate>();
}
else
{
var address = BaseAddress.Replace(SkillNamePlaceholder, skill.Name.Replace(" ", "_"));
this.SkillBrowser.Address = address;
this.SkillBrowser.Width = 400;
this.SkillsListView.Width = 0;
}
e.Handled = true;
}
private void SkillTemplate_RemoveClicked(object sender, System.EventArgs e)
{
sender.As<SkillTemplate>().DataContext = Skill.NoSkill;
}
private void ListView_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (this.selectingSkillTemplate is null)
{
this.SkillsListView.Width = 0;
return;
}
this.selectingSkillTemplate.DataContext = sender.As<ListView>().SelectedItem;
this.SkillsListView.Width = 0;
this.loadedBuild.Build.Skills[0] = Skill0;
this.loadedBuild.Build.Skills[1] = Skill1;
this.loadedBuild.Build.Skills[2] = Skill2;
this.loadedBuild.Build.Skills[3] = Skill3;
this.loadedBuild.Build.Skills[4] = Skill4;
this.loadedBuild.Build.Skills[5] = Skill5;
this.loadedBuild.Build.Skills[6] = Skill6;
this.loadedBuild.Build.Skills[7] = Skill7;
}
private void ListView_DisableMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
e.Handled = true;
}
}
}
@@ -0,0 +1,31 @@
<UserControl x:Class="Daybreak.Controls.SkillTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
</ResourceDictionary>
</UserControl.Resources>
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<Image VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Source="{Binding ElementName=_this, Path=ImageSource, Mode=OneWay}"></Image>
<Border BorderThickness="5" BorderBrush="Black"></Border>
<Border BorderThickness="5" BorderBrush="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Opacity="{Binding ElementName=_this, Path=BorderOpacity, Mode=OneWay}"></Border>
<Rectangle Fill="Transparent" MouseEnter="Border_MouseEnter" MouseLeave="Border_MouseLeave"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MouseLeftButtonDown="Rectangle_MouseLeftButtonDown"></Rectangle>
<local:CancelButton x:Name="CancelButton" Width="30" Height="30" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10"
Visibility="Hidden" Foreground="White" Clicked="CancelButton_Clicked" MouseEnter="Border_MouseEnter"
MouseLeave="Border_MouseLeave"></local:CancelButton>
</Grid>
</UserControl>
@@ -0,0 +1,114 @@
using Daybreak.Launch;
using Daybreak.Models.Builds;
using Daybreak.Services.IconRetrieve;
using System;
using System.Extensions;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for SkillTemplate.xaml
/// </summary>
public partial class SkillTemplate : UserControl
{
public readonly static DependencyProperty ImageSourceProperty =
DependencyPropertyExtensions.Register<SkillTemplate, ImageSource>(nameof(ImageSource));
public readonly static DependencyProperty BorderOpacityProperty =
DependencyPropertyExtensions.Register<SkillTemplate, double>(nameof(BorderOpacity), new PropertyMetadata(0d));
public event EventHandler<RoutedEventArgs> Clicked;
public event EventHandler RemoveClicked;
private readonly IIconRetriever iconRetriever;
public ImageSource ImageSource
{
get => this.GetTypedValue<ImageSource>(ImageSourceProperty);
set => this.SetValue(ImageSourceProperty, value);
}
public double BorderOpacity
{
get => this.GetTypedValue<double>(BorderOpacityProperty);
set => this.SetValue(BorderOpacityProperty, value);
}
public SkillTemplate()
{
this.iconRetriever = Launcher.ApplicationServiceManager.GetService<IIconRetriever>();
this.InitializeComponent();
this.DataContextChanged += SkillTemplate_DataContextChanged;
}
private void SkillTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is Skill)
{
Task.Run(() => GetImageStream(e.NewValue.As<Skill>())).ContinueWith((previousTask) =>
{
this.Dispatcher.Invoke(() =>
{
this.ImageSource = GetImageSource(previousTask.Result);
});
});
}
}
private void Border_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
this.BorderOpacity = 1;
this.CancelButton.Visibility = this.HasSkill() ? Visibility.Visible : Visibility.Hidden;
}
private void Border_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
this.BorderOpacity = 0;
this.CancelButton.Visibility = Visibility.Hidden;
}
private void Rectangle_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
this.Clicked?.Invoke(this, e);
}
private void CancelButton_Clicked(object sender, EventArgs e)
{
this.RemoveClicked?.Invoke(this, e);
}
private bool HasSkill()
{
if (this.DataContext is Skill skill)
{
return skill != Skill.NoSkill;
}
return false;
}
private async Task<Stream> GetImageStream(Skill skill)
{
var maybeStream = await this.iconRetriever.GetIcon(skill);
return maybeStream.ExtractValue();
}
private ImageSource GetImageSource(Stream stream)
{
if (stream is null)
{
return null;
}
return this.Dispatcher.Invoke(() =>
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = stream;
bitmapImage.CacheOption = BitmapCacheOption.OnDemand;
bitmapImage.EndInit();
return bitmapImage;
});
}
}
}
+32
View File
@@ -0,0 +1,32 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace Daybreak.Converters
{
public class HiddenWhenNull : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return GetVerticalAlignment(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
private object GetVerticalAlignment(object value)
{
if (value is null)
{
return Visibility.Hidden;
}
else
{
return Visibility.Visible;
}
}
}
}
+15 -7
View File
@@ -9,39 +9,47 @@
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<LangVersion>preview</LangVersion>
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
<Version>0.6.2</Version>
<Version>0.7.1</Version>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.11.32" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.774.44" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Slim" Version="1.2.1" />
<PackageReference Include="System.Windows.Interactivity.WPF" Version="2.0.20525" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.1.3" />
<PackageReference Include="WCL" Version="1.0.2" />
<PackageReference Include="WpfExtended" Version="0.1.1" />
<PackageReference Include="WpfExtended" Version="0.2.0" />
</ItemGroup>
<ItemGroup>
<Compile Update="Controls\StarGlyph.xaml.cs">
<Compile Update="Controls\Buttons\MinusButton.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Controls\CancelButton.xaml.cs">
<Compile Update="Controls\Glyphs\StarGlyph.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Controls\Buttons\CancelButton.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Page Update="Controls\MaximizeButton.xaml">
<Page Update="Controls\Buttons\MinusButton.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Controls\StarGlyph.xaml">
<Page Update="Controls\Buttons\MaximizeButton.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Controls\CancelButton.xaml">
<Page Update="Controls\Glyphs\StarGlyph.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Controls\Buttons\CancelButton.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
+8 -5
View File
@@ -69,8 +69,6 @@
</controls:ImageViewer.Effect>
</controls:ImageViewer>
</Border>
<Grid x:Name="Container" Grid.Row="1">
</Grid>
<wcl:TitleBar x:Name="Titlebar"
Background="Transparent" MouseLeftButtonDown="TitleBar_MouseLeftButtonDown"
WindowState="Normal" MinimizeButtonClicked="TitleBar_MinimizeButtonClicked"
@@ -80,10 +78,15 @@
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></wcl:TitleBar>
<ToggleButton Style="{StaticResource Window_SettingsButton}" Width="50" Height="30" HorizontalAlignment="Right"
Margin="0, 0, 150, 0" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Click="SettingsButton_Clicked"></ToggleButton>
<TextBox Grid.Row="1" Background="Transparent" BorderBrush="Transparent" BorderThickness="0" Opacity="0.6"
Text="{Binding ElementName=_this, Path=CreditText, Mode=OneWay}" IsReadOnly="True" VerticalAlignment="Bottom"
<controls:OpaqueButton Grid.Row="1" Background="Transparent" BorderBrush="Transparent" BorderThickness="0" Opacity="0.6"
Text="{Binding ElementName=_this, Path=CreditText, Mode=OneWay}" VerticalAlignment="Bottom"
HorizontalAlignment="Right" Margin="0, 0, 20, 30" FontSize="22" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
PreviewMouseLeftButtonDown="CreditTextBox_MouseLeftButtonDown" Cursor="Hand"></TextBox>
Clicked="CreditTextBox_MouseLeftButtonDown" Cursor="Hand"></controls:OpaqueButton>
<TextBox Grid.Row="1" Background="Transparent" BorderBrush="Transparent" BorderThickness="0" Opacity="0.6"
Text="{Binding ElementName=_this, Path=CurrentVersionText, Mode=OneWay}" IsReadOnly="True" VerticalAlignment="Bottom"
HorizontalAlignment="Right" Margin="0, 0, 20, 10" FontSize="10" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></TextBox>
<Grid x:Name="Container" Grid.Row="1">
</Grid>
<wcl:Border OnResize="Border_OnResize" Grid.RowSpan="2" Active="True"></wcl:Border>
</Grid>
</Window>
+12 -9
View File
@@ -1,4 +1,5 @@
using Daybreak.Services.Bloogum;
using Daybreak.Services.Runtime;
using Daybreak.Services.Screenshots;
using Daybreak.Services.Updater;
using Daybreak.Services.ViewManagement;
@@ -23,6 +24,7 @@ namespace Daybreak.Launch
public partial class MainWindow : Window
{
public static readonly DependencyProperty CreditTextProperty = DependencyPropertyExtensions.Register<MainWindow, string>(nameof(CreditText));
public static readonly DependencyProperty CurrentVersionTextProperty = DependencyPropertyExtensions.Register<MainWindow, string>(nameof(CurrentVersionText));
private readonly IViewManager viewManager;
private readonly IScreenshotProvider screenshotProvider;
@@ -36,6 +38,12 @@ namespace Daybreak.Launch
set => this.SetValue(CreditTextProperty, value);
}
public string CurrentVersionText
{
get => this.GetTypedValue<string>(CurrentVersionTextProperty);
set => this.SetValue(CurrentVersionTextProperty, value);
}
public MainWindow(
IViewManager viewManager,
IScreenshotProvider screenshotProvider,
@@ -46,7 +54,8 @@ namespace Daybreak.Launch
this.screenshotProvider = screenshotProvider.ThrowIfNull(nameof(screenshotProvider));
this.bloogumClient = bloogumClient.ThrowIfNull(nameof(bloogumClient));
this.applicationUpdater = applicationUpdater.ThrowIfNull(nameof(applicationUpdater));
InitializeComponent();
this.InitializeComponent();
this.CurrentVersionText = this.applicationUpdater.CurrentVersion;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
@@ -123,7 +132,7 @@ namespace Daybreak.Launch
this.viewManager.ShowView<SettingsCategoryView>();
}
private void CreditTextBox_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
private void CreditTextBox_MouseLeftButtonDown(object sender, EventArgs e)
{
if (Uri.TryCreate(this.CreditText, UriKind.Absolute, out var uri))
{
@@ -165,13 +174,7 @@ namespace Daybreak.Launch
private void PeriodicallyCheckForUpdates()
{
TaskExtensions.RunPeriodicAsync(async () =>
{
if (await this.applicationUpdater.UpdateAvailable())
{
this.Dispatcher.Invoke(() => this.viewManager.ShowView<AskUpdateView>());
}
}, TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(15), CancellationToken.None);
this.applicationUpdater.PeriodicallyCheckForUpdates();
}
private static Color GetAverageColor(BitmapSource bitmap)
+23
View File
@@ -0,0 +1,23 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Daybreak.Models.Browser
{
public class BrowserPayload
{
[JsonConverter(typeof(StringEnumConverter))]
public enum PayloadKeys
{
ContextMenu
}
[JsonProperty("Key")]
public PayloadKeys Key { get; set; }
}
public sealed class BrowserPayload<T> : BrowserPayload
{
[JsonProperty("Value")]
public T Value { get; set; }
}
}
@@ -0,0 +1,14 @@
using Newtonsoft.Json;
namespace Daybreak.Models.Browser
{
public sealed class OnContextMenuPayload
{
[JsonProperty("X")]
public double X { get; set; }
[JsonProperty("Y")]
public double Y { get; set; }
[JsonProperty("Selection")]
public string Selection { get; set; }
}
}
+142
View File
@@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Daybreak.Models.Builds
{
public sealed class Attribute
{
public static Attribute FastCasting { get; } = new() { Name = "Fast Casting", Id = 0 };
public static Attribute IllusionMagic { get; } = new() { Name = "Illusion Magic", Id = 1 };
public static Attribute DominationMagic { get; } = new() { Name = "Domination Magic", Id = 2 };
public static Attribute InspirationMagic { get; } = new() { Name = "Inspiration Magic", Id = 3 };
public static Attribute BloodMagic { get; } = new() { Name = "Blood Magic", Id = 4 };
public static Attribute DeathMagic { get; } = new() { Name = "Death Magic", Id = 5 };
public static Attribute SoulReaping { get; } = new() { Name = "Soul Reaping", Id = 6 };
public static Attribute Curses { get; } = new() { Name = "Curses", Id = 7 };
public static Attribute AirMagic { get; } = new() { Name = "Air Magic", Id = 8 };
public static Attribute EarthMagic { get; } = new() { Name = "Earth Magic", Id = 9 };
public static Attribute FireMagic { get; } = new() { Name = "Fire Magic", Id = 10 };
public static Attribute WaterMagic { get; } = new() { Name = "Water Magic", Id = 11 };
public static Attribute EnergyStorage { get; } = new() { Name = "Energy Storage", Id = 12 };
public static Attribute HealingPrayers { get; } = new() { Name = "Healing Prayers", Id = 13 };
public static Attribute SmitingPrayers { get; } = new() { Name = "Smiting Prayers", Id = 14 };
public static Attribute ProtectionPrayers { get; } = new() { Name = "Protection Prayers", Id = 15 };
public static Attribute DivineFavor { get; } = new() { Name = "Divine Favor", Id = 16 };
public static Attribute Strength { get; } = new() { Name = "Strength", Id = 17 };
public static Attribute AxeMastery { get; } = new() { Name = "Axe Mastery", Id = 18 };
public static Attribute HammerMastery { get; } = new() { Name = "Hammer Mastery", Id = 19 };
public static Attribute Swordsmanship { get; } = new() { Name = "Swordsmanship", Id = 20};
public static Attribute Tactics { get; } = new() { Name = "Tactics", Id = 21 };
public static Attribute BeastMastery { get; } = new() { Name = "Beast Mastery", Id = 22 };
public static Attribute Expertise { get; } = new() { Name = "Expertise", Id = 23 };
public static Attribute WildernessSurvival { get; } = new() { Name = "Wilderness Survival", Id = 24 };
public static Attribute Marksmanship { get; } = new() { Name = "Marksmanship", Id = 25 };
public static Attribute DaggerMastery { get; } = new() { Name = "Dagger Mastery", Id = 29 };
public static Attribute DeadlyArts { get; } = new() { Name = "Deadly Arts", Id = 30 };
public static Attribute ShadowArts { get; } = new() { Name = "Shadow Arts", Id = 31 };
public static Attribute Communing { get; } = new() { Name = "Communing", Id = 32 };
public static Attribute RestorationMagic { get; } = new() { Name = "Restoration Magic", Id = 33 };
public static Attribute ChannelingMagic { get; } = new() { Name = "Channeling Magic", Id = 34 };
public static Attribute CriticalStrikes { get; } = new() { Name = "Critical Strikes", Id = 35 };
public static Attribute SpawningPower { get; } = new() { Name = "Spawning Power", Id = 36 };
public static Attribute SpearMastery { get; } = new() { Name = "Spear Mastery", Id = 37 };
public static Attribute Command { get; } = new() { Name = "Command", Id = 38 };
public static Attribute Motivation { get; } = new() { Name = "Motivation", Id = 39 };
public static Attribute Leadership { get; } = new() { Name = "Leadership", Id = 40 };
public static Attribute ScytheMastery { get; } = new() { Name = "Scythe Mastery", Id = 41 };
public static Attribute WindPrayers { get; } = new() { Name = "Wind Prayers", Id = 42 };
public static Attribute EarthPrayers { get; } = new() { Name = "Earth Prayers", Id = 43 };
public static Attribute Mysticism { get; } = new() { Name = "Mysticism", Id = 44 };
public static IEnumerable<Attribute> Attributes { get; } = new List<Attribute>
{
FastCasting,
IllusionMagic,
DominationMagic,
InspirationMagic,
BloodMagic,
DeathMagic,
SoulReaping,
Curses,
AirMagic,
EarthMagic,
FireMagic,
WaterMagic,
EnergyStorage,
HealingPrayers,
SmitingPrayers,
ProtectionPrayers,
DivineFavor,
Strength,
AxeMastery,
HammerMastery,
Swordsmanship,
Tactics,
BeastMastery,
Expertise,
WildernessSurvival,
Marksmanship,
DaggerMastery,
DeadlyArts,
ShadowArts,
Communing,
RestorationMagic,
ChannelingMagic,
CriticalStrikes,
SpawningPower,
SpearMastery,
Command,
Motivation,
Leadership,
ScytheMastery,
WindPrayers,
EarthMagic,
Mysticism
};
public static bool TryParse(int id, out Attribute attribute)
{
attribute = Attributes.Where(attr => attr.Id == id).FirstOrDefault();
if (attribute is null)
{
return false;
}
return true;
}
public static bool TryParse(string name, out Attribute attribute)
{
attribute = Attributes.Where(attr => attr.Name == name).FirstOrDefault();
if (attribute is null)
{
return false;
}
return true;
}
public static Attribute Parse(int id)
{
if (TryParse(id, out var attribute) is false)
{
throw new InvalidOperationException($"Could not find an attribute with id {id}");
}
return attribute;
}
public static Attribute Parse(string name)
{
if (TryParse(name, out var attribute) is false)
{
throw new InvalidOperationException($"Could not find an attribute with name {name}");
}
return attribute;
}
public int Id { get; private set; }
public string Name { get; private set; }
private Attribute()
{
}
}
}
+31
View File
@@ -0,0 +1,31 @@
using System.ComponentModel;
namespace Daybreak.Models.Builds
{
public sealed class AttributeEntry : INotifyPropertyChanged
{
private Attribute attribute;
private int points;
public Attribute Attribute
{
get => this.attribute;
set
{
this.attribute = value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Attribute)));
}
}
public int Points
{
get => this.points;
set
{
this.points = value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Points)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
+13
View File
@@ -0,0 +1,13 @@
using System.Collections.Generic;
namespace Daybreak.Models.Builds
{
public sealed class Build
{
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();
public List<Skill> Skills { get; set; } = new() { Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill };
}
}
+31
View File
@@ -0,0 +1,31 @@
using System.ComponentModel;
namespace Daybreak.Models.Builds
{
public sealed class BuildEntry : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string name;
private Build build;
public string PreviousName { get; set; }
public string Name
{
get => this.name;
set
{
this.name = value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
}
}
public Build Build
{
get => this.build;
set
{
this.build = value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Build)));
}
}
}
}
+23
View File
@@ -0,0 +1,23 @@
using System.Collections.Generic;
namespace Daybreak.Models.Builds
{
public sealed class BuildMetadata
{
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; }
public int PrimaryProfessionId { get; set; }
public int SecondaryProfessionId { get; set; }
public int AttributeCount { get; set; }
public int AttributesLength { get; set; }
public int SkillsLength { get; set; }
public bool TailPresent { get; set; }
public bool NewTemplate { get; set; }
public List<int> SkillIds { get; set; } = new();
public List<int> AttributesIds { get; set; } = new();
public List<int> AttributePoints { get; set; } = new();
}
}
+81
View File
@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Daybreak.Models.Builds
{
public sealed class Profession
{
public static Profession None { get; } = new() { Name = "None", Id = 0, };
public static Profession Warrior { get; } = new() { Name = "Warrior", Id = 1, PrimaryAttribute = Attribute.Strength, Attributes = new List<Attribute> { Attribute.AxeMastery, Attribute.HammerMastery, Attribute.Swordsmanship, Attribute.Tactics } };
public static Profession Ranger { get; } = new() { Name = "Ranger", Id = 2, PrimaryAttribute = Attribute.Expertise, Attributes = new List<Attribute> { Attribute.BeastMastery, Attribute.Marksmanship, Attribute.WildernessSurvival } };
public static Profession Monk { get; } = new() { Name = "Monk", Id = 3, PrimaryAttribute = Attribute.DivineFavor, Attributes = new List<Attribute> { Attribute.HealingPrayers, Attribute.SmitingPrayers, Attribute.ProtectionPrayers } };
public static Profession Necromancer { get; } = new() { Name = "Necromancer", Id = 4, PrimaryAttribute = Attribute.SoulReaping, Attributes = new List<Attribute> { Attribute.Curses, Attribute.BloodMagic, Attribute.DeathMagic } };
public static Profession Mesmer { get; } = new() { Name = "Mesmer", Id = 5, PrimaryAttribute = Attribute.FastCasting, Attributes = new List<Attribute> { Attribute.DominationMagic, Attribute.IllusionMagic, Attribute.InspirationMagic } };
public static Profession Elementalist { get; } = new() { Name = "Elementalist", Id = 6, PrimaryAttribute = Attribute.EnergyStorage, Attributes = new List<Attribute> { Attribute.AirMagic, Attribute.EarthMagic, Attribute.FireMagic, Attribute.WaterMagic } };
public static Profession Assassin { get; } = new() { Name = "Assassin", Id = 7, PrimaryAttribute = Attribute.CriticalStrikes, Attributes = new List<Attribute> { Attribute.DaggerMastery, Attribute.DeadlyArts, Attribute.ShadowArts } };
public static Profession Ritualist { get; } = new() { Name = "Ritualist", Id = 8, PrimaryAttribute = Attribute.SpawningPower, Attributes = new List<Attribute> { Attribute.ChannelingMagic, Attribute.Communing, Attribute.RestorationMagic } };
public static Profession Paragon { get; } = new() { Name = "Paragon", Id = 9, PrimaryAttribute = Attribute.Leadership, Attributes = new List<Attribute> { Attribute.Command, Attribute.Motivation, Attribute.SpearMastery } };
public static Profession Dervish { get; } = new() { Name = "Dervish", Id = 10, PrimaryAttribute = Attribute.Mysticism, Attributes = new List<Attribute> { Attribute.EarthPrayers, Attribute.ScytheMastery, Attribute.WindPrayers } };
public static IEnumerable<Profession> Professions { get; } = new List<Profession>
{
None,
Warrior,
Ranger,
Monk,
Necromancer,
Mesmer,
Elementalist,
Assassin,
Ritualist,
Paragon,
Dervish
};
public static bool TryParse(int id, out Profession profession)
{
profession = Professions.Where(prof => prof.Id == id).FirstOrDefault();
if (profession is null)
{
return false;
}
return true;
}
public static bool TryParse(string name, out Profession profession)
{
profession = Professions.Where(prof => prof.Name == name).FirstOrDefault();
if (profession is null)
{
return false;
}
return true;
}
public static Profession Parse(int id)
{
if (TryParse(id, out var profession) is false)
{
throw new InvalidOperationException($"Could not find a profession with id {id}");
}
return profession;
}
public static Profession Parse(string name)
{
if (TryParse(name, out var profession) is false)
{
throw new InvalidOperationException($"Could not find a profession with name {name}");
}
return profession;
}
public string Name { get; private set; }
public int Id { get; set; }
public Attribute PrimaryAttribute { get; private set; }
public List<Attribute> Attributes { get; private set; }
private Profession()
{
}
}
}
File diff suppressed because it is too large Load Diff
@@ -5,6 +5,7 @@ using Daybreak.Services.Logging;
using Daybreak.Services.Mutex;
using Daybreak.Utils;
using Microsoft.Win32;
using Pepa.Wpf.Utilities;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -12,12 +13,15 @@ using System.Extensions;
using System.IO;
using System.Linq;
using System.Security;
using System.Text;
using System.Threading.Tasks;
namespace Daybreak.Services.ApplicationLauncher
{
public class ApplicationLauncher : IApplicationLauncher
{
private const string TexModProcessName = "TexMod";
private const string UModProcessName = "uMod";
private const string ToolboxProcessName = "GWToolbox";
private const string ProcessName = "gw";
private const string ArenaNetMutex = "AN-Mute";
@@ -27,6 +31,7 @@ namespace Daybreak.Services.ApplicationLauncher
private readonly IMutexHandler mutexHandler;
private readonly ILogger logger;
public bool IsTexmodRunning => TexModProcessDetected();
public bool IsGuildwarsRunning => this.GuildwarsProcessDetected();
public bool IsToolboxRunning => GuildwarsToolboxProcessDetected();
@@ -80,6 +85,24 @@ namespace Daybreak.Services.ApplicationLauncher
});
}
public Task LaunchTexmod()
{
return Task.Run(() =>
{
var configuration = this.configurationManager.GetConfiguration();
var executable = configuration.TexmodPath;
if (File.Exists(executable) is false)
{
throw new ExecutableNotFoundException($"Texmod executable doesn't exist at {executable}");
}
if (Process.Start(executable) is null)
{
throw new InvalidOperationException($"Unable to launch {executable}");
}
});
}
private void LaunchGuildwarsProcess(string email, Models.SecureString password, string character)
{
var executable = this.configurationManager.GetConfiguration().GuildwarsPaths.Where(path => path.Default).FirstOrDefault();
@@ -132,7 +155,7 @@ namespace Daybreak.Services.ApplicationLauncher
}
}
return Process.GetProcessesByName(ProcessName).FirstOrDefault() is not null;
return Process.GetProcessesByName(ProcessName).Any();
}
private void ClearGwLocks()
@@ -197,7 +220,14 @@ namespace Daybreak.Services.ApplicationLauncher
private static bool GuildwarsToolboxProcessDetected()
{
return Process.GetProcessesByName(ToolboxProcessName).FirstOrDefault() is not null;
return Process.GetProcessesByName(ToolboxProcessName).Any();
}
private static bool TexModProcessDetected()
{
return Process.GetProcesses()
.Where(process => string.Equals(process.ProcessName, UModProcessName, StringComparison.OrdinalIgnoreCase) ||
string.Equals(process.ProcessName, TexModProcessName, StringComparison.OrdinalIgnoreCase)).Any();
}
}
}
@@ -6,7 +6,9 @@ namespace Daybreak.Services.ApplicationLauncher
{
bool IsGuildwarsRunning { get; }
bool IsToolboxRunning { get; }
bool IsTexmodRunning { get; }
Task LaunchGuildwars();
Task LaunchGuildwarsToolbox();
Task LaunchTexmod();
}
}
@@ -0,0 +1,336 @@
using Daybreak.Models.Builds;
using Daybreak.Services.BuildTemplates.Models;
using Daybreak.Services.Logging;
using Daybreak.Utils;
using System;
using System.Collections.Generic;
using System.Extensions;
using System.IO;
using System.Linq;
using System.Text;
namespace Daybreak.Services.BuildTemplates
{
public sealed class BuildTemplateManager : IBuildTemplateManager
{
private const string DecodingLookupTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
private readonly static string BuildsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\Guild Wars\\Templates\\Skills";
private readonly ILogger logger;
public BuildTemplateManager(
ILogger logger)
{
this.logger = logger.ThrowIfNull(nameof(logger));
}
public BuildEntry CreateBuild()
{
var emptyBuild = new Build();
var builds = GetBuilds();
var baseName = "New build";
var name = baseName;
int count = 0;
while(builds.Where(b => b.Name.Equals(name, StringComparison.OrdinalIgnoreCase)).Any())
{
name = baseName + count;
count++;
}
var entry = new BuildEntry { Build = emptyBuild, Name = name, PreviousName = string.Empty };
this.SaveBuild(entry);
return entry;
}
public BuildEntry CreateBuild(string name)
{
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);
File.WriteAllText($"{BuildsPath}\\{buildEntry.Name}.txt", encodedBuild);
if (string.IsNullOrWhiteSpace(buildEntry.PreviousName))
{
return;
}
File.Delete($"{BuildsPath}\\{buildEntry.PreviousName}.txt");
}
public void RemoveBuild(BuildEntry buildEntry)
{
if (File.Exists($"{BuildsPath}\\{buildEntry.Name}.txt"))
{
File.Delete($"{BuildsPath}\\{buildEntry.Name}.txt");
}
if (File.Exists($"{BuildsPath}\\{buildEntry.PreviousName}.txt"))
{
File.Delete($"{BuildsPath}\\{buildEntry.PreviousName}.txt");
}
}
public IEnumerable<BuildEntry> GetBuilds()
{
foreach (var file in Directory.GetFiles(BuildsPath))
{
Build build = default;
try
{
build = this.DecodeTemplate(File.ReadAllText(file));
}
catch(Exception e)
{
this.logger.LogError($"Failed to decode template from file {file}. Details: {e}");
}
if (build is not null)
{
yield return new BuildEntry { Build = build, Name = Path.GetFileNameWithoutExtension(file), PreviousName = Path.GetFileNameWithoutExtension(file) };
}
}
}
public Build DecodeTemplate(string template)
{
return this.DecodeTemplateInner(template);
}
public string EncodeTemplate(Build build)
{
return this.EncodeTemplateInner(build);
}
private Build DecodeTemplateInner(string template)
{
this.logger.LogInformation("Attempting to decode template");
var buildMetadata = ParseEncodedTemplate(template);
this.logger.LogInformation("Decoded template. Beginning parsing");
if (buildMetadata.VersionNumber != 0)
{
this.logger.LogError($"Expected version number to be 0 but found {buildMetadata.VersionNumber}");
throw new InvalidOperationException($"Failed to parse template");
}
var build = new Build()
{
BuildMetadata = buildMetadata,
Skills = new()
};
if (Profession.TryParse(buildMetadata.PrimaryProfessionId, out var primaryProfession) is false)
{
this.logger.LogError($"Failed to parse profession with id {buildMetadata.PrimaryProfessionId}");
throw new InvalidOperationException($"Failed to parse template");
}
build.Primary = primaryProfession;
if (Profession.TryParse(buildMetadata.SecondaryProfessionId, out var secondaryProfession) is false)
{
this.logger.LogError($"Failed to parse profession with id {buildMetadata.SecondaryProfessionId}");
throw new InvalidOperationException($"Failed to parse template");
}
build.Secondary = secondaryProfession;
for(int i = 0; i < buildMetadata.AttributeCount; i++)
{
if (Daybreak.Models.Builds.Attribute.TryParse(buildMetadata.AttributesIds[i], out var attribute) is false)
{
this.logger.LogError($"Failed to parse attribute with id {buildMetadata.AttributesIds[i]}");
throw new InvalidOperationException($"Failed to parse template");
}
build.Attributes.Add(new AttributeEntry { Attribute = attribute, Points = buildMetadata.AttributePoints[i] });
}
for(int i = 0; i < 8; i++)
{
if (Skill.TryParse(buildMetadata.SkillIds[i], out var skill) is false)
{
this.logger.LogError($"Failed to parse skill with id {buildMetadata.SkillIds[i]}");
throw new InvalidOperationException($"Failed to parse template");
}
build.Skills.Add(skill);
}
return build;
}
private string EncodeTemplateInner(Build build)
{
this.logger.LogInformation("Building build metadata");
var buildMetadata = new BuildMetadata
{
VersionNumber = 0,
NewTemplate = true,
Header = 14,
PrimaryProfessionId = build.Primary.Id,
SecondaryProfessionId = build.Secondary.Id,
AttributeCount = build.Attributes.Count,
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(),
TailPresent = true
};
this.logger.LogInformation("Encoding metadata into binary");
var encodedBinary = BuildEncodedString(buildMetadata);
int index = 0;
var encodedBase64 = new List<int>();
while (index < encodedBinary.Length)
{
var subset = new string(encodedBinary.Skip(index).Take(6).ToArray());
encodedBase64.Add(FromBitString(subset));
index += 6;
}
var template = new string(encodedBase64.Select(b => DecodingLookupTable[b]).ToArray());
return template;
}
private static string ToBitString(int value)
{
var sb = new StringBuilder();
while(value > 0)
{
sb.Append(value % 2 == 1 ? 1 : 0);
value /= 2;
}
while(sb.Length < 6)
{
sb.Append(0);
}
return sb.ToString();
}
private static BuildMetadata ParseEncodedTemplate(string template)
{
var curedTemplate = template.Trim();
var buildMetadata = new BuildMetadata();
buildMetadata.Base64Decoded = template.Select(c => DecodingLookupTable.IndexOf(c)).ToList();
buildMetadata.BinaryDecoded = buildMetadata.Base64Decoded.Select(b => ToBitString(b)).ToList();
var stream = new DecodeCharStream(buildMetadata.BinaryDecoded.ToArray());
buildMetadata.Header = stream.Read(4);
if (buildMetadata.Header == 14)
{
buildMetadata.VersionNumber = stream.Read(4);
buildMetadata.NewTemplate = true;
}
else
{
buildMetadata.VersionNumber = buildMetadata.Header;
buildMetadata.NewTemplate = false;
}
buildMetadata.ProfessionIdLength = stream.Read(2) * 2 + 4;
buildMetadata.PrimaryProfessionId = stream.Read(buildMetadata.ProfessionIdLength);
buildMetadata.SecondaryProfessionId = stream.Read(buildMetadata.ProfessionIdLength);
buildMetadata.AttributeCount = stream.Read(4);
buildMetadata.AttributesLength = stream.Read(4) + 4;
for (int i = 0; i < buildMetadata.AttributeCount; i++)
{
buildMetadata.AttributesIds.Add(stream.Read(buildMetadata.AttributesLength));
buildMetadata.AttributePoints.Add(stream.Read(4));
}
buildMetadata.SkillsLength = stream.Read(4) + 8;
for (int i = 0; i < 8; i++)
{
buildMetadata.SkillIds.Add(stream.Read(buildMetadata.SkillsLength));
}
if (stream.Position < stream.Length - 1)
{
buildMetadata.TailPresent = true;
}
return buildMetadata;
}
private static string BuildEncodedString(BuildMetadata buildMetadata)
{
var stream = new EncodeCharStream();
if(buildMetadata.NewTemplate || buildMetadata.Header == 14)
{
stream.Write(14, 4);
}
stream.Write(0, 4);
var desiredProfessionIdLength = GetBitLength(new List<int> { buildMetadata.PrimaryProfessionId, buildMetadata.SecondaryProfessionId }.Max());
var professionIdLength = Math.Max((desiredProfessionIdLength - 4) / 2, 0);
var finalProfessionIdLength = professionIdLength * 2 + 4;
stream.Write(professionIdLength, 2);
stream.Write(buildMetadata.PrimaryProfessionId, finalProfessionIdLength);
stream.Write(buildMetadata.SecondaryProfessionId, finalProfessionIdLength);
stream.Write(buildMetadata.AttributeCount, 4);
var desiredAttributesLength = GetBitLength(buildMetadata.AttributesIds.Any() ? buildMetadata.AttributesIds.Max() : 0);
var attributesLength = Math.Max(desiredAttributesLength - 4, 0);
var finalAttributesLength = attributesLength + 4;
stream.Write(attributesLength, 4);
for(int i = 0; i < buildMetadata.AttributeCount; i++)
{
stream.Write(buildMetadata.AttributesIds[i], finalAttributesLength);
stream.Write(buildMetadata.AttributePoints[i], 4);
}
var desiredSkillsLength = GetBitLength(buildMetadata.SkillIds.Max());
var skillsLength = Math.Max(desiredSkillsLength - 8, 0);
var finalSkillsLength = skillsLength + 8;
stream.Write(skillsLength, 4);
for(int i = 0; i < 8; i++)
{
stream.Write(buildMetadata.SkillIds[i], finalSkillsLength);
}
if (buildMetadata.TailPresent)
{
stream.Write(0, 1);
}
return stream.GetEncodedString();
}
private static int GetBitLength(int value)
{
int decimals = 1;
value /= 2;
while (value > 0)
{
decimals++;
value /= 2;
}
return decimals;
}
private static int FromBitString(string bitString)
{
var sb = new StringBuilder(bitString);
while (sb.Length < 6)
{
sb.Append('0');
}
bitString = sb.ToString();
var value = 0d;
for (int i = 0; i < bitString.Length; i++)
{
value += bitString[i] == '1' ? Math.Pow(2, i) : 0;
}
return (int)value;
}
}
}
@@ -0,0 +1,16 @@
using Daybreak.Models.Builds;
using System.Collections.Generic;
namespace Daybreak.Services.BuildTemplates
{
public interface IBuildTemplateManager
{
BuildEntry CreateBuild();
BuildEntry CreateBuild(string name);
void SaveBuild(BuildEntry buildEntry);
void RemoveBuild(BuildEntry buildEntry);
IEnumerable<BuildEntry> GetBuilds();
Build DecodeTemplate(string template);
string EncodeTemplate(Build build);
}
}
@@ -0,0 +1,36 @@
using System;
namespace Daybreak.Services.BuildTemplates.Models
{
public sealed class DecodeCharStream
{
private readonly string innerCharArray;
public int Length => this.innerCharArray.Length;
public int Position { get; set; }
public DecodeCharStream(string[] encodedValues)
{
this.innerCharArray = string.Join("", encodedValues);
}
public int Read(int count)
{
var value = FromEncodedBinary(this.innerCharArray, this.Position, count);
this.Position += count;
return value;
}
private static int FromEncodedBinary(string encoded, int startIndex, int count)
{
var sum = 0d;
for (int i = startIndex; i < startIndex + count; i++)
{
sum += encoded[i] == '1' ? Math.Pow(2, i - startIndex) : 0;
}
return (int)sum;
}
}
}
@@ -0,0 +1,35 @@
using System.Text;
namespace Daybreak.Services.BuildTemplates.Models
{
public sealed class EncodeCharStream
{
private readonly StringBuilder innerStringBuilder = new StringBuilder();
public void Write(int value, int count)
{
this.EncodeToBinary(value, count);
}
public string GetEncodedString()
{
return innerStringBuilder.ToString();
}
private void EncodeToBinary(int value, int count)
{
while(value > 0 && count > 0)
{
this.innerStringBuilder.Append(value % 2 == 1 ? '1' : '0');
value /= 2;
count--;
}
while (count > 0)
{
this.innerStringBuilder.Append('0');
count--;
}
}
}
}
@@ -0,0 +1,12 @@
using Daybreak.Models.Builds;
using System.Extensions;
using System.IO;
using System.Threading.Tasks;
namespace Daybreak.Services.IconRetrieve
{
public interface IIconRetriever
{
Task<Optional<Stream>> GetIcon(Skill skill);
}
}
@@ -0,0 +1,79 @@
using Daybreak.Models.Builds;
using Daybreak.Services.Logging;
using Daybreak.Utils;
using HtmlAgilityPack;
using System;
using System.Extensions;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace Daybreak.Services.IconRetrieve
{
public sealed class IconRetriever : IIconRetriever
{
private const string NamePlaceholder = "[SKILLNAME]";
private const string BaseUrl = "https://wiki.guildwars.com";
private const string QueryUrl = $"wiki/File:{NamePlaceholder}.jpg";
private readonly HttpClient httpClient = new();
private readonly ILogger logger;
public IconRetriever(
ILogger logger)
{
this.logger = logger.ThrowIfNull(nameof(logger));
this.httpClient.BaseAddress = new Uri(BaseUrl);
}
public async Task<Optional<Stream>> GetIcon(Skill skill)
{
var curedSkillName = skill.Name
.Replace(" ", "_");
var skillIconUrl = QueryUrl.Replace(NamePlaceholder, curedSkillName);
this.logger.LogInformation($"Looking up icon for skill '{skill.Name}' at url {skillIconUrl}");
using var response = await this.httpClient.GetAsync(skillIconUrl).ConfigureAwait(false);
if (response.IsSuccessStatusCode is false)
{
this.logger.LogError($"Client returned status code {response.StatusCode}");
return Optional.None<Stream>();
}
this.logger.LogInformation("Crawling through response for href to latest icon url");
var doc = new HtmlDocument();
doc.LoadHtml(await response.Content.ReadAsStringAsync());
var url = GetHref(doc);
if (url is null)
{
this.logger.LogError("Failed to find latest icon url");
return Optional.None<Stream>();
}
this.logger.LogInformation($"Found latest icon url at {BaseUrl + "/" + url}. Requesting stream");
using var iconResponse = await this.httpClient.GetAsync(url);
if (response.IsSuccessStatusCode)
{
this.logger.LogInformation("Retrieved latest icon stream");
return new MemoryStream(await iconResponse.Content.ReadAsByteArrayAsync());
}
this.logger.LogError($"Failed to retrieve icon from {BaseUrl + "/" + url}");
return Optional.None<Stream>();
}
private static string GetHref(HtmlDocument doc)
{
foreach (var child in doc.DocumentNode.Descendants("a"))
{
var targetAttribute = child.Attributes.Where(a => a.Name == "href" && a.Value.Contains("images")).FirstOrDefault();
if (targetAttribute is not null)
{
return targetAttribute.Value;
}
}
return null;
}
}
}
@@ -8,5 +8,8 @@ namespace Daybreak.Services.ViewManagement
void ShowView<T>()
where T : UserControl;
void ShowView<T>(object dataContext)
where T : UserControl;
}
}
@@ -36,5 +36,13 @@ namespace Daybreak.Services.ViewManagement
this.container.Children.Clear();
this.container.Children.Add(view);
}
public void ShowView<T>(object dataContext) where T : UserControl
{
var view = this.serviceManager.GetService<T>();
this.container.Children.Clear();
this.container.Children.Add(view);
view.DataContext = dataContext;
}
}
}
@@ -0,0 +1,9 @@
namespace Daybreak.Services.Runtime
{
public interface IRuntimeStore
{
void StoreValue<T>(string name, T value);
bool TryGetValue<T>(string name, out T value);
T GetValue<T>(string name);
}
}
+36
View File
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Extensions;
namespace Daybreak.Services.Runtime
{
public sealed class RuntimeStore : IRuntimeStore
{
private Dictionary<string, object> InnerStore { get; } = new Dictionary<string, object>();
public T GetValue<T>(string name)
{
if(this.InnerStore.TryGetValue(name, out var value))
{
return value.Cast<T>();
}
throw new InvalidOperationException($"Could not find any value stored with name {name}");
}
public void StoreValue<T>(string name, T value)
{
this.InnerStore[name] = value;
}
public bool TryGetValue<T>(string name, out T value)
{
if (this.InnerStore.TryGetValue(name, out var valueObj))
{
value = valueObj.Cast<T>();
return true;
}
value = default;
return false;
}
}
}
@@ -1,6 +1,9 @@
using Daybreak.Models;
using Daybreak.Services.Logging;
using Daybreak.Services.Runtime;
using Daybreak.Services.ViewManagement;
using Daybreak.Utils;
using Daybreak.Views;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
@@ -10,12 +13,15 @@ using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace Daybreak.Services.Updater
{
public sealed class ApplicationUpdater : IApplicationUpdater
{
private const string UpdateDesiredKey = "UpdateDesired";
private const string ExecutionPolicyKey = "ExecutionPolicy";
private const string UpdatedKey = "Updating";
private const string RegistryKey = "Daybreak";
@@ -36,13 +42,21 @@ namespace Daybreak.Services.Updater
private const string RemoveTempFile = $"Remove-item {TempFile}";
private const string RemovePs1 = $"Remove-item {ExtractAndRunPs1}";
private readonly CancellationTokenSource updateCancellationTokenSource = new();
private readonly ILogger logger;
private readonly IViewManager viewManager;
private readonly IRuntimeStore runtimeStore;
private readonly HttpClient httpClient = new();
public string CurrentVersion => Assembly.GetExecutingAssembly().GetName().Version.ToString();
public ApplicationUpdater(ILogger logger)
public ApplicationUpdater(
ILogger logger,
IRuntimeStore runtimeStore,
IViewManager viewManager)
{
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.runtimeStore = runtimeStore.ThrowIfNull(nameof(runtimeStore));
this.logger = logger.ThrowIfNull(nameof(logger));
}
@@ -104,6 +118,23 @@ namespace Daybreak.Services.Updater
}).ExtractValue();
}
public void PeriodicallyCheckForUpdates()
{
System.Extensions.TaskExtensions.RunPeriodicAsync(async () =>
{
if (this.runtimeStore.TryGetValue<bool>(UpdateDesiredKey, out var desiringUpdate) && desiringUpdate is false)
{
this.updateCancellationTokenSource.Cancel();
return;
}
if (await this.UpdateAvailable())
{
Application.Current.Dispatcher.Invoke(() => this.viewManager.ShowView<AskUpdateView>());
}
}, TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(15), this.updateCancellationTokenSource.Token);
}
public void FinalizeUpdate()
{
var maybeExecutionPolicy = this.RetrieveExecutionPolicy();
@@ -8,6 +8,7 @@ namespace Daybreak.Services.Updater
{
string CurrentVersion { get; }
void FinalizeUpdate();
void PeriodicallyCheckForUpdates();
Task<bool> UpdateAvailable();
Task<bool> DownloadUpdate(UpdateStatus updateStatus);
}
+3
View File
@@ -1,6 +1,7 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
namespace Pepa.Wpf.Utilities
{
@@ -102,5 +103,7 @@ namespace Pepa.Wpf.Utilities
public static extern NtStatus NtQueryObject(IntPtr ObjectHandle, ObjectInformationClass ObjectInformationClass, IntPtr ObjectInformation, int ObjectInformationLength, out int ReturnLength);
[DllImport("ntdll.dll")]
public static extern NtStatus NtQuerySystemInformation(SystemInformationClass SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, out int ReturnLength);
[DllImport("kernel32.dll")]
public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, StringBuilder lpExeName, ref uint lpdwSize);
}
}
+31
View File
@@ -0,0 +1,31 @@
namespace Daybreak.Utils
{
public static class Scripts
{
public const string AlterContextMenu = @"
document.addEventListener('contextmenu', function (event)
{
var text = '';
if (window.getSelection)
{
text = window.getSelection().toString();
}
else if (document.selection && document.selection.type != 'Control')
{
text = document.selection.createRange().text;
}
let jsonObject =
{
Key: 'ContextMenu',
Value:
{
X: event.screenX,
Y: event.screenY,
Selection: text
}
};
window.chrome.webview.postMessage(jsonObject);
});";
}
}
+9 -1
View File
@@ -1,4 +1,5 @@
using Daybreak.Services.Logging;
using Daybreak.Services.Runtime;
using Daybreak.Services.Updater;
using Daybreak.Services.ViewManagement;
using Daybreak.Utils;
@@ -12,27 +13,34 @@ namespace Daybreak.Views
/// </summary>
public partial class AskUpdateView : UserControl
{
private const string UpdateDesiredKey = "UpdateDesired";
private readonly ILogger logger;
private readonly IViewManager viewManager;
private readonly IRuntimeStore runtimeStore;
public AskUpdateView(
ILogger logger,
IViewManager viewManager)
IViewManager viewManager,
IRuntimeStore runtimeStore)
{
this.logger = logger.ThrowIfNull(nameof(logger));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.runtimeStore = runtimeStore.ThrowIfNull(nameof(runtimeStore));
this.InitializeComponent();
}
private void NoButton_Clicked(object sender, System.EventArgs e)
{
this.logger.LogInformation("User declined update");
this.runtimeStore.StoreValue(UpdateDesiredKey, false);
this.viewManager.ShowView<MainView>();
}
private void YesButton_Clicked(object sender, System.EventArgs e)
{
this.logger.LogInformation("User accepted update");
this.runtimeStore.StoreValue(UpdateDesiredKey, true);
this.viewManager.ShowView<UpdateView>();
}
}
+41
View File
@@ -0,0 +1,41 @@
<UserControl x:Class="Daybreak.Views.BuildTemplateView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Views"
xmlns:controls="clr-namespace:Daybreak.Controls"
xmlns:converters="clr-namespace:Daybreak.Converters"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="#A0202020">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<controls:BackButton Foreground="White" Height="30" Width="30" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5"
Clicked="BackButton_Clicked" Grid.Column="0"></controls:BackButton>
<Grid Grid.Column="1" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="Name: " Foreground="White" FontSize="20"></TextBlock>
<TextBox Grid.Column="1" Background="Transparent" Foreground="White" FontSize="20"
Text="{Binding ElementName=_this, Path=CurrentBuild.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
PreviewTextInput="TextBox_PreviewTextInput" TextChanged="TextBox_TextChanged"></TextBox>
</Grid>
<controls:SaveButton Foreground="White" Height="30" Width="30" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5"
Clicked="SaveButton_Clicked" Grid.Column="2" IsEnabled="{Binding ElementName=_this, Path=SaveButtonEnabled, Mode=OneWay}"></controls:SaveButton>
</Grid>
<controls:BuildTemplate Grid.Row="1" DataContext="{Binding ElementName=_this, Path=CurrentBuild, Mode=OneWay}">
</controls:BuildTemplate>
</Grid>
</UserControl>
+87
View File
@@ -0,0 +1,87 @@
using Daybreak.Models.Builds;
using Daybreak.Services.BuildTemplates;
using Daybreak.Services.ViewManagement;
using System;
using System.Extensions;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Views
{
/// <summary>
/// Interaction logic for BuildTemplatesView.xaml
/// </summary>
public partial class BuildTemplateView : UserControl
{
private const string DisallowedChars = "\r\n\\/.";
public readonly static DependencyProperty CurrentBuildProperty =
DependencyPropertyExtensions.Register<BuildTemplateView, BuildEntry>(nameof(CurrentBuild));
public readonly static DependencyProperty SaveButtonEnabledProperty =
DependencyPropertyExtensions.Register<BuildTemplateView, bool>(nameof(SaveButtonEnabled), new PropertyMetadata(false));
private readonly IViewManager viewManager;
private readonly IBuildTemplateManager buildTemplateManager;
public bool SaveButtonEnabled
{
get => this.GetTypedValue<bool>(SaveButtonEnabledProperty);
set => this.SetValue(SaveButtonEnabledProperty, value);
}
public BuildEntry CurrentBuild
{
get => this.GetTypedValue<BuildEntry>(CurrentBuildProperty);
set => this.SetValue(CurrentBuildProperty, value);
}
public BuildTemplateView(
IViewManager viewManager,
IBuildTemplateManager buildTemplateManager)
{
this.buildTemplateManager = buildTemplateManager.ThrowIfNull(nameof(buildTemplateManager));
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.InitializeComponent();
this.DataContextChanged += (sender, contextArgs) =>
{
if (contextArgs.NewValue is BuildEntry)
{
this.CurrentBuild = contextArgs.NewValue.As<BuildEntry>();
}
};
}
private void BackButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<BuildsListView>();
}
private void SaveButton_Clicked(object sender, EventArgs e)
{
this.buildTemplateManager.SaveBuild(this.CurrentBuild);
this.viewManager.ShowView<BuildsListView>();
}
private void TextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
if (DisallowedChars.ToCharArray().Where(c => e.Text.Contains(c)).Any())
{
e.Handled = true;
}
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (string.IsNullOrWhiteSpace(sender.As<TextBox>().Text))
{
this.SaveButtonEnabled = false;
}
else
{
this.SaveButtonEnabled = true;
}
}
}
}
+29
View File
@@ -0,0 +1,29 @@
<UserControl x:Class="Daybreak.Views.BuildsListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Views"
xmlns:controls="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="#A0202020">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<controls:BackButton Foreground="White" Height="30" Width="30" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5"
Clicked="BackButton_Clicked"></controls:BackButton>
<controls:AddButton Foreground="White" Height="30" Width="30" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="5"
Clicked="AddButton_Clicked"></controls:AddButton>
<ListView Grid.Row="1" Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=BuildEntries, Mode=OneWay}"
MouseDoubleClick="ListView_MouseDoubleClick" HorizontalContentAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<controls:BuildEntryTemplate Margin="5" RemoveClicked="BuildEntryTemplate_RemoveClicked"></controls:BuildEntryTemplate>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</UserControl>
+58
View File
@@ -0,0 +1,58 @@
using Daybreak.Models.Builds;
using Daybreak.Services.BuildTemplates;
using Daybreak.Services.ViewManagement;
using System;
using System.Collections.ObjectModel;
using System.Extensions;
using System.Windows.Controls;
namespace Daybreak.Views
{
/// <summary>
/// Interaction logic for BuildsListView.xaml
/// </summary>
public partial class BuildsListView : UserControl
{
private readonly IViewManager viewManager;
private readonly IBuildTemplateManager buildTemplateManager;
public ObservableCollection<BuildEntry> BuildEntries { get; } = new ObservableCollection<BuildEntry>();
public BuildsListView(
IViewManager viewManager,
IBuildTemplateManager buildTemplateManager)
{
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.buildTemplateManager = buildTemplateManager.ThrowIfNull(nameof(buildTemplateManager));
this.InitializeComponent();
this.LoadBuilds();
}
private void LoadBuilds()
{
this.BuildEntries.ClearAnd().AddRange(this.buildTemplateManager.GetBuilds());
}
private void ListView_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
this.viewManager.ShowView<BuildTemplateView>(sender.As<ListView>().SelectedItem);
}
private void BackButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<SettingsCategoryView>();
}
private void AddButton_Clicked(object sender, EventArgs e)
{
var build = this.buildTemplateManager.CreateBuild();
this.viewManager.ShowView<BuildTemplateView>(build);
}
private void BuildEntryTemplate_RemoveClicked(object sender, BuildEntry e)
{
this.buildTemplateManager.RemoveBuild(e);
this.LoadBuilds();
}
}
}
@@ -90,6 +90,7 @@
<StackPanel>
<TextBlock Text="Multi-launch support" Foreground="White" FontSize="22" VerticalAlignment="Center" Margin="0, 0, 15, 0" Height="30"></TextBlock>
<TextBlock Text="GWToolbox startup delay (in ms)" Foreground="White" FontSize="22" VerticalAlignment="Center" Margin="0, 0, 15, 0" Height="30"></TextBlock>
<TextBlock Text="Detect build templates (in browser)" Foreground="White" FontSize="22" VerticalAlignment="Center" Margin="0, 0, 15, 0" Height="30"></TextBlock>
</StackPanel>
<StackPanel Grid.Column="1">
<ToggleButton IsChecked="{Binding ElementName=_this, Path=MultiLaunch, Mode=TwoWay}" Style="{StaticResource AnimatedSwitch}"
@@ -97,6 +98,8 @@
<TextBox Background="Transparent" Foreground="White" FontSize="16" Height="30"
PreviewTextInput="TextBox_AllowNumbersOnly" Text="{Binding ElementName=_this, Path=GWToolboxLaunchDelay, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
CommandManager.PreviewCanExecute="TextBox_DisallowPaste"></TextBox>
<ToggleButton IsChecked="{Binding ElementName=_this, Path=DynamicBuildLoading, Mode=TwoWay}" Style="{StaticResource AnimatedSwitch}"
Height="30" Width="60"></ToggleButton>
</StackPanel>
</Grid>
</Grid>
@@ -19,6 +19,8 @@ namespace Daybreak.Views
DependencyPropertyExtensions.Register<ExperimentalSettingsView, bool>(nameof(MultiLaunch));
public static readonly DependencyProperty GWToolboxLaunchDelayProperty =
DependencyPropertyExtensions.Register<ExperimentalSettingsView, string>(nameof(GWToolboxLaunchDelay));
public static readonly DependencyProperty DynamicBuildLoadingProperty =
DependencyPropertyExtensions.Register<ExperimentalSettingsView, bool>(nameof(DynamicBuildLoading));
private readonly IViewManager viewManager;
private readonly IConfigurationManager configurationManager;
@@ -33,6 +35,11 @@ namespace Daybreak.Views
get => this.GetTypedValue<string>(GWToolboxLaunchDelayProperty);
set => this.SetValue(GWToolboxLaunchDelayProperty, value);
}
public bool DynamicBuildLoading
{
get => this.GetTypedValue<bool>(DynamicBuildLoadingProperty);
set => this.SetValue(DynamicBuildLoadingProperty, value);
}
public ExperimentalSettingsView(
IViewManager viewManager,
@@ -49,12 +56,14 @@ namespace Daybreak.Views
var config = this.configurationManager.GetConfiguration();
this.MultiLaunch = config.ExperimentalFeatures.MultiLaunchSupport;
this.GWToolboxLaunchDelay = config.ExperimentalFeatures.ToolboxAutoLaunchDelay.ToString();
this.DynamicBuildLoading = config.ExperimentalFeatures.DynamicBuildLoading;
}
private void SaveExperimentalSettings()
{
var config = this.configurationManager.GetConfiguration();
config.ExperimentalFeatures.MultiLaunchSupport = this.MultiLaunch;
config.ExperimentalFeatures.DynamicBuildLoading = this.DynamicBuildLoading;
if (int.TryParse(this.GWToolboxLaunchDelay, out var gwToolboxLaunchDelay))
{
config.ExperimentalFeatures.ToolboxAutoLaunchDelay = gwToolboxLaunchDelay;
+18 -7
View File
@@ -14,7 +14,7 @@
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibility"></BooleanToVisibilityConverter>
</UserControl.Resources>
<Grid Background="Transparent" x:Name="ViewContainer">
<Grid x:Name="ViewContainer">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
@@ -27,22 +27,33 @@
<controls:OpaqueButton Text="Launch game" Highlight="White" TransparentBackground="Black" HighlightOpacity="0.3" BackgroundOpacity="0.2"
Foreground="White" FontSize="36" Width="250" Height="60" VerticalAlignment="Bottom"
IsEnabled="{Binding ElementName=_this, Path=LaunchButtonEnabled, Mode=OneWay}"
Clicked="LaunchButton_Clicked" Grid.Row="0" Grid.ColumnSpan="3"></controls:OpaqueButton>
Clicked="LaunchButton_Clicked" Grid.Row="0" Grid.ColumnSpan="3"
Visibility="{Binding ElementName=_this, Path=ButtonsVisible, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}"></controls:OpaqueButton>
<controls:OpaqueButton Text="Launch toolbox" Highlight="White" TransparentBackground="Black" HighlightOpacity="0.3" BackgroundOpacity="0.2"
Foreground="White" FontSize="24" Width="200" Height="40" Margin="0, 10, 0, 10"
IsEnabled="{Binding ElementName=_this, Path=LaunchToolboxButtonEnabled, Mode=OneWay}"
Clicked="LaunchToolboxButton_Clicked" Grid.Row="1" Grid.ColumnSpan="3"></controls:OpaqueButton>
<Grid x:Name="RightContainer" Grid.Column="2" Margin="10">
Clicked="LaunchToolboxButton_Clicked" Grid.Row="1" Grid.ColumnSpan="2"
Visibility="{Binding ElementName=_this, Path=ButtonsVisible, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}"></controls:OpaqueButton>
<controls:OpaqueButton Text="Launch texmod" Highlight="White" TransparentBackground="Black" HighlightOpacity="0.3" BackgroundOpacity="0.2"
Foreground="White" FontSize="24" Width="200" Height="40" Margin="0, 10, 0, 10"
IsEnabled="{Binding ElementName=_this, Path=LaunchTexmodButtonEnabled, Mode=OneWay}"
Clicked="LaunchTexmodButton_Clicked" Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="1"
Visibility="{Binding ElementName=_this, Path=ButtonsVisible, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}"></controls:OpaqueButton>
<Grid Grid.Column="2" Margin="10" Visibility="{Binding ElementName=_this, Path=BrowsersEnabled, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}">
<controls:ChromiumBrowserWrapper Address="{Binding ElementName=_this, Path=RightBrowserAddress, Mode=OneWay}"
Foreground="White" FavoriteUriChanged="RightBrowser_FavoriteUriChanged"
FavoriteAddress="{Binding ElementName=_this, Path=RightBrowserFavoriteAddress, Mode=OneWay}"
MaximizeClicked="RightChromiumBrowserWrapper_MaximizeClicked"/>
MaximizeClicked="RightChromiumBrowserWrapper_MaximizeClicked"
BuildDecoded="ChromiumBrowserWrapper_BuildDecoded"
CanDownloadBuild="True"/>
</Grid>
<Grid x:Name="LeftContainer" Grid.Column="0" Margin="10">
<Grid Grid.Column="0" Margin="10" Visibility="{Binding ElementName=_this, Path=BrowsersEnabled, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}">
<controls:ChromiumBrowserWrapper Address="{Binding ElementName=_this, Path=LeftBrowserAddress, Mode=OneWay}"
Foreground="White" FavoriteUriChanged="LeftBrowser_FavoriteUriChanged"
FavoriteAddress="{Binding ElementName=_this, Path=LeftBrowserFavoriteAddress, Mode=OneWay}"
MaximizeClicked="LeftChromiumBrowserWrapper_MaximizeClicked"/>
MaximizeClicked="LeftChromiumBrowserWrapper_MaximizeClicked"
BuildDecoded="ChromiumBrowserWrapper_BuildDecoded"
CanDownloadBuild="True"/>
</Grid>
</Grid>
</UserControl>
+56 -8
View File
@@ -1,5 +1,5 @@
using Daybreak.Controls;
using Daybreak.Exceptions;
using Daybreak.Exceptions;
using Daybreak.Models.Builds;
using Daybreak.Services.ApplicationLauncher;
using Daybreak.Services.Configuration;
using Daybreak.Services.ViewManagement;
@@ -18,10 +18,16 @@ namespace Daybreak.Views
/// </summary>
public partial class MainView : UserControl
{
public static readonly DependencyProperty ButtonsVisibleProperty =
DependencyPropertyExtensions.Register<MainView, bool>(nameof(ButtonsVisible), new PropertyMetadata(true));
public static readonly DependencyProperty LaunchButtonEnabledProperty =
DependencyPropertyExtensions.Register<MainView, bool>(nameof(LaunchButtonEnabled));
public static readonly DependencyProperty LaunchToolboxButtonEnabledProperty =
DependencyPropertyExtensions.Register<MainView, bool>(nameof(LaunchToolboxButtonEnabled));
public static readonly DependencyProperty LaunchTexmodButtonEnabledProperty =
DependencyPropertyExtensions.Register<MainView, bool>(nameof(LaunchTexmodButtonEnabled));
public static readonly DependencyProperty BrowsersEnabledProperty =
DependencyPropertyExtensions.Register<MainView, bool>(nameof(BrowsersEnabled), new PropertyMetadata(true));
public static readonly DependencyProperty RightBrowserAddressProperty =
DependencyPropertyExtensions.Register<MainView, string>(nameof(RightBrowserAddress));
public static readonly DependencyProperty LeftBrowserAddressProperty =
@@ -39,6 +45,11 @@ namespace Daybreak.Views
private bool leftBrowserMaximized = false;
private bool rightBrowserMaximized = false;
public bool ButtonsVisible
{
get => this.GetTypedValue<bool>(ButtonsVisibleProperty);
set => this.SetTypedValue(ButtonsVisibleProperty, value);
}
public string RightBrowserFavoriteAddress
{
get => this.GetTypedValue<string>(RightBrowserFavoriteAddressProperty);
@@ -69,6 +80,16 @@ namespace Daybreak.Views
get => this.GetTypedValue<bool>(LaunchToolboxButtonEnabledProperty);
set => this.SetTypedValue(LaunchToolboxButtonEnabledProperty, value);
}
public bool LaunchTexmodButtonEnabled
{
get => this.GetTypedValue<bool>(LaunchTexmodButtonEnabledProperty);
set => this.SetTypedValue(LaunchTexmodButtonEnabledProperty, value);
}
public bool BrowsersEnabled
{
get => this.GetTypedValue<bool>(BrowsersEnabledProperty);
set => this.SetTypedValue(BrowsersEnabledProperty, value);
}
public MainView(
IApplicationLauncher applicationDetector,
@@ -86,10 +107,17 @@ namespace Daybreak.Views
private void NavigateToDefaults()
{
var applicationConfiguration = this.configurationManager.GetConfiguration();
this.LeftBrowserFavoriteAddress = applicationConfiguration.LeftBrowserDefault;
this.RightBrowserFavoriteAddress = applicationConfiguration.RightBrowserDefault;
this.LeftBrowserAddress = applicationConfiguration.LeftBrowserDefault;
this.RightBrowserAddress = applicationConfiguration.RightBrowserDefault;
if (applicationConfiguration.BrowsersEnabled)
{
this.LeftBrowserFavoriteAddress = applicationConfiguration.LeftBrowserDefault;
this.RightBrowserFavoriteAddress = applicationConfiguration.RightBrowserDefault;
this.LeftBrowserAddress = applicationConfiguration.LeftBrowserDefault;
this.RightBrowserAddress = applicationConfiguration.RightBrowserDefault;
}
else
{
this.BrowsersEnabled = false;
}
}
private void PeriodicallyCheckGameState()
@@ -99,8 +127,9 @@ namespace Daybreak.Views
private void CheckGameState()
{
this.LaunchButtonEnabled = applicationDetector.IsGuildwarsRunning is false;
this.LaunchToolboxButtonEnabled = applicationDetector.IsToolboxRunning is false;
this.LaunchButtonEnabled = this.applicationDetector.IsGuildwarsRunning is false;
this.LaunchToolboxButtonEnabled = this.applicationDetector.IsToolboxRunning is false;
this.LaunchTexmodButtonEnabled = this.applicationDetector.IsTexmodRunning is false;
}
private void StartupView_Loaded(object sender, RoutedEventArgs e)
@@ -146,6 +175,23 @@ namespace Daybreak.Views
}
}
private void LaunchTexmodButton_Clicked(object sender, EventArgs e)
{
try
{
this.applicationDetector.LaunchTexmod();
}
catch
{
this.viewManager.ShowView<SettingsView>();
}
}
private void ChromiumBrowserWrapper_BuildDecoded(object sender, Models.Builds.Build e)
{
this.viewManager.ShowView<BuildTemplateView>(new BuildEntry { Build = e, Name = string.Empty });
}
private void LeftBrowser_FavoriteUriChanged(object sender, string e)
{
var config = this.configurationManager.GetConfiguration();
@@ -176,6 +222,7 @@ namespace Daybreak.Views
}
this.leftBrowserMaximized = !this.leftBrowserMaximized;
this.ButtonsVisible = !this.leftBrowserMaximized;
}
private void RightChromiumBrowserWrapper_MaximizeClicked(object sender, EventArgs e)
@@ -194,6 +241,7 @@ namespace Daybreak.Views
}
this.rightBrowserMaximized = !this.rightBrowserMaximized;
this.ButtonsVisible = !this.rightBrowserMaximized;
}
}
}
+6
View File
@@ -36,6 +36,12 @@
<controls:ExperimentGlyph></controls:ExperimentGlyph>
</controls:TileButton.InnerContent>
</controls:TileButton>
<controls:TileButton Title="Builds" Foreground="White" BorderBrush="White" BorderThickness="2"
HighlightColor="White" Clicked="BuildsButton_Clicked" Height="150" Width="150">
<controls:TileButton.InnerContent>
<controls:FireballGlyph></controls:FireballGlyph>
</controls:TileButton.InnerContent>
</controls:TileButton>
</WrapPanel>
</WrapPanel>
</Grid>
@@ -33,6 +33,11 @@ namespace Daybreak.Views
this.viewManager.ShowView<ExperimentalSettingsView>();
}
private void BuildsButton_Clicked(object sender, System.EventArgs e)
{
this.viewManager.ShowView<BuildsListView>();
}
private void FileButton_Clicked(object sender, System.EventArgs e)
{
this.viewManager.ShowView<ExecutablesView>();
+15 -3
View File
@@ -81,13 +81,23 @@
<controls:SaveButton Foreground="White" Height="30" Width="30" Grid.Column="1" HorizontalAlignment="Right" Margin="5"
Clicked="SaveButton_Clicked"></controls:SaveButton>
<StackPanel Orientation="Vertical" Grid.Row="1">
<TextBlock Text="Texmod path" FontSize="22" Foreground="White"></TextBlock>
<TextBlock Text="GWToolbox path: " FontSize="22" Foreground="White"></TextBlock>
<TextBlock Text="GWToolbox auto-launch: " FontSize="22" Foreground="White"></TextBlock>
<TextBlock Text="Address bar readonly: " FontSize="22" Foreground="White"/>
<TextBlock Text="Browsers enabled: " FontSize="22" Foreground="White"/>
<TextBlock Text="Browsers address bar readonly: " FontSize="22" Foreground="White"/>
<TextBlock Text="Left browser homepage: " FontSize="22" Foreground="White"></TextBlock>
<TextBlock Text="Right browser homepage: " FontSize="22" Foreground="White"></TextBlock>
</StackPanel>
<StackPanel Orientation="Vertical" Grid.Row="1" Grid.Column="1">
<Grid>
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
FontSize="22" Margin="0, 0, 30, 0" Background="Transparent" Foreground="White"
Text="{Binding ElementName=_this, Path=TexmodPath, Mode=TwoWay}"></TextBox>
<controls:FilePickerGlyph Height="30" Width="30" HorizontalAlignment="Right"
Foreground="White" BorderBrush="Gray" BorderThickness="0"
Clicked="TexmodFilePickerGlyph_Clicked"></controls:FilePickerGlyph>
</Grid>
<Grid>
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
FontSize="22" Margin="0, 0, 30, 0" Background="Transparent" Foreground="White"
@@ -97,9 +107,11 @@
Clicked="ToolboxFilePickerGlyph_Clicked"></controls:FilePickerGlyph>
</Grid>
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
FontSize="22" Background="Transparent" Foreground="White" IsChecked="{Binding ElementName=_this, Path=ToolboxAutoLaunch, Mode=TwoWay}"></ToggleButton>
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=ToolboxAutoLaunch, Mode=TwoWay}"></ToggleButton>
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
FontSize="22" Background="Transparent" Foreground="White" IsChecked="{Binding ElementName=_this, Path=AddressBarReadonly, Mode=TwoWay}"></ToggleButton>
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=BrowsersEnabled, Mode=TwoWay}"></ToggleButton>
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=AddressBarReadonly, Mode=TwoWay}"></ToggleButton>
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
FontSize="22" Background="Transparent" Foreground="White"
Text="{Binding ElementName=_this, Path=LeftBrowserUrl, Mode=TwoWay}"

Some files were not shown because too many files have changed in this diff Show More