mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-09-16 13:29:30 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d774ab8de | ||
|
|
bc66ca9948 | ||
|
|
524cd21fd4 | ||
|
|
132cb0e1f4 | ||
|
|
09c99e7731 | ||
|
|
c9d0be1117 | ||
|
|
965055c8d7 | ||
|
|
f6bb21d0ef | ||
|
|
465e0a4ce0 | ||
|
|
55f304b885 | ||
|
|
0cb1d97332 | ||
|
|
e2091cd82f | ||
|
|
d2bada4159 |
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Extensions;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Interactivity;
|
||||
|
||||
namespace Daybreak.Behaviors
|
||||
{
|
||||
public class ScrollIntoView : Behavior<ListView>
|
||||
{
|
||||
/// <summary>
|
||||
/// When Beahvior is attached
|
||||
/// </summary>
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
this.AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// On Selection Changed
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
void AssociatedObject_SelectionChanged(object sender,
|
||||
SelectionChangedEventArgs e)
|
||||
{
|
||||
if (sender is ListView)
|
||||
{
|
||||
var listView = sender.As<ListView>();
|
||||
if (listView.SelectedItem != null)
|
||||
{
|
||||
listView.Dispatcher.BeginInvoke(
|
||||
(Action)(() =>
|
||||
{
|
||||
listView.UpdateLayout();
|
||||
if (listView.SelectedItem !=
|
||||
null)
|
||||
listView.ScrollIntoView(
|
||||
listView.SelectedItem);
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// When behavior is detached
|
||||
/// </summary>
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
base.OnDetaching();
|
||||
this.AssociatedObject.SelectionChanged -=
|
||||
AssociatedObject_SelectionChanged;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ namespace Daybreak.Configuration
|
||||
{
|
||||
public sealed class ApplicationConfiguration
|
||||
{
|
||||
[JsonProperty("BrowsersEnabled")]
|
||||
public bool BrowsersEnabled { get; set; } = true;
|
||||
[JsonProperty("ToolboxPath")]
|
||||
public string ToolboxPath { get; set; }
|
||||
[JsonProperty("TexmodPath")]
|
||||
|
||||
@@ -8,5 +8,7 @@ namespace Daybreak.Configuration
|
||||
public bool MultiLaunchSupport { get; set; }
|
||||
[JsonProperty("ToolboxAutoLaunchDelay")]
|
||||
public int ToolboxAutoLaunchDelay { get; set; } = 5000;
|
||||
[JsonProperty("DynamicBuildLoading")]
|
||||
public bool DynamicBuildLoading { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using Daybreak.Services.ApplicationLauncher;
|
||||
using Daybreak.Services.ApplicationLifetime;
|
||||
using Daybreak.Services.Bloogum;
|
||||
using Daybreak.Services.BuildTemplates;
|
||||
using Daybreak.Services.Configuration;
|
||||
using Daybreak.Services.Credentials;
|
||||
using Daybreak.Services.IconRetrieve;
|
||||
using Daybreak.Services.Logging;
|
||||
using Daybreak.Services.Mutex;
|
||||
using Daybreak.Services.Runtime;
|
||||
using Daybreak.Services.Screenshots;
|
||||
using Daybreak.Services.Updater;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
@@ -14,7 +17,6 @@ using System.Extensions;
|
||||
|
||||
namespace Daybreak.Configuration
|
||||
{
|
||||
// TODO: Credit http://bloogum.net/guildwars/
|
||||
public static class ProjectConfiguration
|
||||
{
|
||||
public static void RegisterServices(IServiceProducer serviceProducer)
|
||||
@@ -32,6 +34,9 @@ namespace Daybreak.Configuration
|
||||
serviceProducer.RegisterSingleton<IBloogumClient, BloogumClient>();
|
||||
serviceProducer.RegisterSingleton<IApplicationUpdater, ApplicationUpdater>();
|
||||
serviceProducer.RegisterSingleton<IMutexHandler, MutexHandler>();
|
||||
serviceProducer.RegisterSingleton<IRuntimeStore, RuntimeStore>();
|
||||
serviceProducer.RegisterSingleton<IBuildTemplateManager, BuildTemplateManager>();
|
||||
serviceProducer.RegisterSingleton<IIconRetriever, IconRetriever>();
|
||||
}
|
||||
public static void RegisterLifetimeServices(IApplicationLifetimeProducer applicationLifetimeProducer)
|
||||
{
|
||||
@@ -53,6 +58,8 @@ namespace Daybreak.Configuration
|
||||
viewProducer.RegisterView<AccountsView>();
|
||||
viewProducer.RegisterView<ExperimentalSettingsView>();
|
||||
viewProducer.RegisterView<ExecutablesView>();
|
||||
viewProducer.RegisterView<BuildTemplateView>();
|
||||
viewProducer.RegisterView<BuildsListView>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<UserControl x:Class="Daybreak.Controls.HomeButton"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
|
||||
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" StrokeThickness="3" Width="60" Height="60"></Ellipse>
|
||||
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
|
||||
<Path Data="m42,45.384l-14,0l0,-13l-8,0l0,13l-14,0l0,-21c0,-0.552 0.447,-1 1,-1s1,0.448 1,1l0,19l10,0l0,-13l12,0l0,13l10,0l0,-18c0,-0.552 0.447,-1 1,-1s1,0.448 1,1l0,20z"
|
||||
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
|
||||
<Path Data="m47,24.384c-0.249,0 -0.497,-0.092 -0.691,-0.277l-22.309,-21.339l-22.309,21.339c-0.399,0.381 -1.032,0.368 -1.414,-0.031c-0.382,-0.399 -0.367,-1.032 0.031,-1.414l23.692,-22.662l23.691,22.661c0.398,0.382 0.413,1.015 0.031,1.414c-0.196,0.205 -0.458,0.309 -0.722,0.309z"
|
||||
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
|
||||
<Path Data="m39,12.384c-0.553,0 -1,-0.448 -1,-1l0,-6l-6,0c-0.553,0 -1,-0.448 -1,-1s0.447,-1 1,-1l8,0l0,8c0,0.552 -0.447,1 -1,1z"
|
||||
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
|
||||
</Grid>
|
||||
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Daybreak.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for HomeButton.xaml
|
||||
/// </summary>
|
||||
public partial class HomeButton : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
|
||||
public HomeButton()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
|
||||
{
|
||||
this.BackgroundEllipse.Opacity = 0.6;
|
||||
}
|
||||
|
||||
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
|
||||
{
|
||||
this.BackgroundEllipse.Opacity = 0;
|
||||
}
|
||||
|
||||
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.ChangedButton == MouseButton.Left)
|
||||
{
|
||||
Clicked?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<UserControl x:Class="Daybreak.Controls.MinusButton"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
|
||||
<Path Data="m13,26a13,13 0 1 1 13,-13a13,13 0 0 1 -13,13zm0,-24a11,11 0 1 0 11,11a11,11 0 0 0 -11,-11z"
|
||||
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
|
||||
<Path Data="m19,14l-12,0a1,1 0 0 1 0,-2l12,0a1,1 0 0 1 0,2z"
|
||||
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
|
||||
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Daybreak.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for AddButton.xaml
|
||||
/// </summary>
|
||||
public partial class MinusButton : UserControl
|
||||
{
|
||||
public event EventHandler Clicked;
|
||||
|
||||
public MinusButton()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
|
||||
{
|
||||
this.BackgroundEllipse.Opacity = 0.6;
|
||||
}
|
||||
|
||||
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
|
||||
{
|
||||
this.BackgroundEllipse.Opacity = 0;
|
||||
}
|
||||
|
||||
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.ChangedButton == MouseButton.Left)
|
||||
{
|
||||
Clicked?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,18 @@
|
||||
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" TriggerValue="True"></converters:BooleanToVisibilityConverter>
|
||||
<converters:BooleanToVisibilityConverter x:Key="ReverseBooleanToVisibilityConverter" TriggerValue="False"></converters:BooleanToVisibilityConverter>
|
||||
</UserControl.Resources>
|
||||
<UserControl.ContextMenu>
|
||||
<ContextMenu>
|
||||
<ContextMenu.Template>
|
||||
<ControlTemplate>
|
||||
<StackPanel Margin="10">
|
||||
<local:OpaqueButton Text="Load build template" Foreground="White" Background="#F0202020" BackgroundOpacity="0.4"
|
||||
Clicked="LoadBuildTemplateButton_Click" FontSize="16" Height="40" Width="200"></local:OpaqueButton>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
</ContextMenu.Template>
|
||||
</ContextMenu>
|
||||
</UserControl.ContextMenu>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
@@ -21,7 +33,8 @@
|
||||
</Grid.RowDefinitions>
|
||||
<wv2:WebView2 x:Name="WebBrowser" Source="{Binding ElementName=_this, Path=Address, Mode=TwoWay}"
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"></wv2:WebView2>
|
||||
<Grid Grid.Row="1" Background="#80808080" IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}">
|
||||
<Grid Grid.Row="1" Background="#80808080" IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
|
||||
Visibility="{Binding ElementName=_this, Path=ControlsEnabled, Mode=OneWay, Converter={StaticResource ReverseBooleanToVisibilityConverter}}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
@@ -55,6 +68,10 @@
|
||||
PreviewKeyDown="TextBox_PreviewKeyDown"
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"></TextBox>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal">
|
||||
<local:HomeButton Width="30" Height="30" Margin="5"
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
|
||||
Clicked="HomeButton_Clicked"></local:HomeButton>
|
||||
<local:StarGlyph Height="30" Width="30" Margin="5"
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using Daybreak.Launch;
|
||||
using Daybreak.Models.Browser;
|
||||
using Daybreak.Models.Builds;
|
||||
using Daybreak.Services.BuildTemplates;
|
||||
using Daybreak.Services.Configuration;
|
||||
using Daybreak.Services.Logging;
|
||||
using Daybreak.Utils;
|
||||
@@ -23,16 +26,32 @@ namespace Daybreak.Controls
|
||||
public readonly static DependencyProperty AddressProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, string>(nameof(Address));
|
||||
public readonly static DependencyProperty FavoriteAddressProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, string>(nameof(FavoriteAddress));
|
||||
public readonly static DependencyProperty NavigatingProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(Navigating));
|
||||
public readonly static DependencyProperty BrowserEnabledProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(BrowserEnabled));
|
||||
public readonly static DependencyProperty AddressBarReadonlyProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(AddressBarReadonly));
|
||||
public readonly static DependencyProperty BrowserSupportedProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(BrowserSupported), new PropertyMetadata(true));
|
||||
public readonly static DependencyProperty ControlsEnabledProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(ControlsEnabled), new PropertyMetadata(true));
|
||||
public readonly static DependencyProperty CanNavigateProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(CanNavigate), new PropertyMetadata(true));
|
||||
public readonly static DependencyProperty CanDownloadBuildProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(CanDownloadBuild), new PropertyMetadata(false));
|
||||
|
||||
public event EventHandler<string> FavoriteUriChanged;
|
||||
public event EventHandler MaximizeClicked;
|
||||
public event EventHandler<Build> BuildDecoded;
|
||||
|
||||
private readonly IConfigurationManager configurationManager;
|
||||
private readonly ILogger logger;
|
||||
private readonly IBuildTemplateManager buildTemplateManager;
|
||||
private CoreWebView2Environment coreWebView2Environment;
|
||||
|
||||
public bool CanDownloadBuild
|
||||
{
|
||||
get => this.GetTypedValue<bool>(CanDownloadBuildProperty);
|
||||
set => this.SetTypedValue<bool>(CanDownloadBuildProperty, value);
|
||||
}
|
||||
public bool CanNavigate
|
||||
{
|
||||
get => this.GetTypedValue<bool>(CanNavigateProperty);
|
||||
set => this.SetTypedValue<bool>(CanNavigateProperty, value);
|
||||
}
|
||||
public string Address
|
||||
{
|
||||
get => this.GetTypedValue<string>(AddressProperty);
|
||||
@@ -51,18 +70,29 @@ namespace Daybreak.Controls
|
||||
public bool AddressBarReadonly
|
||||
{
|
||||
get => this.GetTypedValue<bool>(AddressBarReadonlyProperty);
|
||||
private set => this.SetTypedValue<bool>(AddressBarReadonlyProperty, value);
|
||||
set => this.SetTypedValue<bool>(AddressBarReadonlyProperty, value);
|
||||
}
|
||||
public bool BrowserEnabled
|
||||
{
|
||||
get => this.GetTypedValue<bool>(BrowserEnabledProperty);
|
||||
private set => this.SetTypedValue<bool>(BrowserEnabledProperty, value);
|
||||
}
|
||||
public bool BrowserSupported
|
||||
{
|
||||
get => this.GetTypedValue<bool>(BrowserSupportedProperty);
|
||||
private set => this.SetTypedValue<bool>(BrowserSupportedProperty, value);
|
||||
}
|
||||
public bool ControlsEnabled
|
||||
{
|
||||
get => this.GetTypedValue<bool>(ControlsEnabledProperty);
|
||||
set => this.SetTypedValue<bool>(ControlsEnabledProperty, value);
|
||||
}
|
||||
|
||||
public ChromiumBrowserWrapper()
|
||||
{
|
||||
this.configurationManager = Launcher.ApplicationServiceManager.GetService<IConfigurationManager>();
|
||||
this.logger = Launcher.ApplicationServiceManager.GetService<ILogger>();
|
||||
this.buildTemplateManager = Launcher.ApplicationServiceManager.GetService<IBuildTemplateManager>();
|
||||
this.InitializeComponent();
|
||||
this.InitializeEnvironment();
|
||||
this.InitializeBrowser();
|
||||
@@ -77,13 +107,19 @@ namespace Daybreak.Controls
|
||||
}
|
||||
}
|
||||
|
||||
public void ReinitializeBrowser()
|
||||
public async void ReinitializeBrowser()
|
||||
{
|
||||
this.InitializeBrowser();
|
||||
await this.InitializeBrowser();
|
||||
}
|
||||
|
||||
private void InitializeEnvironment()
|
||||
{
|
||||
if (this.configurationManager.GetConfiguration().BrowsersEnabled is false)
|
||||
{
|
||||
this.BrowserSupported = false;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.coreWebView2Environment = System.Extensions.TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", null));
|
||||
@@ -102,9 +138,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,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)
|
||||
@@ -180,6 +285,11 @@ namespace Daybreak.Controls
|
||||
this.FavoriteUriChanged?.Invoke(this, this.FavoriteAddress);
|
||||
}
|
||||
|
||||
private void HomeButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.WebBrowser.CoreWebView2.Navigate(this.FavoriteAddress);
|
||||
}
|
||||
|
||||
private void MaximizeButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.MaximizeClicked?.Invoke(this, e);
|
||||
|
||||
@@ -0,0 +1,553 @@
|
||||
<UserControl x:Class="Daybreak.Controls.CircularLoadingWidget"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
Height="Auto" Width="Auto">
|
||||
<UserControl.Resources>
|
||||
<Storyboard x:Key="ProgressAnimation" RepeatBehavior="Forever">
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#8E000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#00000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block17" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#8E000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="Black"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block16" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#8E000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#EF000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block15" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#8E000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#E2000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block14" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#8E000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#D3000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block13" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#8E000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#C6000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block12" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#8E000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#B7000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block11" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#8E000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#AA000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block10" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#8E000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#23000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#9B000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block9" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#91000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block8" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#91000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#7F000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block7" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#91000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#72000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block6" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#91000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#63000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block5" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#91000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#56000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block4" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#91000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#3D000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block3" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#91000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#26000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block2" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#0C000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#91000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#19000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="block1" Storyboard.TargetProperty="(UIElement.OpacityMask).(SolidColorBrush.Color)">
|
||||
<SplineColorKeyFrame KeyTime="00:00:00" Value="#00000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.2290000" Value="Black"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.4590000" Value="#EF000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.6880000" Value="#E2000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:00.9180000" Value="#D3000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.1470000" Value="#C6000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.3760000" Value="#B7000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.6060000" Value="#AA000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:01.8350000" Value="#9B000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.0650000" Value="#8E000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.2940000" Value="#7F000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.5240000" Value="#72000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.7530000" Value="#63000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:02.9820000" Value="#56000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.2120000" Value="#3D000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.4410000" Value="#26000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.6710000" Value="#19000000"/>
|
||||
<SplineColorKeyFrame KeyTime="00:00:03.9000000" Value="#0C000000"/>
|
||||
</ColorAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</UserControl.Resources>
|
||||
<UserControl.Triggers>
|
||||
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
|
||||
<BeginStoryboard x:Name="ProgressAnimation_BeginStoryboard" Storyboard="{StaticResource ProgressAnimation}"/>
|
||||
</EventTrigger>
|
||||
</UserControl.Triggers>
|
||||
|
||||
<Viewbox>
|
||||
<Canvas x:Name="LayoutRoot" VerticalAlignment="Top" Height="88" Width="88">
|
||||
<Grid Width="10.734" Height="10.004" Canvas.Left="38.614" Canvas.Top="0.331">
|
||||
<Rectangle Fill="White" x:Name="block" RenderTransformOrigin="0.5,4.3689" OpacityMask="#00000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="180"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block1" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#0C000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="-160"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block2" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#19000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="-140"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block3" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#26000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="-119.99999999999999"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block4" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#3D000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="-100"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block5" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#56000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="-80"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block6" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#64000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="-59.999999999999993"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block7" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#72000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="-40"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block8" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#80000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="-19.999999999999996"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block9" Fill="White" OpacityMask="#8E000000" RenderTransformOrigin="0.5,4.3689" VerticalAlignment="Top" Height="10.004"/>
|
||||
<Rectangle x:Name="block10" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#9C000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="19.999999999999996"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block11" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#AA000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="40"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block12" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#B8000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="59.999999999999993"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block13" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#C6000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="80"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block14" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#D4000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="100"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block15" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#E2000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="119.99999999999999"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block16" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#F0000000" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="140"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="block17" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="Black" VerticalAlignment="Top" Height="10.004">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="160"/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
</Grid>
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for CircularLoadingWidget.xaml
|
||||
/// </summary>
|
||||
public partial class CircularLoadingWidget : UserControl
|
||||
{
|
||||
public CircularLoadingWidget()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnPropertyChanged(e);
|
||||
if (e.Property == IsEnabledProperty)
|
||||
{
|
||||
if (e.NewValue is true)
|
||||
{
|
||||
this.ProgressAnimation_BeginStoryboard.Storyboard.Pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ProgressAnimation_BeginStoryboard.Storyboard.Resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<UserControl x:Class="Daybreak.Controls.FireballGlyph"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
<Line Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
X1="15" X2="26" Y1="11" Y2="0"></Line>
|
||||
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Width="4" Height="4"
|
||||
Margin="8,13,13,8"></Ellipse>
|
||||
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Data="m15.025,0l-12.7,11.3c-3.1,3.1 -3.1,8.2 0,11.3s8.2,3.1 11.3,0l12.4,-11.6"></Path>
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Daybreak.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for FireballGlyph.xaml
|
||||
/// </summary>
|
||||
public partial class FireballGlyph : UserControl
|
||||
{
|
||||
public FireballGlyph()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<UserControl x:Class="Daybreak.Controls.AttributeTemplate"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="10, 0, 10, 0">
|
||||
<TextBlock Text="{Binding Attribute.Name}" FontSize="16" Foreground="White"></TextBlock>
|
||||
</WrapPanel>
|
||||
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="10, 0, 10, 0">
|
||||
<local:MinusButton Foreground="White" Height="20" Clicked="MinusButton_Clicked"></local:MinusButton>
|
||||
<TextBox Background="Transparent" Foreground="White" FontSize="16" IsReadOnly="True" Width="30"
|
||||
Text="{Binding Points}"></TextBox>
|
||||
<local:AddButton Foreground="White" Height="20" Clicked="AddButton_Clicked"></local:AddButton>
|
||||
</WrapPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,33 @@
|
||||
using Daybreak.Models.Builds;
|
||||
using System.Extensions;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for AttributeTemplate.xaml
|
||||
/// </summary>
|
||||
public partial class AttributeTemplate : UserControl
|
||||
{
|
||||
public AttributeTemplate()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MinusButton_Clicked(object sender, System.EventArgs e)
|
||||
{
|
||||
if (this.DataContext.As<AttributeEntry>().Points > 0)
|
||||
{
|
||||
this.DataContext.As<AttributeEntry>().Points--;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddButton_Clicked(object sender, System.EventArgs e)
|
||||
{
|
||||
if (this.DataContext.As<AttributeEntry>().Points < 12)
|
||||
{
|
||||
this.DataContext.As<AttributeEntry>().Points++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<UserControl x:Class="Daybreak.Controls.BuildEntryTemplate"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
xmlns:controls="clr-namespace:Daybreak.Controls"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<TextBlock FontSize="16" Foreground="White" Text="{Binding Name}" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
|
||||
<controls:BinButton Width="30" Height="30" Foreground="White" HorizontalAlignment="Right" Clicked="BinButton_Clicked"></controls:BinButton>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,27 @@
|
||||
using Daybreak.Models.Builds;
|
||||
using System;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for BuildEntryTemplate.xaml
|
||||
/// </summary>
|
||||
public partial class BuildEntryTemplate : UserControl
|
||||
{
|
||||
public event EventHandler<BuildEntry> RemoveClicked;
|
||||
|
||||
public BuildEntryTemplate()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void BinButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
if (this.DataContext is BuildEntry buildEntry)
|
||||
{
|
||||
this.RemoveClicked?.Invoke(this, buildEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
<UserControl x:Class="Daybreak.Controls.BuildTemplate"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
xmlns:interactivity="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
|
||||
xmlns:converters="clr-namespace:Daybreak.Converters"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid Background="Transparent" MouseLeftButtonDown="Grid_MouseLeftButtonDown">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="auto"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="Primary Profession: " FontSize="16" Foreground="White"></TextBlock>
|
||||
<ListView FontSize="16" Foreground="White" Grid.Column="1"
|
||||
Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Professions, Mode=OneWay}"
|
||||
SelectedItem="{Binding ElementName=_this, Path=PrimaryProfession, Mode=TwoWay}" Height="25"
|
||||
SelectionMode="Single" ScrollViewer.VerticalScrollBarVisibility="Disabled"
|
||||
PreviewMouseWheel="ListView_DisableMouseWheel">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Name, Mode=OneWay}"></TextBlock>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<behaviors:ScrollIntoView></behaviors:ScrollIntoView>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</ListView>
|
||||
</Grid>
|
||||
<Grid Grid.Row="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="Secondary Profession: " FontSize="16" Foreground="White"></TextBlock>
|
||||
<ListView FontSize="16" Foreground="White" Grid.Column="1"
|
||||
Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Professions, Mode=OneWay}"
|
||||
SelectedItem="{Binding ElementName=_this, Path=SecondaryProfession, Mode=TwoWay}" Height="25"
|
||||
SelectionMode="Single" ScrollViewer.VerticalScrollBarVisibility="Disabled"
|
||||
PreviewMouseWheel="ListView_DisableMouseWheel">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Name, Mode=OneWay}"></TextBlock>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<behaviors:ScrollIntoView></behaviors:ScrollIntoView>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</ListView>
|
||||
</Grid>
|
||||
<Grid Grid.Row="3">
|
||||
<ListBox Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Attributes, Mode=OneWay}"
|
||||
HorizontalContentAlignment="Stretch">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<local:AttributeTemplate></local:AttributeTemplate>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
<Grid Grid.Row="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
<local:SkillTemplate Grid.Column="0"
|
||||
Foreground="White"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill0, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<local:SkillTemplate Grid.Column="1"
|
||||
Foreground="White"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill1, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<local:SkillTemplate Grid.Column="2"
|
||||
Foreground="White"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill2, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<local:SkillTemplate Grid.Column="3"
|
||||
Foreground="White"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill3, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<local:SkillTemplate Grid.Column="4"
|
||||
Foreground="White"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill4, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<local:SkillTemplate Grid.Column="5"
|
||||
Foreground="White"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill5, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<local:SkillTemplate Grid.Column="6"
|
||||
Foreground="White"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill6, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<local:SkillTemplate Grid.Column="7"
|
||||
Foreground="White"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill7, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<TextBlock Grid.Column="0" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill0.Name, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Grid.Column="1" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill1.Name, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Grid.Column="2" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill2.Name, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Grid.Column="3" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill3.Name, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Grid.Column="4" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill4.Name, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Grid.Column="5" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill5.Name, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Grid.Column="6" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill6.Name, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Grid.Column="7" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill7.Name, Mode=OneWay}"></TextBlock>
|
||||
</Grid>
|
||||
<Grid Grid.Column="1" Grid.RowSpan="6">
|
||||
<local:ChromiumBrowserWrapper x:Name="SkillBrowser" ControlsEnabled="False" Width="0" AddressBarReadonly="True" CanNavigate="True"></local:ChromiumBrowserWrapper>
|
||||
</Grid>
|
||||
<Grid Grid.Column="1" Grid.RowSpan="6">
|
||||
<ListView x:Name="SkillsListView" Background="Transparent" Width="0"
|
||||
ItemsSource="{Binding ElementName=_this, Path=AvailableSkills, Mode=OneWay}" MouseDoubleClick="ListView_MouseDoubleClick">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock FontSize="16" Foreground="White" TextWrapping="Wrap" Text="{Binding Name}"></TextBlock>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,296 @@
|
||||
using Daybreak.Launch;
|
||||
using Daybreak.Models.Builds;
|
||||
using Daybreak.Services.IconRetrieve;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Extensions;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Daybreak.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for BuildTemplate.xaml
|
||||
/// </summary>
|
||||
public partial class BuildTemplate : UserControl
|
||||
{
|
||||
private const string SkillNamePlaceholder = "[NAME]";
|
||||
private const string BaseAddress = $"https://wiki.guildwars.com/wiki/{SkillNamePlaceholder}";
|
||||
|
||||
public readonly static DependencyProperty PrimaryProfessionProperty =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Profession>(nameof(PrimaryProfession), new PropertyMetadata(Profession.None));
|
||||
public readonly static DependencyProperty SecondaryProfessionProperty =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Profession>(nameof(SecondaryProfession), new PropertyMetadata(Profession.None));
|
||||
public readonly static DependencyProperty Skill0Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill0), new PropertyMetadata(Skill.NoSkill));
|
||||
public readonly static DependencyProperty Skill1Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill1), new PropertyMetadata(Skill.NoSkill));
|
||||
public readonly static DependencyProperty Skill2Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill2), new PropertyMetadata(Skill.NoSkill));
|
||||
public readonly static DependencyProperty Skill3Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill3), new PropertyMetadata(Skill.NoSkill));
|
||||
public readonly static DependencyProperty Skill4Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill4), new PropertyMetadata(Skill.NoSkill));
|
||||
public readonly static DependencyProperty Skill5Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill5), new PropertyMetadata(Skill.NoSkill));
|
||||
public readonly static DependencyProperty Skill6Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill6), new PropertyMetadata(Skill.NoSkill));
|
||||
public readonly static DependencyProperty Skill7Property =
|
||||
DependencyPropertyExtensions.Register<BuildTemplate, Skill>(nameof(Skill7), new PropertyMetadata(Skill.NoSkill));
|
||||
|
||||
private BuildEntry loadedBuild;
|
||||
private SkillTemplate selectingSkillTemplate;
|
||||
|
||||
public Profession PrimaryProfession
|
||||
{
|
||||
get => this.GetTypedValue<Profession>(PrimaryProfessionProperty);
|
||||
set => this.SetValue(PrimaryProfessionProperty, value);
|
||||
}
|
||||
public Profession SecondaryProfession
|
||||
{
|
||||
get => this.GetTypedValue<Profession>(SecondaryProfessionProperty);
|
||||
set => this.SetValue(SecondaryProfessionProperty, value);
|
||||
}
|
||||
public Skill Skill0
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill0Property);
|
||||
set => this.SetValue(Skill0Property, value);
|
||||
}
|
||||
public Skill Skill1
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill1Property);
|
||||
set => this.SetValue(Skill1Property, value);
|
||||
}
|
||||
public Skill Skill2
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill2Property);
|
||||
set => this.SetValue(Skill2Property, value);
|
||||
}
|
||||
public Skill Skill3
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill3Property);
|
||||
set => this.SetValue(Skill3Property, value);
|
||||
}
|
||||
public Skill Skill4
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill4Property);
|
||||
set => this.SetValue(Skill4Property, value);
|
||||
}
|
||||
public Skill Skill5
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill5Property);
|
||||
set => this.SetValue(Skill5Property, value);
|
||||
}
|
||||
public Skill Skill6
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill6Property);
|
||||
set => this.SetValue(Skill6Property, value);
|
||||
}
|
||||
public Skill Skill7
|
||||
{
|
||||
get => this.GetTypedValue<Skill>(Skill7Property);
|
||||
set => this.SetValue(Skill7Property, value);
|
||||
}
|
||||
public ObservableCollection<Skill> AvailableSkills { get; } = new ObservableCollection<Skill>();
|
||||
public ObservableCollection<AttributeEntry> Attributes { get; } = new ObservableCollection<AttributeEntry>();
|
||||
public ObservableCollection<Profession> Professions { get; } = new ObservableCollection<Profession>(Profession.Professions);
|
||||
|
||||
public BuildTemplate()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.DataContextChanged += BuildTemplate_DataContextChanged;
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnPropertyChanged(e);
|
||||
if (e.Property == PrimaryProfessionProperty || e.Property == SecondaryProfessionProperty)
|
||||
{
|
||||
if (e.Property == PrimaryProfessionProperty)
|
||||
{
|
||||
this.loadedBuild.Build.Primary = this.PrimaryProfession;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.loadedBuild.Build.Secondary = this.SecondaryProfession;
|
||||
}
|
||||
this.LoadSkills();
|
||||
this.LoadAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if(e.NewValue is BuildEntry)
|
||||
{
|
||||
this.LoadBuild();
|
||||
this.LoadSkills();
|
||||
this.LoadAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
private void Grid_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
this.SkillBrowser.Width = 0;
|
||||
this.SkillsListView.Width = 0;
|
||||
}
|
||||
|
||||
private void LoadAttributes()
|
||||
{
|
||||
var possibleAttributes = new List<AttributeEntry>();
|
||||
if (this.PrimaryProfession != Profession.None)
|
||||
{
|
||||
possibleAttributes.Add(new AttributeEntry { Attribute = this.PrimaryProfession.PrimaryAttribute });
|
||||
possibleAttributes.AddRange(this.PrimaryProfession.Attributes.Select(a => new AttributeEntry { Attribute = a }));
|
||||
}
|
||||
|
||||
if (this.SecondaryProfession != Profession.None && this.SecondaryProfession != this.PrimaryProfession)
|
||||
{
|
||||
possibleAttributes.AddRange(this.SecondaryProfession.Attributes.Select(a => new AttributeEntry { Attribute = a }));
|
||||
}
|
||||
|
||||
this.Attributes.ClearAnd().AddRange(possibleAttributes.Select(entry =>
|
||||
{
|
||||
var maybePresentAttribute = this.loadedBuild.Build.Attributes.Where(buildEntry => entry.Attribute == buildEntry.Attribute).FirstOrDefault();
|
||||
if (maybePresentAttribute is null)
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
entry.Points = maybePresentAttribute.Points;
|
||||
return entry;
|
||||
}));
|
||||
|
||||
this.loadedBuild.Build.Attributes = this.Attributes.ToList();
|
||||
}
|
||||
|
||||
private void LoadSkills()
|
||||
{
|
||||
var possibleSkills = Skill.Skills
|
||||
.Where(s => s.Profession == PrimaryProfession || s.Profession == SecondaryProfession || s.Profession == Profession.None)
|
||||
.Where(s => s != Skill.NoSkill)
|
||||
.OrderBy(s => s.Name);
|
||||
this.AvailableSkills.ClearAnd().AddRange(possibleSkills);
|
||||
|
||||
if (this.Skill0.Profession != PrimaryProfession &&
|
||||
this.Skill0.Profession != SecondaryProfession &&
|
||||
this.Skill0.Profession != Profession.None)
|
||||
{
|
||||
this.Skill0 = Skill.NoSkill;
|
||||
}
|
||||
if (this.Skill1.Profession != PrimaryProfession &&
|
||||
this.Skill1.Profession != SecondaryProfession &&
|
||||
this.Skill1.Profession != Profession.None)
|
||||
{
|
||||
this.Skill1 = Skill.NoSkill;
|
||||
}
|
||||
if (this.Skill2.Profession != PrimaryProfession &&
|
||||
this.Skill2.Profession != SecondaryProfession &&
|
||||
this.Skill2.Profession != Profession.None)
|
||||
{
|
||||
this.Skill2 = Skill.NoSkill;
|
||||
}
|
||||
if (this.Skill3.Profession != PrimaryProfession &&
|
||||
this.Skill3.Profession != SecondaryProfession &&
|
||||
this.Skill3.Profession != Profession.None)
|
||||
{
|
||||
this.Skill3 = Skill.NoSkill;
|
||||
}
|
||||
if (this.Skill4.Profession != PrimaryProfession &&
|
||||
this.Skill4.Profession != SecondaryProfession &&
|
||||
this.Skill4.Profession != Profession.None)
|
||||
{
|
||||
this.Skill4 = Skill.NoSkill;
|
||||
}
|
||||
if (this.Skill5.Profession != PrimaryProfession &&
|
||||
this.Skill5.Profession != SecondaryProfession &&
|
||||
this.Skill5.Profession != Profession.None)
|
||||
{
|
||||
this.Skill5 = Skill.NoSkill;
|
||||
}
|
||||
if (this.Skill6.Profession != PrimaryProfession &&
|
||||
this.Skill6.Profession != SecondaryProfession &&
|
||||
this.Skill6.Profession != Profession.None)
|
||||
{
|
||||
this.Skill6 = Skill.NoSkill;
|
||||
}
|
||||
if (this.Skill7.Profession != PrimaryProfession &&
|
||||
this.Skill7.Profession != SecondaryProfession &&
|
||||
this.Skill7.Profession != Profession.None)
|
||||
{
|
||||
this.Skill7 = Skill.NoSkill;
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadBuild()
|
||||
{
|
||||
var build = this.DataContext.As<BuildEntry>();
|
||||
this.loadedBuild = build;
|
||||
this.PrimaryProfession = build.Build.Primary;
|
||||
this.SecondaryProfession = build.Build.Secondary;
|
||||
this.Skill0 = build.Build.Skills[0];
|
||||
this.Skill1 = build.Build.Skills[1];
|
||||
this.Skill2 = build.Build.Skills[2];
|
||||
this.Skill3 = build.Build.Skills[3];
|
||||
this.Skill4 = build.Build.Skills[4];
|
||||
this.Skill5 = build.Build.Skills[5];
|
||||
this.Skill6 = build.Build.Skills[6];
|
||||
this.Skill7 = build.Build.Skills[7];
|
||||
}
|
||||
|
||||
private void SkillTemplate_Clicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var skill = sender.As<SkillTemplate>().DataContext.As<Skill>();
|
||||
if (skill == Skill.NoSkill)
|
||||
{
|
||||
this.SkillsListView.Width = 400;
|
||||
this.SkillBrowser.Width = 0;
|
||||
this.selectingSkillTemplate = sender.As<SkillTemplate>();
|
||||
}
|
||||
else
|
||||
{
|
||||
var address = BaseAddress.Replace(SkillNamePlaceholder, skill.Name.Replace(" ", "_"));
|
||||
this.SkillBrowser.Address = address;
|
||||
this.SkillBrowser.Width = 400;
|
||||
this.SkillsListView.Width = 0;
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void SkillTemplate_RemoveClicked(object sender, System.EventArgs e)
|
||||
{
|
||||
sender.As<SkillTemplate>().DataContext = Skill.NoSkill;
|
||||
}
|
||||
|
||||
private void ListView_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
if (this.selectingSkillTemplate is null)
|
||||
{
|
||||
this.SkillsListView.Width = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectingSkillTemplate.DataContext = sender.As<ListView>().SelectedItem;
|
||||
this.SkillsListView.Width = 0;
|
||||
this.loadedBuild.Build.Skills[0] = Skill0;
|
||||
this.loadedBuild.Build.Skills[1] = Skill1;
|
||||
this.loadedBuild.Build.Skills[2] = Skill2;
|
||||
this.loadedBuild.Build.Skills[3] = Skill3;
|
||||
this.loadedBuild.Build.Skills[4] = Skill4;
|
||||
this.loadedBuild.Build.Skills[5] = Skill5;
|
||||
this.loadedBuild.Build.Skills[6] = Skill6;
|
||||
this.loadedBuild.Build.Skills[7] = Skill7;
|
||||
}
|
||||
|
||||
private void ListView_DisableMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<UserControl x:Class="Daybreak.Controls.SkillTemplate"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
<Image VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
|
||||
Source="{Binding ElementName=_this, Path=ImageSource, Mode=OneWay}"></Image>
|
||||
<Border BorderThickness="5" BorderBrush="Black"></Border>
|
||||
<Border BorderThickness="5" BorderBrush="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Opacity="{Binding ElementName=_this, Path=BorderOpacity, Mode=OneWay}"></Border>
|
||||
<Rectangle Fill="Transparent" MouseEnter="Border_MouseEnter" MouseLeave="Border_MouseLeave"
|
||||
VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MouseLeftButtonDown="Rectangle_MouseLeftButtonDown"></Rectangle>
|
||||
<local:CancelButton x:Name="CancelButton" Width="30" Height="30" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10"
|
||||
Visibility="Hidden" Foreground="White" Clicked="CancelButton_Clicked" MouseEnter="Border_MouseEnter"
|
||||
MouseLeave="Border_MouseLeave"></local:CancelButton>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,114 @@
|
||||
using Daybreak.Launch;
|
||||
using Daybreak.Models.Builds;
|
||||
using Daybreak.Services.IconRetrieve;
|
||||
using System;
|
||||
using System.Extensions;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Daybreak.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for SkillTemplate.xaml
|
||||
/// </summary>
|
||||
public partial class SkillTemplate : UserControl
|
||||
{
|
||||
public readonly static DependencyProperty ImageSourceProperty =
|
||||
DependencyPropertyExtensions.Register<SkillTemplate, ImageSource>(nameof(ImageSource));
|
||||
public readonly static DependencyProperty BorderOpacityProperty =
|
||||
DependencyPropertyExtensions.Register<SkillTemplate, double>(nameof(BorderOpacity), new PropertyMetadata(0d));
|
||||
|
||||
public event EventHandler<RoutedEventArgs> Clicked;
|
||||
public event EventHandler RemoveClicked;
|
||||
|
||||
private readonly IIconRetriever iconRetriever;
|
||||
|
||||
public ImageSource ImageSource
|
||||
{
|
||||
get => this.GetTypedValue<ImageSource>(ImageSourceProperty);
|
||||
set => this.SetValue(ImageSourceProperty, value);
|
||||
}
|
||||
public double BorderOpacity
|
||||
{
|
||||
get => this.GetTypedValue<double>(BorderOpacityProperty);
|
||||
set => this.SetValue(BorderOpacityProperty, value);
|
||||
}
|
||||
|
||||
public SkillTemplate()
|
||||
{
|
||||
this.iconRetriever = Launcher.ApplicationServiceManager.GetService<IIconRetriever>();
|
||||
this.InitializeComponent();
|
||||
this.DataContextChanged += SkillTemplate_DataContextChanged;
|
||||
}
|
||||
|
||||
private void SkillTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.NewValue is Skill)
|
||||
{
|
||||
Task.Run(() => GetImageStream(e.NewValue.As<Skill>())).ContinueWith((previousTask) =>
|
||||
{
|
||||
this.Dispatcher.Invoke(() =>
|
||||
{
|
||||
this.ImageSource = GetImageSource(previousTask.Result);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void Border_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
|
||||
{
|
||||
this.BorderOpacity = 1;
|
||||
this.CancelButton.Visibility = this.HasSkill() ? Visibility.Visible : Visibility.Hidden;
|
||||
}
|
||||
private void Border_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
|
||||
{
|
||||
this.BorderOpacity = 0;
|
||||
this.CancelButton.Visibility = Visibility.Hidden;
|
||||
}
|
||||
private void Rectangle_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
this.Clicked?.Invoke(this, e);
|
||||
}
|
||||
private void CancelButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.RemoveClicked?.Invoke(this, e);
|
||||
}
|
||||
|
||||
private bool HasSkill()
|
||||
{
|
||||
if (this.DataContext is Skill skill)
|
||||
{
|
||||
return skill != Skill.NoSkill;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
private async Task<Stream> GetImageStream(Skill skill)
|
||||
{
|
||||
var maybeStream = await this.iconRetriever.GetIcon(skill);
|
||||
return maybeStream.ExtractValue();
|
||||
}
|
||||
private ImageSource GetImageSource(Stream stream)
|
||||
{
|
||||
if (stream is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.Dispatcher.Invoke(() =>
|
||||
{
|
||||
var bitmapImage = new BitmapImage();
|
||||
bitmapImage.BeginInit();
|
||||
bitmapImage.StreamSource = stream;
|
||||
bitmapImage.CacheOption = BitmapCacheOption.OnDemand;
|
||||
bitmapImage.EndInit();
|
||||
return bitmapImage;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,39 +9,47 @@
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
|
||||
<Version>0.6.3</Version>
|
||||
<Version>0.7.2</Version>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.774.44" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.33" />
|
||||
<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.1.1" />
|
||||
<PackageReference Include="WpfExtended" Version="0.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Controls\StarGlyph.xaml.cs">
|
||||
<Compile Update="Controls\Buttons\MinusButton.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Controls\CancelButton.xaml.cs">
|
||||
<Compile Update="Controls\Glyphs\StarGlyph.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Controls\Buttons\CancelButton.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\MaximizeButton.xaml">
|
||||
<Page Update="Controls\Buttons\MinusButton.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Controls\StarGlyph.xaml">
|
||||
<Page Update="Controls\Buttons\MaximizeButton.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Controls\CancelButton.xaml">
|
||||
<Page Update="Controls\Glyphs\StarGlyph.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Controls\Buttons\CancelButton.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
|
||||
@@ -69,8 +69,6 @@
|
||||
</controls:ImageViewer.Effect>
|
||||
</controls:ImageViewer>
|
||||
</Border>
|
||||
<Grid x:Name="Container" Grid.Row="1">
|
||||
</Grid>
|
||||
<wcl:TitleBar x:Name="Titlebar"
|
||||
Background="Transparent" MouseLeftButtonDown="TitleBar_MouseLeftButtonDown"
|
||||
WindowState="Normal" MinimizeButtonClicked="TitleBar_MinimizeButtonClicked"
|
||||
@@ -80,10 +78,15 @@
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></wcl:TitleBar>
|
||||
<ToggleButton Style="{StaticResource Window_SettingsButton}" Width="50" Height="30" HorizontalAlignment="Right"
|
||||
Margin="0, 0, 150, 0" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Click="SettingsButton_Clicked"></ToggleButton>
|
||||
<TextBox Grid.Row="1" Background="Transparent" BorderBrush="Transparent" BorderThickness="0" Opacity="0.6"
|
||||
Text="{Binding ElementName=_this, Path=CreditText, Mode=OneWay}" IsReadOnly="True" VerticalAlignment="Bottom"
|
||||
<controls:OpaqueButton Grid.Row="1" Background="Transparent" BorderBrush="Transparent" BorderThickness="0" Opacity="0.6"
|
||||
Text="{Binding ElementName=_this, Path=CreditText, Mode=OneWay}" VerticalAlignment="Bottom"
|
||||
HorizontalAlignment="Right" Margin="0, 0, 20, 30" FontSize="22" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
PreviewMouseLeftButtonDown="CreditTextBox_MouseLeftButtonDown" Cursor="Hand"></TextBox>
|
||||
Clicked="CreditTextBox_MouseLeftButtonDown" Cursor="Hand"></controls:OpaqueButton>
|
||||
<TextBox Grid.Row="1" Background="Transparent" BorderBrush="Transparent" BorderThickness="0" Opacity="0.6"
|
||||
Text="{Binding ElementName=_this, Path=CurrentVersionText, Mode=OneWay}" IsReadOnly="True" VerticalAlignment="Bottom"
|
||||
HorizontalAlignment="Right" Margin="0, 0, 20, 10" FontSize="10" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></TextBox>
|
||||
<Grid x:Name="Container" Grid.Row="1">
|
||||
</Grid>
|
||||
<wcl:Border OnResize="Border_OnResize" Grid.RowSpan="2" Active="True"></wcl:Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Daybreak.Services.Bloogum;
|
||||
using Daybreak.Services.Runtime;
|
||||
using Daybreak.Services.Screenshots;
|
||||
using Daybreak.Services.Updater;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
@@ -23,6 +24,7 @@ namespace Daybreak.Launch
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public static readonly DependencyProperty CreditTextProperty = DependencyPropertyExtensions.Register<MainWindow, string>(nameof(CreditText));
|
||||
public static readonly DependencyProperty CurrentVersionTextProperty = DependencyPropertyExtensions.Register<MainWindow, string>(nameof(CurrentVersionText));
|
||||
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly IScreenshotProvider screenshotProvider;
|
||||
@@ -36,6 +38,12 @@ namespace Daybreak.Launch
|
||||
set => this.SetValue(CreditTextProperty, value);
|
||||
}
|
||||
|
||||
public string CurrentVersionText
|
||||
{
|
||||
get => this.GetTypedValue<string>(CurrentVersionTextProperty);
|
||||
set => this.SetValue(CurrentVersionTextProperty, value);
|
||||
}
|
||||
|
||||
public MainWindow(
|
||||
IViewManager viewManager,
|
||||
IScreenshotProvider screenshotProvider,
|
||||
@@ -46,7 +54,8 @@ namespace Daybreak.Launch
|
||||
this.screenshotProvider = screenshotProvider.ThrowIfNull(nameof(screenshotProvider));
|
||||
this.bloogumClient = bloogumClient.ThrowIfNull(nameof(bloogumClient));
|
||||
this.applicationUpdater = applicationUpdater.ThrowIfNull(nameof(applicationUpdater));
|
||||
InitializeComponent();
|
||||
this.InitializeComponent();
|
||||
this.CurrentVersionText = this.applicationUpdater.CurrentVersion;
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
@@ -123,7 +132,7 @@ namespace Daybreak.Launch
|
||||
this.viewManager.ShowView<SettingsCategoryView>();
|
||||
}
|
||||
|
||||
private void CreditTextBox_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
private void CreditTextBox_MouseLeftButtonDown(object sender, EventArgs e)
|
||||
{
|
||||
if (Uri.TryCreate(this.CreditText, UriKind.Absolute, out var uri))
|
||||
{
|
||||
@@ -165,13 +174,7 @@ namespace Daybreak.Launch
|
||||
|
||||
private void PeriodicallyCheckForUpdates()
|
||||
{
|
||||
TaskExtensions.RunPeriodicAsync(async () =>
|
||||
{
|
||||
if (await this.applicationUpdater.UpdateAvailable())
|
||||
{
|
||||
this.Dispatcher.Invoke(() => this.viewManager.ShowView<AskUpdateView>());
|
||||
}
|
||||
}, TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(15), CancellationToken.None);
|
||||
this.applicationUpdater.PeriodicallyCheckForUpdates();
|
||||
}
|
||||
|
||||
private static Color GetAverageColor(BitmapSource bitmap)
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 };
|
||||
}
|
||||
}
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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,351 @@
|
||||
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);
|
||||
File.WriteAllText($"{BuildsPath}\\{buildEntry.Name}.txt", encodedBuild);
|
||||
if (string.IsNullOrWhiteSpace(buildEntry.PreviousName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
File.Delete($"{BuildsPath}\\{buildEntry.PreviousName}.txt");
|
||||
}
|
||||
|
||||
public void RemoveBuild(BuildEntry buildEntry)
|
||||
{
|
||||
if (File.Exists($"{BuildsPath}\\{buildEntry.Name}.txt"))
|
||||
{
|
||||
File.Delete($"{BuildsPath}\\{buildEntry.Name}.txt");
|
||||
}
|
||||
|
||||
if (File.Exists($"{BuildsPath}\\{buildEntry.PreviousName}.txt"))
|
||||
{
|
||||
File.Delete($"{BuildsPath}\\{buildEntry.PreviousName}.txt");
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<BuildEntry> GetBuilds()
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(BuildsPath))
|
||||
{
|
||||
Build build = default;
|
||||
try
|
||||
{
|
||||
build = this.DecodeTemplate(File.ReadAllText(file));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
this.logger.LogError($"Failed to decode template from file {file}. Details: {e}");
|
||||
}
|
||||
|
||||
if (build is not null)
|
||||
{
|
||||
yield return new BuildEntry { Build = build, Name = Path.GetFileNameWithoutExtension(file), PreviousName = Path.GetFileNameWithoutExtension(file) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Build DecodeTemplate(string template)
|
||||
{
|
||||
return this.DecodeTemplateInner(template);
|
||||
}
|
||||
|
||||
public string EncodeTemplate(Build build)
|
||||
{
|
||||
return this.EncodeTemplateInner(build);
|
||||
}
|
||||
|
||||
private Build DecodeTemplateInner(string template)
|
||||
{
|
||||
this.logger.LogInformation("Attempting to decode template");
|
||||
var buildMetadata = ParseEncodedTemplate(template);
|
||||
this.logger.LogInformation("Decoded template. Beginning parsing");
|
||||
if (buildMetadata.VersionNumber != 0)
|
||||
{
|
||||
this.logger.LogError($"Expected version number to be 0 but found {buildMetadata.VersionNumber}");
|
||||
throw new InvalidOperationException($"Failed to parse template");
|
||||
}
|
||||
|
||||
var build = new Build()
|
||||
{
|
||||
BuildMetadata = buildMetadata,
|
||||
Skills = new()
|
||||
};
|
||||
|
||||
if (Profession.TryParse(buildMetadata.PrimaryProfessionId, out var primaryProfession) is false)
|
||||
{
|
||||
this.logger.LogError($"Failed to parse profession with id {buildMetadata.PrimaryProfessionId}");
|
||||
throw new InvalidOperationException($"Failed to parse template");
|
||||
}
|
||||
|
||||
build.Primary = primaryProfession;
|
||||
if (Profession.TryParse(buildMetadata.SecondaryProfessionId, out var secondaryProfession) is false)
|
||||
{
|
||||
this.logger.LogError($"Failed to parse profession with id {buildMetadata.SecondaryProfessionId}");
|
||||
throw new InvalidOperationException($"Failed to parse template");
|
||||
}
|
||||
|
||||
build.Secondary = secondaryProfession;
|
||||
for(int i = 0; i < buildMetadata.AttributeCount; i++)
|
||||
{
|
||||
if (Daybreak.Models.Builds.Attribute.TryParse(buildMetadata.AttributesIds[i], out var attribute) is false)
|
||||
{
|
||||
this.logger.LogError($"Failed to parse attribute with id {buildMetadata.AttributesIds[i]}");
|
||||
throw new InvalidOperationException($"Failed to parse template");
|
||||
}
|
||||
|
||||
build.Attributes.Add(new AttributeEntry { Attribute = attribute, Points = buildMetadata.AttributePoints[i] });
|
||||
}
|
||||
|
||||
for(int i = 0; i < 8; i++)
|
||||
{
|
||||
if (Skill.TryParse(buildMetadata.SkillIds[i], out var skill) is false)
|
||||
{
|
||||
this.logger.LogError($"Failed to parse skill with id {buildMetadata.SkillIds[i]}");
|
||||
throw new InvalidOperationException($"Failed to parse template");
|
||||
}
|
||||
|
||||
build.Skills.Add(skill);
|
||||
}
|
||||
|
||||
return build;
|
||||
}
|
||||
|
||||
private string EncodeTemplateInner(Build build)
|
||||
{
|
||||
this.logger.LogInformation("Building build metadata");
|
||||
var buildMetadata = new BuildMetadata
|
||||
{
|
||||
VersionNumber = 0,
|
||||
NewTemplate = true,
|
||||
Header = 14,
|
||||
PrimaryProfessionId = build.Primary.Id,
|
||||
SecondaryProfessionId = build.Secondary.Id,
|
||||
AttributeCount = build.Attributes.Count,
|
||||
AttributesIds = build.Attributes.Select(attrEntry => attrEntry.Attribute.Id).ToList(),
|
||||
AttributePoints = build.Attributes.Select(attrEntry => attrEntry.Points).ToList(),
|
||||
SkillIds = build.Skills.Select(skill => skill.Id).ToList(),
|
||||
TailPresent = true
|
||||
};
|
||||
|
||||
this.logger.LogInformation("Encoding metadata into binary");
|
||||
var encodedBinary = BuildEncodedString(buildMetadata);
|
||||
int index = 0;
|
||||
var encodedBase64 = new List<int>();
|
||||
while (index < encodedBinary.Length)
|
||||
{
|
||||
var subset = new string(encodedBinary.Skip(index).Take(6).ToArray());
|
||||
encodedBase64.Add(FromBitString(subset));
|
||||
index += 6;
|
||||
}
|
||||
|
||||
var template = new string(encodedBase64.Select(b => DecodingLookupTable[b]).ToArray());
|
||||
return template;
|
||||
}
|
||||
|
||||
private static string ToBitString(int value)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
while(value > 0)
|
||||
{
|
||||
sb.Append(value % 2 == 1 ? 1 : 0);
|
||||
value /= 2;
|
||||
}
|
||||
|
||||
while(sb.Length < 6)
|
||||
{
|
||||
sb.Append(0);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static BuildMetadata ParseEncodedTemplate(string template)
|
||||
{
|
||||
var curedTemplate = template.Trim();
|
||||
|
||||
var buildMetadata = new BuildMetadata();
|
||||
buildMetadata.Base64Decoded = template.Select(c => DecodingLookupTable.IndexOf(c)).ToList();
|
||||
buildMetadata.BinaryDecoded = buildMetadata.Base64Decoded.Select(b => ToBitString(b)).ToList();
|
||||
|
||||
var stream = new DecodeCharStream(buildMetadata.BinaryDecoded.ToArray());
|
||||
buildMetadata.Header = stream.Read(4);
|
||||
if (buildMetadata.Header == 14)
|
||||
{
|
||||
buildMetadata.VersionNumber = stream.Read(4);
|
||||
buildMetadata.NewTemplate = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
buildMetadata.VersionNumber = buildMetadata.Header;
|
||||
buildMetadata.NewTemplate = false;
|
||||
}
|
||||
|
||||
buildMetadata.ProfessionIdLength = stream.Read(2) * 2 + 4;
|
||||
buildMetadata.PrimaryProfessionId = stream.Read(buildMetadata.ProfessionIdLength);
|
||||
buildMetadata.SecondaryProfessionId = stream.Read(buildMetadata.ProfessionIdLength);
|
||||
buildMetadata.AttributeCount = stream.Read(4);
|
||||
buildMetadata.AttributesLength = stream.Read(4) + 4;
|
||||
for (int i = 0; i < buildMetadata.AttributeCount; i++)
|
||||
{
|
||||
buildMetadata.AttributesIds.Add(stream.Read(buildMetadata.AttributesLength));
|
||||
buildMetadata.AttributePoints.Add(stream.Read(4));
|
||||
}
|
||||
|
||||
buildMetadata.SkillsLength = stream.Read(4) + 8;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
buildMetadata.SkillIds.Add(stream.Read(buildMetadata.SkillsLength));
|
||||
}
|
||||
|
||||
if (stream.Position < stream.Length - 1)
|
||||
{
|
||||
buildMetadata.TailPresent = true;
|
||||
}
|
||||
|
||||
return buildMetadata;
|
||||
}
|
||||
|
||||
private static string BuildEncodedString(BuildMetadata buildMetadata)
|
||||
{
|
||||
var stream = new EncodeCharStream();
|
||||
if(buildMetadata.NewTemplate || buildMetadata.Header == 14)
|
||||
{
|
||||
stream.Write(14, 4);
|
||||
}
|
||||
|
||||
stream.Write(0, 4);
|
||||
|
||||
var desiredProfessionIdLength = GetBitLength(new List<int> { buildMetadata.PrimaryProfessionId, buildMetadata.SecondaryProfessionId }.Max());
|
||||
var professionIdLength = Math.Max((desiredProfessionIdLength - 4) / 2, 0);
|
||||
var finalProfessionIdLength = professionIdLength * 2 + 4;
|
||||
stream.Write(professionIdLength, 2);
|
||||
stream.Write(buildMetadata.PrimaryProfessionId, finalProfessionIdLength);
|
||||
stream.Write(buildMetadata.SecondaryProfessionId, finalProfessionIdLength);
|
||||
|
||||
stream.Write(buildMetadata.AttributeCount, 4);
|
||||
var desiredAttributesLength = GetBitLength(buildMetadata.AttributesIds.Any() ? buildMetadata.AttributesIds.Max() : 0);
|
||||
var attributesLength = Math.Max(desiredAttributesLength - 4, 0);
|
||||
var finalAttributesLength = attributesLength + 4;
|
||||
stream.Write(attributesLength, 4);
|
||||
for(int i = 0; i < buildMetadata.AttributeCount; i++)
|
||||
{
|
||||
stream.Write(buildMetadata.AttributesIds[i], finalAttributesLength);
|
||||
stream.Write(buildMetadata.AttributePoints[i], 4);
|
||||
}
|
||||
|
||||
var desiredSkillsLength = GetBitLength(buildMetadata.SkillIds.Max());
|
||||
var skillsLength = Math.Max(desiredSkillsLength - 8, 0);
|
||||
var finalSkillsLength = skillsLength + 8;
|
||||
stream.Write(skillsLength, 4);
|
||||
for(int i = 0; i < 8; i++)
|
||||
{
|
||||
stream.Write(buildMetadata.SkillIds[i], finalSkillsLength);
|
||||
}
|
||||
|
||||
if (buildMetadata.TailPresent)
|
||||
{
|
||||
stream.Write(0, 1);
|
||||
}
|
||||
|
||||
return stream.GetEncodedString();
|
||||
}
|
||||
|
||||
private static int GetBitLength(int value)
|
||||
{
|
||||
int decimals = 1;
|
||||
value /= 2;
|
||||
while (value > 0)
|
||||
{
|
||||
decimals++;
|
||||
value /= 2;
|
||||
}
|
||||
|
||||
return decimals;
|
||||
}
|
||||
|
||||
private static int FromBitString(string bitString)
|
||||
{
|
||||
var sb = new StringBuilder(bitString);
|
||||
while (sb.Length < 6)
|
||||
{
|
||||
sb.Append('0');
|
||||
}
|
||||
|
||||
bitString = sb.ToString();
|
||||
var value = 0d;
|
||||
for (int i = 0; i < bitString.Length; i++)
|
||||
{
|
||||
value += bitString[i] == '1' ? Math.Pow(2, i) : 0;
|
||||
}
|
||||
|
||||
return (int)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Daybreak.Services.Runtime
|
||||
{
|
||||
public interface IRuntimeStore
|
||||
{
|
||||
void StoreValue<T>(string name, T value);
|
||||
bool TryGetValue<T>(string name, out T value);
|
||||
T GetValue<T>(string name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Extensions;
|
||||
|
||||
namespace Daybreak.Services.Runtime
|
||||
{
|
||||
public sealed class RuntimeStore : IRuntimeStore
|
||||
{
|
||||
private Dictionary<string, object> InnerStore { get; } = new Dictionary<string, object>();
|
||||
|
||||
public T GetValue<T>(string name)
|
||||
{
|
||||
if(this.InnerStore.TryGetValue(name, out var value))
|
||||
{
|
||||
return value.Cast<T>();
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Could not find any value stored with name {name}");
|
||||
}
|
||||
public void StoreValue<T>(string name, T value)
|
||||
{
|
||||
this.InnerStore[name] = value;
|
||||
}
|
||||
public bool TryGetValue<T>(string name, out T value)
|
||||
{
|
||||
if (this.InnerStore.TryGetValue(name, out var valueObj))
|
||||
{
|
||||
value = valueObj.Cast<T>();
|
||||
return true;
|
||||
}
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Services.Logging;
|
||||
using Daybreak.Services.Runtime;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using Daybreak.Utils;
|
||||
using Daybreak.Views;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -10,12 +13,15 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace Daybreak.Services.Updater
|
||||
{
|
||||
public sealed class ApplicationUpdater : IApplicationUpdater
|
||||
{
|
||||
private const string UpdateDesiredKey = "UpdateDesired";
|
||||
private const string ExecutionPolicyKey = "ExecutionPolicy";
|
||||
private const string UpdatedKey = "Updating";
|
||||
private const string RegistryKey = "Daybreak";
|
||||
@@ -36,13 +42,21 @@ namespace Daybreak.Services.Updater
|
||||
private const string RemoveTempFile = $"Remove-item {TempFile}";
|
||||
private const string RemovePs1 = $"Remove-item {ExtractAndRunPs1}";
|
||||
|
||||
private readonly CancellationTokenSource updateCancellationTokenSource = new();
|
||||
private readonly ILogger logger;
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly IRuntimeStore runtimeStore;
|
||||
private readonly HttpClient httpClient = new();
|
||||
|
||||
public string CurrentVersion => Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||
|
||||
public ApplicationUpdater(ILogger logger)
|
||||
public ApplicationUpdater(
|
||||
ILogger logger,
|
||||
IRuntimeStore runtimeStore,
|
||||
IViewManager viewManager)
|
||||
{
|
||||
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
|
||||
this.runtimeStore = runtimeStore.ThrowIfNull(nameof(runtimeStore));
|
||||
this.logger = logger.ThrowIfNull(nameof(logger));
|
||||
}
|
||||
|
||||
@@ -104,6 +118,23 @@ namespace Daybreak.Services.Updater
|
||||
}).ExtractValue();
|
||||
}
|
||||
|
||||
public void PeriodicallyCheckForUpdates()
|
||||
{
|
||||
System.Extensions.TaskExtensions.RunPeriodicAsync(async () =>
|
||||
{
|
||||
if (this.runtimeStore.TryGetValue<bool>(UpdateDesiredKey, out var desiringUpdate) && desiringUpdate is false)
|
||||
{
|
||||
this.updateCancellationTokenSource.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (await this.UpdateAvailable())
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.viewManager.ShowView<AskUpdateView>());
|
||||
}
|
||||
}, TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(15), this.updateCancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
public void FinalizeUpdate()
|
||||
{
|
||||
var maybeExecutionPolicy = this.RetrieveExecutionPolicy();
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Daybreak.Services.Updater
|
||||
{
|
||||
string CurrentVersion { get; }
|
||||
void FinalizeUpdate();
|
||||
void PeriodicallyCheckForUpdates();
|
||||
Task<bool> UpdateAvailable();
|
||||
Task<bool> DownloadUpdate(UpdateStatus updateStatus);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});";
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Daybreak.Services.Logging;
|
||||
using Daybreak.Services.Runtime;
|
||||
using Daybreak.Services.Updater;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using Daybreak.Utils;
|
||||
@@ -12,27 +13,34 @@ namespace Daybreak.Views
|
||||
/// </summary>
|
||||
public partial class AskUpdateView : UserControl
|
||||
{
|
||||
private const string UpdateDesiredKey = "UpdateDesired";
|
||||
|
||||
private readonly ILogger logger;
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly IRuntimeStore runtimeStore;
|
||||
|
||||
public AskUpdateView(
|
||||
ILogger logger,
|
||||
IViewManager viewManager)
|
||||
IViewManager viewManager,
|
||||
IRuntimeStore runtimeStore)
|
||||
{
|
||||
this.logger = logger.ThrowIfNull(nameof(logger));
|
||||
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
|
||||
this.runtimeStore = runtimeStore.ThrowIfNull(nameof(runtimeStore));
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private void NoButton_Clicked(object sender, System.EventArgs e)
|
||||
{
|
||||
this.logger.LogInformation("User declined update");
|
||||
this.runtimeStore.StoreValue(UpdateDesiredKey, false);
|
||||
this.viewManager.ShowView<MainView>();
|
||||
}
|
||||
|
||||
private void YesButton_Clicked(object sender, System.EventArgs e)
|
||||
{
|
||||
this.logger.LogInformation("User accepted update");
|
||||
this.runtimeStore.StoreValue(UpdateDesiredKey, true);
|
||||
this.viewManager.ShowView<UpdateView>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibility"></BooleanToVisibilityConverter>
|
||||
</UserControl.Resources>
|
||||
<Grid Background="Transparent" x:Name="ViewContainer">
|
||||
<Grid x:Name="ViewContainer">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
@@ -27,26 +27,33 @@
|
||||
<controls:OpaqueButton Text="Launch game" Highlight="White" TransparentBackground="Black" HighlightOpacity="0.3" BackgroundOpacity="0.2"
|
||||
Foreground="White" FontSize="36" Width="250" Height="60" VerticalAlignment="Bottom"
|
||||
IsEnabled="{Binding ElementName=_this, Path=LaunchButtonEnabled, Mode=OneWay}"
|
||||
Clicked="LaunchButton_Clicked" Grid.Row="0" Grid.ColumnSpan="3"></controls:OpaqueButton>
|
||||
Clicked="LaunchButton_Clicked" Grid.Row="0" Grid.ColumnSpan="3"
|
||||
Visibility="{Binding ElementName=_this, Path=ButtonsVisible, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}"></controls:OpaqueButton>
|
||||
<controls:OpaqueButton Text="Launch toolbox" Highlight="White" TransparentBackground="Black" HighlightOpacity="0.3" BackgroundOpacity="0.2"
|
||||
Foreground="White" FontSize="24" Width="200" Height="40" Margin="0, 10, 0, 10"
|
||||
IsEnabled="{Binding ElementName=_this, Path=LaunchToolboxButtonEnabled, Mode=OneWay}"
|
||||
Clicked="LaunchToolboxButton_Clicked" Grid.Row="1" Grid.ColumnSpan="2"></controls:OpaqueButton>
|
||||
Clicked="LaunchToolboxButton_Clicked" Grid.Row="1" Grid.ColumnSpan="2"
|
||||
Visibility="{Binding ElementName=_this, Path=ButtonsVisible, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}"></controls:OpaqueButton>
|
||||
<controls:OpaqueButton Text="Launch texmod" Highlight="White" TransparentBackground="Black" HighlightOpacity="0.3" BackgroundOpacity="0.2"
|
||||
Foreground="White" FontSize="24" Width="200" Height="40" Margin="0, 10, 0, 10"
|
||||
IsEnabled="{Binding ElementName=_this, Path=LaunchTexmodButtonEnabled, Mode=OneWay}"
|
||||
Clicked="LaunchTexmodButton_Clicked" Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="1"></controls:OpaqueButton>
|
||||
<Grid x:Name="RightContainer" Grid.Column="2" Margin="10">
|
||||
Clicked="LaunchTexmodButton_Clicked" Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="1"
|
||||
Visibility="{Binding ElementName=_this, Path=ButtonsVisible, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}"></controls:OpaqueButton>
|
||||
<Grid Grid.Column="2" Margin="10" Visibility="{Binding ElementName=_this, Path=BrowsersEnabled, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}">
|
||||
<controls:ChromiumBrowserWrapper Address="{Binding ElementName=_this, Path=RightBrowserAddress, Mode=OneWay}"
|
||||
Foreground="White" FavoriteUriChanged="RightBrowser_FavoriteUriChanged"
|
||||
FavoriteAddress="{Binding ElementName=_this, Path=RightBrowserFavoriteAddress, Mode=OneWay}"
|
||||
MaximizeClicked="RightChromiumBrowserWrapper_MaximizeClicked"/>
|
||||
MaximizeClicked="RightChromiumBrowserWrapper_MaximizeClicked"
|
||||
BuildDecoded="ChromiumBrowserWrapper_BuildDecoded"
|
||||
CanDownloadBuild="True"/>
|
||||
</Grid>
|
||||
<Grid x:Name="LeftContainer" Grid.Column="0" Margin="10">
|
||||
<Grid Grid.Column="0" Margin="10" Visibility="{Binding ElementName=_this, Path=BrowsersEnabled, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}">
|
||||
<controls:ChromiumBrowserWrapper Address="{Binding ElementName=_this, Path=LeftBrowserAddress, Mode=OneWay}"
|
||||
Foreground="White" FavoriteUriChanged="LeftBrowser_FavoriteUriChanged"
|
||||
FavoriteAddress="{Binding ElementName=_this, Path=LeftBrowserFavoriteAddress, Mode=OneWay}"
|
||||
MaximizeClicked="LeftChromiumBrowserWrapper_MaximizeClicked"/>
|
||||
MaximizeClicked="LeftChromiumBrowserWrapper_MaximizeClicked"
|
||||
BuildDecoded="ChromiumBrowserWrapper_BuildDecoded"
|
||||
CanDownloadBuild="True"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Daybreak.Controls;
|
||||
using Daybreak.Exceptions;
|
||||
using Daybreak.Exceptions;
|
||||
using Daybreak.Models.Builds;
|
||||
using Daybreak.Services.ApplicationLauncher;
|
||||
using Daybreak.Services.Configuration;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
@@ -18,12 +18,16 @@ namespace Daybreak.Views
|
||||
/// </summary>
|
||||
public partial class MainView : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty ButtonsVisibleProperty =
|
||||
DependencyPropertyExtensions.Register<MainView, bool>(nameof(ButtonsVisible), new PropertyMetadata(true));
|
||||
public static readonly DependencyProperty LaunchButtonEnabledProperty =
|
||||
DependencyPropertyExtensions.Register<MainView, bool>(nameof(LaunchButtonEnabled));
|
||||
public static readonly DependencyProperty LaunchToolboxButtonEnabledProperty =
|
||||
DependencyPropertyExtensions.Register<MainView, bool>(nameof(LaunchToolboxButtonEnabled));
|
||||
public static readonly DependencyProperty LaunchTexmodButtonEnabledProperty =
|
||||
DependencyPropertyExtensions.Register<MainView, bool>(nameof(LaunchTexmodButtonEnabled));
|
||||
public static readonly DependencyProperty BrowsersEnabledProperty =
|
||||
DependencyPropertyExtensions.Register<MainView, bool>(nameof(BrowsersEnabled), new PropertyMetadata(true));
|
||||
public static readonly DependencyProperty RightBrowserAddressProperty =
|
||||
DependencyPropertyExtensions.Register<MainView, string>(nameof(RightBrowserAddress));
|
||||
public static readonly DependencyProperty LeftBrowserAddressProperty =
|
||||
@@ -41,6 +45,11 @@ namespace Daybreak.Views
|
||||
private bool leftBrowserMaximized = false;
|
||||
private bool rightBrowserMaximized = false;
|
||||
|
||||
public bool ButtonsVisible
|
||||
{
|
||||
get => this.GetTypedValue<bool>(ButtonsVisibleProperty);
|
||||
set => this.SetTypedValue(ButtonsVisibleProperty, value);
|
||||
}
|
||||
public string RightBrowserFavoriteAddress
|
||||
{
|
||||
get => this.GetTypedValue<string>(RightBrowserFavoriteAddressProperty);
|
||||
@@ -76,6 +85,11 @@ namespace Daybreak.Views
|
||||
get => this.GetTypedValue<bool>(LaunchTexmodButtonEnabledProperty);
|
||||
set => this.SetTypedValue(LaunchTexmodButtonEnabledProperty, value);
|
||||
}
|
||||
public bool BrowsersEnabled
|
||||
{
|
||||
get => this.GetTypedValue<bool>(BrowsersEnabledProperty);
|
||||
set => this.SetTypedValue(BrowsersEnabledProperty, value);
|
||||
}
|
||||
|
||||
public MainView(
|
||||
IApplicationLauncher applicationDetector,
|
||||
@@ -93,10 +107,17 @@ namespace Daybreak.Views
|
||||
private void NavigateToDefaults()
|
||||
{
|
||||
var applicationConfiguration = this.configurationManager.GetConfiguration();
|
||||
this.LeftBrowserFavoriteAddress = applicationConfiguration.LeftBrowserDefault;
|
||||
this.RightBrowserFavoriteAddress = applicationConfiguration.RightBrowserDefault;
|
||||
this.LeftBrowserAddress = applicationConfiguration.LeftBrowserDefault;
|
||||
this.RightBrowserAddress = applicationConfiguration.RightBrowserDefault;
|
||||
if (applicationConfiguration.BrowsersEnabled)
|
||||
{
|
||||
this.LeftBrowserFavoriteAddress = applicationConfiguration.LeftBrowserDefault;
|
||||
this.RightBrowserFavoriteAddress = applicationConfiguration.RightBrowserDefault;
|
||||
this.LeftBrowserAddress = applicationConfiguration.LeftBrowserDefault;
|
||||
this.RightBrowserAddress = applicationConfiguration.RightBrowserDefault;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.BrowsersEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void PeriodicallyCheckGameState()
|
||||
@@ -166,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();
|
||||
@@ -196,6 +222,7 @@ namespace Daybreak.Views
|
||||
}
|
||||
|
||||
this.leftBrowserMaximized = !this.leftBrowserMaximized;
|
||||
this.ButtonsVisible = !this.leftBrowserMaximized;
|
||||
}
|
||||
|
||||
private void RightChromiumBrowserWrapper_MaximizeClicked(object sender, EventArgs e)
|
||||
@@ -214,6 +241,7 @@ namespace Daybreak.Views
|
||||
}
|
||||
|
||||
this.rightBrowserMaximized = !this.rightBrowserMaximized;
|
||||
this.ButtonsVisible = !this.rightBrowserMaximized;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -84,7 +84,8 @@
|
||||
<TextBlock Text="Texmod path" FontSize="22" Foreground="White"></TextBlock>
|
||||
<TextBlock Text="GWToolbox path: " FontSize="22" Foreground="White"></TextBlock>
|
||||
<TextBlock Text="GWToolbox auto-launch: " FontSize="22" Foreground="White"></TextBlock>
|
||||
<TextBlock Text="Address bar readonly: " FontSize="22" Foreground="White"/>
|
||||
<TextBlock Text="Browsers enabled: " FontSize="22" Foreground="White"/>
|
||||
<TextBlock Text="Browsers address bar readonly: " FontSize="22" Foreground="White"/>
|
||||
<TextBlock Text="Left browser homepage: " FontSize="22" Foreground="White"></TextBlock>
|
||||
<TextBlock Text="Right browser homepage: " FontSize="22" Foreground="White"></TextBlock>
|
||||
</StackPanel>
|
||||
@@ -106,9 +107,11 @@
|
||||
Clicked="ToolboxFilePickerGlyph_Clicked"></controls:FilePickerGlyph>
|
||||
</Grid>
|
||||
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
|
||||
FontSize="22" Background="Transparent" Foreground="White" IsChecked="{Binding ElementName=_this, Path=ToolboxAutoLaunch, Mode=TwoWay}"></ToggleButton>
|
||||
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=ToolboxAutoLaunch, Mode=TwoWay}"></ToggleButton>
|
||||
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
|
||||
FontSize="22" Background="Transparent" Foreground="White" IsChecked="{Binding ElementName=_this, Path=AddressBarReadonly, Mode=TwoWay}"></ToggleButton>
|
||||
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=BrowsersEnabled, Mode=TwoWay}"></ToggleButton>
|
||||
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
|
||||
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=AddressBarReadonly, Mode=TwoWay}"></ToggleButton>
|
||||
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
FontSize="22" Background="Transparent" Foreground="White"
|
||||
Text="{Binding ElementName=_this, Path=LeftBrowserUrl, Mode=TwoWay}"
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace Daybreak.Views
|
||||
DependencyPropertyExtensions.Register<SettingsView, string>(nameof(ToolboxPath));
|
||||
public static readonly DependencyProperty AddressBarReadonlyProperty =
|
||||
DependencyPropertyExtensions.Register<SettingsView, bool>(nameof(AddressBarReadonly));
|
||||
public static readonly DependencyProperty BrowsersEnabledProperty =
|
||||
DependencyPropertyExtensions.Register<SettingsView, bool>(nameof(BrowsersEnabled));
|
||||
public static readonly DependencyProperty LeftBrowserUrlProperty =
|
||||
DependencyPropertyExtensions.Register<SettingsView, string>(nameof(LeftBrowserUrl));
|
||||
public static readonly DependencyProperty RightBrowserUrlProperty =
|
||||
@@ -60,6 +62,11 @@ namespace Daybreak.Views
|
||||
get => this.GetTypedValue<string>(RightBrowserUrlProperty);
|
||||
set => this.SetValue(RightBrowserUrlProperty, value);
|
||||
}
|
||||
public bool BrowsersEnabled
|
||||
{
|
||||
get => this.GetTypedValue<bool>(BrowsersEnabledProperty);
|
||||
set => this.SetValue(BrowsersEnabledProperty, value);
|
||||
}
|
||||
|
||||
public SettingsView(
|
||||
IConfigurationManager configurationManager,
|
||||
@@ -80,6 +87,7 @@ namespace Daybreak.Views
|
||||
this.RightBrowserUrl = config.RightBrowserDefault;
|
||||
this.ToolboxAutoLaunch = config.ToolboxAutoLaunch;
|
||||
this.TexmodPath = config.TexmodPath;
|
||||
this.BrowsersEnabled = config.BrowsersEnabled;
|
||||
}
|
||||
|
||||
private void SaveButton_Clicked(object sender, EventArgs e)
|
||||
@@ -91,6 +99,7 @@ namespace Daybreak.Views
|
||||
currentConfig.RightBrowserDefault = this.RightBrowserUrl;
|
||||
currentConfig.ToolboxAutoLaunch = this.ToolboxAutoLaunch;
|
||||
currentConfig.TexmodPath = this.TexmodPath;
|
||||
currentConfig.BrowsersEnabled = this.BrowsersEnabled;
|
||||
this.configurationManager.SaveConfiguration(currentConfig);
|
||||
this.viewManager.ShowView<SettingsCategoryView>();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ Requires webview2 runtime https://go.microsoft.com/fwlink/p/?LinkId=2124703.
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
# 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.
|
||||

|
||||
|
||||
To manage builds, go into Settings, Builds. Here you can select/remove builds.
|
||||

|
||||
|
||||
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.
|
||||

|
||||
|
||||
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.
|
||||
|
||||

|
||||
|
||||
Reference in New Issue
Block a user