Compare commits

...
12 Commits
Author SHA1 Message Date
Alexandru Macocian 458696ad8f Fixed a bug where skill templates would try to load the image for No Skill.
Fixed a bug where build template manager would delete saved template.
2021-04-23 17:28:12 +02:00
Alexandru Macocian 6201702563 Skill holder now properly shows the top half of icons in the case where icons are bigger than normal. 2021-04-23 17:14:24 +02:00
Alexandru Macocian c5bea23a8f Make professions and attributes searchable.
Minor QOL changes to build view.
Handle exception caused by browser initialization getting canceled.
2021-04-23 16:59:31 +02:00
Alexandru Macocian e5f38f77ef Reverted html agility pack. 2021-04-23 11:40:05 +02:00
Alexandru Macocian 1d774ab8de Disable script injection when dynamic build loading is disabled.
Fixed a bug where earth prayers was not a recognized attribute.
2021-04-23 11:11:19 +02:00
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
92 changed files with 6177 additions and 16 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;
}
}
}
@@ -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,8 +1,10 @@
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;
@@ -33,6 +35,8 @@ namespace Daybreak.Configuration
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)
{
@@ -54,6 +58,8 @@ namespace Daybreak.Configuration
viewProducer.RegisterView<AccountsView>();
viewProducer.RegisterView<ExperimentalSettingsView>();
viewProducer.RegisterView<ExecutablesView>();
viewProducer.RegisterView<BuildTemplateView>();
viewProducer.RegisterView<BuildsListView>();
}
}
}
+19
View File
@@ -0,0 +1,19 @@
<UserControl x:Class="Daybreak.Controls.HelpButton"
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" Width="30" Height="30" />
<Ellipse Width="30" Height="30" StrokeThickness="2" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Ellipse>
<Path Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" VerticalAlignment="Center" HorizontalAlignment="Center"
Data="m4.99353,17.899l0,-1.47c0,-1.436 0.322,-2.188 1.075,-3.229l2.404,-3.3c1.254,-1.721 1.684,-2.546 1.684,-3.766c0,-2.044 -1.434,-3.335 -3.479,-3.335c-2.008,0 -3.299,1.219 -3.729,3.407c-0.036,0.215 -0.179,0.323 -0.395,0.287l-2.259,-0.395c-0.216,-0.036 -0.323,-0.179 -0.288,-0.395c0.539,-3.443 3.014,-5.703 6.744,-5.703c3.872,0 6.49,2.546 6.49,6.097c0,1.722 -0.608,2.977 -1.828,4.663l-2.403,3.3c-0.717,0.968 -0.933,1.47 -0.933,2.689l0,1.147c0,0.215 -0.143,0.358 -0.358,0.358l-2.367,0c-0.215,0.004 -0.358,-0.14 -0.358,-0.355zm-0.179,3.444c0,-0.215 0.143,-0.358 0.359,-0.358l2.726,0c0.215,0 0.358,0.144 0.358,0.358l0,3.084c0,0.216 -0.144,0.358 -0.358,0.358l-2.726,0c-0.217,0 -0.359,-0.143 -0.359,-0.358l0,-3.084z"></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 HelpButton : UserControl
{
public event EventHandler Clicked;
public HelpButton()
{
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)
{
this.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);
}
}
}
}
+14 -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>
@@ -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;
@@ -26,14 +29,29 @@ namespace Daybreak.Controls
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);
@@ -52,7 +70,7 @@ 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
{
@@ -64,11 +82,17 @@ namespace Daybreak.Controls
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();
@@ -114,9 +138,27 @@ 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;
if (this.CanDownloadBuild)
{
await this.WebBrowser.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(Scripts.SendSelectionOnContextMenu);
}
}
}
@@ -158,9 +200,60 @@ 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>>();
var maybeTemplate = contextMenuPayload.Value.Selection;
if (string.IsNullOrWhiteSpace(maybeTemplate))
{
return;
}
if (this.buildTemplateManager.IsTemplate(maybeTemplate) is false)
{
return;
}
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)
@@ -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,25 @@
<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"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="10, 0, 10, 0">
<local:HelpButton Width="20" Height="20" Margin="3, 0, 3, 0" Foreground="White"
Clicked="HelpButton_Clicked" Cursor="Hand"></local:HelpButton>
<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" Cursor="Hand"
IsEnabled="{Binding ElementName=_this, Path=CanSubtract, Mode=OneWay}"></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" Cursor="Hand"
IsEnabled="{Binding ElementName=_this, Path=CanAdd, Mode=OneWay}"></local:AddButton>
</WrapPanel>
</Grid>
</UserControl>
@@ -0,0 +1,84 @@
using Daybreak.Models.Builds;
using System;
using System.Extensions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for AttributeTemplate.xaml
/// </summary>
public partial class AttributeTemplate : UserControl
{
public readonly static DependencyProperty CanAddProperty =
DependencyPropertyExtensions.Register<AttributeTemplate, bool>(nameof(CanAdd), new PropertyMetadata(false));
public readonly static DependencyProperty CanSubtractProperty =
DependencyPropertyExtensions.Register<AttributeTemplate, bool>(nameof(CanSubtract), new PropertyMetadata(false));
public event EventHandler<AttributeEntry> HelpClicked;
public bool CanAdd
{
get => this.GetTypedValue<bool>(CanAddProperty);
private set => this.SetValue(CanAddProperty, value);
}
public bool CanSubtract
{
get => this.GetTypedValue<bool>(CanSubtractProperty);
private set => this.SetValue(CanSubtractProperty, value);
}
public AttributeTemplate()
{
this.InitializeComponent();
this.DataContextChanged += AttributeTemplate_DataContextChanged;
}
private void AttributeTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is AttributeEntry attributeEntry)
{
if (attributeEntry.Points > 0)
{
this.CanSubtract = true;
}
if (attributeEntry.Points < 12)
{
this.CanAdd = true;
}
}
}
private void MinusButton_Clicked(object sender, System.EventArgs e)
{
if (this.DataContext.As<AttributeEntry>().Points > 0)
{
this.DataContext.As<AttributeEntry>().Points--;
this.CanSubtract = this.DataContext.As<AttributeEntry>().Points > 0;
this.CanAdd = true;
}
}
private void AddButton_Clicked(object sender, System.EventArgs e)
{
if (this.DataContext.As<AttributeEntry>().Points < 12)
{
this.DataContext.As<AttributeEntry>().Points++;
this.CanAdd = this.DataContext.As<AttributeEntry>().Points < 12;
this.CanSubtract = true;
}
}
private void HelpButton_Clicked(object sender, System.EventArgs e)
{
if (this.DataContext is AttributeEntry attributeEntry)
{
this.HelpClicked?.Invoke(this, attributeEntry);
}
}
}
}
@@ -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,169 @@
<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>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="Primary Profession: " FontSize="16" Foreground="White"></TextBlock>
<ListView FontSize="16" Foreground="White" Grid.Column="1" BorderThickness="0"
Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Professions, Mode=OneWay}"
SelectedItem="{Binding ElementName=_this, Path=PrimaryProfession, Mode=TwoWay}" Height="30"
SelectionMode="Single" ScrollViewer.VerticalScrollBarVisibility="Disabled"
PreviewMouseWheel="ListView_NavigateWithMouseWheel">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name, Mode=OneWay}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
<interactivity:Interaction.Behaviors>
<behaviors:ScrollIntoView></behaviors:ScrollIntoView>
</interactivity:Interaction.Behaviors>
</ListView>
<local:HelpButton Grid.Column="2" Foreground="White" Width="20" Height="20" Margin="3"
Clicked="HelpButtonPrimary_Clicked" Cursor="Hand"></local:HelpButton>
</Grid>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="Secondary Profession: " FontSize="16" Foreground="White"></TextBlock>
<ListView FontSize="16" Foreground="White" Grid.Column="1" BorderThickness="0"
Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Professions, Mode=OneWay}"
SelectedItem="{Binding ElementName=_this, Path=SecondaryProfession, Mode=TwoWay}" Height="30"
SelectionMode="Single" ScrollViewer.VerticalScrollBarVisibility="Disabled"
PreviewMouseWheel="ListView_NavigateWithMouseWheel">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name, Mode=OneWay}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
<interactivity:Interaction.Behaviors>
<behaviors:ScrollIntoView></behaviors:ScrollIntoView>
</interactivity:Interaction.Behaviors>
</ListView>
<local:HelpButton Grid.Column="2" Foreground="White" Width="20" Height="20" Margin="3"
Clicked="HelpButtonSecondary_Clicked" Cursor="Hand"></local:HelpButton>
</Grid>
<Grid Grid.Row="3">
<ListBox Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Attributes, Mode=OneWay}"
HorizontalContentAlignment="Stretch" BorderThickness="0">
<ListBox.ItemTemplate>
<DataTemplate>
<local:AttributeTemplate HelpClicked="AttributeTemplate_HelpClicked"></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" Cursor="Hand"
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" Cursor="Hand"
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" Cursor="Hand"
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" Cursor="Hand"
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" Cursor="Hand"
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" Cursor="Hand"
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" Cursor="Hand"
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" Cursor="Hand"
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,367 @@
using Daybreak.Launch;
using Daybreak.Models.Builds;
using Daybreak.Services.IconRetrieve;
using System.Collections;
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 InfoNamePlaceholder = "[NAME]";
private const string BaseAddress = $"https://wiki.guildwars.com/wiki/{InfoNamePlaceholder}";
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.HideSkillListView();
this.HideInfoBrowser();
}
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 BrowseToInfo(string infoName)
{
var address = BaseAddress.Replace(InfoNamePlaceholder, infoName.Replace(" ", "_"));
this.SkillBrowser.Address = address;
this.ShowInfoBrowser();
}
private void ShowInfoBrowser()
{
this.SkillBrowser.Width = 400;
this.SkillsListView.Width = 0;
}
private void HideInfoBrowser()
{
this.SkillBrowser.Width = 0;
}
private void ShowSkillListView()
{
this.SkillBrowser.Width = 0;
this.SkillsListView.Width = 400;
}
private void HideSkillListView()
{
this.SkillsListView.Width = 0;
}
private void HelpButtonPrimary_Clicked(object sender, System.EventArgs e)
{
if (this.PrimaryProfession == Profession.None)
{
return;
}
this.BrowseToInfo(PrimaryProfession.Name);
if (e is RoutedEventArgs routedEventArgs)
{
routedEventArgs.Handled = true;
}
}
private void HelpButtonSecondary_Clicked(object sender, System.EventArgs e)
{
if (this.SecondaryProfession == Profession.None)
{
return;
}
this.BrowseToInfo(this.SecondaryProfession.Name);
if (e is RoutedEventArgs routedEventArgs)
{
routedEventArgs.Handled = true;
}
}
private void AttributeTemplate_HelpClicked(object sender, AttributeEntry e)
{
this.BrowseToInfo(e.Attribute.Name);
}
private void SkillTemplate_Clicked(object sender, RoutedEventArgs e)
{
var skill = sender.As<SkillTemplate>().DataContext.As<Skill>();
if (skill == Skill.NoSkill)
{
this.ShowSkillListView();
this.selectingSkillTemplate = sender.As<SkillTemplate>();
}
else
{
this.BrowseToInfo(skill.Name);
}
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.HideSkillListView();
return;
}
this.selectingSkillTemplate.DataContext = sender.As<ListView>().SelectedItem;
this.HideSkillListView();
this.loadedBuild.Build.Skills[0] = Skill0;
this.loadedBuild.Build.Skills[1] = Skill1;
this.loadedBuild.Build.Skills[2] = Skill2;
this.loadedBuild.Build.Skills[3] = Skill3;
this.loadedBuild.Build.Skills[4] = Skill4;
this.loadedBuild.Build.Skills[5] = Skill5;
this.loadedBuild.Build.Skills[6] = Skill6;
this.loadedBuild.Build.Skills[7] = Skill7;
}
private void ListView_NavigateWithMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
e.Handled = true;
if (e.Delta > 0)
{
sender.As<ListView>().SelectedIndex = sender.As<ListView>().SelectedIndex > 0 ?
sender.As<ListView>().SelectedIndex - 1 :
0;
}
else
{
sender.As<ListView>().SelectedIndex = sender.As<ListView>().SelectedIndex < sender.As<ListView>().Items.Count - 1 ?
sender.As<ListView>().SelectedIndex + 1 :
sender.As<ListView>().Items.Count;
}
}
}
}
@@ -0,0 +1,34 @@
<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="Top" HorizontalAlignment="Left"
Width="{Binding ElementName=_this, Path=ActualWidth, Mode=OneWay}"
Height="{Binding ElementName=_this, Path=ActualWidth, Mode=OneWay}"
Source="{Binding ElementName=_this, Path=ImageSource, Mode=OneWay}"
Stretch="UniformToFill"></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 skill && skill != Skill.NoSkill)
{
Task.Run(() => GetImageStream(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;
}
}
}
}
+23 -8
View File
@@ -9,39 +9,54 @@
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<LangVersion>preview</LangVersion>
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
<Version>0.6.7</Version>
<Version>0.7.6</Version>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.774.44" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.32" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.818.41" />
<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="SystemExtensions.NetStandard" Version="1.1.4" />
<PackageReference Include="WCL" Version="1.0.2" />
<PackageReference Include="WpfExtended" Version="0.2.0" />
</ItemGroup>
<ItemGroup>
<Compile Update="Controls\StarGlyph.xaml.cs">
<Compile Update="Controls\Buttons\HelpButton.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Controls\CancelButton.xaml.cs">
<Compile Update="Controls\Buttons\MinusButton.xaml.cs">
<SubType>Code</SubType>
</Compile>
<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\HelpButton.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Controls\StarGlyph.xaml">
<Page Update="Controls\Buttons\MinusButton.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Controls\CancelButton.xaml">
<Page Update="Controls\Buttons\MaximizeButton.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<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>
+14
View File
@@ -9,6 +9,8 @@ using Microsoft.Web.WebView2.Wpf;
using Slim;
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Extensions;
@@ -45,6 +47,18 @@ namespace Daybreak.Launch
MessageBox.Show(fatalException.ToString());
return false;
}
else if (e is AggregateException aggregateException)
{
if (aggregateException.InnerExceptions.FirstOrDefault() is COMException comException &&
comException.Message.Contains("Invalid window handle"))
{
/*
* Ignore exception caused by browser failing to initialize due to missing window.
* Likely caused by switching windows before browser was initialized.
*/
return true;
}
}
MessageBox.Show(e.ToString());
return true;
+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; }
}
}
+143
View File
@@ -0,0 +1,143 @@
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,
EarthPrayers,
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
@@ -0,0 +1,350 @@
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 bool IsTemplate(string template)
{
if (template.IsNullOrWhiteSpace())
{
return false;
}
if (template.Where(c => DecodingLookupTable.Contains(c) is false).Any())
{
return false;
}
return true;
}
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);
if (string.IsNullOrWhiteSpace(buildEntry.PreviousName))
{
File.Delete($"{BuildsPath}\\{buildEntry.PreviousName}.txt");
}
File.WriteAllText($"{BuildsPath}\\{buildEntry.Name}.txt", encodedBuild);
}
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,17 @@
using Daybreak.Models.Builds;
using System.Collections.Generic;
namespace Daybreak.Services.BuildTemplates
{
public interface IBuildTemplateManager
{
bool IsTemplate(string template);
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;
}
}
}
+35
View File
@@ -0,0 +1,35 @@
namespace Daybreak.Utils
{
public static class Scripts
{
public const string SendSelectionOnContextMenu = @"
document.addEventListener('contextmenu', function (event)
{
var text = '';
var activeEl = document.activeElement;
var activeElTagName = activeEl ? activeEl.tagName.toLowerCase() : null;
if ((activeElTagName == 'textarea') || (activeElTagName == 'input' &&
/^(?:text|search|password|tel|url)$/i.test(activeEl.type)) &&
(typeof activeEl.selectionStart == 'number'))
{
text = activeEl.value.slice(activeEl.selectionStart, activeEl.selectionEnd);
}
else if (window.getSelection)
{
text = window.getSelection().toString();
}
let jsonObject =
{
Key: 'ContextMenu',
Value:
{
X: event.screenX,
Y: event.screenY,
Selection: text
}
};
window.chrome.webview.postMessage(jsonObject);
});";
}
}
+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;
+6 -2
View File
@@ -43,13 +43,17 @@
<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 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>
+7 -2
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;
@@ -187,6 +187,11 @@ namespace Daybreak.Views
}
}
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();
+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>();
+12
View File
@@ -5,6 +5,8 @@ Requires webview2 runtime https://go.microsoft.com/fwlink/p/?LinkId=2124703.
![Showcase 1](https://media1.giphy.com/media/Z32o0OZ5pZHDOIodzD/giphy.gif)
![Showcase 2](https://media0.giphy.com/media/aQ8Wl7lsuhT0AblCPI/giphy.gif)
![Showcase 3](https://media2.giphy.com/media/s06PtxgeAAZtoJhTx6/giphy.gif)
![Build Management Showcase](https://media2.giphy.com/media/C399pwfypdZvkmoJpi/giphy.gif)
![Dynamic build loading](https://media2.giphy.com/media/UKtJaoBk6NeuOmE8al/giphy.gif)
# Features
Automatically detect if guildwars is running or not. Includes the ability to launch guildwars from the client.
@@ -43,3 +45,13 @@ To adjust executables, go into Guildwars settings. Clicking on the star next to
To enable multiboxing (multi-launch), go into Experimental settings. Then, switch between executables/accounts and launch them.
![Multibox toggle](https://i.imgur.com/vEFF2pb.png)
To manage builds, go into Settings, Builds. Here you can select/remove builds.
![Builds list view](https://i.imgur.com/OFxnFcZ.png)
Doubleclick on one of the builds to enter the template management view. Here you can click on skills to open the wiki page of the skill. You can adjust professions, attributes and add/remove skills.
![Builds management view](https://i.imgur.com/exKWJb8.png)
To dynamically load a build, while browsing in the browsers from the main page, select and rightclick any text on the page that might be a template. If it is a template, the client will open a context menu with a button called "Load build template". Click on that button to load the build and switch to build template view.
![Dynamically load build](https://i.imgur.com/V5vvgsg.png)