Compare commits

...
65 Commits
Author SHA1 Message Date
amacocianandGitHub 54ae742899 Increment version (#40) 2022-08-12 13:22:59 +02:00
amacocianandGitHub 4c862463d7 Fix IconRetriever (#38)
Use browser to bypass header issues with http client
2022-08-12 13:15:46 +02:00
amacocianandGitHub b455c89ddc Minor improvements (#36)
Deprecate Microsoft.Xaml.Behaviors.Wpf
Reverse version order in management view
2022-08-04 23:05:55 +02:00
amacocianandGitHub 782b76cd8e Remove admin mode when updating (#31) 2022-08-04 21:59:55 +02:00
amacocianandGitHub 230c2d9457 Setup executable installer (#29)
* Setup executable installer

* Increment update to 0.9.3

* Improve installer
2022-08-04 21:39:17 +02:00
amacocianandGitHub 63531e3b8c Hide console window (#25) 2022-08-04 19:52:54 +02:00
amacocianandGitHub ac430305f4 Update to .net 6 and update dependencies (#24)
* Update to .net 6 and update dependencies
2022-08-04 19:25:53 +02:00
amacocianandGitHub 3d830cfc16 Update dependencies (#23) 2021-07-10 13:39:00 +03:00
amacocianandGitHub b529aa8861 Fix logging on startup when ILogger is null (#22) 2021-07-10 12:45:44 +03:00
amacocianandGitHub 3798daa54e Update dependencies (#21)
* Update dependencies
* Minor nit fixes
* Fix UTs
2021-07-10 12:08:43 +03:00
amacocianandGitHub 624380ed86 Use IOptions instead of IConfigurationManager (#20)
* Use IOptions instead of dependency on IConfigurationManager
2021-06-22 15:48:37 +03:00
amacocianandGitHub 2b025e225b Updated wpfextended dependency 2021-06-11 13:50:58 +02:00
amacocianandGitHub 15a67ea28c Minor fixes
Stop showing browser when browser is disabled
Prevent setting address of browser when browser is disabled (should prevent browser from instantiating when disabled)
Ignore errors from browser caused by switching view before the browser could be initialized
Provide expression to filter logs
Button to export logs to json file
2021-06-07 14:33:54 +02:00
amacocianandGitHub c6b62fd5fd Logging improvements
Log uncaught exceptions
Logview expander
2021-06-07 00:34:43 +02:00
amacocianandGitHub 3c0877c1a0 Ability to keep a local cache of icons (#16) 2021-06-03 21:12:31 +02:00
967b57b9a8 Fix build code encoding/decoding view (#15)
Co-authored-by: Alexandru Macocian <almacoci@microsoft.com>
2021-06-03 20:40:56 +02:00
amacocianandGitHub f47cc319b5 Build template code field 2021-06-03 19:57:29 +02:00
amacocianandGitHub 26da84c4e7 Update to new version of wpfextended
Fix a bug where version parsing would ignore all 0s before the first digit
Remove LoggerFactory and LoggerProviders duplicated in WpfExtended
2021-06-03 14:48:35 +02:00
a39e8dc5c6 Separate CV from message (#12)
Co-authored-by: Alexandru Macocian <almacoci@microsoft.com>
2021-06-01 21:57:27 +02:00
1bb4669135 Introduce correlated logs (#11)
Co-authored-by: Alexandru Macocian <almacoci@microsoft.com>
2021-06-01 20:43:55 +02:00
amacocianandGitHub 0203eef006 Rework logging (#10)
* Rework log storing into a litedb.
LogView implementation to view logs.
Create crash.log on crash.

* Rename Logs namespace to Logging.
2021-05-18 19:49:51 +02:00
amacocianandGitHub 4ab50ee191 Use Microsoft.Logging.Abstractions
Typed ILogger.
2021-05-14 14:31:33 +02:00
amacocianandGitHub 06c1ec1ac2 Add scoped http client. (#8)
* Introduce scoped http client.
* Uts for scoped httpclient
2021-05-10 12:46:01 +02:00
amacocianandGitHub ef4befdc38 Version management view.
Enable/disable version autocheck.
Version management view.
2021-05-06 18:23:07 +02:00
amacocianandGitHub 33f49ddffa Cleanup cd pipeline (#6)
* Cleanup cd pipeline

* Remove cd pipeline on PR

* Cleanup CI pipeline comments.
2021-05-06 12:33:58 +02:00
amacocianandGitHub 49aa249b5b Generate changelog from last release tag.
Generate changelog from last release tag.
2021-05-05 23:01:57 +02:00
amacocianandGitHub c387d44890 Generate changelog from latest release.
Auto-generate changelog.
2021-05-05 21:31:45 +02:00
d4d09e7267 Update version (#3)
Co-authored-by: Alexandru Macocian <almacoci@microsoft.com>
2021-05-05 20:52:43 +02:00
amacocianandGitHub dd7bf02a97 Add CI & CD pipelines
Add CD&CI pipelines
2021-05-05 20:46:36 +02:00
Alexandru Macocian 6d0eeb478f Use source generator to generate dependency properties. 2021-05-05 17:23:37 +02:00
d4e9de48b1 Add ci pipeline (#1)
* Add ci pipeline

* Remove unused env variables.

* Change dotnet version to 5.0.5

* Change to dotnet 5.0.202

Co-authored-by: Alexandru Macocian <almacoci@microsoft.com>
2021-05-03 17:11:59 +02:00
Alexandru Macocian 6bd9877925 Remove dependency on InputSimulator. 2021-05-03 16:23:30 +02:00
Alexandru Macocian d38df6596f Remove keyboard macro functionality for now.
Unify input prompts.
Modify screenshot manager functionality to apply functionality of settings changed.
Update to 0.8.6.
2021-05-03 16:16:00 +02:00
Alexandru Macocian b4e31e859c Merge branch 'master' of https://github.com/AlexMacocian/Daybreak 2021-05-02 18:49:31 +02:00
Alexandru Macocian 1acd07c1be Change the way shortcut manager manages shortcuts.
Base for keyboard macros.
2021-05-02 18:49:25 +02:00
amacocianandGitHub b9b25bb098 Update README.md 2021-04-27 17:28:25 +02:00
amacocianandGitHub 5ea2981dc7 Update README.md 2021-04-27 17:25:03 +02:00
Alexandru Macocian 4fb96ca3a4 Ability to place screenshots in desired location. 2021-04-27 17:06:28 +02:00
Alexandru Macocian 6de52f5585 Ability to test placement while guildwars is running. 2021-04-26 11:26:43 +02:00
Alexandru Macocian 6622e41f64 Wait for guildwars window to be initialized before moving to desired window. 2021-04-26 11:02:23 +02:00
Alexandru Macocian 8405e4d1e5 Return to settings category after saving desired window. 2021-04-25 18:26:29 +02:00
Alexandru Macocian 0edc3f1560 Throw exception when screen id is invalid. 2021-04-25 18:24:51 +02:00
Alexandru Macocian c109fe7561 Ability to select on which window to place guildwars. 2021-04-25 18:20:45 +02:00
Alexandru Macocian b5413dca5c Include [Admin] tag when running as administrator. 2021-04-24 01:35:46 +02:00
Alexandru Macocian 6c2d4a1e70 No longer require administrator rights for normal usage.
Request elevation only in necesarry parts of the code.
Request elevation on update.
After update, launch application without elevation.
2021-04-24 01:20:36 +02:00
Alexandru Macocian be03f1a32d Run updates as admin 2021-04-23 23:37:01 +02:00
Alexandru Macocian 3ed1cc453a Implemented functionality to launch guildwars with lower privilege. 2021-04-23 20:24:28 +02:00
Alexandru Macocian 16030063ed Fix skill icon not unloading.
Moved all help icons on same side.
2021-04-23 19:52:09 +02:00
Alexandru Macocian 458696ad8f Fixed a bug where skill templates would try to load the image for No Skill.
Fixed a bug where build template manager would delete saved template.
2021-04-23 17:28:12 +02:00
Alexandru Macocian 6201702563 Skill holder now properly shows the top half of icons in the case where icons are bigger than normal. 2021-04-23 17:14:24 +02:00
Alexandru Macocian c5bea23a8f Make professions and attributes searchable.
Minor QOL changes to build view.
Handle exception caused by browser initialization getting canceled.
2021-04-23 16:59:31 +02:00
Alexandru Macocian e5f38f77ef Reverted html agility pack. 2021-04-23 11:40:05 +02:00
Alexandru Macocian 1d774ab8de Disable script injection when dynamic build loading is disabled.
Fixed a bug where earth prayers was not a recognized attribute.
2021-04-23 11:11:19 +02:00
Alexandru Macocian bc66ca9948 Feature flag to disable dynamic build loading in experimental settings. 2021-04-22 17:53:04 +02:00
amacocianandGitHub 524cd21fd4 Update README.md 2021-04-22 17:39:51 +02:00
amacocianandGitHub 132cb0e1f4 Update README.md 2021-04-22 17:32:35 +02:00
amacocianandGitHub 09c99e7731 Update README.md 2021-04-22 17:29:49 +02:00
Alexandru Macocian c9d0be1117 Update to 0.7.0 2021-04-22 17:02:48 +02:00
Alexandru Macocian 965055c8d7 Build management implementation.
Load build from browser when selection is detected to be a build template.
Load skill images from internet on demand.
Load skill details page when a skill is selected.
Separate skills on professions.
2021-04-22 17:02:28 +02:00
Alexandru Macocian f6bb21d0ef Build template parser and encoder.
Unit test project.
2021-04-20 20:06:15 +02:00
Alexandru Macocian 465e0a4ce0 Fix buttons while browser is fullscreen. 2021-04-20 12:51:26 +02:00
Alexandru Macocian 55f304b885 Update to wpfextended 0.2 2021-04-19 21:37:15 +02:00
Alexandru Macocian 0cb1d97332 Remove hyperlink from version text. 2021-04-17 20:04:20 +02:00
Alexandru Macocian e2091cd82f Home button for browsers.
Stop asking for updates if user already answered no.
2021-04-17 19:39:56 +02:00
Alexandru Macocian d2bada4159 Button to disable browsers. 2021-04-17 10:21:06 +02:00
187 changed files with 9748 additions and 1202 deletions
+101
View File
@@ -0,0 +1,101 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
# This continuous integration pipeline is triggered anytime a user pushes code to the repo.
# This pipeline builds the Wpf project, runs unit tests, then saves the MSIX build artifact.
name: Daybreak CD Pipeline
on:
push:
branches:
- master
jobs:
build:
strategy:
matrix:
targetplatform: [x64]
runs-on: windows-latest
env:
Configuration: Release
Solution_Path: Daybreak.sln
Test_Project_Path: Daybreak.Tests\Daybreak.Tests.csproj
Wpf_Project_Path: Daybreak\Daybreal.csproj
Actions_Allow_Unsecure_Commands: true
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Get Latest Tag
id: getLatestTag
uses: WyriHaximus/github-action-get-previous-tag@v1
- name: Generate changelog
id: gen_changelog
run: |
$changeLog = git log --no-merges --pretty="%h - %s (%an)<br />" ${{ env.LatestReleaseTag }}..HEAD
echo "::set-env name=Changelog::$changeLog"
env:
LatestReleaseTag: ${{steps.getLatestTag.outputs.tag}}
- name: Print changelog
run: |
echo "${{ env.Changelog }}"
- name: Install .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.x'
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.0.1
- name: Restore project
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
env:
RuntimeIdentifier: win-${{ matrix.targetplatform }}
- name: Build Daybreak project
run: dotnet build Daybreak -c $env:Configuration
- name: Set version variable
run: |
$version = .\Scripts\GetBuildVersion.ps1
echo "::set-env name=Version::$version"
- name: Create publish launcher files
run: dotnet publish .\Daybreak\Daybreak.csproj -c $env:Configuration -r $env:RuntimeIdentifier -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -o .\Publish
env:
RuntimeIdentifier: win-${{ matrix.targetplatform }}
- name: Create publish installer files
run: dotnet publish .\Daybreak.Installer\Daybreak.Installer.csproj -c $env:Configuration -r $env:RuntimeIdentifier -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -o .\Publish
env:
RuntimeIdentifier: win-${{ matrix.targetplatform }}
- name: Pack publish files
run: |
Write-Host $env
.\Scripts\BuildRelease.ps1 -version $env:Version
shell: pwsh
- name: Publish release
uses: Xotl/cool-github-releases@v1.1.2
with:
mode: update
tag_name: v${{ env.Version }}
release_name: Daybreak v${{ env.Version }}
assets: .\Publish\daybreakv${{ env.Version }}.zip
github_token: ${{ env.GITHUB_TOKEN }}
replace_assets: true
body_mrkdwn: ${{ env.Changelog }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+53
View File
@@ -0,0 +1,53 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
# This continuous integration pipeline is triggered anytime a user pushes code to the repo.
# This pipeline builds the Wpf project, runs unit tests, then saves the MSIX build artifact.
name: Daybreak CI Pipeline
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
strategy:
matrix:
targetplatform: [x64]
runs-on: windows-latest
env:
Solution_Path: Daybreak.sln
Test_Project_Path: Daybreak.Tests\Daybreak.Tests.csproj
Wpf_Project_Path: Daybreak\Daybreal.csproj
Actions_Allow_Unsecure_Commands: true
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Install .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.x'
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.0.1
- name: Execute Unit Tests
run: dotnet test $env:Test_Project_Path
- name: Restore the Wpf application to populate the obj folder
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
env:
Configuration: Debug
RuntimeIdentifier: win-${{ matrix.targetplatform }}
+1
View File
@@ -9,6 +9,7 @@
*.user
*.userosscache
*.sln.docstates
*.version
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
+41
View File
@@ -0,0 +1,41 @@
// See https://aka.ms/new-console-template for more information
using System.Diagnostics;
using System.IO.Compression;
const string tempFile = "tempfile.zip";
const string executableName = "Daybreak.exe";
Console.Title = "Daybreak Installer";
Console.WriteLine("Starting installation...");
if (File.Exists(tempFile) is false)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Unable to find launcher package. Aborting installation");
Console.ReadKey();
return;
}
Console.WriteLine("Unpacking files...");
try
{
ZipFile.ExtractToDirectory(tempFile, AppContext.BaseDirectory, true);
}
catch
{
}
Console.WriteLine("Deleting package");
File.Delete(tempFile);
Console.WriteLine("Launching application");
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = executableName
}
};
if (process.Start() is false)
{
Console.WriteLine("Failed to launch application");
Console.ReadKey();
}
+22
View File
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.7.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0-preview-20220707-01" />
<PackageReference Include="Moq" Version="4.18.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Daybreak\Daybreak.csproj" />
</ItemGroup>
</Project>
+136
View File
@@ -0,0 +1,136 @@
using Daybreak.Models.Versioning;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;
using Version = Daybreak.Models.Versioning.Version;
namespace Daybreak.Tests.Models
{
[TestClass]
public class VersionTests
{
[DataRow("v0.1.0.0.1", "v0.1.0.0.1")]
[DataRow("v0.1.0.0.1.0.0.0.0", "v0.1.0.0.1")]
[DataRow("v0.1.0", "v0.1")]
[DataRow("0.1.0", "0.1")]
[DataRow("v0.1.0.0.0", "v0.1")]
[DataRow("0.1.0.0.0", "0.1")]
[DataRow("v0", "v0")]
[DataRow("0", "0")]
[DataRow("v0.1", "v0.1")]
[DataRow("0.1-release", "0.1-release")]
[DataRow("v0.1-release", "v0.1-release")]
[TestMethod]
public void VersionToString(string version, string expectedString)
{
var parsedVersion = Version.Parse(version);
parsedVersion.ToString().Should().Be(expectedString);
}
[DataRow("v0", false)]
[DataRow("0", false)]
[DataRow("v0.1", false)]
[DataRow("0.1-release", true)]
[DataRow("v0.1-release", true)]
[TestMethod]
public void VersionHasStringSuffix(string version, bool hasSuffix)
{
var parsedVersion = Version.Parse(version);
if (hasSuffix)
{
parsedVersion.VersionTokens.Last().Should().BeOfType<VersionStringToken>();
}
else
{
parsedVersion.VersionTokens.Last().Should().BeOfType<VersionNumberToken>();
}
}
[DataRow("v0", true)]
[DataRow("0", false)]
[DataRow("v0.1", true)]
[DataRow("0.1", false)]
[TestMethod]
public void VersionTokensHasPrefix(string version, bool hasPrefix)
{
var parsedVersion = Version.Parse(version);
parsedVersion.HasPrefix.Should().Be(hasPrefix);
}
[DataRow(null, false)]
[DataRow("", false)]
[DataRow("asd", false)]
[DataRow("ads.pls.er", false)]
[DataRow("0.0.1", true)]
[DataRow("1", true)]
[DataRow("0.1.asd", false)]
[DataRow("0.", false)]
[DataRow(".1", false)]
[DataRow("0.1-", false)]
[DataRow("0.1-release", true)]
[DataRow("0..1", false)]
[TestMethod]
public void TryParseVersionTest(string version, bool result)
{
var success = Version.TryParse(version, out var parsedVersion);
success.Should().Be(result);
if (success is true)
{
parsedVersion.Should().NotBeNull();
}
}
[DataRow(null, false)]
[DataRow("", false)]
[DataRow("asd", false)]
[DataRow("ads.pls.er", false)]
[DataRow("0.0.1", true)]
[DataRow("1", true)]
[DataRow("0.1.asd", false)]
[DataRow("0.", false)]
[DataRow(".1", false)]
[DataRow("0.1-", false)]
[DataRow("0.1-release", true)]
[DataRow("0..1", false)]
[TestMethod]
public void ParseVersionTest(string version, bool shouldNotThrow)
{
var action = new Action(() => Version.Parse(version));
if (shouldNotThrow is false)
{
action.Should().Throw<InvalidOperationException>();
}
else
{
action.Should().NotThrow<InvalidOperationException>();
}
}
[DataRow(null, false)]
[DataRow("", false)]
[DataRow("asd", false)]
[DataRow("ads.pls.er", false)]
[DataRow("0.0.1", true)]
[DataRow("1", true)]
[DataRow("0.1.asd", false)]
[DataRow("0.", false)]
[DataRow(".1", false)]
[DataRow("0.1-", false)]
[DataRow("0.1-release", true)]
[DataRow("0..1", false)]
[TestMethod]
public void VersionConstructorTest(string version, bool shouldNotThrow)
{
var action = new Action(() => new Version(version));
if (shouldNotThrow is false)
{
action.Should().Throw<ArgumentException>();
}
else
{
action.Should().NotThrow<ArgumentException>();
}
}
}
}
@@ -0,0 +1,63 @@
using Daybreak.Configuration;
using Daybreak.Services.Configuration;
using Daybreak.Services.Options;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
namespace Daybreak.Tests.Services
{
[TestClass]
public class ApplicationConfigurationOptionsManagerTests
{
private ApplicationConfigurationOptionsManager applicationConfigurationOptionsManager;
[TestInitialize]
public void TestInitialize()
{
var configurationManagerMock = new Mock<IConfigurationManager>();
configurationManagerMock
.Setup(u => u.GetConfiguration())
.Returns(new ApplicationConfiguration());
this.applicationConfigurationOptionsManager = new ApplicationConfigurationOptionsManager(configurationManagerMock.Object);
}
[TestMethod]
public void GetApplicationConfiguration_ReturnsObject()
{
var config = this.applicationConfigurationOptionsManager.GetOptions<ApplicationConfiguration>();
config.Should().NotBeNull();
}
[TestMethod]
public void GetOtherOptions_ThrowsInvalidOperationException()
{
var action = new Action(() =>
{
this.applicationConfigurationOptionsManager.GetOptions<object>();
});
action.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public void UpdateOptions_OnApplicationConfiguration_Succeeds()
{
this.applicationConfigurationOptionsManager.UpdateOptions(new ApplicationConfiguration());
}
[TestMethod]
public void UpdateOptions_OnOthers_ThrowsInvalidOperationException()
{
var action = new Action(() =>
{
this.applicationConfigurationOptionsManager.UpdateOptions(new object());
});
action.Should().Throw<InvalidOperationException>();
}
}
}
@@ -0,0 +1,96 @@
using Daybreak.Models.Builds;
using Daybreak.Services.BuildTemplates;
using FluentAssertions;
using Microsoft.Extensions.Logging;
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<BuildTemplateManager>>().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);
}
}
}
@@ -0,0 +1,74 @@
using Daybreak.Services.Logging;
using FluentAssertions;
using LiteDB;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
using System.Linq;
using System.Logging;
namespace Daybreak.Tests.Services
{
[TestClass]
public class JsonLoggerProviderTests
{
private ILogsManager logsManager;
private ILoggerProvider loggerProvider;
private ILiteDatabase liteDatabase;
[TestInitialize]
public void InitializeProvider()
{
File.Delete("Daybreak.db");
this.liteDatabase = new LiteDatabase("Daybreak.db");
this.logsManager = new JsonLogsManager(this.liteDatabase);
this.loggerProvider = new CVLoggerProvider(this.logsManager);
}
[TestCleanup]
public void TestCleanup()
{
this.liteDatabase.Dispose();
}
[TestMethod]
public void CreateLoggerReturnsLogger()
{
var logger = this.loggerProvider.CreateLogger("SomeCategory");
logger.Should().NotBeNull();
}
[TestMethod]
public void LoggerLogsAndReaderReadsFiltered()
{
var logger = this.loggerProvider.CreateLogger("SomeCategory");
logger.LogTrace("Logging some trace");
logger.LogInformation("Logging some stuff");
logger.LogError("Logging some error");
this.logsManager.GetLogs(l => l.LogLevel < LogLevel.Information).Should().HaveCount(1);
var log = this.logsManager.GetLogs(l => l.LogLevel < LogLevel.Information).First();
log.LogLevel.Should().Be(LogLevel.Error);
}
[TestMethod]
public void LoggerLogsAndReaderReads()
{
var logger = this.loggerProvider.CreateLogger("SomeCategory");
logger.LogInformation("Logging some stuff");
logger.LogError("Logging some error");
this.logsManager.GetLogs().Should().HaveCount(2);
}
[TestMethod]
public void DeletingLogsShouldDeleteLogs()
{
var logger = this.loggerProvider.CreateLogger("SomeCategory");
logger.LogInformation("Logging some stuff");
logger.LogError("Logging some error");
this.logsManager.GetLogs().Should().HaveCount(2);
this.logsManager.DeleteLogs();
this.logsManager.GetLogs().Should().HaveCount(0);
}
}
}
+32 -6
View File
@@ -1,10 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31005.135
# Visual Studio Version 17
VisualStudioVersion = 17.2.32616.157
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Daybreak", "Daybreak\Daybreak.csproj", "{AA45C2B1-8BD0-466C-9271-699F168905AF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Daybreak.Tests", "Daybreak.Tests\Daybreak.Tests.csproj", "{C911C1C2-6566-419C-89C7-F802EB3FE709}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Pipelines", "Pipelines", "{067BF93F-E5B2-4E99-886E-039C04F35EAB}"
ProjectSection(SolutionItems) = preProject
.github\workflows\cd.yaml = .github\workflows\cd.yaml
.github\workflows\ci.yaml = .github\workflows\ci.yaml
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Daybreak.Installer", "Daybreak.Installer\Daybreak.Installer.csproj", "{4E2BB805-135D-4F02-8C53-3D8B6876D323}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -15,12 +25,28 @@ Global
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Debug|x64.ActiveCfg = Debug|x64
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Debug|x64.Build.0 = Debug|x64
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Debug|x64.ActiveCfg = Debug|Any CPU
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Debug|x64.Build.0 = Debug|Any CPU
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{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
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Release|x64.ActiveCfg = Release|Any CPU
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Release|x64.Build.0 = Release|Any CPU
{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
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x64.ActiveCfg = Debug|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x64.Build.0 = Debug|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|Any CPU.Build.0 = Release|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x64.ActiveCfg = Release|Any CPU
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+2 -2
View File
@@ -1,9 +1,9 @@
using System;
using Microsoft.Xaml.Behaviors;
using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;
namespace Daybreak.Behaviors
+55
View File
@@ -0,0 +1,55 @@
using Microsoft.Xaml.Behaviors;
using System;
using System.Extensions;
using System.Windows.Controls;
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;
}
}
}
@@ -1,11 +1,18 @@
using Daybreak.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace Daybreak.Configuration
{
public sealed class ApplicationConfiguration
{
[JsonProperty("SetGuildwarsWindowSizeOnLaunch")]
public bool SetGuildwarsWindowSizeOnLaunch { get; set; }
[JsonProperty("DesiredGuildwarsScreen")]
public int DesiredGuildwarsScreen { get; set; }
[JsonProperty("BrowsersEnabled")]
public bool BrowsersEnabled { get; set; } = true;
[JsonProperty("ToolboxPath")]
public string ToolboxPath { get; set; }
[JsonProperty("TexmodPath")]
@@ -24,5 +31,11 @@ namespace Daybreak.Configuration
public bool AddressBarReadonly { get; set; } = true;
[JsonProperty("ExperimentalFeatures")]
public ExperimentalFeatures ExperimentalFeatures { get; set; } = new();
[JsonProperty("ShortcutLocation")]
public string ShortcutLocation { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
[JsonProperty("PlaceShortcut")]
public bool PlaceShortcut { get; set; }
[JsonProperty("AutoCheckUpdate")]
public bool AutoCheckUpdate { get; set; } = true;
}
}
+13 -1
View File
@@ -1,4 +1,6 @@
using Newtonsoft.Json;
using Daybreak.Models;
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Daybreak.Configuration
{
@@ -8,5 +10,15 @@ namespace Daybreak.Configuration
public bool MultiLaunchSupport { get; set; }
[JsonProperty("ToolboxAutoLaunchDelay")]
public int ToolboxAutoLaunchDelay { get; set; } = 5000;
[JsonProperty("DynamicBuildLoading")]
public bool DynamicBuildLoading { get; set; } = true;
[JsonProperty("LaunchGuildwarsAsCurrentUser")]
public bool LaunchGuildwarsAsCurrentUser { get; set; } = true;
[JsonProperty("CanInterceptKeys")]
public bool CanInterceptKeys { get; set; }
[JsonProperty("DownloadIcons")]
public bool DownloadIcons { get; set; }
[JsonProperty("Macros")]
public List<KeyMacro> Macros { get; set; } = new();
}
}
+48 -18
View File
@@ -1,46 +1,70 @@
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.Privilege;
using Daybreak.Services.Screens;
using Daybreak.Services.Screenshots;
using Daybreak.Services.Shortcuts;
using Daybreak.Services.Updater;
using Daybreak.Services.ViewManagement;
using Daybreak.Views;
using Microsoft.Extensions.Http.Logging;
using Microsoft.Extensions.Logging;
using Slim;
using System.Extensions;
using System.Net.Http;
using LiteDB;
using Daybreak.Services.Options;
using Daybreak.Models;
using Microsoft.CorrelationVector;
using Services.IconRetrieve;
namespace Daybreak.Configuration
{
// TODO: Credit http://bloogum.net/guildwars/
public static class ProjectConfiguration
{
public static void RegisterResolvers(IServiceManager serviceManager)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterHttpFactory((serviceProvider, categoryType) =>
{
var loggerType = typeof(ILogger<>).MakeGenericType(categoryType);
var logger = serviceProvider.GetService(loggerType).As<ILogger>();
var handler = new LoggingHttpMessageHandler(logger) { InnerHandler = new HttpClientHandler() };
return handler;
});
serviceManager.RegisterOptionsManager<ApplicationConfigurationOptionsManager>();
}
public static void RegisterServices(IServiceProducer serviceProducer)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceProducer.RegisterSingleton<ICredentialManager, CredentialManager>();
serviceProducer.RegisterSingleton<ILoggingDatabase, FlatLoggingDatabase>();
serviceProducer.RegisterSingleton<ILogger, Logger>();
serviceProducer.RegisterSingleton<ApplicationLifetimeManager>();
serviceProducer.RegisterSingleton<ViewManager>();
serviceProducer.RegisterSingleton<IApplicationLauncher, ApplicationLauncher>();
serviceProducer.RegisterSingleton<IScreenshotProvider, ScreenshotProvider>();
serviceProducer.RegisterSingleton<ViewManager>(registerAllInterfaces: true);
serviceProducer.RegisterSingleton<IConfigurationManager, ConfigurationManager>();
serviceProducer.RegisterSingleton<IBloogumClient, BloogumClient>();
serviceProducer.RegisterSingleton<IApplicationUpdater, ApplicationUpdater>();
serviceProducer.RegisterSingleton<ILiteDatabase, LiteDatabase>(sp => new LiteDatabase("Daybreak.db"));
serviceProducer.RegisterSingleton<IMutexHandler, MutexHandler>();
serviceProducer.RegisterSingleton<IShortcutManager, ShortcutManager>();
serviceProducer.RegisterSingleton<IIconBrowser, IconBrowser>();
serviceProducer.RegisterScoped<ICredentialManager, CredentialManager>();
serviceProducer.RegisterScoped<IApplicationLauncher, ApplicationLauncher>();
serviceProducer.RegisterScoped<IScreenshotProvider, ScreenshotProvider>();
serviceProducer.RegisterScoped<IBloogumClient, BloogumClient>();
serviceProducer.RegisterScoped<IApplicationUpdater, ApplicationUpdater>();
serviceProducer.RegisterScoped<IBuildTemplateManager, BuildTemplateManager>();
serviceProducer.RegisterScoped<IIconRetriever, IconRetriever>();
serviceProducer.RegisterScoped<IPrivilegeManager, PrivilegeManager>();
serviceProducer.RegisterScoped<IScreenManager, ScreenManager>();
serviceProducer.RegisterLogWriter<ILogsManager, JsonLogsManager>();
serviceProducer.RegisterScoped((sp) => new ScopeMetadata(new CorrelationVector()));
}
public static void RegisterLifetimeServices(IApplicationLifetimeProducer applicationLifetimeProducer)
{
applicationLifetimeProducer.ThrowIfNull(nameof(applicationLifetimeProducer));
applicationLifetimeProducer.RegisterService<ILoggingDatabase>();
applicationLifetimeProducer.RegisterService<IScreenshotProvider>();
applicationLifetimeProducer.RegisterService<IApplicationUpdater>();
}
public static void RegisterViews(IViewProducer viewProducer)
{
viewProducer.ThrowIfNull(nameof(viewProducer));
@@ -53,6 +77,12 @@ namespace Daybreak.Configuration
viewProducer.RegisterView<AccountsView>();
viewProducer.RegisterView<ExperimentalSettingsView>();
viewProducer.RegisterView<ExecutablesView>();
viewProducer.RegisterView<BuildTemplateView>();
viewProducer.RegisterView<BuildsListView>();
viewProducer.RegisterView<RequestElevationView>();
viewProducer.RegisterView<ScreenChoiceView>();
viewProducer.RegisterView<VersionManagementView>();
viewProducer.RegisterView<LogsView>();
}
}
}
+19
View File
@@ -0,0 +1,19 @@
<UserControl x:Class="Daybreak.Controls.HelpButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" Width="30" Height="30" />
<Ellipse Width="30" Height="30" StrokeThickness="2" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Ellipse>
<Path Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" VerticalAlignment="Center" HorizontalAlignment="Center"
Data="m4.99353,17.899l0,-1.47c0,-1.436 0.322,-2.188 1.075,-3.229l2.404,-3.3c1.254,-1.721 1.684,-2.546 1.684,-3.766c0,-2.044 -1.434,-3.335 -3.479,-3.335c-2.008,0 -3.299,1.219 -3.729,3.407c-0.036,0.215 -0.179,0.323 -0.395,0.287l-2.259,-0.395c-0.216,-0.036 -0.323,-0.179 -0.288,-0.395c0.539,-3.443 3.014,-5.703 6.744,-5.703c3.872,0 6.49,2.546 6.49,6.097c0,1.722 -0.608,2.977 -1.828,4.663l-2.403,3.3c-0.717,0.968 -0.933,1.47 -0.933,2.689l0,1.147c0,0.215 -0.143,0.358 -0.358,0.358l-2.367,0c-0.215,0.004 -0.358,-0.14 -0.358,-0.355zm-0.179,3.444c0,-0.215 0.143,-0.358 0.359,-0.358l2.726,0c0.215,0 0.358,0.144 0.358,0.358l0,3.084c0,0.216 -0.144,0.358 -0.358,0.358l-2.726,0c-0.217,0 -0.359,-0.143 -0.359,-0.358l0,-3.084z"></Path>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
</UserControl>
@@ -0,0 +1,37 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for AddButton.xaml
/// </summary>
public partial class HelpButton : UserControl
{
public event EventHandler Clicked;
public HelpButton()
{
InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.Clicked?.Invoke(this, e);
}
}
}
}
+25
View File
@@ -0,0 +1,25 @@
<UserControl x:Class="Daybreak.Controls.HomeButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" StrokeThickness="3" Width="60" Height="60"></Ellipse>
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Path Data="m42,45.384l-14,0l0,-13l-8,0l0,13l-14,0l0,-21c0,-0.552 0.447,-1 1,-1s1,0.448 1,1l0,19l10,0l0,-13l12,0l0,13l10,0l0,-18c0,-0.552 0.447,-1 1,-1s1,0.448 1,1l0,20z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Path Data="m47,24.384c-0.249,0 -0.497,-0.092 -0.691,-0.277l-22.309,-21.339l-22.309,21.339c-0.399,0.381 -1.032,0.368 -1.414,-0.031c-0.382,-0.399 -0.367,-1.032 0.031,-1.414l23.692,-22.662l23.691,22.661c0.398,0.382 0.413,1.015 0.031,1.414c-0.196,0.205 -0.458,0.309 -0.722,0.309z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Path Data="m39,12.384c-0.553,0 -1,-0.448 -1,-1l0,-6l-6,0c-0.553,0 -1,-0.448 -1,-1s0.447,-1 1,-1l8,0l0,8c0,0.552 -0.447,1 -1,1z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
</Grid>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
</UserControl>
@@ -0,0 +1,37 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for HomeButton.xaml
/// </summary>
public partial class HomeButton : UserControl
{
public event EventHandler Clicked;
public HomeButton()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
}
}
}
@@ -0,0 +1,20 @@
<UserControl x:Class="Daybreak.Controls.MinusButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
<Path Data="m13,26a13,13 0 1 1 13,-13a13,13 0 0 1 -13,13zm0,-24a11,11 0 1 0 11,11a11,11 0 0 0 -11,-11z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Path Data="m19,14l-12,0a1,1 0 0 1 0,-2l12,0a1,1 0 0 1 0,2z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
</UserControl>
@@ -0,0 +1,37 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for AddButton.xaml
/// </summary>
public partial class MinusButton : UserControl
{
public event EventHandler Clicked;
public MinusButton()
{
InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
}
}
}
@@ -4,7 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
xmlns:converters="clr-namespace:Daybreak.Converters"
x:Name="_this"
+18 -1
View File
@@ -14,6 +14,18 @@
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" TriggerValue="True"></converters:BooleanToVisibilityConverter>
<converters:BooleanToVisibilityConverter x:Key="ReverseBooleanToVisibilityConverter" TriggerValue="False"></converters:BooleanToVisibilityConverter>
</UserControl.Resources>
<UserControl.ContextMenu>
<ContextMenu>
<ContextMenu.Template>
<ControlTemplate>
<StackPanel Margin="10">
<local:OpaqueButton Text="Load build template" Foreground="White" Background="#F0202020" BackgroundOpacity="0.4"
Clicked="LoadBuildTemplateButton_Click" FontSize="16" Height="40" Width="200"></local:OpaqueButton>
</StackPanel>
</ControlTemplate>
</ContextMenu.Template>
</ContextMenu>
</UserControl.ContextMenu>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
@@ -21,7 +33,8 @@
</Grid.RowDefinitions>
<wv2:WebView2 x:Name="WebBrowser" Source="{Binding ElementName=_this, Path=Address, Mode=TwoWay}"
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"></wv2:WebView2>
<Grid Grid.Row="1" Background="#80808080" IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}">
<Grid Grid.Row="1" Background="#80808080" IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
Visibility="{Binding ElementName=_this, Path=ControlsEnabled, Mode=OneWay, Converter={StaticResource ReverseBooleanToVisibilityConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
@@ -55,6 +68,10 @@
PreviewKeyDown="TextBox_PreviewKeyDown"
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"></TextBox>
<StackPanel Grid.Column="2" Orientation="Horizontal">
<local:HomeButton Width="30" Height="30" Margin="5"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
Clicked="HomeButton_Clicked"></local:HomeButton>
<local:StarGlyph Height="30" Width="30" Margin="5"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
+138 -41
View File
@@ -1,9 +1,12 @@
using Daybreak.Launch;
using Daybreak.Services.Configuration;
using Daybreak.Services.Logging;
using Daybreak.Configuration;
using Daybreak.Models.Browser;
using Daybreak.Models.Builds;
using Daybreak.Services.BuildTemplates;
using Daybreak.Utils;
using Microsoft.Extensions.Logging;
using Microsoft.Web.WebView2.Core;
using System;
using System.Configuration;
using System.Diagnostics;
using System.Extensions;
using System.Threading.Tasks;
@@ -16,56 +19,56 @@ namespace Daybreak.Controls
/// <summary>
/// Interaction logic for ChromiumBrowserWrapper.xaml
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
public partial class ChromiumBrowserWrapper : UserControl
{
public static readonly DependencyProperty AddressProperty =
DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, string>(nameof(Address));
private const string BrowserDownloadLink = "https://developer.microsoft.com/en-us/microsoft-edge/webview2/";
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 AddressBarReadonlyProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(AddressBarReadonly));
public readonly static DependencyProperty BrowserSupportedProperty = DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, bool>(nameof(BrowserSupported), new PropertyMetadata(true));
public event EventHandler<string> FavoriteUriChanged;
public event EventHandler MaximizeClicked;
public event EventHandler<Build> BuildDecoded;
private readonly IConfigurationManager configurationManager;
private readonly ILogger logger;
private ILiveOptions<ApplicationConfiguration> liveOptions;
private ILogger<ChromiumBrowserWrapper> logger;
private IBuildTemplateManager buildTemplateManager;
private CoreWebView2Environment coreWebView2Environment;
[GenerateDependencyProperty(InitialValue = true)]
private bool canDownloadBuild;
[GenerateDependencyProperty(InitialValue = true)]
private bool canNavigate;
[GenerateDependencyProperty(InitialValue = true)]
private bool controlsEnabled;
[GenerateDependencyProperty]
private bool browserSupported;
[GenerateDependencyProperty]
private bool addressBarReadonly;
[GenerateDependencyProperty]
private bool browserEnabled;
[GenerateDependencyProperty]
private bool navigating;
[GenerateDependencyProperty]
private string favoriteAddress;
public string Address
{
get => this.GetTypedValue<string>(AddressProperty);
set => this.SetTypedValue(AddressProperty, value);
}
public string FavoriteAddress
{
get => this.GetTypedValue<string>(FavoriteAddressProperty);
set => this.SetTypedValue(FavoriteAddressProperty, value);
}
public bool Navigating
{
get => this.GetTypedValue<bool>(NavigatingProperty);
private set => this.SetTypedValue<bool>(NavigatingProperty, value);
}
public bool AddressBarReadonly
{
get => this.GetTypedValue<bool>(AddressBarReadonlyProperty);
private set => this.SetTypedValue<bool>(AddressBarReadonlyProperty, value);
}
public bool BrowserSupported
{
get => this.GetTypedValue<bool>(BrowserSupportedProperty);
private set => this.SetTypedValue<bool>(BrowserSupportedProperty, value);
set
{
if (this.BrowserSupported is true)
{
this.SetValue(AddressProperty, value);
}
}
}
public ChromiumBrowserWrapper()
{
this.configurationManager = Launcher.ApplicationServiceManager.GetService<IConfigurationManager>();
this.logger = Launcher.ApplicationServiceManager.GetService<ILogger>();
this.InitializeComponent();
this.InitializeEnvironment();
this.InitializeBrowser();
this.WebBrowser.IsEnabled = false;
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
@@ -77,13 +80,31 @@ namespace Daybreak.Controls
}
}
public void ReinitializeBrowser()
public async void InitializeBrowser(
ILiveOptions<ApplicationConfiguration> liveOptions,
IBuildTemplateManager buildTemplateManager,
ILogger<ChromiumBrowserWrapper> logger)
{
this.InitializeBrowser();
this.liveOptions = liveOptions;
this.buildTemplateManager = buildTemplateManager;
this.logger = logger;
this.InitializeEnvironment();
await this.InitializeBrowser();
}
public async void ReinitializeBrowser()
{
await this.InitializeBrowser();
}
private void InitializeEnvironment()
{
if (this.liveOptions.Value.BrowsersEnabled is false)
{
this.BrowserSupported = false;
return;
}
try
{
this.coreWebView2Environment = System.Extensions.TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", null));
@@ -100,11 +121,30 @@ namespace Daybreak.Controls
{
if (this.BrowserSupported is true)
{
this.WebBrowser.IsEnabled = true;
await this.WebBrowser.EnsureCoreWebView2Async(this.coreWebView2Environment);
this.AddressBarReadonly = this.configurationManager.GetConfiguration().AddressBarReadonly;
this.AddressBarReadonly = this.liveOptions.Value.AddressBarReadonly;
this.CanDownloadBuild = this.liveOptions.Value.ExperimentalFeatures.DynamicBuildLoading;
this.WebBrowser.CoreWebView2.NewWindowRequested += (browser, args) => args.Handled = true;
this.WebBrowser.NavigationStarting += (browser, args) => 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 +186,61 @@ 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, $"Exception encountered when deserializing {nameof(BrowserPayload)}");
}
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 +272,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();
}
}
}
+14
View File
@@ -0,0 +1,14 @@
<UserControl x:Class="Daybreak.Controls.LogsGlyph"
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>
<Path Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m7,3l0,-1.00209c0,-1.09965 0.89762,-1.99791 2.00488,-1.99791l0.99024,0c1.11098,0 2.00488,0.8945 2.00488,1.99791l0,1.00209l2.00442,0c0.55074,0 0.99558,0.44725 0.99558,0.99896l0,1.00208c0,0.5563 -0.44574,0.99896 -0.99558,0.99896l-9.00884,0c-0.55074,0 -0.99558,-0.44725 -0.99558,-0.99896l0,-1.00208c0,-0.5563 0.44574,-0.99896 0.99558,-0.99896l2.00442,0l0,0zm8.99999,1l1.00259,0c1.10649,0 1.99742,0.89704 1.99742,2.00359l0,20.99282c0,1.11383 -0.89428,2.00359 -1.99742,2.00359l-15.00516,0c-1.10649,0 -1.99742,-0.89704 -1.99742,-2.00359l0,-20.99282c0,-1.11383 0.89428,-2.00359 1.99742,-2.00359l1.00259,0c-0.00001,0.00163 -0.00001,0.00325 -0.00001,0.00488l0,0.99024c0,1.10726 0.89354,2.00488 2.00276,2.00488l8.99448,0c1.10609,0 2.00276,-0.8939 2.00276,-2.00488l0,-0.99024c0,-0.00163 0,-0.00325 -0.00001,-0.00488l0,0l0,0zm-6.49999,-1c0.27614,0 0.5,-0.22386 0.5,-0.5c0,-0.27614 -0.22386,-0.5 -0.5,-0.5c-0.27614,0 -0.5,0.22386 -0.5,0.5c0,0.27614 0.22386,0.5 0.5,0.5l0,0zm-6.5,8l0,1l13,0l0,-1l-13,0l0,0zm0,3l0,1l13,0l0,-1l-13,0l0,0zm0,3l0,1l13,0l0,-1l-13,0l0,0zm0,3l0,1l13,0l0,-1l-13,0l0,0zm0,3l0,1l13,0l0,-1l-13,0l0,0z"></Path>
</Viewbox>
</UserControl>
@@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for LogsGlyph.xaml
/// </summary>
public partial class LogsGlyph : UserControl
{
public LogsGlyph()
{
InitializeComponent();
}
}
}
+14
View File
@@ -0,0 +1,14 @@
<UserControl x:Class="Daybreak.Controls.StaticGlyph"
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>
<Polygon Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Points="209.89999389648438,829.800048828125 279.1999816894531,493.9000244140625 0,493.9000244140625 415.89996337890625,0 346.699951171875,335.8999938964844 625.800048828125,335.8999938964844"></Polygon>
</Viewbox>
</UserControl>
@@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for StaticGlyph.xaml
/// </summary>
public partial class StaticGlyph : UserControl
{
public StaticGlyph()
{
this.InitializeComponent();
}
}
}
+3 -4
View File
@@ -1,5 +1,4 @@
using Daybreak.Utils;
using System;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
@@ -39,7 +38,7 @@ namespace Daybreak.Controls
}
nextVisible.Source = imageSource;
this.Transition(currentVisible, nextVisible);
Transition(currentVisible, nextVisible);
}
private Image CurrentVisible()
@@ -64,7 +63,7 @@ namespace Daybreak.Controls
return this.Image1;
}
}
private void Transition(Image from, Image to)
private static void Transition(Image from, Image to)
{
to.Visibility = Visibility.Visible;
to.Opacity = 0;
@@ -10,37 +10,21 @@ namespace Daybreak.Controls
/// <summary>
/// Interaction logic for AccountTemplate.xaml
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
public partial class AccountTemplate : UserControl
{
public static readonly DependencyProperty UsernameProperty = DependencyPropertyExtensions.Register<AccountTemplate, string>(nameof(Username));
public static readonly DependencyProperty CharacterNameProperty = DependencyPropertyExtensions.Register<AccountTemplate, string>(nameof(CharacterName));
public static readonly DependencyProperty PasswordProperty = DependencyPropertyExtensions.Register<AccountTemplate, string>(nameof(Password));
public static readonly DependencyProperty IsDefaultProperty = DependencyPropertyExtensions.Register<AccountTemplate, bool>(nameof(IsDefault));
public event EventHandler RemoveClicked;
public event EventHandler DefaultClicked;
public string Username
{
get => this.GetTypedValue<string>(UsernameProperty);
set => this.SetValue(UsernameProperty, value);
}
public string Password
{
get => this.GetTypedValue<string>(PasswordProperty);
set => this.SetValue(PasswordProperty, value);
}
public string CharacterName
{
get => this.GetTypedValue<string>(CharacterNameProperty);
set => this.SetValue(CharacterNameProperty, value);
}
public bool IsDefault
{
get => this.GetTypedValue<bool>(IsDefaultProperty);
set => this.SetValue(IsDefaultProperty, value);
}
[GenerateDependencyProperty]
private string username;
[GenerateDependencyProperty]
private string password;
[GenerateDependencyProperty]
private string characterName;
[GenerateDependencyProperty]
private bool isDefault;
public AccountTemplate()
{
@@ -0,0 +1,25 @@
<UserControl x:Class="Daybreak.Controls.AttributeTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="10, 0, 10, 0">
<local:HelpButton Width="20" Height="20" Margin="3, 0, 3, 0" Foreground="White"
Clicked="HelpButton_Clicked" Cursor="Hand"></local:HelpButton>
<TextBlock Text="{Binding Attribute.Name}" FontSize="16" Foreground="White"></TextBlock>
</WrapPanel>
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="10, 0, 10, 0">
<local:MinusButton Foreground="White" Height="20" Clicked="MinusButton_Clicked" Cursor="Hand"
IsEnabled="{Binding ElementName=_this, Path=CanSubtract, Mode=OneWay}"></local:MinusButton>
<TextBox Background="Transparent" Foreground="White" FontSize="16" IsReadOnly="True" Width="30"
Text="{Binding Points}"></TextBox>
<local:AddButton Foreground="White" Height="20" Clicked="AddButton_Clicked" Cursor="Hand"
IsEnabled="{Binding ElementName=_this, Path=CanAdd, Mode=OneWay}"></local:AddButton>
</WrapPanel>
</Grid>
</UserControl>
@@ -0,0 +1,77 @@
using Daybreak.Models.Builds;
using System;
using System.Extensions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for AttributeTemplate.xaml
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
public partial class AttributeTemplate : UserControl
{
public event EventHandler<AttributeEntry> HelpClicked;
public event EventHandler<AttributeEntry> AttributeChanged;
[GenerateDependencyProperty(InitialValue = false)]
private bool canAdd;
[GenerateDependencyProperty(InitialValue = false)]
private bool canSubtract;
public AttributeTemplate()
{
this.InitializeComponent();
this.DataContextChanged += AttributeTemplate_DataContextChanged;
}
private void AttributeTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is AttributeEntry attributeEntry)
{
if (attributeEntry.Points > 0)
{
this.CanSubtract = true;
}
if (attributeEntry.Points < 12)
{
this.CanAdd = true;
}
}
}
private void MinusButton_Clicked(object sender, System.EventArgs e)
{
if (this.DataContext.As<AttributeEntry>().Points > 0)
{
this.DataContext.As<AttributeEntry>().Points--;
this.CanSubtract = this.DataContext.As<AttributeEntry>().Points > 0;
this.CanAdd = true;
this.AttributeChanged?.Invoke(this, this.DataContext.As<AttributeEntry>());
}
}
private void AddButton_Clicked(object sender, System.EventArgs e)
{
if (this.DataContext.As<AttributeEntry>().Points < 12)
{
this.DataContext.As<AttributeEntry>().Points++;
this.CanAdd = this.DataContext.As<AttributeEntry>().Points < 12;
this.CanSubtract = true;
this.AttributeChanged?.Invoke(this, this.DataContext.As<AttributeEntry>());
}
}
private void HelpButton_Clicked(object sender, System.EventArgs e)
{
if (this.DataContext is AttributeEntry attributeEntry)
{
this.HelpClicked?.Invoke(this, attributeEntry);
}
}
}
}
@@ -0,0 +1,14 @@
<UserControl x:Class="Daybreak.Controls.BuildEntryTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
xmlns:controls="clr-namespace:Daybreak.Controls"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock FontSize="16" Foreground="White" Text="{Binding Name}" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
<controls:BinButton Width="30" Height="30" Foreground="White" HorizontalAlignment="Right" Clicked="BinButton_Clicked"></controls:BinButton>
</Grid>
</UserControl>
@@ -0,0 +1,27 @@
using Daybreak.Models.Builds;
using System;
using System.Windows.Controls;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for BuildEntryTemplate.xaml
/// </summary>
public partial class BuildEntryTemplate : UserControl
{
public event EventHandler<BuildEntry> RemoveClicked;
public BuildEntryTemplate()
{
InitializeComponent();
}
private void BinButton_Clicked(object sender, EventArgs e)
{
if (this.DataContext is BuildEntry buildEntry)
{
this.RemoveClicked?.Invoke(this, buildEntry);
}
}
}
}
@@ -0,0 +1,170 @@
<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/xaml/behaviors"
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
xmlns:converters="clr-namespace:Daybreak.Converters"
mc:Ignorable="d"
x:Name="_this"
Unloaded="BuildTemplate_Unloaded"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="Transparent" MouseLeftButtonDown="Grid_MouseLeftButtonDown">
<Grid.RowDefinitions>
<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="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="Primary Profession: " FontSize="16" Foreground="White" Grid.Column="1"></TextBlock>
<ListView FontSize="16" Foreground="White" Grid.Column="2" BorderThickness="0"
Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Professions, Mode=OneWay}"
SelectedItem="{Binding ElementName=_this, Path=PrimaryProfession, Mode=TwoWay}" Height="30"
SelectionMode="Single" ScrollViewer.VerticalScrollBarVisibility="Disabled"
PreviewMouseWheel="ListView_NavigateWithMouseWheel">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name, Mode=OneWay}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
<interactivity:Interaction.Behaviors>
<behaviors:ScrollIntoView></behaviors:ScrollIntoView>
</interactivity:Interaction.Behaviors>
</ListView>
<local:HelpButton Grid.Column="0" Foreground="White" Width="20" Height="20" Margin="3"
Clicked="HelpButtonPrimary_Clicked" Cursor="Hand"></local:HelpButton>
</Grid>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="Secondary Profession: " FontSize="16" Foreground="White" Grid.Column="1"></TextBlock>
<ListView FontSize="16" Foreground="White" Grid.Column="2" BorderThickness="0"
Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Professions, Mode=OneWay}"
SelectedItem="{Binding ElementName=_this, Path=SecondaryProfession, Mode=TwoWay}" Height="30"
SelectionMode="Single" ScrollViewer.VerticalScrollBarVisibility="Disabled"
PreviewMouseWheel="ListView_NavigateWithMouseWheel">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name, Mode=OneWay}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
<interactivity:Interaction.Behaviors>
<behaviors:ScrollIntoView></behaviors:ScrollIntoView>
</interactivity:Interaction.Behaviors>
</ListView>
<local:HelpButton Grid.Column="0" Foreground="White" Width="20" Height="20" Margin="3"
Clicked="HelpButtonSecondary_Clicked" Cursor="Hand"></local:HelpButton>
</Grid>
<Grid Grid.Row="3">
<ListBox Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Attributes, Mode=OneWay}"
HorizontalContentAlignment="Stretch" BorderThickness="0">
<ListBox.ItemTemplate>
<DataTemplate>
<local:AttributeTemplate HelpClicked="AttributeTemplate_HelpClicked" AttributeChanged="AttributeTemplate_AttributeChanged"></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" x:Name="SkillTemplate0"
Foreground="White" Cursor="Hand"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill0, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<local:SkillTemplate Grid.Column="1" x:Name="SkillTemplate1"
Foreground="White" Cursor="Hand"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill1, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<local:SkillTemplate Grid.Column="2" x:Name="SkillTemplate2"
Foreground="White" Cursor="Hand"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill2, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<local:SkillTemplate Grid.Column="3" x:Name="SkillTemplate3"
Foreground="White" Cursor="Hand"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill3, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<local:SkillTemplate Grid.Column="4" x:Name="SkillTemplate4"
Foreground="White" Cursor="Hand"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill4, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<local:SkillTemplate Grid.Column="5" x:Name="SkillTemplate5"
Foreground="White" Cursor="Hand"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill5, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<local:SkillTemplate Grid.Column="6" x:Name="SkillTemplate6"
Foreground="White" Cursor="Hand"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill6, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<local:SkillTemplate Grid.Column="7" x:Name="SkillTemplate7"
Foreground="White" Cursor="Hand"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill7, Mode=TwoWay}"
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
<TextBlock Grid.Column="0" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill0.Name, Mode=OneWay}"></TextBlock>
<TextBlock Grid.Column="1" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill1.Name, Mode=OneWay}"></TextBlock>
<TextBlock Grid.Column="2" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill2.Name, Mode=OneWay}"></TextBlock>
<TextBlock Grid.Column="3" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill3.Name, Mode=OneWay}"></TextBlock>
<TextBlock Grid.Column="4" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill4.Name, Mode=OneWay}"></TextBlock>
<TextBlock Grid.Column="5" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill5.Name, Mode=OneWay}"></TextBlock>
<TextBlock Grid.Column="6" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill6.Name, Mode=OneWay}"></TextBlock>
<TextBlock Grid.Column="7" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
Foreground="White" Text="{Binding ElementName=_this, Path=Skill7.Name, Mode=OneWay}"></TextBlock>
</Grid>
<Grid Grid.Column="1" Grid.RowSpan="6">
<local:ChromiumBrowserWrapper x:Name="SkillBrowser" ControlsEnabled="False" Width="0" AddressBarReadonly="True" CanNavigate="True"></local:ChromiumBrowserWrapper>
</Grid>
<Grid Grid.Column="1" Grid.RowSpan="6">
<ListView x:Name="SkillsListView" Background="Transparent" Width="0"
ItemsSource="{Binding ElementName=_this, Path=AvailableSkills, Mode=OneWay}" MouseDoubleClick="ListView_MouseDoubleClick">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock FontSize="16" Foreground="White" TextWrapping="Wrap" Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Grid>
</UserControl>
@@ -0,0 +1,421 @@
using Daybreak.Configuration;
using Daybreak.Models.Builds;
using Daybreak.Services.BuildTemplates;
using Daybreak.Services.IconRetrieve;
using Microsoft.Extensions.Logging;
using Services.IconRetrieve;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Core.Extensions;
using System.Extensions;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for BuildTemplate.xaml
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
public partial class BuildTemplate : UserControl
{
private const string InfoNamePlaceholder = "[NAME]";
private const string BaseAddress = $"https://wiki.guildwars.com/wiki/{InfoNamePlaceholder}";
private bool suppressBuildChanged = false;
private bool loadedProperties = false;
private IIconBrowser iconBrowser;
private BuildEntry loadedBuild;
private SkillTemplate selectingSkillTemplate;
private CancellationTokenSource cancellationTokenSource = new();
public event EventHandler BuildChanged;
[GenerateDependencyProperty]
private Profession primaryProfession;
[GenerateDependencyProperty]
private Profession secondaryProfession;
[GenerateDependencyProperty]
private Skill skill0;
[GenerateDependencyProperty]
private Skill skill1;
[GenerateDependencyProperty]
private Skill skill2;
[GenerateDependencyProperty]
private Skill skill3;
[GenerateDependencyProperty]
private Skill skill4;
[GenerateDependencyProperty]
private Skill skill5;
[GenerateDependencyProperty]
private Skill skill6;
[GenerateDependencyProperty]
private Skill skill7;
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.InitializeProperties();
this.DataContextChanged += this.BuildTemplate_DataContextChanged;
}
public void InitializeTemplate(
IIconRetriever iconRetriever,
IIconBrowser iconBrowser,
ILiveOptions<ApplicationConfiguration> liveOptions,
IBuildTemplateManager buildTemplateManager,
ILogger<ChromiumBrowserWrapper> logger)
{
this.iconBrowser = iconBrowser.ThrowIfNull();
this.SkillBrowser.InitializeBrowser(liveOptions, buildTemplateManager, logger);
this.iconBrowser.InitializeWebView(this.SkillBrowser.WebBrowser, this.cancellationTokenSource.Token);
this.SkillTemplate0.InitializeSkillTemplate(iconRetriever);
this.SkillTemplate1.InitializeSkillTemplate(iconRetriever);
this.SkillTemplate2.InitializeSkillTemplate(iconRetriever);
this.SkillTemplate3.InitializeSkillTemplate(iconRetriever);
this.SkillTemplate4.InitializeSkillTemplate(iconRetriever);
this.SkillTemplate5.InitializeSkillTemplate(iconRetriever);
this.SkillTemplate6.InitializeSkillTemplate(iconRetriever);
this.SkillTemplate7.InitializeSkillTemplate(iconRetriever);
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (this.loadedProperties is false)
{
return;
}
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();
if (this.suppressBuildChanged is false)
{
this.BuildChanged?.Invoke(this, new EventArgs());
}
}
if (e.Property == Skill0Property ||
e.Property == Skill1Property ||
e.Property == Skill2Property ||
e.Property == Skill3Property ||
e.Property == Skill4Property ||
e.Property == Skill5Property ||
e.Property == Skill6Property ||
e.Property == Skill7Property)
{
if (this.suppressBuildChanged is false)
{
this.loadedBuild.Build.Skills[0] = this.Skill0;
this.loadedBuild.Build.Skills[1] = this.Skill1;
this.loadedBuild.Build.Skills[2] = this.Skill2;
this.loadedBuild.Build.Skills[3] = this.Skill3;
this.loadedBuild.Build.Skills[4] = this.Skill4;
this.loadedBuild.Build.Skills[5] = this.Skill5;
this.loadedBuild.Build.Skills[6] = this.Skill6;
this.loadedBuild.Build.Skills[7] = this.Skill7;
this.BuildChanged?.Invoke(this, new EventArgs());
}
}
}
private void BuildTemplate_Unloaded(object sender, RoutedEventArgs e)
{
this.cancellationTokenSource.Cancel();
}
private void InitializeProperties()
{
this.PrimaryProfession = Profession.None;
this.SecondaryProfession = Profession.None;
this.Skill0 = Skill.NoSkill;
this.Skill1 = Skill.NoSkill;
this.Skill2 = Skill.NoSkill;
this.Skill3 = Skill.NoSkill;
this.Skill4 = Skill.NoSkill;
this.Skill5 = Skill.NoSkill;
this.Skill6 = Skill.NoSkill;
this.Skill7 = Skill.NoSkill;
this.loadedProperties = true;
}
private void BuildTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if(e.NewValue is BuildEntry)
{
this.LoadBuild();
this.LoadSkills();
this.LoadAttributes();
}
}
private void Grid_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
this.HideSkillListView();
this.HideInfoBrowser();
}
private void LoadAttributes()
{
var possibleAttributes = new List<AttributeEntry>();
if (this.PrimaryProfession != Profession.None)
{
possibleAttributes.Add(new AttributeEntry { Attribute = this.PrimaryProfession.PrimaryAttribute });
possibleAttributes.AddRange(this.PrimaryProfession.Attributes.Select(a => new AttributeEntry { Attribute = a }));
}
if (this.SecondaryProfession != Profession.None && this.SecondaryProfession != this.PrimaryProfession)
{
possibleAttributes.AddRange(this.SecondaryProfession.Attributes.Select(a => new AttributeEntry { Attribute = a }));
}
this.Attributes.ClearAnd().AddRange(possibleAttributes.Select(entry =>
{
var maybePresentAttribute = this.loadedBuild.Build.Attributes.Where(buildEntry => entry.Attribute == buildEntry.Attribute).FirstOrDefault();
if (maybePresentAttribute is null)
{
return entry;
}
entry.Points = maybePresentAttribute.Points;
return entry;
}));
this.loadedBuild.Build.Attributes = this.Attributes.ToList();
}
private void LoadSkills()
{
var possibleSkills = Skill.Skills
.Where(s => s.Profession == this.PrimaryProfession || s.Profession == this.SecondaryProfession || s.Profession == Profession.None)
.Where(s => s != Skill.NoSkill)
.OrderBy(s => s.Name);
this.AvailableSkills.ClearAnd().AddRange(possibleSkills);
if (this.Skill0.Profession != this.PrimaryProfession &&
this.Skill0.Profession != this.SecondaryProfession &&
this.Skill0.Profession != Profession.None)
{
this.Skill0 = Skill.NoSkill;
}
if (this.Skill1.Profession != this.PrimaryProfession &&
this.Skill1.Profession != this.SecondaryProfession &&
this.Skill1.Profession != Profession.None)
{
this.Skill1 = Skill.NoSkill;
}
if (this.Skill2.Profession != this.PrimaryProfession &&
this.Skill2.Profession != this.SecondaryProfession &&
this.Skill2.Profession != Profession.None)
{
this.Skill2 = Skill.NoSkill;
}
if (this.Skill3.Profession != this.PrimaryProfession &&
this.Skill3.Profession != this.SecondaryProfession &&
this.Skill3.Profession != Profession.None)
{
this.Skill3 = Skill.NoSkill;
}
if (this.Skill4.Profession != this.PrimaryProfession &&
this.Skill4.Profession != this.SecondaryProfession &&
this.Skill4.Profession != Profession.None)
{
this.Skill4 = Skill.NoSkill;
}
if (this.Skill5.Profession != this.PrimaryProfession &&
this.Skill5.Profession != this.SecondaryProfession &&
this.Skill5.Profession != Profession.None)
{
this.Skill5 = Skill.NoSkill;
}
if (this.Skill6.Profession != this.PrimaryProfession &&
this.Skill6.Profession != this.SecondaryProfession &&
this.Skill6.Profession != Profession.None)
{
this.Skill6 = Skill.NoSkill;
}
if (this.Skill7.Profession != this.PrimaryProfession &&
this.Skill7.Profession != this.SecondaryProfession &&
this.Skill7.Profession != Profession.None)
{
this.Skill7 = Skill.NoSkill;
}
}
private void LoadBuild()
{
this.suppressBuildChanged = true;
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];
this.suppressBuildChanged = false;
}
private void BrowseToInfo(string infoName)
{
var address = BaseAddress.Replace(InfoNamePlaceholder, infoName.Replace(" ", "_"));
this.SkillBrowser.Address = address;
this.ShowInfoBrowser();
}
private void ShowInfoBrowser()
{
if (this.SkillBrowser.BrowserSupported is true)
{
this.SkillBrowser.Width = 400;
this.SkillsListView.Width = 0;
}
}
private void HideInfoBrowser()
{
if (this.SkillBrowser.BrowserSupported is true)
{
this.SkillBrowser.Width = 0;
}
}
private void ShowSkillListView()
{
this.SkillBrowser.Width = 0;
this.SkillsListView.Width = 400;
}
private void HideSkillListView()
{
this.SkillsListView.Width = 0;
}
private void HelpButtonPrimary_Clicked(object sender, System.EventArgs e)
{
if (this.PrimaryProfession == Profession.None)
{
return;
}
this.BrowseToInfo(this.PrimaryProfession.Name);
if (e is RoutedEventArgs routedEventArgs)
{
routedEventArgs.Handled = true;
}
}
private void HelpButtonSecondary_Clicked(object sender, System.EventArgs e)
{
if (this.SecondaryProfession == Profession.None)
{
return;
}
this.BrowseToInfo(this.SecondaryProfession.Name);
if (e is RoutedEventArgs routedEventArgs)
{
routedEventArgs.Handled = true;
}
}
private void AttributeTemplate_HelpClicked(object sender, AttributeEntry e)
{
this.BrowseToInfo(e.Attribute.Name);
}
private void AttributeTemplate_AttributeChanged(object sender, AttributeEntry e)
{
this.BuildChanged?.Invoke(this, new EventArgs());
}
private void SkillTemplate_Clicked(object sender, RoutedEventArgs e)
{
var skill = sender.As<SkillTemplate>().DataContext.As<Skill>();
if (skill == Skill.NoSkill)
{
this.ShowSkillListView();
this.selectingSkillTemplate = sender.As<SkillTemplate>();
}
else
{
this.BrowseToInfo(skill.Name);
}
e.Handled = true;
}
private void SkillTemplate_RemoveClicked(object sender, System.EventArgs e)
{
sender.As<SkillTemplate>().DataContext = Skill.NoSkill;
}
private void ListView_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (this.selectingSkillTemplate is null)
{
this.HideSkillListView();
return;
}
this.selectingSkillTemplate.DataContext = sender.As<ListView>().SelectedItem;
this.HideSkillListView();
this.loadedBuild.Build.Skills[0] = this.Skill0;
this.loadedBuild.Build.Skills[1] = this.Skill1;
this.loadedBuild.Build.Skills[2] = this.Skill2;
this.loadedBuild.Build.Skills[3] = this.Skill3;
this.loadedBuild.Build.Skills[4] = this.Skill4;
this.loadedBuild.Build.Skills[5] = this.Skill5;
this.loadedBuild.Build.Skills[6] = this.Skill6;
this.loadedBuild.Build.Skills[7] = this.Skill7;
}
private void ListView_NavigateWithMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
e.Handled = true;
if (e.Delta > 0)
{
sender.As<ListView>().SelectedIndex = sender.As<ListView>().SelectedIndex > 0 ?
sender.As<ListView>().SelectedIndex - 1 :
0;
}
else
{
sender.As<ListView>().SelectedIndex = sender.As<ListView>().SelectedIndex < sender.As<ListView>().Items.Count - 1 ?
sender.As<ListView>().SelectedIndex + 1 :
sender.As<ListView>().Items.Count;
}
}
}
}
@@ -11,24 +11,17 @@ namespace Daybreak.Controls
/// <summary>
/// Interaction logic for GuildwarsPathTemplate.xaml
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
public partial class GuildwarsPathTemplate : UserControl
{
public static readonly DependencyProperty PathProperty = DependencyPropertyExtensions.Register<GuildwarsPathTemplate, string>(nameof(Path));
public static readonly DependencyProperty IsDefaultProperty = DependencyPropertyExtensions.Register<GuildwarsPathTemplate, bool>(nameof(IsDefault));
public event EventHandler RemoveClicked;
public event EventHandler DefaultClicked;
public string Path
{
get => this.GetTypedValue<string>(PathProperty);
set => this.SetValue(PathProperty, value);
}
public bool IsDefault
{
get => this.GetTypedValue<bool>(IsDefaultProperty);
set => this.SetValue(IsDefaultProperty, value);
}
[GenerateDependencyProperty]
private string path;
[GenerateDependencyProperty]
private bool isDefault;
public GuildwarsPathTemplate()
{
@@ -0,0 +1,18 @@
<UserControl x:Class="Daybreak.Controls.LogMessageTemplate"
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"
x:Name="_this"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"></BooleanToVisibilityConverter>
</UserControl.Resources>
<Grid HorizontalAlignment="Stretch">
<TextBlock Text="{Binding ElementName=_this, Path=Message, Mode=OneWay}" Background="Transparent"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
MouseLeftButtonDown="TextBox_MouseLeftButtonDown" MaxHeight="18" TextWrapping="Wrap"></TextBlock>
</Grid>
</UserControl>
@@ -0,0 +1,36 @@
using System.Windows.Extensions;
using System.Windows.Controls;
using System.Windows.Input;
using System.Extensions;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for LogTemplate.xaml
/// </summary>
public partial class LogMessageTemplate : UserControl
{
private bool expanded;
[GenerateDependencyProperty]
private string message;
public LogMessageTemplate()
{
this.InitializeComponent();
}
private void TextBox_MouseLeftButtonDown(object sender, MouseButtonEventArgs eventArgs)
{
this.expanded = !this.expanded;
if (this.expanded)
{
sender.As<TextBlock>().MaxHeight = double.MaxValue;
}
else
{
sender.As<TextBlock>().MaxHeight = 18;
}
}
}
}
@@ -0,0 +1,17 @@
<UserControl x:Class="Daybreak.Controls.Templates.ScreenTemplate"
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.Templates"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Rectangle Stroke="{Binding ElementName=_this, Path=Highlight, Mode=OneWay}" StrokeThickness="15"></Rectangle>
<TextBlock FontSize="168" VerticalAlignment="Center" HorizontalAlignment="Center"
Text="{Binding ElementName=_this, Path=ScreenId, Mode=OneWay}"
Foreground="{Binding ElementName=_this, Path=Highlight, Mode=OneWay}"></TextBlock>
<Rectangle Fill="Transparent" MouseEnter="Rectangle_MouseEnter" MouseLeave="Rectangle_MouseLeave" MouseLeftButtonDown="Rectangle_MouseLeftButtonDown"></Rectangle>
</Grid>
</UserControl>
@@ -0,0 +1,63 @@
using Daybreak.Models;
using System;
using System.Extensions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Media;
namespace Daybreak.Controls.Templates
{
/// <summary>
/// Interaction logic for ScreenTemplate.xaml
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
public partial class ScreenTemplate : UserControl
{
public event EventHandler<Screen> Clicked;
[GenerateDependencyProperty]
private string screenId;
[GenerateDependencyProperty]
private Brush highlight;
public ScreenTemplate()
{
this.InitializeComponent();
this.DataContextChanged += ScreenTemplate_DataContextChanged;
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == ForegroundProperty)
{
this.Highlight = e.NewValue.As<Brush>();
}
}
private void ScreenTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is Screen screen)
{
this.ScreenId = screen.Id.ToString();
}
}
private void Rectangle_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
this.Highlight = Brushes.LightSteelBlue;
}
private void Rectangle_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
this.Highlight = this.Foreground;
}
private void Rectangle_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
this.Clicked?.Invoke(this, this.DataContext.As<Screen>());
}
}
}
@@ -0,0 +1,35 @@
<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:webview="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
</ResourceDictionary>
</UserControl.Resources>
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<Image VerticalAlignment="Top" HorizontalAlignment="Left"
Width="{Binding ElementName=_this, Path=ActualWidth, Mode=OneWay}"
Height="{Binding ElementName=_this, Path=ActualWidth, Mode=OneWay}"
Source="{Binding ElementName=_this, Path=ImageSource, Mode=OneWay}"
Stretch="UniformToFill"></Image>
<Border BorderThickness="5" BorderBrush="Black"></Border>
<Border BorderThickness="5" BorderBrush="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Opacity="{Binding ElementName=_this, Path=BorderOpacity, Mode=OneWay}"></Border>
<Rectangle Fill="Transparent" MouseEnter="Border_MouseEnter" MouseLeave="Border_MouseLeave"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MouseLeftButtonDown="Rectangle_MouseLeftButtonDown"></Rectangle>
<local:CancelButton x:Name="CancelButton" Width="30" Height="30" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10"
Visibility="Hidden" Foreground="White" Clicked="CancelButton_Clicked" MouseEnter="Border_MouseEnter"
MouseLeave="Border_MouseLeave"></local:CancelButton>
</Grid>
</UserControl>
@@ -0,0 +1,88 @@
using Daybreak.Models.Builds;
using Daybreak.Services.IconRetrieve;
using System;
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>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
public partial class SkillTemplate : UserControl
{
public event EventHandler<RoutedEventArgs> Clicked;
public event EventHandler RemoveClicked;
private IIconRetriever iconRetriever;
[GenerateDependencyProperty]
private ImageSource imageSource;
[GenerateDependencyProperty]
private double borderOpacity;
public SkillTemplate()
{
this.InitializeComponent();
this.DataContextChanged += SkillTemplate_DataContextChanged;
}
public void InitializeSkillTemplate(IIconRetriever iconRetriever)
{
this.iconRetriever = iconRetriever;
}
private async void SkillTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is Skill skill)
{
if (skill != Skill.NoSkill)
{
var maybeUri = await this.iconRetriever.GetIconUri(skill).ConfigureAwait(true);
if (maybeUri.ExtractValue() is Uri uri)
{
this.ImageSource = new BitmapImage(uri);
}
}
else if (this.ImageSource is not null)
{
this.ImageSource = null;
}
}
}
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;
}
}
}
+32
View File
@@ -0,0 +1,32 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace Daybreak.Converters
{
public class HiddenWhenNull : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return GetVerticalAlignment(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
private object GetVerticalAlignment(object value)
{
if (value is null)
{
return Visibility.Hidden;
}
else
{
return Visibility.Visible;
}
}
}
}
+50 -15
View File
@@ -1,50 +1,85 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<Platforms>AnyCPU</Platforms>
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<LangVersion>preview</LangVersion>
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
<Version>0.6.3</Version>
<ApplicationManifest>app.manifest</ApplicationManifest>
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
<Version>0.9.3.3</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.774.44" />
<PackageReference Include="LiteDB" Version="5.0.12" />
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1264.42" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="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="NReco.Logging.File" Version="1.1.5" />
<PackageReference Include="securifybv.ShellLink" Version="0.1.0" />
<PackageReference Include="Slim" Version="1.7.3" />
<PackageReference Include="SystemExtensions.NetCore" Version="1.0.1" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.5.0" />
<PackageReference Include="WCL" Version="1.0.2" />
<PackageReference Include="WpfExtended" Version="0.1.1" />
<PackageReference Include="WpfExtended" Version="0.6.2" />
<PackageReference Include="WpfExtended.SourceGeneration" Version="0.1.1" />
<PackageReference Include="WpfScreenHelper" Version="2.0.0" />
</ItemGroup>
<ItemGroup>
<Compile Update="Controls\StarGlyph.xaml.cs">
<Compile Update="Controls\Buttons\HelpButton.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Controls\CancelButton.xaml.cs">
<Compile Update="Controls\Buttons\MinusButton.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Controls\Glyphs\StarGlyph.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Controls\Buttons\CancelButton.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Page Update="Controls\MaximizeButton.xaml">
<Page Update="Controls\Buttons\HelpButton.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Controls\StarGlyph.xaml">
<Page Update="Controls\Buttons\MinusButton.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Controls\CancelButton.xaml">
<Page Update="Controls\Buttons\MaximizeButton.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Controls\Glyphs\StarGlyph.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Controls\Buttons\CancelButton.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
<Exec Command="echo.&gt;$(Version).version" />
</Target>
<Target Name="RemoveDuplicateAnalyzers" BeforeTargets="CoreCompile">
<!-- Work around https://github.com/dotnet/wpf/issues/6792 -->
<ItemGroup>
<FilteredAnalyzer Include="@(Analyzer-&gt;Distinct())" />
<Analyzer Remove="@(Analyzer)" />
<Analyzer Include="@(FilteredAnalyzer)" />
</ItemGroup>
</Target>
</Project>
+50 -14
View File
@@ -1,15 +1,13 @@
using Daybreak.Configuration;
using Daybreak.Exceptions;
using Daybreak.Services.ApplicationLifetime;
using Daybreak.Services.Logging;
using Daybreak.Services.ViewManagement;
using Daybreak.Utils;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.Wpf;
using Microsoft.Extensions.Logging;
using Slim;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Extensions;
@@ -17,7 +15,7 @@ namespace Daybreak.Launch
{
public sealed class Launcher : ExtendedApplication<MainWindow>
{
public static IServiceManager ApplicationServiceManager { get; private set; }
private ILogger logger;
private readonly static Launcher launcher = new();
[STAThread]
@@ -26,10 +24,14 @@ namespace Daybreak.Launch
return LaunchMainWindow();
}
protected override void SetupServiceManager(IServiceManager serviceManager)
{
ProjectConfiguration.RegisterResolvers(serviceManager);
}
protected override void RegisterServices(IServiceProducer serviceProducer)
{
ProjectConfiguration.RegisterServices(this.ServiceManager);
ProjectConfiguration.RegisterLifetimeServices(this.ServiceManager.GetService<IApplicationLifetimeManager>());
ServiceManager.BuildSingletons();
ProjectConfiguration.RegisterViews(this.ServiceManager.GetService<IViewManager>());
}
protected override bool HandleException(Exception e)
@@ -39,25 +41,59 @@ namespace Daybreak.Launch
return false;
}
this.ServiceManager.GetService<ILogger>().LogCritical(e);
if (e is FatalException fatalException)
if (this.logger is null)
{
MessageBox.Show(fatalException.ToString());
return false;
}
if (e is FatalException fatalException)
{
this.logger.LogCritical(e, $"{nameof(FatalException)} encountered. Closing application");
MessageBox.Show(fatalException.ToString());
File.WriteAllText("crash.log", e.ToString());
return false;
}
else if (e is TargetInvocationException targetInvocationException && e.InnerException is FatalException innerFatalException)
{
this.logger.LogCritical(e, $"{nameof(FatalException)} encountered. Closing application");
MessageBox.Show(innerFatalException.ToString());
File.WriteAllText("crash.log", e.ToString());
return false;
}
else if (e is AggregateException aggregateException)
{
if (aggregateException.InnerExceptions.FirstOrDefault() is COMException comException &&
comException.Message.Contains("Invalid window handle"))
{
/*
* Ignore exception caused by browser failing to initialize due to missing window.
* Likely caused by switching views before browser was initialized.
*/
this.logger.LogError(e, "Failed to initialize browser");
return true;
}
}
else if (e.Message.Contains("Invalid window handle.") && e.StackTrace.Contains("CoreWebView2Environment.CreateCoreWebView2ControllerAsync"))
{
/*
* Ignore exception caused by browser failing to initialize due to missing window.
* Likely caused by switching views before the browser was initialized.
*/
this.logger.LogError(e, "Failed to initialize browser");
return true;
}
this.logger.LogError(e, $"Unhandled exception caught {e.GetType()}");
MessageBox.Show(e.ToString());
return true;
}
protected override void ApplicationStarting()
{
ApplicationServiceManager = this.ServiceManager;
this.ServiceManager.GetService<IApplicationLifetimeManager>().OnStartup();
this.logger = this.ServiceManager.GetService<ILogger<Launcher>>();
this.RegisterViewContainer();
}
protected override void ApplicationClosing()
{
this.ServiceManager.GetService<IApplicationLifetimeManager>().OnClosing();
}
private void RegisterViewContainer()
+57 -40
View File
@@ -16,43 +16,46 @@
Title="Daybreak"
d:DesignHeight="450" d:DesignWidth="800">
<Window.Resources>
<Style x:Key="Window_SettingsButton" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Grid>
<Rectangle x:Name="OverlayRect" Fill="{TemplateBinding Background}" Opacity="0"></Rectangle>
<Viewbox Margin="5" Stretch="Uniform">
<Grid>
<Path Stroke="{TemplateBinding Foreground}" VerticalAlignment="Center" HorizontalAlignment="Center"
<ResourceDictionary>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
<Style x:Key="Window_SettingsButton" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Grid>
<Rectangle x:Name="OverlayRect" Fill="{TemplateBinding Background}" Opacity="0"></Rectangle>
<Viewbox Margin="5" Stretch="Uniform">
<Grid>
<Path Stroke="{TemplateBinding Foreground}" VerticalAlignment="Center" HorizontalAlignment="Center"
Data="m76.89,45.018c0,-1.587 -0.151,-3.138 -0.383,-4.66l11.227,-6.48l-11.639,-20.136l-11.616,6.47c-2.421,-1.931 -5.479,-3.506 -8.479,-4.664l0,-11.548l-22,0l0,11.548c-4,1.112 -5.649,2.617 -8.005,4.448l-11.251,-6.604l-11.914,20.006l11.12,6.604c-0.262,1.643 -0.45,3.308 -0.45,5.016c0,1.587 0.153,3.136 0.376,4.658l-11.228,6.484l11.634,20.135l11.424,-6.472c2.431,1.933 4.294,3.506 8.294,4.665l0,12.512l22,0l0,-12.512c3,-1.115 5.839,-2.618 8.19,-4.449l11.348,6.604l11.96,-20.006l-11.095,-6.603c0.258,-1.64 0.487,-3.304 0.487,-5.016zm-31.704,14.137c-7.799,0 -14.138,-6.332 -14.138,-14.138c0,-7.808 6.339,-14.136 14.138,-14.136c7.81,0 14.14,6.328 14.14,14.136c-0.001,7.806 -6.331,14.138 -14.14,14.138z"></Path>
<Path Fill="{TemplateBinding Foreground}" VerticalAlignment="Center" HorizontalAlignment="Center"
<Path Fill="{TemplateBinding Foreground}" VerticalAlignment="Center" HorizontalAlignment="Center"
Data="m56.5,89l-22,0c-1.381,0 -2.5,-1.119 -2.5,-2.5l0,-10.199c-2.612,-0.955 -4.464,-2.126 -6.274,-3.49l-10.229,5.671c-1.192,0.661 -2.694,0.244 -3.377,-0.936l-11.633,-20.135c-0.331,-0.574 -0.422,-1.257 -0.25,-1.897s0.591,-1.188 1.165,-1.519l9.794,-5.654c-0.121,-1.164 -0.181,-2.262 -0.181,-3.323c0,-1.317 0.112,-2.592 0.254,-3.721l-9.656,-5.75c-0.57,-0.34 -0.982,-0.893 -1.145,-1.537c-0.163,-0.644 -0.063,-1.326 0.279,-1.896l11.977,-20.006c0.702,-1.173 2.218,-1.564 3.399,-0.878l9.927,5.762c1.618,-1.213 3.362,-2.346 5.949,-3.273l0,-10.219c0.001,-1.381 1.12,-2.5 2.501,-2.5l22,0c1.381,0 2.5,1.119 2.5,2.5l0,10.377c2.124,0.938 4.104,2.059 5.919,3.35l9.939,-5.657c1.19,-0.677 2.713,-0.269 3.4,0.922l11.639,20.135c0.332,0.574 0.423,1.257 0.251,1.897s-0.591,1.188 -1.165,1.519l-9.781,5.646c0.126,1.165 0.188,2.266 0.188,3.329c0,1.327 -0.108,2.597 -0.246,3.717l9.692,5.752c0.571,0.339 0.983,0.891 1.147,1.533c0.163,0.644 0.065,1.325 -0.274,1.896l-11.897,20.005c-0.703,1.183 -2.234,1.573 -3.416,0.876l-9.798,-5.765c-1.782,1.25 -3.634,2.29 -5.598,3.144l0,10.324c0,1.381 -1.119,2.5 -2.5,2.5zm-19.5,-5l17,0l0,-9.512c0,-1.045 0.649,-1.979 1.629,-2.344c2.624,-0.975 5.004,-2.309 7.275,-4.078c0.809,-0.629 1.921,-0.702 2.804,-0.182l9.078,5.341l9.347,-15.716l-8.974,-5.325c-0.88,-0.522 -1.354,-1.528 -1.194,-2.538c0.198,-1.259 0.425,-2.923 0.425,-4.629c0,-1.314 -0.116,-2.716 -0.354,-4.284c-0.154,-1.018 0.33,-2.026 1.222,-2.541l9.061,-5.23l-9.145,-15.818l-9.208,5.241c-0.888,0.505 -1.995,0.42 -2.795,-0.219c-2.199,-1.754 -4.747,-3.196 -7.57,-4.286c-0.964,-0.372 -1.6,-1.299 -1.6,-2.332l0,-9.548l-17.001,0l0,9.548c0,1.123 -0.748,2.107 -1.83,2.408c-3.47,0.965 -5.073,2.212 -7.293,3.938l-0.098,0.076c-0.804,0.625 -1.909,0.7 -2.789,0.188l-9.243,-5.365l-9.423,15.739l8.937,5.321c0.879,0.524 1.351,1.531 1.189,2.542c-0.202,1.27 -0.435,2.943 -0.435,4.622c0,1.318 0.112,2.724 0.342,4.297c0.148,1.013 -0.337,2.015 -1.224,2.526l-9.065,5.234l9.151,15.842l9.525,-5.28c0.883,-0.49 1.976,-0.4 2.768,0.229c2.384,1.896 4.207,3.214 7.684,4.221c1.069,0.31 1.804,1.29 1.804,2.402l0,9.512zm8.186,-22.345c-9.174,0 -16.638,-7.464 -16.638,-16.638c0,-9.173 7.464,-16.636 16.638,-16.636c9.175,0 16.64,7.463 16.64,16.636c-0.001,9.174 -7.466,16.638 -16.64,16.638zm0,-28.273c-6.417,0 -11.638,5.22 -11.638,11.636c0,6.417 5.221,11.638 11.638,11.638c6.418,0 11.64,-5.221 11.64,-11.638c-0.001,-6.416 -5.222,-11.636 -11.64,-11.636z"></Path>
</Grid>
</Viewbox>
</Grid>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"></Condition>
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Opacity" TargetName="OverlayRect" Value="0.5"></Setter>
</MultiTrigger.Setters>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="False"></Condition>
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Opacity" TargetName="OverlayRect" Value="0"></Setter>
</MultiTrigger.Setters>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid>
</Viewbox>
</Grid>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"></Condition>
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Opacity" TargetName="OverlayRect" Value="0.5"></Setter>
</MultiTrigger.Setters>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="False"></Condition>
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Opacity" TargetName="OverlayRect" Value="0"></Setter>
</MultiTrigger.Setters>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid Background="Black">
<Grid.RowDefinitions>
@@ -69,8 +72,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 +81,26 @@
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>
<WrapPanel Grid.Row="1" Margin="0, 0, 20, 10" VerticalAlignment="Bottom" HorizontalAlignment="Right">
<controls:OpaqueButton Grid.Row="1" Background="Transparent" BorderBrush="Transparent" BorderThickness="0" Opacity="0.6"
Text="{Binding ElementName=_this, Path=CurrentVersionText, Mode=OneWay}" FontSize="10"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Clicked="VersionText_Clicked"></controls:OpaqueButton>
<controls:OpaqueButton Grid.Row="1" Background="Transparent" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Opacity="0.6" Text=" - " FontSize="10" BorderBrush="Transparent" BorderThickness="0"
Visibility="{Binding ElementName=_this, Path=IsRunningAsAdmin, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
Clicked="VersionText_Clicked"></controls:OpaqueButton>
<controls:OpaqueButton Grid.Row="1" Background="Transparent" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Opacity="0.6" Text="[Admin]" FontSize="10" BorderBrush="Transparent" BorderThickness="0"
Visibility="{Binding ElementName=_this, Path=IsRunningAsAdmin, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
Clicked="VersionText_Clicked"></controls:OpaqueButton>
</WrapPanel>
<Grid x:Name="Container" Grid.Row="1">
</Grid>
<wcl:Border OnResize="Border_OnResize" Grid.RowSpan="2" Active="True"></wcl:Border>
</Grid>
</Window>
+31 -19
View File
@@ -1,10 +1,13 @@
using Daybreak.Services.Bloogum;
using Daybreak.Configuration;
using Daybreak.Services.Bloogum;
using Daybreak.Services.Privilege;
using Daybreak.Services.Screenshots;
using Daybreak.Services.Updater;
using Daybreak.Services.ViewManagement;
using Daybreak.Views;
using Pepa.Wpf.Utilities;
using System;
using System.Configuration;
using System.Diagnostics;
using System.Extensions;
using System.Threading;
@@ -20,35 +23,45 @@ namespace Daybreak.Launch
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Fields used by source generator for DependencyProperty")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Used by source generators")]
public partial class MainWindow : Window
{
public static readonly DependencyProperty CreditTextProperty = DependencyPropertyExtensions.Register<MainWindow, string>(nameof(CreditText));
private readonly IViewManager viewManager;
private readonly IScreenshotProvider screenshotProvider;
private readonly IBloogumClient bloogumClient;
private readonly IApplicationUpdater applicationUpdater;
private readonly IPrivilegeManager privilegeManager;
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
private readonly CancellationTokenSource cancellationToken = new();
public string CreditText
{
get => this.GetTypedValue<string>(CreditTextProperty);
set => this.SetValue(CreditTextProperty, value);
}
[GenerateDependencyProperty]
private string creditText;
[GenerateDependencyProperty]
private string currentVersionText;
[GenerateDependencyProperty]
private bool isRunningAsAdmin;
public MainWindow(
IViewManager viewManager,
IScreenshotProvider screenshotProvider,
IBloogumClient bloogumClient,
IApplicationUpdater applicationUpdater)
IApplicationUpdater applicationUpdater,
IPrivilegeManager privilegeManager,
ILiveOptions<ApplicationConfiguration> liveOptions)
{
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
this.screenshotProvider = screenshotProvider.ThrowIfNull(nameof(screenshotProvider));
this.bloogumClient = bloogumClient.ThrowIfNull(nameof(bloogumClient));
this.applicationUpdater = applicationUpdater.ThrowIfNull(nameof(applicationUpdater));
InitializeComponent();
this.privilegeManager = privilegeManager.ThrowIfNull(nameof(privilegeManager));
this.liveOptions = liveOptions.ThrowIfNull(nameof(liveOptions));
this.InitializeComponent();
this.CurrentVersionText = this.applicationUpdater.CurrentVersion.ToString();
this.IsRunningAsAdmin = this.privilegeManager.AdminPrivileges;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.SetupImageCycle();
@@ -123,7 +136,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))
{
@@ -131,6 +144,11 @@ namespace Daybreak.Launch
}
}
private void VersionText_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<VersionManagementView>();
}
private void SetImage(ImageSource imageSource)
{
this.ImageViewer.ShowImage(imageSource);
@@ -151,7 +169,7 @@ namespace Daybreak.Launch
private async void CheckForUpdates()
{
var updateAvailable = await this.applicationUpdater.UpdateAvailable().ConfigureAwait(true);
var updateAvailable = this.liveOptions.Value.AutoCheckUpdate is true && await this.applicationUpdater.UpdateAvailable().ConfigureAwait(true);
if (updateAvailable)
{
this.viewManager.ShowView<AskUpdateView>();
@@ -165,13 +183,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)
+24
View File
@@ -0,0 +1,24 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Daybreak.Models.Browser
{
public class BrowserPayload
{
[JsonConverter(typeof(StringEnumConverter))]
public enum PayloadKeys
{
None,
ContextMenu
}
[JsonProperty("Key")]
public PayloadKeys Key { get; set; }
}
public sealed class BrowserPayload<T> : BrowserPayload
{
[JsonProperty("Value")]
public T Value { get; set; }
}
}
@@ -0,0 +1,14 @@
using Newtonsoft.Json;
namespace Daybreak.Models.Browser
{
public sealed class OnContextMenuPayload
{
[JsonProperty("X")]
public double X { get; set; }
[JsonProperty("Y")]
public double Y { get; set; }
[JsonProperty("Selection")]
public string Selection { get; set; }
}
}
+143
View File
@@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Daybreak.Models.Builds
{
public sealed class Attribute
{
public static Attribute FastCasting { get; } = new() { Name = "Fast Casting", Id = 0 };
public static Attribute IllusionMagic { get; } = new() { Name = "Illusion Magic", Id = 1 };
public static Attribute DominationMagic { get; } = new() { Name = "Domination Magic", Id = 2 };
public static Attribute InspirationMagic { get; } = new() { Name = "Inspiration Magic", Id = 3 };
public static Attribute BloodMagic { get; } = new() { Name = "Blood Magic", Id = 4 };
public static Attribute DeathMagic { get; } = new() { Name = "Death Magic", Id = 5 };
public static Attribute SoulReaping { get; } = new() { Name = "Soul Reaping", Id = 6 };
public static Attribute Curses { get; } = new() { Name = "Curses", Id = 7 };
public static Attribute AirMagic { get; } = new() { Name = "Air Magic", Id = 8 };
public static Attribute EarthMagic { get; } = new() { Name = "Earth Magic", Id = 9 };
public static Attribute FireMagic { get; } = new() { Name = "Fire Magic", Id = 10 };
public static Attribute WaterMagic { get; } = new() { Name = "Water Magic", Id = 11 };
public static Attribute EnergyStorage { get; } = new() { Name = "Energy Storage", Id = 12 };
public static Attribute HealingPrayers { get; } = new() { Name = "Healing Prayers", Id = 13 };
public static Attribute SmitingPrayers { get; } = new() { Name = "Smiting Prayers", Id = 14 };
public static Attribute ProtectionPrayers { get; } = new() { Name = "Protection Prayers", Id = 15 };
public static Attribute DivineFavor { get; } = new() { Name = "Divine Favor", Id = 16 };
public static Attribute Strength { get; } = new() { Name = "Strength", Id = 17 };
public static Attribute AxeMastery { get; } = new() { Name = "Axe Mastery", Id = 18 };
public static Attribute HammerMastery { get; } = new() { Name = "Hammer Mastery", Id = 19 };
public static Attribute Swordsmanship { get; } = new() { Name = "Swordsmanship", Id = 20};
public static Attribute Tactics { get; } = new() { Name = "Tactics", Id = 21 };
public static Attribute BeastMastery { get; } = new() { Name = "Beast Mastery", Id = 22 };
public static Attribute Expertise { get; } = new() { Name = "Expertise", Id = 23 };
public static Attribute WildernessSurvival { get; } = new() { Name = "Wilderness Survival", Id = 24 };
public static Attribute Marksmanship { get; } = new() { Name = "Marksmanship", Id = 25 };
public static Attribute DaggerMastery { get; } = new() { Name = "Dagger Mastery", Id = 29 };
public static Attribute DeadlyArts { get; } = new() { Name = "Deadly Arts", Id = 30 };
public static Attribute ShadowArts { get; } = new() { Name = "Shadow Arts", Id = 31 };
public static Attribute Communing { get; } = new() { Name = "Communing", Id = 32 };
public static Attribute RestorationMagic { get; } = new() { Name = "Restoration Magic", Id = 33 };
public static Attribute ChannelingMagic { get; } = new() { Name = "Channeling Magic", Id = 34 };
public static Attribute CriticalStrikes { get; } = new() { Name = "Critical Strikes", Id = 35 };
public static Attribute SpawningPower { get; } = new() { Name = "Spawning Power", Id = 36 };
public static Attribute SpearMastery { get; } = new() { Name = "Spear Mastery", Id = 37 };
public static Attribute Command { get; } = new() { Name = "Command", Id = 38 };
public static Attribute Motivation { get; } = new() { Name = "Motivation", Id = 39 };
public static Attribute Leadership { get; } = new() { Name = "Leadership", Id = 40 };
public static Attribute ScytheMastery { get; } = new() { Name = "Scythe Mastery", Id = 41 };
public static Attribute WindPrayers { get; } = new() { Name = "Wind Prayers", Id = 42 };
public static Attribute EarthPrayers { get; } = new() { Name = "Earth Prayers", Id = 43 };
public static Attribute Mysticism { get; } = new() { Name = "Mysticism", Id = 44 };
public static IEnumerable<Attribute> Attributes { get; } = new List<Attribute>
{
FastCasting,
IllusionMagic,
DominationMagic,
InspirationMagic,
BloodMagic,
DeathMagic,
SoulReaping,
Curses,
AirMagic,
EarthMagic,
FireMagic,
WaterMagic,
EnergyStorage,
HealingPrayers,
SmitingPrayers,
ProtectionPrayers,
DivineFavor,
Strength,
AxeMastery,
HammerMastery,
Swordsmanship,
Tactics,
BeastMastery,
Expertise,
WildernessSurvival,
Marksmanship,
DaggerMastery,
DeadlyArts,
ShadowArts,
Communing,
RestorationMagic,
ChannelingMagic,
CriticalStrikes,
SpawningPower,
SpearMastery,
Command,
Motivation,
Leadership,
ScytheMastery,
EarthPrayers,
WindPrayers,
EarthMagic,
Mysticism
};
public static bool TryParse(int id, out Attribute attribute)
{
attribute = Attributes.Where(attr => attr.Id == id).FirstOrDefault();
if (attribute is null)
{
return false;
}
return true;
}
public static bool TryParse(string name, out Attribute attribute)
{
attribute = Attributes.Where(attr => attr.Name == name).FirstOrDefault();
if (attribute is null)
{
return false;
}
return true;
}
public static Attribute Parse(int id)
{
if (TryParse(id, out var attribute) is false)
{
throw new InvalidOperationException($"Could not find an attribute with id {id}");
}
return attribute;
}
public static Attribute Parse(string name)
{
if (TryParse(name, out var attribute) is false)
{
throw new InvalidOperationException($"Could not find an attribute with name {name}");
}
return attribute;
}
public int Id { get; private set; }
public string Name { get; private set; }
private Attribute()
{
}
}
}
+31
View File
@@ -0,0 +1,31 @@
using System.ComponentModel;
namespace Daybreak.Models.Builds
{
public sealed class AttributeEntry : INotifyPropertyChanged
{
private Attribute attribute;
private int points;
public Attribute Attribute
{
get => this.attribute;
set
{
this.attribute = value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Attribute)));
}
}
public int Points
{
get => this.points;
set
{
this.points = value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Points)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
+13
View File
@@ -0,0 +1,13 @@
using System.Collections.Generic;
namespace Daybreak.Models.Builds
{
public sealed class Build
{
public BuildMetadata BuildMetadata { get; set; }
public Profession Primary { get; set; } = Profession.None;
public Profession Secondary { get; set; } = Profession.None;
public List<AttributeEntry> Attributes { get; set; } = new();
public List<Skill> Skills { get; set; } = new() { Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill };
}
}
+31
View File
@@ -0,0 +1,31 @@
using System.ComponentModel;
namespace Daybreak.Models.Builds
{
public sealed class BuildEntry : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string name;
private Build build;
public string PreviousName { get; set; }
public string Name
{
get => this.name;
set
{
this.name = value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
}
}
public Build Build
{
get => this.build;
set
{
this.build = value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Build)));
}
}
}
}
+23
View File
@@ -0,0 +1,23 @@
using System.Collections.Generic;
namespace Daybreak.Models.Builds
{
public sealed class BuildMetadata
{
public List<int> Base64Decoded { get; set; }
public List<string> BinaryDecoded { get; set; }
public int Header { get; set; }
public int VersionNumber { get; set; }
public int ProfessionIdLength { get; set; }
public int PrimaryProfessionId { get; set; }
public int SecondaryProfessionId { get; set; }
public int AttributeCount { get; set; }
public int AttributesLength { get; set; }
public int SkillsLength { get; set; }
public bool TailPresent { get; set; }
public bool NewTemplate { get; set; }
public List<int> SkillIds { get; set; } = new();
public List<int> AttributesIds { get; set; } = new();
public List<int> AttributePoints { get; set; } = new();
}
}
+81
View File
@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Daybreak.Models.Builds
{
public sealed class Profession
{
public static Profession None { get; } = new() { Name = "None", Id = 0, };
public static Profession Warrior { get; } = new() { Name = "Warrior", Id = 1, PrimaryAttribute = Attribute.Strength, Attributes = new List<Attribute> { Attribute.AxeMastery, Attribute.HammerMastery, Attribute.Swordsmanship, Attribute.Tactics } };
public static Profession Ranger { get; } = new() { Name = "Ranger", Id = 2, PrimaryAttribute = Attribute.Expertise, Attributes = new List<Attribute> { Attribute.BeastMastery, Attribute.Marksmanship, Attribute.WildernessSurvival } };
public static Profession Monk { get; } = new() { Name = "Monk", Id = 3, PrimaryAttribute = Attribute.DivineFavor, Attributes = new List<Attribute> { Attribute.HealingPrayers, Attribute.SmitingPrayers, Attribute.ProtectionPrayers } };
public static Profession Necromancer { get; } = new() { Name = "Necromancer", Id = 4, PrimaryAttribute = Attribute.SoulReaping, Attributes = new List<Attribute> { Attribute.Curses, Attribute.BloodMagic, Attribute.DeathMagic } };
public static Profession Mesmer { get; } = new() { Name = "Mesmer", Id = 5, PrimaryAttribute = Attribute.FastCasting, Attributes = new List<Attribute> { Attribute.DominationMagic, Attribute.IllusionMagic, Attribute.InspirationMagic } };
public static Profession Elementalist { get; } = new() { Name = "Elementalist", Id = 6, PrimaryAttribute = Attribute.EnergyStorage, Attributes = new List<Attribute> { Attribute.AirMagic, Attribute.EarthMagic, Attribute.FireMagic, Attribute.WaterMagic } };
public static Profession Assassin { get; } = new() { Name = "Assassin", Id = 7, PrimaryAttribute = Attribute.CriticalStrikes, Attributes = new List<Attribute> { Attribute.DaggerMastery, Attribute.DeadlyArts, Attribute.ShadowArts } };
public static Profession Ritualist { get; } = new() { Name = "Ritualist", Id = 8, PrimaryAttribute = Attribute.SpawningPower, Attributes = new List<Attribute> { Attribute.ChannelingMagic, Attribute.Communing, Attribute.RestorationMagic } };
public static Profession Paragon { get; } = new() { Name = "Paragon", Id = 9, PrimaryAttribute = Attribute.Leadership, Attributes = new List<Attribute> { Attribute.Command, Attribute.Motivation, Attribute.SpearMastery } };
public static Profession Dervish { get; } = new() { Name = "Dervish", Id = 10, PrimaryAttribute = Attribute.Mysticism, Attributes = new List<Attribute> { Attribute.EarthPrayers, Attribute.ScytheMastery, Attribute.WindPrayers } };
public static IEnumerable<Profession> Professions { get; } = new List<Profession>
{
None,
Warrior,
Ranger,
Monk,
Necromancer,
Mesmer,
Elementalist,
Assassin,
Ritualist,
Paragon,
Dervish
};
public static bool TryParse(int id, out Profession profession)
{
profession = Professions.Where(prof => prof.Id == id).FirstOrDefault();
if (profession is null)
{
return false;
}
return true;
}
public static bool TryParse(string name, out Profession profession)
{
profession = Professions.Where(prof => prof.Name == name).FirstOrDefault();
if (profession is null)
{
return false;
}
return true;
}
public static Profession Parse(int id)
{
if (TryParse(id, out var profession) is false)
{
throw new InvalidOperationException($"Could not find a profession with id {id}");
}
return profession;
}
public static Profession Parse(string name)
{
if (TryParse(name, out var profession) is false)
{
throw new InvalidOperationException($"Could not find a profession with name {name}");
}
return profession;
}
public string Name { get; private set; }
public int Id { get; set; }
public Attribute PrimaryAttribute { get; private set; }
public List<Attribute> Attributes { get; private set; }
private Profession()
{
}
}
}
File diff suppressed because it is too large Load Diff
+11
View File
@@ -0,0 +1,11 @@
using System;
namespace Daybreak.Models
{
public sealed class ElevationRequest
{
public object DataContext { get; set; }
public Type View { get; set; }
public string MessageToUser { get; set; }
}
}
+14
View File
@@ -0,0 +1,14 @@
using Newtonsoft.Json;
namespace Daybreak.Models.Github
{
public sealed class GithubRefTag
{
[JsonProperty("ref")]
public string Ref;
[JsonProperty("node_id")]
public string NodeId;
[JsonProperty("url")]
public string Url;
}
}
+8
View File
@@ -0,0 +1,8 @@
namespace Models
{
public sealed class IconPayload
{
public string SkillUrl { get; set; }
public string SkillImage { get; set; }
}
}
+11
View File
@@ -0,0 +1,11 @@
using Daybreak.Models.Builds;
namespace Models
{
public sealed class IconRequest
{
public Skill Skill { get; set; }
public string IconBase64 { get; set; }
public bool Finished { get; set; }
}
}
+11
View File
@@ -0,0 +1,11 @@
using System.Collections.Generic;
using System.Windows.Forms;
namespace Daybreak.Models
{
public sealed class KeyMacro
{
public List<Keys> Keys { get; set; }
public Keys TargetKey { get; set; }
}
}
+17
View File
@@ -0,0 +1,17 @@
namespace Daybreak.Models
{
public sealed class KeyboardHookEventArgs
{
public bool Handled { get; set; }
public KeyboardState KeyboardState { get; }
public KeyboardInput KeyboardInput { get; }
public KeyboardHookEventArgs(
KeyboardState keyboardState,
KeyboardInput keyboardInput)
{
this.KeyboardState = keyboardState;
this.KeyboardInput = keyboardInput;
}
}
}
+41
View File
@@ -0,0 +1,41 @@
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Daybreak.Models
{
[StructLayout(LayoutKind.Sequential)]
public struct KeyboardInput
{
/// <summary>
/// A virtual-key code. The code must be a value in the range 1 to 254.
/// </summary>
public int VirtualCode;
// EDT: added a conversion from VirtualCode to Keys.
/// <summary>
/// The VirtualCode converted to typeof(Keys) for higher usability.
/// </summary>
public Keys Key { get { return (Keys)VirtualCode; } }
/// <summary>
/// A hardware scan code for the key.
/// </summary>
public int HardwareScanCode;
/// <summary>
/// The extended-key flag, event-injected Flags, context code, and transition-state flag. This member is specified as follows. An application can use the following values to test the keystroke Flags. Testing LLKHF_INJECTED (bit 4) will tell you whether the event was injected. If it was, then testing LLKHF_LOWER_IL_INJECTED (bit 1) will tell you whether or not the event was injected from a process running at lower integrity level.
/// </summary>
public int Flags;
/// <summary>
/// The time stamp stamp for this message, equivalent to what GetMessageTime would return for this message.
/// </summary>
public int TimeStamp;
/// <summary>
/// Additional information associated with the message.
/// </summary>
public IntPtr AdditionalInformation;
}
}

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