Compare commits

...
29 Commits
Author SHA1 Message Date
f2cc59a4ab Daybreak 0.9.8.18 (#179)
* Minimap implementation

* Fix minimap

* Add debounce logic to entities positions

* Cleanup

* Fix x64 build memory reading
Move build to x64
Fix entity debouncing
Added some backstops to prevent reading corrupted memory

* Add minimap zooming and panning functionality
Add main window position saving procedure

* Increment version

---------

Co-authored-by: Alex Macocian <amacocian@hotmail.com>
2023-03-20 21:38:53 +02:00
amacocianandGitHub 6ea77f7e05 Bugfixes and improvements (#176)
Closes #175
Closes #174
Closes #173
2023-03-09 19:53:28 +00:00
amacocianandGitHub 5ea8df7cb9 Bugfixes to memory reader (#172) 2023-03-08 20:17:58 +00:00
amacocianandGitHub c70e8ec90d Implement Guildwars downloader (#171) 2023-03-08 13:24:14 +00:00
amacocianandGitHub 210e3a8cb1 Add title data to memory retrieval (#169)
Add metrics for diagnostics
Add metrics view
2023-03-07 17:20:20 +00:00
amacocianandGitHub a0c3bb094c Performance improvements (#168)
* Performance improvements and bugfixes

* Increment version

* Better builds links

* Unify loading widget size
2023-03-05 08:55:21 +01:00
amacocianandGitHub b4d932692a Reduce words in FocusView character line (#167) 2023-03-04 17:18:03 +00:00
amacocianandGitHub 667534a07a Fix version parsing (#166) 2023-03-04 18:06:53 +01:00
amacocianandGitHub 159928f24b Integrate builds with Focus view (#164)
* Integrate builds with Focus view
Detect when GameData is invalid
Detect when reading memory is faulty
Show current character data in Focus View
Closes #161
Closes #162
Closes #163

* Increment version

* Bugfix version comparison script
2023-03-04 17:21:08 +01:00
amacocianandGitHub 8a91ded610 Fix buildtemplate skill removal (#160)
Closes #159
2023-03-03 22:28:27 +00:00
amacocianandGitHub 4226b7eb32 Improve performance of buildtemplateview (#158) 2023-03-03 21:50:25 +00:00
amacocianandGitHub b61c99dd1c Fix build template failing to load secondary attributes (#157)
Improve build template handling logic
Add attribute points calculator
2023-03-03 20:51:03 +00:00
amacocianandGitHub 1ccb0d5334 Add map entry to FocusView (#155)
Fix Icon Downloader
Improve settings navigation
Change multiple views to match the design of the rest of the application
2023-03-02 20:11:00 +01:00
amacocianandGitHub 7fa01353dd UX Bugfixes and improvements (#151)
Fix memory reading issues when restarting the game
Fixed current energy and health retrieval and calculation
Added health and energy bars in focus view
Fixed focus view size calculation
Improved buildtemplate performance
Improved buildtemplate navigation
Added loading widgets to menus that are loading asynchronously
2023-03-02 16:49:00 +00:00
amacocianandGitHub 4f849d880b Ux improvements (#148)
Rearrange quest log layout
Fix some quest names
Fix some buttons ux
Mitigate issues when reading guildwars memory
2023-03-02 01:58:07 +00:00
amacocianandGitHub 4b60c96aad Closes #146 #145 (#147) 2023-03-02 00:39:52 +00:00
amacocianandGitHub a4dc0d65cf Implement Focus View (#144)
* Implement Focus View
Read extra information from guildwars

* Prever focusview browser from being disposed
2023-03-01 18:42:53 +00:00
amacocianandGitHub 85e017423f #142 - Fix Vanguard Quests Missing (#143)
Closes #142
2023-02-28 18:24:37 +00:00
amacocianandGitHub b38488937b Alexmacocian/gwca integration (#141)
Setup memory scanner
Setup Focus View
Scan for player information and show in the Focus View
Setup Quest parsing
2023-02-27 17:22:04 +01:00
amacocianandGitHub d291d5825a #125 - Setup onboarding flow (#133)
* #125 - Setup onboarding flow
Closes #125

* Fix MenuService logging
2023-02-03 15:27:06 +00:00
amacocianandGitHub 9d6162f65f #131 - Downgrade to .net6 (#132) 2023-02-02 20:50:35 +00:00
amacocianandGitHub f54ab42a92 #129 - Change hashing algorithm to SHA512 (#130) 2023-02-02 18:31:07 +00:00
amacocianandGitHub 78c8ae3e8f #127 - Introduce Nullable Support (#128) 2023-02-02 18:05:10 +00:00
amacocianandGitHub c64830c5b6 #123 #113 #105 Build Templates Improvements (#124) 2023-01-21 21:35:16 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
561c7cf7b1 Bump microsoft/setup-msbuild from 1.0.1 to 1.1.3 (#111)
Bumps [microsoft/setup-msbuild](https://github.com/microsoft/setup-msbuild) from 1.0.1 to 1.1.3.
- [Release notes](https://github.com/microsoft/setup-msbuild/releases)
- [Changelog](https://github.com/microsoft/setup-msbuild/blob/master/building-release.md)
- [Commits](https://github.com/microsoft/setup-msbuild/compare/v1.0.1...v1.1.3)

---
updated-dependencies:
- dependency-name: microsoft/setup-msbuild
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-09 15:22:44 +01:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2c6862de41 Bump coverlet.collector from 3.1.2 to 3.2.0 (#112)
Bumps [coverlet.collector](https://github.com/coverlet-coverage/coverlet) from 3.1.2 to 3.2.0.
- [Release notes](https://github.com/coverlet-coverage/coverlet/releases)
- [Commits](https://github.com/coverlet-coverage/coverlet/commits/v3.2.0)

---
updated-dependencies:
- dependency-name: coverlet.collector
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-09 15:10:18 +01:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
69842cbadf Bump Microsoft.NET.Test.Sdk from 17.4.0-preview-20221003-03 to 17.4.0 (#116)
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.4.0-preview-20221003-03 to 17.4.0.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Commits](https://github.com/microsoft/vstest/compare/v17.4.0-preview-20221003-03...v17.4.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-09 14:24:26 +01:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c7327e7bb2 Bump Microsoft.NET.Test.Sdk (#108)
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.4.0-preview-20220726-02 to 17.4.0-preview-20221003-03.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Commits](https://github.com/microsoft/vstest/compare/v17.4.0-preview-20220726-02...v17.4.0-preview-20221003-03)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-11 10:18:44 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
de33ed7fc4 Bump actions/setup-dotnet from 2 to 3 (#107)
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 2 to 3.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-11 10:09:29 +00:00
327 changed files with 21476 additions and 10839 deletions
+4 -4
View File
@@ -53,12 +53,12 @@ jobs:
echo "${{ env.Changelog }}"
- name: Install .NET Core
uses: actions/setup-dotnet@v2
uses: actions/setup-dotnet@v3
with:
dotnet-version: '6.x'
dotnet-version: '7.x'
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.0.1
uses: microsoft/setup-msbuild@v1.3.1
- name: Setup project secrets
run: |
@@ -95,7 +95,7 @@ jobs:
shell: pwsh
- name: Publish release
uses: Xotl/cool-github-releases@v1.1.7
uses: Xotl/cool-github-releases@v1.1.8
with:
mode: update
tag_name: v${{ env.Version }}
+3 -3
View File
@@ -36,12 +36,12 @@ jobs:
fetch-depth: 0
- name: Install .NET Core
uses: actions/setup-dotnet@v2
uses: actions/setup-dotnet@v3
with:
dotnet-version: '6.x'
dotnet-version: '7.x'
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.0.1
uses: microsoft/setup-msbuild@v1.3.1
- name: Execute Unit Tests
run: dotnet test $env:Test_Project_Path
+1 -1
View File
@@ -57,7 +57,7 @@ jobs:
# If this step fails, then you should remove it and run the build manually (see below)
- name: Install .NET Core
uses: actions/setup-dotnet@v2
uses: actions/setup-dotnet@v3
with:
dotnet-version: '6.x'
@@ -5,6 +5,7 @@
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Platforms>AnyCPU;x86;x64</Platforms>
</PropertyGroup>
</Project>
+7 -6
View File
@@ -3,15 +3,16 @@
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<IsPackable>false</IsPackable>
<Platforms>AnyCPU;x86;x64</Platforms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.7.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0-preview-20220726-02" />
<PackageReference Include="Moq" Version="4.18.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
<PackageReference Include="FluentAssertions" Version="6.10.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
</ItemGroup>
+170 -120
View File
@@ -5,132 +5,182 @@ using System;
using System.Linq;
using Version = Daybreak.Models.Versioning.Version;
namespace Daybreak.Tests.Models
namespace Daybreak.Tests.Models;
[TestClass]
public class VersionTests
{
[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)
{
[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);
}
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)
[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)
{
var parsedVersion = Version.Parse(version);
if (hasSuffix)
{
parsedVersion.VersionTokens.Last().Should().BeOfType<VersionStringToken>();
}
else
{
parsedVersion.VersionTokens.Last().Should().BeOfType<VersionNumberToken>();
}
parsedVersion.VersionTokens.Last().Should().BeOfType<VersionStringToken>();
}
[DataRow("v0", true)]
[DataRow("0", false)]
[DataRow("v0.1", true)]
[DataRow("0.1", false)]
[TestMethod]
public void VersionTokensHasPrefix(string version, bool hasPrefix)
else
{
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>();
}
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>();
}
}
[DataRow("v0.1.0.0.1", "v0.1.0.0.1", true)]
[DataRow("v0.1.0.0.1.0.0.0.0", "v0.1.0.0.1", true)]
[DataRow("v0.1.0", "v0.1", true)]
[DataRow("0.1.0", "0.1", true)]
[DataRow("v0.1.0.0.0", "v0.1", true)]
[DataRow("0.1.0.0.0", "0.1", true)]
[DataRow("v0", "v0", true)]
[DataRow("0", "0", true)]
[DataRow("v0.1", "v0.1", true)]
[DataRow("0.1-release", "0.1-release", true)]
[DataRow("v0.1-release", "v0.1-release", true)]
[DataRow("v0.1.0.0", "v0.1.0.0.1", false)]
[DataRow("v0.1.0.0.1", "v0.1.0.0", false)]
[DataRow("v0.9.8.9", "v0.9.8.10", false)]
[DataRow("0.1-release", "0.2-release", false)]
[DataRow("v1.1-release", "v0.1-release", false)]
[TestMethod]
public void Equals(string version, string version2, bool result)
{
var parsedVersion1 = Version.Parse(version);
var parsedVersion2 = Version.Parse(version2);
parsedVersion1.Equals(parsedVersion2).Should().Be(result);
}
[DataRow("v0.1.0.0.1", "v0.1.0.0.1", 0)]
[DataRow("v0.1.0.0.1.0.0.0.0", "v0.1.0.0.1", 0)]
[DataRow("v0.1.0", "v0.1", 0)]
[DataRow("0.1.0", "0.1", 0)]
[DataRow("v0.1.0.0.0", "v0.1", 0)]
[DataRow("0.1.0.0.0", "0.1", 0)]
[DataRow("v0", "v0", 0)]
[DataRow("0", "0", 0)]
[DataRow("v0.1", "v0.1", 0)]
[DataRow("0.1-release", "0.1-release", 0)]
[DataRow("v0.1-release", "v0.1-release", 0)]
[DataRow("v0.1.0.0", "v0.1.0.0.1", -1)]
[DataRow("v0.1.0.0.1", "v0.1.0.0", 1)]
[DataRow("v0.9.8.9", "v0.9.8.10", -1)]
[DataRow("v0.9.8.10", "v0.9.8.9", 1)]
[DataRow("0.1-release", "0.2-release", -1)]
[DataRow("v1.1-release", "v0.1-release", 1)]
[TestMethod]
public void CompareTo(string version, string version2, int comparisonResult)
{
var parsedVersion1 = Version.Parse(version);
var parsedVersion2 = Version.Parse(version2);
parsedVersion1.CompareTo(parsedVersion2).Should().Be(comparisonResult);
}
}
@@ -6,58 +6,57 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
namespace Daybreak.Tests.Services
namespace Daybreak.Tests.Services;
[TestClass]
public class ApplicationConfigurationOptionsManagerTests
{
[TestClass]
public class ApplicationConfigurationOptionsManagerTests
private ApplicationConfigurationOptionsManager applicationConfigurationOptionsManager;
[TestInitialize]
public void TestInitialize()
{
private ApplicationConfigurationOptionsManager applicationConfigurationOptionsManager;
var configurationManagerMock = new Mock<IConfigurationManager>();
configurationManagerMock
.Setup(u => u.GetConfiguration())
.Returns(new ApplicationConfiguration());
[TestInitialize]
public void TestInitialize()
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(() =>
{
var configurationManagerMock = new Mock<IConfigurationManager>();
configurationManagerMock
.Setup(u => u.GetConfiguration())
.Returns(new ApplicationConfiguration());
this.applicationConfigurationOptionsManager.GetOptions<object>();
});
this.applicationConfigurationOptionsManager = new ApplicationConfigurationOptionsManager(configurationManagerMock.Object);
}
action.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public void GetApplicationConfiguration_ReturnsObject()
[TestMethod]
public void UpdateOptions_OnApplicationConfiguration_Succeeds()
{
this.applicationConfigurationOptionsManager.UpdateOptions(new ApplicationConfiguration());
}
[TestMethod]
public void UpdateOptions_OnOthers_ThrowsInvalidOperationException()
{
var action = new Action(() =>
{
var config = this.applicationConfigurationOptionsManager.GetOptions<ApplicationConfiguration>();
this.applicationConfigurationOptionsManager.UpdateOptions(new object());
});
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>();
}
action.Should().Throw<InvalidOperationException>();
}
}
@@ -1,4 +1,5 @@
using Daybreak.Models.Builds;
using Daybreak.Models.Guildwars;
using Daybreak.Services.BuildTemplates;
using FluentAssertions;
using Microsoft.Extensions.Logging;
@@ -6,91 +7,90 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System.Collections.Generic;
namespace Daybreak.Tests.Services
namespace Daybreak.Tests.Services;
[TestClass]
public class BuildTemplateManagerTests
{
[TestClass]
public class BuildTemplateManagerTests
private const string EncodedTemplate = "OwBk0texXNu0Dj/z+TDzBj+TN4AE";
private IBuildTemplateManager buildTemplateManager;
[TestInitialize]
public void Initialize()
{
private const string EncodedTemplate = "OwBk0texXNu0Dj/z+TDzBj+TN4AE";
private IBuildTemplateManager buildTemplateManager;
this.buildTemplateManager = new BuildTemplateManager(new Mock<ILogger<BuildTemplateManager>>().Object);
}
[TestInitialize]
public void Initialize()
{
this.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[1].Attribute.Should().Be(Attribute.DaggerMastery);
build.Attributes[1].Points.Should().Be(11);
build.Attributes[2].Attribute.Should().Be(Attribute.DeadlyArts);
build.Attributes[2].Points.Should().Be(1);
build.Attributes[3].Attribute.Should().Be(Attribute.ShadowArts);
build.Attributes[3].Points.Should().Be(5);
build.Attributes[0].Attribute.Should().Be(Attribute.CriticalStrikes);
build.Attributes[0].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 TestDecode()
[TestMethod]
public void TestEncode()
{
var build = new Build()
{
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>
{
Primary = Profession.Assassin,
Secondary = Profession.None,
Attributes = new List<AttributeEntry>
new 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
}
Attribute = Attribute.DaggerMastery,
Points = 11
},
Skills = new List<Skill>
new AttributeEntry
{
Skill.UnsuspectingStrike,
Skill.WildStrike,
Skill.CriticalStrike,
Skill.MoebiusStrike,
Skill.DeathBlossom,
Skill.CriticalEye,
Skill.CriticalAgility,
Skill.CriticalDefenses
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);
}
var encoded = this.buildTemplateManager.EncodeTemplate(build);
encoded.Should().Be(EncodedTemplate);
}
}
@@ -7,68 +7,67 @@ using System.IO;
using System.Linq;
using System.Logging;
namespace Daybreak.Tests.Services
namespace Daybreak.Tests.Services;
[TestClass]
public class JsonLoggerProviderTests
{
[TestClass]
public class JsonLoggerProviderTests
private ILogsManager logsManager;
private ILoggerProvider loggerProvider;
private ILiteDatabase liteDatabase;
[TestInitialize]
public void InitializeProvider()
{
private ILogsManager logsManager;
private ILoggerProvider loggerProvider;
private ILiteDatabase liteDatabase;
File.Delete("Daybreak.db");
this.liteDatabase = new LiteDatabase("Daybreak.db");
this.logsManager = new JsonLogsManager(this.liteDatabase);
this.loggerProvider = new CVLoggerProvider(this.logsManager);
}
[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();
}
[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");
[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(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);
}
[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.GetLogs().Should().HaveCount(2);
this.logsManager.DeleteLogs();
this.logsManager.GetLogs().Should().HaveCount(0);
}
this.logsManager.DeleteLogs();
this.logsManager.GetLogs().Should().HaveCount(0);
}
}
+26 -12
View File
@@ -35,34 +35,48 @@ Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
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|Any CPU
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Debug|x64.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|x86.ActiveCfg = Debug|x86
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Debug|x86.Build.0 = Debug|x86
{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|Any CPU
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Release|x64.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|x86.ActiveCfg = Release|x86
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Release|x86.Build.0 = Release|x86
{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}.Debug|x64.ActiveCfg = Debug|x64
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Debug|x64.Build.0 = Debug|x64
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Debug|x86.ActiveCfg = Debug|x86
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Debug|x86.Build.0 = Debug|x86
{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
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x64.ActiveCfg = Release|x64
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x64.Build.0 = Release|x64
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x86.ActiveCfg = Release|x86
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x86.Build.0 = Release|x86
{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}.Debug|x64.ActiveCfg = Debug|x64
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x64.Build.0 = Debug|x64
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x86.ActiveCfg = Debug|x86
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x86.Build.0 = Debug|x86
{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
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x64.ActiveCfg = Release|x64
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x64.Build.0 = Release|x64
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x86.ActiveCfg = Release|x86
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+62 -63
View File
@@ -6,74 +6,73 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Daybreak.Behaviors
namespace Daybreak.Behaviors;
public class ScaleFontWithSize : Behavior<TextBlock>
{
public class ScaleFontWithSize : Behavior<TextBlock>
public static readonly DependencyProperty MaxFontSizeProperty = DependencyProperty.Register("MaxFontSize", typeof(double), typeof(ScaleFontWithSize), new PropertyMetadata(12d));
public double MaxFontSize
{
public static readonly DependencyProperty MaxFontSizeProperty = DependencyProperty.Register("MaxFontSize", typeof(double), typeof(ScaleFontWithSize), new PropertyMetadata(12d));
public double MaxFontSize
get
{
get
{
return (double)this.GetValue(MaxFontSizeProperty);
}
set
{
this.SetValue(MaxFontSizeProperty, value);
}
return (double)this.GetValue(MaxFontSizeProperty);
}
protected override void OnAttached()
set
{
base.OnAttached();
this.AssociatedObject.SizeChanged += (_, __) => this.CalculateFontSize();
DependencyPropertyDescriptor.FromProperty(
TextBlock.TextProperty, typeof(TextBlock)).AddValueChanged(this.AssociatedObject, (_, __) => this.CalculateFontSize());
DependencyPropertyDescriptor.FromProperty(
TextBlock.FontSizeProperty, typeof(TextBlock)).AddValueChanged(this.AssociatedObject, (_, __) => this.CalculateFontSize());
}
private void CalculateFontSize()
{
var textMeasurement = this.MeasureText(this.AssociatedObject.FontSize);
var maximumTextMeasurement = this.MeasureText(this.MaxFontSize);
var desiredWidthFontSize = this.MaxFontSize;
var desiredHeightFontSize = this.MaxFontSize;
if (Math.Round(textMeasurement.Height) != Math.Round(this.AssociatedObject.ActualHeight))
{
var scale = this.AssociatedObject.ActualHeight / maximumTextMeasurement.Height;
desiredHeightFontSize = (this.MaxFontSize * scale) - 1;
desiredHeightFontSize = desiredHeightFontSize <= this.MaxFontSize ? desiredHeightFontSize : this.MaxFontSize;
}
if (Math.Round(textMeasurement.Width) != Math.Round(this.AssociatedObject.ActualWidth))
{
var scale = this.AssociatedObject.ActualWidth / maximumTextMeasurement.Width;
desiredWidthFontSize = (this.MaxFontSize * scale) - 1;
desiredWidthFontSize = desiredWidthFontSize <= this.MaxFontSize ? desiredWidthFontSize : this.MaxFontSize;
}
var desiredFontSize = Math.Min(desiredHeightFontSize, desiredWidthFontSize);
if ((int)desiredFontSize != (int)this.AssociatedObject.FontSize && desiredFontSize > 0)
{
this.AssociatedObject.FontSize = desiredFontSize;
return;
}
}
private Size MeasureText(double fontSize)
{
var formattedText = new FormattedText(this.AssociatedObject.Text, CultureInfo.CurrentUICulture,
FlowDirection.LeftToRight,
new Typeface(this.AssociatedObject.FontFamily, this.AssociatedObject.FontStyle, this.AssociatedObject.FontWeight, this.AssociatedObject.FontStretch),
fontSize, Brushes.Black, VisualTreeHelper.GetDpi(this.AssociatedObject).PixelsPerDip);
return new Size(formattedText.Width, formattedText.Height);
this.SetValue(MaxFontSizeProperty, value);
}
}
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.SizeChanged += (_, __) => this.CalculateFontSize();
DependencyPropertyDescriptor.FromProperty(
TextBlock.TextProperty, typeof(TextBlock)).AddValueChanged(this.AssociatedObject, (_, __) => this.CalculateFontSize());
DependencyPropertyDescriptor.FromProperty(
TextBlock.FontSizeProperty, typeof(TextBlock)).AddValueChanged(this.AssociatedObject, (_, __) => this.CalculateFontSize());
}
private void CalculateFontSize()
{
var textMeasurement = this.MeasureText(this.AssociatedObject.FontSize);
var maximumTextMeasurement = this.MeasureText(this.MaxFontSize);
var desiredWidthFontSize = this.MaxFontSize;
var desiredHeightFontSize = this.MaxFontSize;
if (Math.Round(textMeasurement.Height) != Math.Round(this.AssociatedObject.ActualHeight))
{
var scale = this.AssociatedObject.ActualHeight / maximumTextMeasurement.Height;
desiredHeightFontSize = (this.MaxFontSize * scale) - 1;
desiredHeightFontSize = desiredHeightFontSize <= this.MaxFontSize ? desiredHeightFontSize : this.MaxFontSize;
}
if (Math.Round(textMeasurement.Width) != Math.Round(this.AssociatedObject.ActualWidth))
{
var scale = this.AssociatedObject.ActualWidth / maximumTextMeasurement.Width;
desiredWidthFontSize = (this.MaxFontSize * scale) - 1;
desiredWidthFontSize = desiredWidthFontSize <= this.MaxFontSize ? desiredWidthFontSize : this.MaxFontSize;
}
var desiredFontSize = Math.Min(desiredHeightFontSize, desiredWidthFontSize);
if ((int)desiredFontSize != (int)this.AssociatedObject.FontSize && desiredFontSize > 0)
{
this.AssociatedObject.FontSize = desiredFontSize;
return;
}
}
private Size MeasureText(double fontSize)
{
var formattedText = new FormattedText(this.AssociatedObject.Text, CultureInfo.CurrentUICulture,
FlowDirection.LeftToRight,
new Typeface(this.AssociatedObject.FontFamily, this.AssociatedObject.FontStyle, this.AssociatedObject.FontWeight, this.AssociatedObject.FontStretch),
fontSize, Brushes.Black, VisualTreeHelper.GetDpi(this.AssociatedObject).PixelsPerDip);
return new Size(formattedText.Width, formattedText.Height);
}
}
+41 -42
View File
@@ -3,53 +3,52 @@ 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 += this.AssociatedObject_SelectionChanged;
}
namespace Daybreak.Behaviors;
/// <summary>
/// On Selection Changed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void AssociatedObject_SelectionChanged(object sender,
SelectionChangedEventArgs e)
public class ScrollIntoView : Behavior<ListView>
{
/// <summary>
/// When Beahvior is attached
/// </summary>
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.SelectionChanged += this.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)
{
if (sender is ListView)
var listView = sender.As<ListView>();
if (listView.SelectedItem != null)
{
var listView = sender.As<ListView>();
if (listView.SelectedItem != null)
{
listView.Dispatcher.BeginInvoke(
(Action)(() =>
{
listView.UpdateLayout();
if (listView.SelectedItem !=
null)
listView.ScrollIntoView(
listView.SelectedItem);
}));
}
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 -=
this.AssociatedObject_SelectionChanged;
}
/// <summary>
/// When behavior is detached
/// </summary>
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.SelectionChanged -=
this.AssociatedObject_SelectionChanged;
}
}
}
@@ -1,45 +1,49 @@
using Daybreak.Models;
using Daybreak.Configuration.FocusView;
using Daybreak.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace Daybreak.Configuration
namespace Daybreak.Configuration;
public sealed class ApplicationConfiguration
{
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")]
public string TexmodPath { get; set; }
[JsonProperty("ToolboxAutoLaunch")]
public bool ToolboxAutoLaunch { get; set; }
[JsonProperty("LeftBrowserDefault")]
public string LeftBrowserDefault { get; set; } = "https://gwpvx.fandom.com/wiki/PvX_wiki";
[JsonProperty("RightBrowserDefault")]
public string RightBrowserDefault { get; set; } = "https://wiki.guildwars.com/wiki/Quick_access_links";
[JsonProperty("GuildwarsPaths")]
public List<GuildwarsPath> GuildwarsPaths { get; set; } = new();
[JsonProperty("ProtectedLoginCredentials")]
public List<ProtectedLoginCredentials> ProtectedLoginCredentials { get; set; } = new();
[JsonProperty("AddressBarReadonly")]
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;
[JsonProperty("ProtectedGraphAccessToken")]
public string ProtectedGraphAccessToken { get; set; }
[JsonProperty("ProtectedGraphRefreshToken")]
public string ProtectedGraphRefreshToken { get; set; }
}
[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")]
public string? TexmodPath { get; set; }
[JsonProperty("ToolboxAutoLaunch")]
public bool ToolboxAutoLaunch { get; set; }
[JsonProperty("LeftBrowserDefault")]
public string? LeftBrowserDefault { get; set; } = "https://gwpvx.fandom.com/wiki/PvX_wiki";
[JsonProperty("RightBrowserDefault")]
public string? RightBrowserDefault { get; set; } = "https://wiki.guildwars.com/wiki/Quick_access_links";
[JsonProperty("GuildwarsPaths")]
public List<GuildwarsPath> GuildwarsPaths { get; set; } = new();
[JsonProperty("ProtectedLoginCredentials")]
public List<ProtectedLoginCredentials> ProtectedLoginCredentials { get; set; } = new();
[JsonProperty("AddressBarReadonly")]
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;
[JsonProperty("ProtectedGraphAccessToken")]
public string? ProtectedGraphAccessToken { get; set; }
[JsonProperty("ProtectedGraphRefreshToken")]
public string? ProtectedGraphRefreshToken { get; set; }
[JsonProperty("FocusViewOptions")]
public FocusViewOptions FocusViewOptions { get; set; } = new FocusViewOptions();
[JsonProperty("ScreenManagerOptions")]
public ScreenManagerOptions ScreenManagerOptions { get; set; } = new ScreenManagerOptions();
}
+21 -18
View File
@@ -2,23 +2,26 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Daybreak.Configuration
namespace Daybreak.Configuration;
public sealed class ExperimentalFeatures
{
public sealed class ExperimentalFeatures
{
[JsonProperty("MultiLaunchSupport")]
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();
}
[JsonProperty("MultiLaunchSupport")]
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("FocusViewEnabled")]
public bool FocusViewEnabled { get; set; }
[JsonProperty("MemoryReaderFrequency")]
public double MemoryReaderFrequency { get; set; } = 16;
[JsonProperty("Macros")]
public List<KeyMacro> Macros { get; set; } = new();
}
@@ -0,0 +1,9 @@
namespace Daybreak.Configuration.FocusView;
public enum ExperienceDisplay
{
TotalCurretAndTotalMax,
CurrentLevelCurrentAndCurrentLevelMax,
RemainingUntilNextLevel,
Percentage
}
@@ -0,0 +1,25 @@
using Newtonsoft.Json;
namespace Daybreak.Configuration.FocusView;
public sealed class FocusViewOptions
{
[JsonProperty("ExperienceDisplay")]
public ExperienceDisplay ExperienceDisplay { get; set; }
[JsonProperty("KurzickPointsDisplay")]
public PointsDisplay KurzickPointsDisplay { get; set; }
[JsonProperty("LuxonPointsDisplay")]
public PointsDisplay LuxonPointsDisplay { get; set; }
[JsonProperty("BalthazarPointsDisplay")]
public PointsDisplay BalthazarPointsDisplay { get; set; }
[JsonProperty("ImperialPointsDisplay")]
public PointsDisplay ImperialPointsDisplay { get; set; }
[JsonProperty("VanquishingDisplay")]
public PointsDisplay VanquishingDisplay { get; set; }
[JsonProperty("HealthDisplay")]
public PointsDisplay HealthDisplay { get; set; }
[JsonProperty("EnergyDisplay")]
public PointsDisplay EnergyDisplay { get; set; }
[JsonProperty("BrowserUrl")]
public string? BrowserUrl { get; set; } = string.Empty;
}
@@ -0,0 +1,8 @@
namespace Daybreak.Configuration.FocusView;
public enum PointsDisplay
{
CurrentAndMax,
Remaining,
Percentage
}
+51 -6
View File
@@ -28,11 +28,22 @@ using Daybreak.Services.Updater.PostUpdate.Actions;
using Daybreak.Services.Graph;
using Microsoft.Extensions.DependencyInjection;
using Daybreak.Services.Navigation;
using Daybreak.Services.Onboarding;
using Daybreak.Services.Menu;
using Daybreak.Services.Scanner;
using Daybreak.Services.Experience;
using Daybreak.Services.Metrics;
using Daybreak.Services.Monitoring;
using System.Net;
using System.Net.Http.Headers;
using Daybreak.Services.Downloads;
namespace Daybreak.Configuration;
public static class ProjectConfiguration
{
private const string DaybreakUserAgent = "Daybreak";
public static void RegisterResolvers(IServiceManager serviceManager)
{
serviceManager.ThrowIfNull();
@@ -44,22 +55,33 @@ public static class ProjectConfiguration
.WithMessageHandler(sp =>
{
var logger = sp.GetService<ILogger<ApplicationUpdater>>();
return new LoggingHttpMessageHandler(logger) { InnerHandler = new HttpClientHandler() };
return new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() };
})
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
.Build()
.RegisterHttpClient<BloogumClient>()
.WithMessageHandler(sp =>
{
var logger = sp.GetService<ILogger<BloogumClient>>();
return new LoggingHttpMessageHandler(logger) { InnerHandler = new HttpClientHandler() };
return new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() };
})
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
.Build()
.RegisterHttpClient<GraphClient>()
.WithMessageHandler(sp =>
{
var logger = sp.GetService<ILogger<GraphClient>>();
return new LoggingHttpMessageHandler(logger) { InnerHandler = new HttpClientHandler() };
return new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() };
})
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
.Build()
.RegisterHttpClient<DownloadService>()
.WithMessageHandler(sp =>
{
var logger = sp.GetService<ILogger<GraphClient>>();
return new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() };
})
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
.Build();
}
@@ -69,6 +91,7 @@ public static class ProjectConfiguration
services.AddSingleton<ILogsManager, JsonLogsManager>();
services.AddSingleton<IDebugLogsWriter, Services.Logging.DebugLogsWriter>();
services.AddSingleton<IEventViewerLogsWriter, EventViewerLogsWriter>();
services.AddSingleton<ILoggerFactory, LoggerFactory>(sp =>
{
var factory = new LoggerFactory();
@@ -76,23 +99,29 @@ public static class ProjectConfiguration
return factory;
});
services.AddSingleton<ILogsWriter, CompositeLogsWriter>(sp => new CompositeLogsWriter(
sp.GetService<ILogsManager>(),
sp.GetService<IDebugLogsWriter>()));
sp.GetService<ILogsManager>()!,
sp.GetService<IDebugLogsWriter>()!,
sp.GetService<IEventViewerLogsWriter>()!));
services.AddScoped((sp) => new ScopeMetadata(new CorrelationVector()));
services.AddSingleton<ViewManager>();
services.AddSingleton<ProcessorUsageMonitor>();
services.AddSingleton<MemoryUsageMonitor>();
services.AddSingleton<IViewManager, ViewManager>(sp => sp.GetRequiredService<ViewManager>());
services.AddSingleton<IViewProducer, ViewManager>(sp => sp.GetRequiredService<ViewManager>());
services.AddSingleton<PostUpdateActionManager>();
services.AddSingleton<IPostUpdateActionManager>(sp => sp.GetRequiredService<PostUpdateActionManager>());
services.AddSingleton<IPostUpdateActionProducer>(sp => sp.GetRequiredService<PostUpdateActionManager>());
services.AddSingleton<IPostUpdateActionProvider>(sp => sp.GetRequiredService<PostUpdateActionManager>());
services.AddSingleton<IMenuService, MenuService>();
services.AddSingleton<IMenuServiceInitializer, MenuService>(sp => sp.GetRequiredService<IMenuService>().As<MenuService>());
services.AddSingleton<IConfigurationManager, ConfigurationManager>();
services.AddSingleton<ILiteDatabase, LiteDatabase>(sp => new LiteDatabase("Daybreak.db"));
services.AddSingleton<IMutexHandler, MutexHandler>();
services.AddSingleton<IShortcutManager, ShortcutManager>();
services.AddSingleton<IIconBrowser, IconBrowser>();
services.AddSingleton<IIconDownloader, IconDownloader>();
services.AddSingleton<IMetricsService, MetricsService>();
services.AddScoped<ICredentialManager, CredentialManager>();
services.AddScoped<IApplicationLauncher, ApplicationLauncher>();
services.AddScoped<IScreenshotProvider, ScreenshotProvider>();
@@ -103,13 +132,21 @@ public static class ProjectConfiguration
services.AddScoped<IPrivilegeManager, PrivilegeManager>();
services.AddScoped<IScreenManager, ScreenManager>();
services.AddScoped<IGraphClient, GraphClient>();
services.AddScoped<IOnboardingService, OnboardingService>();
services.AddScoped<IGuildwarsMemoryReader, GuildwarsMemoryReader>();
services.AddScoped<IMemoryScanner, MemoryScanner>();
services.AddScoped<IExperienceCalculator, ExperienceCalculator>();
services.AddScoped<IAttributePointCalculator, AttributePointCalculator>();
services.AddScoped<IDownloadService, DownloadService>();
services.AddScoped<IGuildwarsEntityDebouncer, GuildwarsEntityDebouncer>();
}
public static void RegisterViews(IViewProducer viewProducer)
{
viewProducer.ThrowIfNull();
viewProducer.RegisterPermanentView<CompanionView>();
viewProducer.RegisterPermanentView<LauncherView>();
viewProducer.RegisterPermanentView<Views.FocusView>();
viewProducer.RegisterView<SettingsView>();
viewProducer.RegisterView<AskUpdateView>();
viewProducer.RegisterView<UpdateView>();
@@ -125,6 +162,9 @@ public static class ProjectConfiguration
viewProducer.RegisterView<IconDownloadView>();
viewProducer.RegisterView<GraphAuthorizationView>();
viewProducer.RegisterView<BuildsSynchronizationView>();
viewProducer.RegisterView<OnboardingView>();
viewProducer.RegisterView<MetricsView>();
viewProducer.RegisterView<DownloadView>();
}
public static void RegisterPostUpdateActions(IPostUpdateActionProducer postUpdateActionProducer)
@@ -133,4 +173,9 @@ public static class ProjectConfiguration
postUpdateActionProducer.AddPostUpdateAction<RenameInstallerAction>();
}
private static void SetupDaybreakUserAgent(HttpRequestHeaders httpRequestHeaders)
{
httpRequestHeaders.ThrowIfNull().TryAddWithoutValidation("User-Agent", DaybreakUserAgent);
}
}
@@ -0,0 +1,9 @@
namespace Daybreak.Configuration;
public sealed class ScreenManagerOptions
{
public double X { get; set; }
public double Y { get; set; }
public double Width { get; set; }
public double Height { get; set; }
}
+1 -1
View File
@@ -5,7 +5,7 @@ public class SecretKeys
public static readonly SecretKeys AadApplicationId = new() { Key = "AadApplicationId" };
public static readonly SecretKeys AadTenantId = new() { Key = "AadTenantId" };
public string Key { get; private set; }
public string Key { get; private set; } = string.Empty;
private SecretKeys()
{
}
+3 -3
View File
@@ -7,7 +7,7 @@ namespace Daybreak.Configuration;
public static class SecretManager
{
private static JObject SecretsHolder;
private static JObject? SecretsHolder;
public static string GetSecret(SecretKeys secretKey)
{
@@ -16,7 +16,7 @@ public static class SecretManager
LoadSecrets();
}
return SecretsHolder.Value<string>(secretKey.Key);
return SecretsHolder!.Value<string>(secretKey.Key)!;
}
public static T GetSecret<T>(SecretKeys secretKey)
@@ -26,7 +26,7 @@ public static class SecretManager
LoadSecrets();
}
return SecretsHolder.Value<T>(secretKey.Key);
return SecretsHolder!.Value<T>(secretKey.Key)!;
}
private static void LoadSecrets()
+1
View File
@@ -6,6 +6,7 @@
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
+23 -24
View File
@@ -2,36 +2,35 @@
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for AddButton.xaml
/// </summary>
public partial class AddButton : UserControl
{
/// <summary>
/// Interaction logic for AddButton.xaml
/// </summary>
public partial class AddButton : UserControl
public event EventHandler? Clicked;
public AddButton()
{
public event EventHandler Clicked;
this.InitializeComponent();
}
public AddButton()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
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_MouseLeave(object sender, MouseEventArgs e)
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
Clicked?.Invoke(this, e);
}
}
}
@@ -6,6 +6,7 @@
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
+23 -24
View File
@@ -2,36 +2,35 @@
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for BackButton.xaml
/// </summary>
public partial class BackButton : UserControl
{
/// <summary>
/// Interaction logic for BackButton.xaml
/// </summary>
public partial class BackButton : UserControl
public event EventHandler? Clicked;
public BackButton()
{
public event EventHandler Clicked;
this.InitializeComponent();
}
public BackButton()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
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_MouseLeave(object sender, MouseEventArgs e)
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
Clicked?.Invoke(this, e);
}
}
}
+1
View File
@@ -6,6 +6,7 @@
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
+24 -25
View File
@@ -2,35 +2,34 @@
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for BinButton.xaml
/// </summary>
public partial class BinButton : UserControl
{
/// <summary>
/// Interaction logic for BinButton.xaml
/// </summary>
public partial class BinButton : UserControl
public event EventHandler? Clicked;
public BinButton()
{
public event EventHandler Clicked;
public BinButton()
{
this.InitializeComponent();
}
this.InitializeComponent();
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
if (e.ChangedButton == MouseButton.Left)
{
this.Clicked?.Invoke(this, e);
}
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Visible;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Hidden;
this.Clicked?.Invoke(this, e);
}
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Visible;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Hidden;
}
}
@@ -6,6 +6,7 @@
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
+23 -24
View File
@@ -2,36 +2,35 @@
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for BackButton.xaml
/// </summary>
public partial class CancelButton : UserControl
{
/// <summary>
/// Interaction logic for BackButton.xaml
/// </summary>
public partial class CancelButton : UserControl
public event EventHandler? Clicked;
public CancelButton()
{
public event EventHandler Clicked;
this.InitializeComponent();
}
public CancelButton()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
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_MouseLeave(object sender, MouseEventArgs e)
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
Clicked?.Invoke(this, e);
}
}
}
@@ -6,6 +6,7 @@
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
@@ -2,36 +2,35 @@
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for FilePickerGlyph.xaml
/// </summary>
public partial class FilePickerGlyph : UserControl
{
/// <summary>
/// Interaction logic for FilePickerGlyph.xaml
/// </summary>
public partial class FilePickerGlyph : UserControl
public event EventHandler? Clicked;
public FilePickerGlyph()
{
public event EventHandler Clicked;
this.InitializeComponent();
}
public FilePickerGlyph()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
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_MouseLeave(object sender, MouseEventArgs e)
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.Clicked?.Invoke(this, e);
}
this.Clicked?.Invoke(this, e);
}
}
}
@@ -6,6 +6,7 @@
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
+23 -24
View File
@@ -2,36 +2,35 @@
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for AddButton.xaml
/// </summary>
public partial class HelpButton : UserControl
{
/// <summary>
/// Interaction logic for AddButton.xaml
/// </summary>
public partial class HelpButton : UserControl
public event EventHandler? Clicked;
public HelpButton()
{
public event EventHandler Clicked;
this.InitializeComponent();
}
public HelpButton()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
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_MouseLeave(object sender, MouseEventArgs e)
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.Clicked?.Invoke(this, e);
}
this.Clicked?.Invoke(this, e);
}
}
}
+2 -1
View File
@@ -4,8 +4,9 @@
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"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
+23 -24
View File
@@ -2,36 +2,35 @@
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for HomeButton.xaml
/// </summary>
public partial class HomeButton : UserControl
{
/// <summary>
/// Interaction logic for HomeButton.xaml
/// </summary>
public partial class HomeButton : UserControl
public event EventHandler? Clicked;
public HomeButton()
{
public event EventHandler Clicked;
this.InitializeComponent();
}
public HomeButton()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
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_MouseLeave(object sender, MouseEventArgs e)
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
Clicked?.Invoke(this, e);
}
}
}
@@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
x:Name="_this"
Cursor="Hand"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="50">
<Grid>
@@ -2,36 +2,35 @@
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for SaveButton.xaml
/// </summary>
public partial class MaximizeButton : UserControl
{
/// <summary>
/// Interaction logic for SaveButton.xaml
/// </summary>
public partial class MaximizeButton : UserControl
public event EventHandler? Clicked;
public MaximizeButton()
{
public event EventHandler Clicked;
this.InitializeComponent();
}
public MaximizeButton()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Visible;
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Visible;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Hidden;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Hidden;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
Clicked?.Invoke(this, e);
}
}
}
@@ -8,6 +8,7 @@
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
xmlns:converters="clr-namespace:Daybreak.Converters"
x:Name="_this"
Cursor="Hand"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
+5 -5
View File
@@ -11,16 +11,16 @@ namespace Daybreak.Controls.Buttons;
/// </summary>
public partial class MenuButton : UserControl
{
public event EventHandler Clicked;
public event EventHandler? Clicked;
[GenerateDependencyProperty]
private bool highlighted;
[GenerateDependencyProperty]
private Brush highlightColor;
private Brush highlightColor = default!;
[GenerateDependencyProperty]
private FrameworkElement innerContent;
[GenerateDependencyProperty]
private string title;
private FrameworkElement innerContent = default!;
[GenerateDependencyProperty(InitialValue = "")]
private string title = string.Empty;
public MenuButton()
{
@@ -6,6 +6,7 @@
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
+23 -24
View File
@@ -2,36 +2,35 @@
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for AddButton.xaml
/// </summary>
public partial class MinusButton : UserControl
{
/// <summary>
/// Interaction logic for AddButton.xaml
/// </summary>
public partial class MinusButton : UserControl
public event EventHandler? Clicked;
public MinusButton()
{
public event EventHandler Clicked;
this.InitializeComponent();
}
public MinusButton()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
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_MouseLeave(object sender, MouseEventArgs e)
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
Clicked?.Invoke(this, e);
}
}
}
+4 -4
View File
@@ -6,6 +6,7 @@
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
@@ -20,13 +21,12 @@
FontStretch="{Binding ElementName=_this, Path=FontStretch, Mode=OneWay}"
FontWeight="{Binding ElementName=_this, Path=FontWeight, Mode=OneWay}"
FontStyle="{Binding ElementName=_this, Path=FontStyle, Mode=OneWay}"
VerticalAlignment="Center"
HorizontalAlignment="Center"></TextBlock>
VerticalAlignment="{Binding ElementName=_this, Path=TextVerticalAlignment, Mode=OneWay}"
HorizontalAlignment="{Binding ElementName=_this, Path=TextHorizontalAlignment, Mode=OneWay}"></TextBlock>
<Rectangle Fill="{Binding ElementName=_this, Path=Highlight, Mode=OneWay}"
Opacity="{Binding ElementName=_this, Path=HighlightOpacity, Mode=OneWay}"
Visibility="{Binding ElementName=_this, Path=HighlightVisible, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"></Rectangle>
<Rectangle MouseEnter="Rectangle_MouseEnter" MouseLeave="Rectangle_MouseLeave"
MouseLeftButtonDown="Rectangle_MouseLeftButtonDown" Fill="Transparent"
Cursor="Hand"></Rectangle>
MouseLeftButtonDown="Rectangle_MouseLeftButtonDown" Fill="Transparent"></Rectangle>
</Grid>
</UserControl>
+39 -77
View File
@@ -5,87 +5,49 @@ using System.Windows.Extensions;
using System.Windows.Input;
using System.Windows.Media;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for OpaqueButton.xaml
/// </summary>
public partial class OpaqueButton : UserControl
{
/// <summary>
/// Interaction logic for OpaqueButton.xaml
/// </summary>
public partial class OpaqueButton : UserControl
public event EventHandler? Clicked;
[GenerateDependencyProperty(InitialValue = "")]
private string text = string.Empty;
[GenerateDependencyProperty]
private Brush transparentBackground = default!;
[GenerateDependencyProperty]
private Brush highlight = default!;
[GenerateDependencyProperty]
public double backgroundOpacity;
[GenerateDependencyProperty]
public double highlightOpacity;
[GenerateDependencyProperty]
public bool highlightVisible;
[GenerateDependencyProperty(InitialValue = VerticalAlignment.Center)]
public VerticalAlignment textVerticalAlignment;
[GenerateDependencyProperty(InitialValue = HorizontalAlignment.Center)]
public HorizontalAlignment textHorizontalAlignment;
public OpaqueButton()
{
public static readonly DependencyProperty TextProperty =
DependencyPropertyExtensions.Register<OpaqueButton, string>(nameof(Text));
this.InitializeComponent();
}
public static readonly DependencyProperty TransparentBackgroundProperty =
DependencyPropertyExtensions.Register<OpaqueButton, Brush>(nameof(TransparentBackground));
private void Rectangle_MouseEnter(object sender, MouseEventArgs e)
{
this.HighlightVisible = true;
}
public static readonly DependencyProperty HighlightProperty =
DependencyPropertyExtensions.Register<OpaqueButton, Brush>(nameof(Highlight));
private void Rectangle_MouseLeave(object sender, MouseEventArgs e)
{
this.HighlightVisible = false;
}
public static readonly DependencyProperty BackgroundOpacityProperty =
DependencyPropertyExtensions.Register<OpaqueButton, double>(nameof(BackgroundOpacity));
public static readonly DependencyProperty HighlightOpacityProperty =
DependencyPropertyExtensions.Register<OpaqueButton, double>(nameof(HighlightOpacity));
public static readonly DependencyProperty HighlightVisibleProperty =
DependencyPropertyExtensions.Register<OpaqueButton, bool>(nameof(HighlightVisible));
public event EventHandler Clicked;
public string Text
{
get => this.GetTypedValue<string>(TextProperty);
set => this.SetTypedValue(TextProperty, value);
}
public Brush TransparentBackground
{
get => this.GetTypedValue<Brush>(TransparentBackgroundProperty);
set => this.SetTypedValue(TransparentBackgroundProperty, value);
}
public Brush Highlight
{
get => this.GetTypedValue<Brush>(HighlightProperty);
set => this.SetTypedValue(HighlightProperty, value);
}
public double BackgroundOpacity
{
get => this.GetTypedValue<double>(BackgroundOpacityProperty);
set => this.SetTypedValue(BackgroundOpacityProperty, value);
}
public double HighlightOpacity
{
get => this.GetTypedValue<double>(HighlightOpacityProperty);
set => this.SetTypedValue(HighlightOpacityProperty, value);
}
public bool HighlightVisible
{
get => this.GetTypedValue<bool>(HighlightVisibleProperty);
set => this.SetTypedValue(HighlightVisibleProperty, value);
}
public OpaqueButton()
{
this.InitializeComponent();
}
private void Rectangle_MouseEnter(object sender, MouseEventArgs e)
{
this.HighlightVisible = true;
}
private void Rectangle_MouseLeave(object sender, MouseEventArgs e)
{
this.HighlightVisible = false;
}
private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.Clicked?.Invoke(this, e);
}
private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.Clicked?.Invoke(this, e);
}
}
@@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
x:Name="_this"
Cursor="Hand"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
+23 -24
View File
@@ -2,36 +2,35 @@
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for SaveButton.xaml
/// </summary>
public partial class SaveButton : UserControl
{
/// <summary>
/// Interaction logic for SaveButton.xaml
/// </summary>
public partial class SaveButton : UserControl
public event EventHandler? Clicked;
public SaveButton()
{
public event EventHandler Clicked;
this.InitializeComponent();
}
public SaveButton()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Visible;
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Visible;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Hidden;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Hidden;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
Clicked?.Invoke(this, e);
}
}
}
@@ -6,6 +6,7 @@
xmlns:local="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
@@ -9,7 +9,7 @@ namespace Daybreak.Controls;
/// </summary>
public partial class SynchronizeButton : UserControl
{
public event EventHandler Clicked;
public event EventHandler? Clicked;
public SynchronizeButton()
{
@@ -8,6 +8,7 @@
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
xmlns:converters="clr-namespace:Daybreak.Converters"
x:Name="_this"
Cursor="Hand"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
+10 -33
View File
@@ -1,6 +1,7 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Media;
namespace Daybreak.Controls;
@@ -10,46 +11,22 @@ namespace Daybreak.Controls;
/// </summary>
public partial class TileButton : UserControl
{
public event EventHandler Clicked;
public event EventHandler? Clicked;
public static readonly DependencyProperty HighlightedProperty =
DependencyProperty.Register("Highlighted", typeof(bool), typeof(TileButton), null);
public static readonly DependencyProperty HighlightColorProperty =
DependencyProperty.Register("HighlightColor", typeof(Brush), typeof(TileButton), null);
public static readonly DependencyProperty InnerContentProperty =
DependencyProperty.Register("InnerContent", typeof(FrameworkElement), typeof(TileButton), null);
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(TileButton), null);
[GenerateDependencyProperty]
public bool highlighted;
[GenerateDependencyProperty(InitialValue = "")]
public string title = string.Empty;
[GenerateDependencyProperty]
public FrameworkElement InnerContent = default!;
[GenerateDependencyProperty]
public Brush HighlightColor = default!;
public TileButton()
{
this.InitializeComponent();
}
public bool Highlighted
{
get => (bool)this.GetValue(HighlightedProperty);
set => this.SetValue(HighlightedProperty, value);
}
public string Title
{
get => this.GetValue(TitleProperty) as string;
set => this.SetValue(TitleProperty, value);
}
public FrameworkElement InnerContent
{
get => this.GetValue(InnerContentProperty) as FrameworkElement;
set => this.SetValue(InnerContentProperty, value);
}
public Brush HighlightColor
{
get => this.GetValue(HighlightColorProperty) as Brush;
set => this.SetValue(HighlightColorProperty, value);
}
private void Grid_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
this.Highlighted = true;
+11 -8
View File
@@ -9,6 +9,7 @@
mc:Ignorable="d"
Unloaded="UserControl_Unloaded"
x:Name="_this"
Initialized="UserControl_Initialized"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" TriggerValue="True"></converters:BooleanToVisibilityConverter>
@@ -19,7 +20,7 @@
<ContextMenu.Template>
<ControlTemplate>
<StackPanel Margin="10">
<local:OpaqueButton Text="Load build template" Foreground="White" Background="#F0202020" BackgroundOpacity="0.4"
<local:OpaqueButton Text="Load build template" Foreground="White" Background="#F0212121" BackgroundOpacity="0.4"
Clicked="LoadBuildTemplateButton_Click" FontSize="16" Height="40" Width="200"></local:OpaqueButton>
</StackPanel>
</ControlTemplate>
@@ -33,7 +34,7 @@
</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="#F0212121" 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>
@@ -69,17 +70,19 @@
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"></TextBox>
<StackPanel Grid.Column="2" Orientation="Horizontal">
<local:HomeButton Width="30" Height="30" Margin="5"
Visibility="{Binding ElementName=_this, Path=HomeButtonVisible, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
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}"
Clicked="StarGlyph_Clicked" x:Name="FavoriteButton"></local:StarGlyph>
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Visibility="{Binding ElementName=_this, Path=HomeButtonVisible, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
Clicked="StarGlyph_Clicked" x:Name="FavoriteButton"></local:StarGlyph>
<local:MaximizeButton Height="30" Width="30" Margin="5"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
Clicked="MaximizeButton_Clicked"></local:MaximizeButton>
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
Clicked="MaximizeButton_Clicked"></local:MaximizeButton>
</StackPanel>
</Grid>
<Grid Grid.RowSpan="2" Background="Gray"
+314 -295
View File
@@ -1,6 +1,6 @@
using Daybreak.Configuration;
using Daybreak.Models.Browser;
using Daybreak.Models.Builds;
using Daybreak.Models.Guildwars;
using Daybreak.Services.BuildTemplates;
using Daybreak.Utils;
using Microsoft.Extensions.DependencyInjection;
@@ -8,339 +8,358 @@ using Microsoft.Extensions.Logging;
using Microsoft.Web.WebView2.Core;
using System;
using System.Configuration;
using System.Core.Extensions;
using System.Diagnostics;
using System.Extensions;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Controls
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
{
/// <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 BrowserSearchPlaceholder = "[PLACEHOLDER]";
private const string BrowserSearchLink = $"https://www.google.com/search?q={BrowserSearchPlaceholder}";
private const string BrowserDownloadLink = "https://developer.microsoft.com/en-us/microsoft-edge/webview2/";
private static readonly Regex WebAddressRegex = new("^((http|ftp|https)://)?([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])?", RegexOptions.Compiled);
private static CoreWebView2Environment? coreWebView2Environment;
public event EventHandler<string>? FavoriteUriChanged;
public event EventHandler? MaximizeClicked;
public event EventHandler<Build>? BuildDecoded;
private readonly Task initializationTask;
private readonly ILiveOptions<ApplicationConfiguration>? liveOptions;
private readonly ILogger<ChromiumBrowserWrapper>? logger;
private readonly IBuildTemplateManager? buildTemplateManager;
[GenerateDependencyProperty(InitialValue = true)]
private bool canDownloadBuild;
[GenerateDependencyProperty(InitialValue = true)]
private bool canNavigate;
[GenerateDependencyProperty(InitialValue = true)]
private bool controlsEnabled;
[GenerateDependencyProperty(InitialValue = null)]
private bool? browserSupported;
[GenerateDependencyProperty]
private bool addressBarReadonly;
[GenerateDependencyProperty]
private bool browserEnabled;
[GenerateDependencyProperty]
private bool navigating;
[GenerateDependencyProperty]
private string favoriteAddress = string.Empty;
[GenerateDependencyProperty(InitialValue = false)]
private bool preventDispose;
[GenerateDependencyProperty(InitialValue = true)]
private bool homeButtonVisible = true;
[GenerateDependencyProperty(InitialValue = true)]
private bool favoriteButtonVisible = true;
public string Address
{
public static readonly DependencyProperty AddressProperty =
DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, string>(nameof(Address));
private const string BrowserDownloadLink = "https://developer.microsoft.com/en-us/microsoft-edge/webview2/";
private static CoreWebView2Environment coreWebView2Environment;
public event EventHandler<string> FavoriteUriChanged;
public event EventHandler MaximizeClicked;
public event EventHandler<Build> BuildDecoded;
private ILiveOptions<ApplicationConfiguration> liveOptions;
private ILogger<ChromiumBrowserWrapper> logger;
private IBuildTemplateManager buildTemplateManager;
[GenerateDependencyProperty(InitialValue = true)]
private bool canDownloadBuild;
[GenerateDependencyProperty(InitialValue = true)]
private bool canNavigate;
[GenerateDependencyProperty(InitialValue = true)]
private bool controlsEnabled;
[GenerateDependencyProperty(InitialValue = null)]
private bool? browserSupported;
[GenerateDependencyProperty]
private bool addressBarReadonly;
[GenerateDependencyProperty]
private bool browserEnabled;
[GenerateDependencyProperty]
private bool navigating;
[GenerateDependencyProperty]
private string favoriteAddress;
[GenerateDependencyProperty(InitialValue = false)]
private bool preventDispose;
public string Address
{
get => this.GetTypedValue<string>(AddressProperty);
set
{
if (this.BrowserSupported is true)
{
this.SetValue(AddressProperty, value);
}
}
}
public ChromiumBrowserWrapper()
{
this.InitializeComponent();
this.WebBrowser.IsEnabled = false;
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == AddressProperty || e.Property == FavoriteAddressProperty)
{
this.CheckFavoriteAddress();
}
}
public async Task InitializeDefaultBrowser()
{
var options = Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<ILiveOptions<ApplicationConfiguration>>();
var buildTemplateManager = Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IBuildTemplateManager>();
var logger = Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<ILogger<ChromiumBrowserWrapper>>();
await this.InitializeDefaultBrowser(options, buildTemplateManager, logger);
}
public async Task InitializeDefaultBrowser(
ILiveOptions<ApplicationConfiguration> liveOptions,
IBuildTemplateManager buildTemplateManager,
ILogger<ChromiumBrowserWrapper> logger)
{
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
{
if (coreWebView2Environment is null)
{
coreWebView2Environment = System.Extensions.TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", null));
}
this.BrowserSupported = true;
}
catch(Exception e)
{
this.logger.LogWarning($"Browser initialization failed. Details: {e}");
this.BrowserSupported = false;
}
}
private async Task InitializeBrowser()
get => this.GetTypedValue<string>(AddressProperty);
set
{
if (this.BrowserSupported is true)
{
this.WebBrowser.IsEnabled = true;
this.BrowserEnabled = true;
await this.WebBrowser.EnsureCoreWebView2Async(coreWebView2Environment);
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.SetValue(AddressProperty, value);
}
}
}
public ChromiumBrowserWrapper()
: this(Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<ILiveOptions<ApplicationConfiguration>>(),
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IBuildTemplateManager>(),
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<ILogger<ChromiumBrowserWrapper>>())
{
}
public ChromiumBrowserWrapper(
ILiveOptions<ApplicationConfiguration> liveOptions,
IBuildTemplateManager buildTemplateManager,
ILogger<ChromiumBrowserWrapper> logger)
{
this.liveOptions = liveOptions.ThrowIfNull();
this.buildTemplateManager = buildTemplateManager.ThrowIfNull();
this.logger = logger.ThrowIfNull();
this.initializationTask = this.InitializeBrowser();
this.InitializeComponent();
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == AddressProperty || e.Property == FavoriteAddressProperty)
{
this.CheckFavoriteAddress();
}
}
public async Task ReinitializeBrowser()
{
await this.InitializeBrowser();
}
public Task InitializationTask() => this.initializationTask;
private async void UserControl_Initialized(object sender, EventArgs e)
{
this.InitializeEnvironment();
await this.InitializeBrowser();
}
private void InitializeEnvironment()
{
if (this.liveOptions!.Value.BrowsersEnabled is false)
{
this.BrowserSupported = false;
return;
}
try
{
coreWebView2Environment ??= System.Extensions.TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", null));
this.BrowserSupported = true;
}
catch(Exception e)
{
this.logger!.LogWarning($"Browser initialization failed. Details: {e}");
this.BrowserSupported = false;
}
}
private async Task InitializeBrowser()
{
if (this.BrowserSupported is true)
{
this.WebBrowser.IsEnabled = true;
this.BrowserEnabled = true;
await this.WebBrowser.EnsureCoreWebView2Async(coreWebView2Environment);
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) =>
{
if (this.CanNavigate is false && args.Uri != this.Address)
{
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);
args.Cancel = true;
}
}
}
private async void RetryInitializeButton_Clicked(object sender, EventArgs e)
{
this.InitializeEnvironment();
try
{
await this.InitializeBrowser();
}
catch
{
this.BrowserSupported = false;
}
}
private void Hyperlink_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (Uri.TryCreate(BrowserDownloadLink, UriKind.Absolute, out var uri))
{
Process.Start("explorer.exe", uri.ToString());
}
}
private void TextBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Enter)
{
var newAddress = sender.As<TextBox>().Text;
newAddress = SanitizeAddress(newAddress);
if (newAddress is null)
else
{
return;
this.Navigating = true;
}
this.Address = newAddress;
this.WebBrowser.CoreWebView2.Navigate(this.Address);
e.Handled = 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);
}
}
}
private void CoreWebView2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs args)
private async void RetryInitializeButton_Clicked(object sender, EventArgs e)
{
this.InitializeEnvironment();
try
{
BrowserPayload payload = default;
try
await this.InitializeBrowser();
}
catch
{
this.BrowserSupported = false;
}
}
private void Hyperlink_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (Uri.TryCreate(BrowserDownloadLink, UriKind.Absolute, out var uri))
{
Process.Start("explorer.exe", uri.ToString());
}
}
private void TextBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Enter)
{
var input = sender.As<TextBox>().Text;
var maybeAddress = SanitizeAddress(input);
// If input is address, navigate to address. Otherwise search for the text input in Google
if (Uri.TryCreate(maybeAddress, UriKind.Absolute, out _))
{
payload = args.WebMessageAsJson.Deserialize<BrowserPayload>();
this.Address = maybeAddress;
}
catch(Exception e)
else
{
this.logger.LogError(e, $"Exception encountered when deserializing {nameof(BrowserPayload)}");
var address = BrowserSearchLink.Replace(BrowserSearchPlaceholder, maybeAddress);
this.Address = address;
}
if (payload?.Key == BrowserPayload.PayloadKeys.ContextMenu)
{
var contextMenuPayload = args.WebMessageAsJson.Deserialize<BrowserPayload<OnContextMenuPayload>>();
var maybeTemplate = contextMenuPayload.Value.Selection;
if (string.IsNullOrWhiteSpace(maybeTemplate))
{
return;
}
this.WebBrowser.CoreWebView2.Navigate(this.Address);
e.Handled = true;
}
}
if (this.buildTemplateManager is null)
{
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 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)}");
}
private void LoadBuildTemplateButton_Click(object sender, EventArgs e)
if (payload?.Key == BrowserPayload.PayloadKeys.ContextMenu)
{
var build = this.ContextMenu.DataContext.As<Build>();
this.ContextMenu.IsOpen = false;
this.BuildDecoded?.Invoke(this, build);
}
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
{
if (this.PreventDispose)
var contextMenuPayload = args.WebMessageAsJson.Deserialize<BrowserPayload<OnContextMenuPayload>>();
var maybeTemplate = contextMenuPayload.Value!.Selection;
if (string.IsNullOrWhiteSpace(maybeTemplate))
{
return;
}
this.WebBrowser?.Dispose();
}
private void BackButton_Clicked(object sender, EventArgs e)
{
this.WebBrowser.GoBack();
this.Address = this.WebBrowser.Source.ToString();
}
private void ForwardButton_Clicked(object sender, EventArgs e)
{
this.WebBrowser.GoForward();
this.Address = this.WebBrowser.Source.ToString();
}
private void RefreshGlyph_Clicked(object sender, EventArgs e)
{
this.WebBrowser.Reload();
this.Address = this.WebBrowser.Source.ToString();
}
private void CancelGlyph_Clicked(object sender, EventArgs e)
{
this.WebBrowser.Stop();
}
private void StarGlyph_Clicked(object sender, EventArgs e)
{
this.FavoriteAddress = this.Address;
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);
}
private void CheckFavoriteAddress()
{
if (this.Address == this.FavoriteAddress)
if (this.buildTemplateManager is null)
{
this.FavoriteButton.IsEnabled = false;
}
else
{
this.FavoriteButton.IsEnabled = true;
}
}
private static string SanitizeAddress(string address)
{
if (string.IsNullOrWhiteSpace(address))
{
return null;
return;
}
if (address.StartsWith("www") is false &&
address.StartsWith("http") is false)
if (this.buildTemplateManager.IsTemplate(maybeTemplate) is false)
{
address = "https://www." + address;
}
else if (address.StartsWith("www"))
{
address = "https://" + address;
return;
}
Uri.TryCreate(address, UriKind.Absolute, out var uri);
return uri?.ToString();
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)
{
if (this.PreventDispose)
{
return;
}
this.WebBrowser?.Dispose();
}
private void BackButton_Clicked(object sender, EventArgs e)
{
this.WebBrowser.GoBack();
this.Address = this.WebBrowser.Source.ToString();
}
private void ForwardButton_Clicked(object sender, EventArgs e)
{
this.WebBrowser.GoForward();
this.Address = this.WebBrowser.Source.ToString();
}
private void RefreshGlyph_Clicked(object sender, EventArgs e)
{
this.WebBrowser.Reload();
this.Address = this.WebBrowser.Source.ToString();
}
private void CancelGlyph_Clicked(object sender, EventArgs e)
{
this.WebBrowser.Stop();
}
private void StarGlyph_Clicked(object sender, EventArgs e)
{
this.FavoriteAddress = this.Address;
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);
}
private void CheckFavoriteAddress()
{
if (this.Address == this.FavoriteAddress)
{
this.FavoriteButton.IsEnabled = false;
}
else
{
this.FavoriteButton.IsEnabled = true;
}
}
private static string SanitizeAddress(string address)
{
if (string.IsNullOrWhiteSpace(address))
{
return default!;
}
if (WebAddressRegex.IsMatch(address) is false)
{
return address;
}
if (address.StartsWith("www") is false &&
address.StartsWith("http") is false)
{
address = "https://www." + address;
}
else if (address.StartsWith("www"))
{
address = "https://" + address;
}
Uri.TryCreate(address, UriKind.Absolute, out var uri);
return uri?.ToString() ?? string.Empty;
}
}
+21 -22
View File
@@ -1,31 +1,30 @@
using System.Windows;
using System.Windows.Controls;
namespace Daybreak.Controls
{
/// <summary>
/// Interaction logic for CircularLoadingWidget.xaml
/// </summary>
public partial class CircularLoadingWidget : UserControl
{
public CircularLoadingWidget()
{
this.InitializeComponent();
}
namespace Daybreak.Controls;
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
/// <summary>
/// Interaction logic for CircularLoadingWidget.xaml
/// </summary>
public partial class CircularLoadingWidget : UserControl
{
public CircularLoadingWidget()
{
this.InitializeComponent();
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == IsEnabledProperty)
{
base.OnPropertyChanged(e);
if (e.Property == IsEnabledProperty)
if (e.NewValue is true)
{
if (e.NewValue is true)
{
this.ProgressAnimation_BeginStoryboard.Storyboard.Pause();
}
else
{
this.ProgressAnimation_BeginStoryboard.Storyboard.Resume();
}
this.ProgressAnimation_BeginStoryboard.Storyboard.Pause();
}
else
{
this.ProgressAnimation_BeginStoryboard.Storyboard.Resume();
}
}
}
+8 -9
View File
@@ -1,15 +1,14 @@
using System.Windows.Controls;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for AvatarGlyph.xaml
/// </summary>
public partial class AvatarGlyph : UserControl
{
/// <summary>
/// Interaction logic for AvatarGlyph.xaml
/// </summary>
public partial class AvatarGlyph : UserControl
public AvatarGlyph()
{
public AvatarGlyph()
{
this.InitializeComponent();
}
this.InitializeComponent();
}
}
@@ -0,0 +1,18 @@
<UserControl x:Class="Daybreak.Controls.Glyphs.DownloadGlyph"
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.Glyphs"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" StrokeThickness="3"
Data="m32,30.454c0,0 8.312,0 9.098,0c4.365,0 7.902,-3.537 7.902,-7.901s-3.537,-7.902 -7.902,-7.902c-0.02,0 -0.038,0.003 -0.058,0.003c0.061,-0.494 0.103,-0.994 0.103,-1.504c0,-6.71 -5.439,-12.15 -12.15,-12.15c-5.229,0 -9.672,3.309 -11.386,7.941c-1.087,-1.089 -2.591,-1.764 -4.251,-1.764c-3.319,0 -6.009,2.69 -6.009,6.008c0,0.085 0.01,0.167 0.013,0.251c-3.665,1.013 -6.36,4.362 -6.36,8.349c0,4.788 3.881,8.669 8.67,8.669c0.827,0 8.33,0 8.33,0"></Path>
<Polyline Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Points="30,36 25,41 20,36" StrokeThickness="3"></Polyline>
<Line X1="25" X2="25" Y1="21" Y2="41" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" StrokeThickness="3"></Line>
</Grid>
</Viewbox>
</UserControl>
@@ -0,0 +1,14 @@
using System.Windows.Controls;
namespace Daybreak.Controls.Glyphs;
/// <summary>
/// Interaction logic for DownloadGlyph.xaml
/// </summary>
public partial class DownloadGlyph : UserControl
{
public DownloadGlyph()
{
this.InitializeComponent();
}
}
@@ -13,16 +13,15 @@ using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for ExperimentGlyph.xaml
/// </summary>
public partial class ExperimentGlyph : UserControl
{
/// <summary>
/// Interaction logic for ExperimentGlyph.xaml
/// </summary>
public partial class ExperimentGlyph : UserControl
public ExperimentGlyph()
{
public ExperimentGlyph()
{
this.InitializeComponent();
}
this.InitializeComponent();
}
}
+8 -9
View File
@@ -1,15 +1,14 @@
using System.Windows.Controls;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for FileGlyph.xaml
/// </summary>
public partial class FileGlyph : UserControl
{
/// <summary>
/// Interaction logic for FileGlyph.xaml
/// </summary>
public partial class FileGlyph : UserControl
public FileGlyph()
{
public FileGlyph()
{
this.InitializeComponent();
}
this.InitializeComponent();
}
}
@@ -13,16 +13,15 @@ using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for FireballGlyph.xaml
/// </summary>
public partial class FireballGlyph : UserControl
{
/// <summary>
/// Interaction logic for FireballGlyph.xaml
/// </summary>
public partial class FireballGlyph : UserControl
public FireballGlyph()
{
public FireballGlyph()
{
this.InitializeComponent();
}
this.InitializeComponent();
}
}
+20
View File
@@ -0,0 +1,20 @@
<UserControl x:Class="Daybreak.Controls.Glyphs.GaugeGlyph"
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.Glyphs"
mc:Ignorable="d"
Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m13.5,13.5c1.44772,-1.44772 2.5,-3.29086 2.5,-5.5c0,-4.41828 -3.58172,-8 -8,-8s-8,3.58172 -8,8c0,2.20914 1.05228,4.05228 2.5,5.5"></Path>
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m8,8l-4,-4"></Path>
<Ellipse Margin="6, 7.5, 6, 6" Width="1.5" Height="1.5"
Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Ellipse>
</Grid>
</Viewbox>
</UserControl>
@@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace Daybreak.Controls.Glyphs
{
/// <summary>
/// Interaction logic for GaugeGlyph.xaml
/// </summary>
public partial class GaugeGlyph : UserControl
{
public GaugeGlyph()
{
this.InitializeComponent();
}
}
}
@@ -13,16 +13,15 @@ using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for GoldenArrowGlyph.xaml
/// </summary>
public partial class GoldenArrowGlyph : UserControl
{
/// <summary>
/// Interaction logic for GoldenArrowGlyph.xaml
/// </summary>
public partial class GoldenArrowGlyph : UserControl
public GoldenArrowGlyph()
{
public GoldenArrowGlyph()
{
this.InitializeComponent();
}
this.InitializeComponent();
}
}
+8 -9
View File
@@ -1,15 +1,14 @@
using System.Windows.Controls;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for LogsGlyph.xaml
/// </summary>
public partial class LogsGlyph : UserControl
{
/// <summary>
/// Interaction logic for LogsGlyph.xaml
/// </summary>
public partial class LogsGlyph : UserControl
public LogsGlyph()
{
public LogsGlyph()
{
this.InitializeComponent();
}
this.InitializeComponent();
}
}
+28
View File
@@ -0,0 +1,28 @@
<UserControl x:Class="Daybreak.Controls.Glyphs.MapGlyph"
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.Glyphs"
mc:Ignorable="d"
Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m18.53,14.53a9.37,9.37 0 0 1 -9.26,9.47l0,0a9.5,9.5 0 0 1 -3.26,-18.33a9.61,9.61 0 0 0 0.77,1.82a14.22,14.22 0 0 0 2.51,3.25a14.06,14.06 0 0 0 2.49,-3.24a9.2,9.2 0 0 0 0.75,-1.83a9.47,9.47 0 0 1 6,8.86z"></Path>
<Polyline Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Points="9.270000457763672,24 9.270000457763672,23.989999771118164 9.270000457763672,10.739999771118164"></Polyline>
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m9.27,24l0,0c-0.32,-0.22 -5.27,-3.85 -4.94,-10.1a11.36,11.36 0 0 1 2.44,-6.4"></Path>
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m9.25,24a0,0 0 0 1 0,0l0,0c0.4,-0.29 5.25,-3.91 4.92,-10.1a11.35,11.35 0 0 0 -2.43,-6.39"></Path>
<Line Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
X1="0" X2="18.53" Y1="14.53" Y2="14.53"></Line>
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m12.35,1.89a3.81,3.81 0 0 0 -3.08,-1.89a3.82,3.82 0 0 0 -3.09,1.89a4.75,4.75 0 0 0 -0.19,3.78a9.61,9.61 0 0 0 0.77,1.82a14.22,14.22 0 0 0 2.51,3.25a14.06,14.06 0 0 0 2.49,-3.24a9.2,9.2 0 0 0 0.77,-1.83a4.79,4.79 0 0 0 -0.18,-3.78z"></Path>
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Width="1.24" Height="1.26" Margin="8.6, 3" HorizontalAlignment="Left" VerticalAlignment="Top"></Ellipse>
</Grid>
</Viewbox>
</UserControl>
+15
View File
@@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace Daybreak.Controls.Glyphs
{
/// <summary>
/// Interaction logic for MapGlyph.xaml
/// </summary>
public partial class MapGlyph : UserControl
{
public MapGlyph()
{
this.InitializeComponent();
}
}
}
+23 -24
View File
@@ -2,36 +2,35 @@
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for RefreshGlyph.xaml
/// </summary>
public partial class RefreshGlyph : UserControl
{
/// <summary>
/// Interaction logic for RefreshGlyph.xaml
/// </summary>
public partial class RefreshGlyph : UserControl
public event EventHandler? Clicked;
public RefreshGlyph()
{
public event EventHandler Clicked;
this.InitializeComponent();
}
public RefreshGlyph()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
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_MouseLeave(object sender, MouseEventArgs e)
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.Clicked?.Invoke(this, e);
}
this.Clicked?.Invoke(this, e);
}
}
}
+23 -24
View File
@@ -2,36 +2,35 @@
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for BackButton.xaml
/// </summary>
public partial class StarGlyph : UserControl
{
/// <summary>
/// Interaction logic for BackButton.xaml
/// </summary>
public partial class StarGlyph : UserControl
public event EventHandler? Clicked;
public StarGlyph()
{
public event EventHandler Clicked;
this.InitializeComponent();
}
public StarGlyph()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
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_MouseLeave(object sender, MouseEventArgs e)
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
Clicked?.Invoke(this, e);
}
}
}
+8 -9
View File
@@ -1,15 +1,14 @@
using System.Windows.Controls;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for StaticGlyph.xaml
/// </summary>
public partial class StaticGlyph : UserControl
{
/// <summary>
/// Interaction logic for StaticGlyph.xaml
/// </summary>
public partial class StaticGlyph : UserControl
public StaticGlyph()
{
public StaticGlyph()
{
this.InitializeComponent();
}
this.InitializeComponent();
}
}
+19
View File
@@ -0,0 +1,19 @@
<UserControl x:Class="Daybreak.Controls.GuildwarsMinimap"
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"
MouseWheel="GuildwarsMinimap_MouseWheel"
MouseDown="GuildwarsMinimap_MouseDown"
MouseUp="GuildwarsMinimap_MouseUp"
MouseMove="GuildwarsMinimap_MouseMove">
<Grid>
<Image x:Name="MapDrawingHost" VerticalAlignment="Top" HorizontalAlignment="Left" Stretch="None">
</Image>
<Image x:Name="EntitiesDrawingHost" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
</Grid>
</UserControl>
+330
View File
@@ -0,0 +1,330 @@
using Daybreak.Models.Guildwars;
using Daybreak.Models;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System;
using System.Extensions;
using Daybreak.Services.Scanner;
using Microsoft.Extensions.DependencyInjection;
using System.Core.Extensions;
using System.Windows.Input;
using System.Linq;
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for GuildwarsMinimap.xaml
/// </summary>
public partial class GuildwarsMinimap : UserControl
{
private readonly IGuildwarsEntityDebouncer guildwarsEntityDebouncer;
private bool resizeEntities;
private bool dragging;
private double mapMinWidth;
private double mapMinHeight;
private double mapWidth;
private double mapHeight;
private Point originPoint = new(0, 0);
private Vector originOffset = new(0, 0);
private Point initialClickPoint = new(0, 0);
private DebounceResponse? cachedDebounceResponse;
[GenerateDependencyProperty]
private PathingData pathingData = new();
[GenerateDependencyProperty]
private GameData gameData = new();
[GenerateDependencyProperty]
private double zoom = 0.08;
public GuildwarsMinimap()
:this(Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IGuildwarsEntityDebouncer>())
{
}
public GuildwarsMinimap(
IGuildwarsEntityDebouncer guildwarsEntityDebouncer)
{
this.guildwarsEntityDebouncer = guildwarsEntityDebouncer.ThrowIfNull();
this.InitializeComponent();
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == ActualHeightProperty ||
e.Property == ActualWidthProperty)
{
this.resizeEntities = true;
}
else if (e.Property == PathingDataProperty ||
e.Property == ZoomProperty)
{
this.guildwarsEntityDebouncer.ClearCaches();
this.DrawMap();
}
else if (e.Property == GameDataProperty &&
this.GameData.Valid)
{
this.UpdateGameData();
}
}
private void UpdateGameData()
{
var debounceResponse = this.guildwarsEntityDebouncer.DebounceEntities(this.gameData);
if (!double.IsFinite(this.mapWidth) ||
!double.IsFinite(this.mapHeight) ||
!double.IsFinite(this.mapMinWidth) ||
!double.IsFinite(this.mapMinHeight))
{
return;
}
var screenVirtualWidth = this.ActualWidth / this.Zoom;
var screenVirtualHeight = this.ActualHeight / this.Zoom;
var position = debounceResponse.MainPlayer.Position!.Value;
this.originPoint = new Point(
position.X - (screenVirtualWidth / 2) - (this.originOffset.X / this.Zoom),
position.Y + (screenVirtualHeight / 2) + (this.originOffset.Y / this.Zoom));
var adjustedPosition = new Point((int)((position.X - this.mapMinWidth / this.Zoom) * this.Zoom), (int)(this.mapHeight / this.Zoom - position.Y + this.mapMinHeight / this.Zoom) * this.Zoom);
this.MapDrawingHost.Margin = new Thickness(
(-adjustedPosition.X + this.ActualWidth / 2) + this.originOffset.X,
(-adjustedPosition.Y + this.ActualHeight / 2) + this.originOffset.Y,
0,
0);
this.DrawEntities(debounceResponse);
this.cachedDebounceResponse = debounceResponse;
}
private void DrawMap()
{
if (this.PathingData.Trapezoids is null)
{
return;
}
var maxWidth = double.MinValue;
var maxHeight = double.MinValue;
var minWidth = double.MaxValue;
var minHeight = double.MaxValue;
foreach (var trapezoid in this.PathingData.Trapezoids!)
{
if (trapezoid.YT < minHeight)
{
minHeight = trapezoid.YT;
}
if (trapezoid.YB > maxHeight)
{
maxHeight = trapezoid.YB;
}
if (trapezoid.XTL < minWidth)
{
minWidth = trapezoid.XTL;
}
if (trapezoid.XBL < minWidth)
{
minWidth = trapezoid.XBL;
}
if (trapezoid.XTR > maxWidth)
{
maxWidth = trapezoid.XTR;
}
if (trapezoid.XBR > maxWidth)
{
maxWidth = trapezoid.XBR;
}
}
var width = maxWidth - minWidth;
var height = maxHeight - minHeight;
this.mapMinHeight = minHeight * this.Zoom;
this.mapMinWidth = minWidth * this.Zoom;
this.mapWidth = width * this.Zoom;
this.mapHeight = height * this.Zoom;
if (width <= 0 || height <= 0 ||
!double.IsFinite(width) ||
!double.IsFinite(height))
{
return;
}
var bitmap = BitmapFactory.New((int)(width * this.Zoom), (int)(height * this.Zoom));
this.MapDrawingHost.Source = bitmap;
this.MapDrawingHost.Width = width * this.Zoom;
this.MapDrawingHost.Height = height * this.Zoom;
using var bitmapContext = bitmap.GetBitmapContext();
bitmap.Clear(Colors.Transparent);
foreach (var trapezoid in this.PathingData.Trapezoids!)
{
var a = new Point((int)((trapezoid.XTL - minWidth) * this.Zoom), (int)((height - trapezoid.YT + minHeight) * this.Zoom));
var b = new Point((int)((trapezoid.XTR - minWidth) * this.Zoom), (int)((height - trapezoid.YT + minHeight) * this.Zoom));
var c = new Point((int)((trapezoid.XBR - minWidth) * this.Zoom), (int)((height - trapezoid.YB + minHeight) * this.Zoom));
var d = new Point((int)((trapezoid.XBL - minWidth) * this.Zoom), (int)((height - trapezoid.YB + minHeight) * this.Zoom));
var e = new Point((int)((trapezoid.XTL - minWidth) * this.Zoom), (int)((height - trapezoid.YT + minHeight) * this.Zoom));
bitmap.FillPolygon(new int[] { (int)a.X, (int)a.Y, (int)b.X, (int)b.Y, (int)c.X, (int)c.Y, (int)d.X, (int)d.Y, (int)e.X, (int)e.Y, (int)a.X, (int)a.Y }, Colors.White);
}
}
private void DrawEntities(DebounceResponse debounceResponse)
{
if (this.EntitiesDrawingHost.Source is not WriteableBitmap bitmap || this.resizeEntities)
{
bitmap = BitmapFactory.New((int)this.ActualWidth, (int)this.ActualHeight);
this.EntitiesDrawingHost.Source = bitmap;
this.resizeEntities = false;
}
bitmap.Clear(Colors.Transparent);
using var context = bitmap.GetBitmapContext();
this.FillEllipse(debounceResponse.MainPlayer.Position, bitmap, Colors.Green);
foreach (var partyMember in debounceResponse.Party)
{
this.FillEllipse(partyMember.Position, bitmap, Colors.Green);
}
foreach (var player in debounceResponse.WorldPlayers)
{
this.FillEllipse(player.Position, bitmap, Colors.CornflowerBlue);
}
foreach (var livingEntity in debounceResponse.LivingEntities)
{
if (livingEntity.State is LivingEntityState.ToBeCleanedUp)
{
continue;
}
else if (livingEntity.State is LivingEntityState.Dead)
{
this.FillEllipse(livingEntity.Position, bitmap, Colors.Gray);
}
else if (livingEntity.State is LivingEntityState.Boss)
{
this.FillEllipse(livingEntity.Position, bitmap, Colors.DarkRed);
}
else if (livingEntity.Allegiance is LivingEntityAllegiance.AllyNonAttackable)
{
this.FillEllipse(livingEntity.Position, bitmap, Colors.Green);
}
else if (livingEntity.Allegiance is LivingEntityAllegiance.Neutral)
{
this.FillEllipse(livingEntity.Position, bitmap, Colors.Gray);
}
else if (livingEntity.Allegiance is LivingEntityAllegiance.Enemy)
{
this.FillTriangle(livingEntity.Position, bitmap, Colors.Red);
}
else if (livingEntity.Allegiance is LivingEntityAllegiance.SpiritOrPet)
{
this.FillTriangle(livingEntity.Position, bitmap, Colors.Green);
}
else if (livingEntity.Allegiance is LivingEntityAllegiance.Minion)
{
this.FillTriangle(livingEntity.Position, bitmap, Colors.Green);
}
else if (livingEntity.Allegiance is LivingEntityAllegiance.NpcOrMinipet)
{
this.FillTriangle(livingEntity.Position, bitmap, Colors.LimeGreen);
}
}
}
private void FillEllipse(Position? position, WriteableBitmap bitmap, Color color)
{
if (position.HasValue is false)
{
return;
}
var x = (int)((position.Value.X - this.originPoint.X) * this.Zoom);
var y = 0 - (int)((position.Value.Y - this.originPoint.Y) * this.Zoom);
if (x < 0 || x > bitmap.Width ||
y < 0 || y > bitmap.Height)
{
return;
}
bitmap.FillEllipseCentered(
x,
y,
(int)(100 * this.Zoom),
(int)(100 * this.Zoom),
color);
}
private void FillTriangle(Position? position, WriteableBitmap bitmap, Color color)
{
if (position.HasValue is false)
{
return;
}
var x = (int)((position.Value.X - this.originPoint.X) * this.Zoom);
var y = 0 - (int)((position.Value.Y - this.originPoint.Y) * this.Zoom);
if (x < 0 || x > bitmap.Width ||
y < 0 || y > bitmap.Height)
{
return;
}
bitmap.FillTriangle(
(int)((position.Value.X - this.originPoint.X - 100) * this.Zoom),
0 - (int)((position.Value.Y - this.originPoint.Y + 100) * this.Zoom),
(int)((position.Value.X - this.originPoint.X) * this.Zoom),
0 - (int)((position.Value.Y - this.originPoint.Y - 100) * this.Zoom),
(int)((position.Value.X - this.originPoint.X + 100) * this.Zoom),
0 - (int)((position.Value.Y - this.originPoint.Y + 100) * this.Zoom),
color);
}
private bool MouseOverEntity(IEntity entity, Point mousePosition)
{
var x = (int)((entity.Position!.Value.X - this.originPoint.X) * this.Zoom);
var y = 0 - (int)((entity.Position!.Value.Y - this.originPoint.Y) * this.Zoom);
return Math.Pow(mousePosition.X - x, 2) + Math.Pow(mousePosition.Y - y, 2) < Math.Pow(100 * this.Zoom, 2);
}
private void GuildwarsMinimap_MouseDown(object sender, MouseButtonEventArgs e)
{
this.initialClickPoint = Mouse.GetPosition(this);
this.dragging = true;
}
private void GuildwarsMinimap_MouseUp(object sender, MouseButtonEventArgs e)
{
this.dragging = false;
this.originOffset = new(0, 0);
}
private void GuildwarsMinimap_MouseMove(object sender, MouseEventArgs e)
{
if (this.dragging is false)
{
return;
}
var mousePosition = e.GetPosition(this);
this.originOffset = mousePosition - this.initialClickPoint;
}
private void GuildwarsMinimap_MouseWheel(object sender, MouseWheelEventArgs e)
{
var delta = e.Delta > 0 ? 0.1 : -0.1;
this.Zoom += this.Zoom * delta;
}
}
@@ -0,0 +1,37 @@
<UserControl x:Class="Daybreak.Controls.HorizontalResourceBar"
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>
<Viewbox VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Stretch="Fill">
<Grid Height="1">
<Rectangle
Fill="{Binding ElementName=_this, Path=BarColor, Mode=OneWay}"
VerticalAlignment="Stretch"
HorizontalAlignment="{Binding ElementName=_this, Path=FillAlignment, Mode=OneWay}"
Width="{Binding ElementName=_this, Path=MaxResourceValue, Mode=TwoWay}"></Rectangle>
<Rectangle
Fill="#F0202020"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"></Rectangle>
<Rectangle
Fill="{Binding ElementName=_this, Path=BarColor, Mode=OneWay}"
VerticalAlignment="Stretch"
HorizontalAlignment="{Binding ElementName=_this, Path=FillAlignment, Mode=OneWay}"
Width="{Binding ElementName=_this, Path=CurrentResourceValue, Mode=TwoWay}"></Rectangle>
</Grid>
</Viewbox>
<TextBlock
FontSize="{Binding ElementName=_this, Path=FontSize, Mode=OneWay}"
FontFamily="{Binding ElementName=_this, Path=FontFamily, Mode=OneWay}"
Text="{Binding ElementName=_this, Path=Text, Mode=OneWay}"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
VerticalAlignment="Center"
HorizontalAlignment="Center"></TextBlock>
</Grid>
</UserControl>
@@ -0,0 +1,34 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Media;
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for ResourceBar.xaml
/// </summary>
public partial class HorizontalResourceBar : UserControl
{
[GenerateDependencyProperty]
private double currentResourceValue;
[GenerateDependencyProperty]
private double maxResourceValue;
[GenerateDependencyProperty]
private Brush barColor;
[GenerateDependencyProperty]
private string text;
[GenerateDependencyProperty(InitialValue = HorizontalAlignment.Left)]
private HorizontalAlignment fillAlignment;
public HorizontalResourceBar()
{
this.InitializeComponent();
this.MaxResourceValue = 1;
this.CurrentResourceValue = 0;
this.barColor = Brushes.Transparent;
this.text = string.Empty;
}
}
+72 -73
View File
@@ -5,88 +5,87 @@ using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for ImageViewer.xaml
/// </summary>
public partial class ImageViewer : UserControl
{
/// <summary>
/// Interaction logic for ImageViewer.xaml
/// </summary>
public partial class ImageViewer : UserControl
public ImageSource ImageSource
{
public ImageSource ImageSource
get => this.CurrentVisible().Source;
set => this.ShowImage(value);
}
public ImageViewer()
{
this.InitializeComponent();
this.Image1.Visibility = Visibility.Visible;
this.Image1.Opacity = 1;
this.Image2.Visibility = Visibility.Hidden;
this.Image2.Opacity = 0;
}
public async void ShowImage(ImageSource imageSource)
{
var currentVisible = this.CurrentVisible();
var nextVisible = this.NextVisible();
if (nextVisible.Source is BitmapImage bitmapImage)
{
get => this.CurrentVisible().Source;
set => this.ShowImage(value);
await bitmapImage.StreamSource.DisposeAsync().ConfigureAwait(true);
}
public ImageViewer()
{
this.InitializeComponent();
this.Image1.Visibility = Visibility.Visible;
this.Image1.Opacity = 1;
this.Image2.Visibility = Visibility.Hidden;
this.Image2.Opacity = 0;
}
nextVisible.Source = imageSource;
Transition(currentVisible, nextVisible);
}
public async void ShowImage(ImageSource imageSource)
private Image CurrentVisible()
{
if (this.Image1.Visibility == Visibility.Visible)
{
var currentVisible = this.CurrentVisible();
var nextVisible = this.NextVisible();
if (nextVisible.Source is BitmapImage bitmapImage)
{
await bitmapImage.StreamSource.DisposeAsync().ConfigureAwait(true);
}
nextVisible.Source = imageSource;
Transition(currentVisible, nextVisible);
return this.Image1;
}
private Image CurrentVisible()
else
{
if (this.Image1.Visibility == Visibility.Visible)
{
return this.Image1;
}
else
{
return this.Image2;
}
}
private Image NextVisible()
{
if (this.Image1.Visibility == Visibility.Visible)
{
return this.Image2;
}
else
{
return this.Image1;
}
}
private static void Transition(Image from, Image to)
{
to.Visibility = Visibility.Visible;
to.Opacity = 0;
from.Visibility = Visibility.Visible;
from.Opacity = 1;
var showAnimation = new DoubleAnimation()
{
From = 0,
To = 1,
Duration = TimeSpan.FromSeconds(1.5)
};
var hideAnimation = new DoubleAnimation
{
From = 1,
To = 0,
Duration = TimeSpan.FromSeconds(1.5)
};
hideAnimation.Completed += (s, e) =>
{
from.Visibility = Visibility.Hidden;
to.BeginAnimation(Image.OpacityProperty, showAnimation);
};
from.BeginAnimation(Image.OpacityProperty, hideAnimation);
return this.Image2;
}
}
private Image NextVisible()
{
if (this.Image1.Visibility == Visibility.Visible)
{
return this.Image2;
}
else
{
return this.Image1;
}
}
private static void Transition(Image from, Image to)
{
to.Visibility = Visibility.Visible;
to.Opacity = 0;
from.Visibility = Visibility.Visible;
from.Opacity = 1;
var showAnimation = new DoubleAnimation()
{
From = 0,
To = 1,
Duration = TimeSpan.FromSeconds(1.5)
};
var hideAnimation = new DoubleAnimation
{
From = 1,
To = 0,
Duration = TimeSpan.FromSeconds(1.5)
};
hideAnimation.Completed += (s, e) =>
{
from.Visibility = Visibility.Hidden;
to.BeginAnimation(Image.OpacityProperty, showAnimation);
};
from.BeginAnimation(Image.OpacityProperty, hideAnimation);
}
}
+31
View File
@@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Controls"
xmlns:buttons="clr-namespace:Daybreak.Controls.Buttons"
xmlns:glyphs="clr-namespace:Daybreak.Controls.Glyphs"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel>
@@ -12,6 +13,7 @@
Foreground="White"
HighlightColor="White"
Height="30"
Cursor="Hand"
Clicked="GameCompanionButton_Clicked">
<buttons:MenuButton.InnerContent>
<local:GoldenArrowGlyph Foreground="White"
@@ -22,16 +24,29 @@
Foreground="White"
HighlightColor="White"
Height="30"
Cursor="Hand"
Clicked="ManageBuildsButton_Clicked">
<buttons:MenuButton.InnerContent>
<local:FireballGlyph Foreground="White"
Width="40"></local:FireballGlyph>
</buttons:MenuButton.InnerContent>
</buttons:MenuButton>
<buttons:MenuButton Title="Download Guildwars"
Foreground="White"
HighlightColor="White"
Height="30"
Cursor="Hand"
Clicked="DownloadGuildwarsButton_Clicked">
<buttons:MenuButton.InnerContent>
<glyphs:DownloadGlyph Foreground="White"
Width="40"></glyphs:DownloadGlyph>
</buttons:MenuButton.InnerContent>
</buttons:MenuButton>
<buttons:MenuButton Title="Account settings"
Foreground="White"
HighlightColor="White"
Height="30"
Cursor="Hand"
Clicked="AccountSettingsButton_Clicked">
<buttons:MenuButton.InnerContent>
<local:AvatarGlyph Foreground="White"
@@ -42,6 +57,7 @@
Foreground="White"
HighlightColor="White"
Height="30"
Cursor="Hand"
Clicked="GuildwarsSettingsButton_Clicked">
<buttons:MenuButton.InnerContent>
<local:FileGlyph Foreground="White"
@@ -52,6 +68,7 @@
Foreground="White"
HighlightColor="White"
Height="30"
Cursor="Hand"
Clicked="LauncherSettingsButton_Clicked">
<buttons:MenuButton.InnerContent>
<local:CogGlyph Foreground="White"
@@ -63,6 +80,7 @@
Foreground="White"
HighlightColor="White"
Height="30"
Cursor="Hand"
Clicked="ExperimentalSettingsButton_Clicked">
<buttons:MenuButton.InnerContent>
<local:ExperimentGlyph Foreground="White"
@@ -73,6 +91,7 @@
Foreground="White"
HighlightColor="White"
Height="30"
Cursor="Hand"
Clicked="VersionManagementButton_Clicked">
<buttons:MenuButton.InnerContent>
<local:StaticGlyph Foreground="White"
@@ -83,11 +102,23 @@
Foreground="White"
HighlightColor="White"
Height="30"
Cursor="Hand"
Clicked="LogsButton_Clicked">
<buttons:MenuButton.InnerContent>
<local:LogsGlyph Foreground="White"
Width="40"></local:LogsGlyph>
</buttons:MenuButton.InnerContent>
</buttons:MenuButton>
<buttons:MenuButton Title="Metrics"
Foreground="White"
HighlightColor="White"
Height="30"
Cursor="Hand"
Clicked="MetricsButton_Clicked">
<buttons:MenuButton.InnerContent>
<glyphs:GaugeGlyph Foreground="White"
Width="40"></glyphs:GaugeGlyph>
</buttons:MenuButton.InnerContent>
</buttons:MenuButton>
</StackPanel>
</UserControl>
+69 -54
View File
@@ -5,74 +5,89 @@ using Daybreak.Views;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Configuration;
using System.Core.Extensions;
using System.Windows.Controls;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for MenuList.xaml
/// </summary>
public partial class MenuList : UserControl
{
/// <summary>
/// Interaction logic for MenuList.xaml
/// </summary>
public partial class MenuList : UserControl
private readonly IViewManager viewManager;
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
public MenuList()
: this(
Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>(),
Launcher.Instance.ApplicationServiceProvider.GetRequiredService<ILiveOptions<ApplicationConfiguration>>())
{
public MenuList()
{
this.InitializeComponent();
}
this.InitializeComponent();
}
private void GameCompanionButton_Clicked(object sender, EventArgs e)
{
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
viewManager.ShowView<CompanionView>();
}
private MenuList(
IViewManager viewManager,
ILiveOptions<ApplicationConfiguration> liveOptions)
{
this.viewManager = viewManager.ThrowIfNull();
this.liveOptions = liveOptions.ThrowIfNull();
}
private void AccountSettingsButton_Clicked(object sender, EventArgs e)
{
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
viewManager.ShowView<AccountsView>();
}
private void GameCompanionButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<LauncherView>();
}
private void GuildwarsSettingsButton_Clicked(object sender, EventArgs e)
{
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
viewManager.ShowView<ExecutablesView>();
}
private void AccountSettingsButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<AccountsView>();
}
private void LauncherSettingsButton_Clicked(object sender, EventArgs e)
{
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
viewManager.ShowView<SettingsView>();
}
private void GuildwarsSettingsButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<ExecutablesView>();
}
private void ExperimentalSettingsButton_Clicked(object sender, EventArgs e)
{
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
viewManager.ShowView<ExperimentalSettingsView>();
}
private void LauncherSettingsButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<SettingsView>();
}
private void ManageBuildsButton_Clicked(object sender, EventArgs e)
{
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
var options = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<ILiveOptions<ApplicationConfiguration>>();
if (options.Value.ExperimentalFeatures.DownloadIcons)
{
viewManager.ShowView<IconDownloadView>();
}
else
{
viewManager.ShowView<BuildsListView>();
}
}
private void ExperimentalSettingsButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<ExperimentalSettingsView>();
}
private void VersionManagementButton_Clicked(object sender, EventArgs e)
private void ManageBuildsButton_Clicked(object sender, EventArgs e)
{
if (this.liveOptions.Value.ExperimentalFeatures.DownloadIcons)
{
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
viewManager.ShowView<VersionManagementView>();
this.viewManager.ShowView<IconDownloadView>();
}
private void LogsButton_Clicked(object sender, EventArgs e)
else
{
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
viewManager.ShowView<LogsView>();
this.viewManager.ShowView<BuildsListView>();
}
}
private void VersionManagementButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<VersionManagementView>();
}
private void LogsButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<LogsView>();
}
private void MetricsButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<MetricsView>();
}
private void DownloadGuildwarsButton_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<DownloadView>();
}
}
+27 -28
View File
@@ -4,39 +4,38 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for SearchTextBox.xaml
/// </summary>
public partial class SearchTextBox : UserControl
{
/// <summary>
/// Interaction logic for SearchTextBox.xaml
/// </summary>
public partial class SearchTextBox : UserControl
public event EventHandler<string>? TextChanged;
[GenerateDependencyProperty(InitialValue = true)]
private bool placeholderVisibility;
[GenerateDependencyProperty]
private string searchText = default!;
public SearchTextBox()
{
public event EventHandler<string> TextChanged;
this.InitializeComponent();
}
[GenerateDependencyProperty(InitialValue = true)]
private bool placeholderVisibility;
[GenerateDependencyProperty]
private string searchText;
public SearchTextBox()
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var searchText = e.Source.As<TextBox>().Text;
if (searchText.IsNullOrWhiteSpace())
{
this.InitializeComponent();
this.PlaceholderVisibility = true;
}
else
{
this.PlaceholderVisibility = false;
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var searchText = e.Source.As<TextBox>().Text;
if (searchText.IsNullOrWhiteSpace())
{
this.PlaceholderVisibility = true;
}
else
{
this.PlaceholderVisibility = false;
}
this.SearchText = searchText;
this.TextChanged?.Invoke(this, searchText);
}
this.SearchText = searchText;
this.TextChanged?.Invoke(this, searchText);
}
}
@@ -5,68 +5,67 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Controls
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
{
/// <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 event EventHandler? RemoveClicked;
public event EventHandler? DefaultClicked;
[GenerateDependencyProperty]
private string username = string.Empty;
[GenerateDependencyProperty]
private string password = string.Empty;
[GenerateDependencyProperty]
private string characterName = string.Empty;
[GenerateDependencyProperty]
private bool isDefault;
public AccountTemplate()
{
public event EventHandler RemoveClicked;
public event EventHandler DefaultClicked;
[GenerateDependencyProperty]
private string username;
[GenerateDependencyProperty]
private string password;
[GenerateDependencyProperty]
private string characterName;
[GenerateDependencyProperty]
private bool isDefault;
this.InitializeComponent();
this.DataContextChanged += this.AccountTemplate_DataContextChanged;
}
public AccountTemplate()
private void AccountTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is LoginCredentials loginCredentials)
{
this.InitializeComponent();
this.DataContextChanged += this.AccountTemplate_DataContextChanged;
}
private void AccountTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is LoginCredentials loginCredentials)
{
this.PasswordBox.Password = loginCredentials.Password;
this.Username = loginCredentials.Username;
this.CharacterName = loginCredentials.CharacterName;
this.IsDefault = loginCredentials.Default;
}
}
private void BinButton_Clicked(object sender, EventArgs e)
{
this.RemoveClicked?.Invoke(this, e);
}
private void UsernameTextbox_TextChanged(object sender, EventArgs e)
{
this.DataContext.As<LoginCredentials>().Username = this.Username;
}
private void CharacterNameTextbox_TextChanged(object sender, EventArgs e)
{
this.DataContext.As<LoginCredentials>().CharacterName = this.CharacterName;
}
private void Passwordbox_PasswordChanged(object sender, EventArgs e)
{
this.Password = sender.As<PasswordBox>()?.Password;
this.DataContext.As<LoginCredentials>().Password = this.Password;
}
private void StarGlyph_Clicked(object sender, EventArgs e)
{
this.DefaultClicked?.Invoke(this, e);
this.PasswordBox.Password = loginCredentials.Password;
this.Username = loginCredentials.Username;
this.CharacterName = loginCredentials.CharacterName;
this.IsDefault = loginCredentials.Default;
}
}
private void BinButton_Clicked(object sender, EventArgs e)
{
this.RemoveClicked?.Invoke(this, e);
}
private void UsernameTextbox_TextChanged(object sender, EventArgs e)
{
this.DataContext.As<LoginCredentials>().Username = this.Username;
}
private void CharacterNameTextbox_TextChanged(object sender, EventArgs e)
{
this.DataContext.As<LoginCredentials>().CharacterName = this.CharacterName;
}
private void Passwordbox_PasswordChanged(object sender, EventArgs e)
{
this.Password = sender.As<PasswordBox>()?.Password;
this.DataContext.As<LoginCredentials>().Password = this.Password;
}
private void StarGlyph_Clicked(object sender, EventArgs e)
{
this.DefaultClicked?.Invoke(this, e);
}
}
@@ -1,77 +1,107 @@
using Daybreak.Models.Builds;
using Daybreak.Services.BuildTemplates;
using System;
using System.Core.Extensions;
using System.Extensions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Controls
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
{
/// <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;
private IAttributePointCalculator? attributePointCalculator;
[GenerateDependencyProperty(InitialValue = false)]
private bool canAdd;
[GenerateDependencyProperty(InitialValue = false)]
private bool canSubtract;
[GenerateDependencyProperty]
private int attributePoints;
public AttributeTemplate()
{
public event EventHandler<AttributeEntry> HelpClicked;
public event EventHandler<AttributeEntry> AttributeChanged;
[GenerateDependencyProperty(InitialValue = false)]
private bool canAdd;
[GenerateDependencyProperty(InitialValue = false)]
private bool canSubtract;
this.InitializeComponent();
this.DataContextChanged += this.AttributeTemplate_DataContextChanged;
}
public AttributeTemplate()
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == AttributePointsProperty &&
this.DataContext is AttributeEntry attributeEntry)
{
this.InitializeComponent();
this.DataContextChanged += this.AttributeTemplate_DataContextChanged;
}
private void AttributeTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is AttributeEntry attributeEntry)
var remainingPoints = this.AttributePoints;
var requiredPointsForNextLevel = this.attributePointCalculator?.GetPointsRequiredToIncreaseRank(attributeEntry.Points) ?? 0;
if (remainingPoints < requiredPointsForNextLevel)
{
if (attributeEntry.Points > 0)
{
this.CanSubtract = true;
}
if (attributeEntry.Points < 12)
{
this.CanAdd = true;
}
this.CanAdd = false;
}
}
private void MinusButton_Clicked(object sender, System.EventArgs e)
{
if (this.DataContext.As<AttributeEntry>().Points > 0)
else if (this.DataContext.As<AttributeEntry>().Points < 12)
{
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);
}
}
}
public void InitializeAttributeTemplate(
IAttributePointCalculator attributePointCalculator)
{
this.attributePointCalculator = attributePointCalculator.ThrowIfNull();
}
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);
}
}
}
@@ -2,26 +2,25 @@
using System;
using System.Windows.Controls;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for BuildEntryTemplate.xaml
/// </summary>
public partial class BuildEntryTemplate : UserControl
{
/// <summary>
/// Interaction logic for BuildEntryTemplate.xaml
/// </summary>
public partial class BuildEntryTemplate : UserControl
public event EventHandler<BuildEntry>? RemoveClicked;
public BuildEntryTemplate()
{
public event EventHandler<BuildEntry> RemoveClicked;
this.InitializeComponent();
}
public BuildEntryTemplate()
private void BinButton_Clicked(object sender, EventArgs e)
{
if (this.DataContext is BuildEntry buildEntry)
{
this.InitializeComponent();
}
private void BinButton_Clicked(object sender, EventArgs e)
{
if (this.DataContext is BuildEntry buildEntry)
{
this.RemoveClicked?.Invoke(this, buildEntry);
}
this.RemoveClicked?.Invoke(this, buildEntry);
}
}
}
+68 -48
View File
@@ -11,6 +11,9 @@
x:Name="_this"
Unloaded="BuildTemplate_Unloaded"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
</UserControl.Resources>
<Grid Background="Transparent" MouseLeftButtonDown="Grid_MouseLeftButtonDown">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
@@ -30,20 +33,15 @@
<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:OpaqueButton Grid.Column="2"
Text="{Binding ElementName=_this, Path=BuildEntry.Primary.Name, Mode=OneWay}"
Foreground="White"
Highlight="White"
HighlightOpacity="0.4"
FontSize="16"
TextHorizontalAlignment="Left"
Margin="0, 0, 10, 0"
Clicked="PrimaryProfessionButton_Clicked"></local:OpaqueButton>
<local:HelpButton Grid.Column="0" Foreground="White" Width="20" Height="20" Margin="3"
Clicked="HelpButtonPrimary_Clicked" Cursor="Hand"></local:HelpButton>
</Grid>
@@ -54,29 +52,27 @@
<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:OpaqueButton Grid.Column="2"
Text="{Binding ElementName=_this, Path=BuildEntry.Secondary.Name, Mode=OneWay}"
Foreground="White"
Highlight="White"
HighlightOpacity="0.4"
FontSize="16"
TextHorizontalAlignment="Left"
Margin="0, 0, 10, 0"
Clicked="SecondaryProfessionButton_Clicked"></local:OpaqueButton>
<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}"
<ListBox Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=BuildEntry.Attributes, Mode=OneWay}"
HorizontalContentAlignment="Stretch" BorderThickness="0">
<ListBox.ItemTemplate>
<DataTemplate>
<local:AttributeTemplate HelpClicked="AttributeTemplate_HelpClicked" AttributeChanged="AttributeTemplate_AttributeChanged"></local:AttributeTemplate>
<local:AttributeTemplate HelpClicked="AttributeTemplate_HelpClicked"
AttributeChanged="AttributeTemplate_AttributeChanged"
Loaded="AttributeTemplate_Loaded"
AttributePoints="{Binding Path=AttributePoints, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"></local:AttributeTemplate>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
@@ -98,60 +94,60 @@
</Grid.RowDefinitions>
<local:SkillTemplate Grid.Column="0" x:Name="SkillTemplate0"
Foreground="White" Cursor="Hand"
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill0, Mode=TwoWay}"
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.FirstSkill, 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}"
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.SecondSkill, 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}"
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.ThirdSkill, 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}"
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.FourthSkill, 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}"
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.FifthSkill, 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}"
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.SixthSkill, 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}"
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.SeventhSkill, 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}"
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.EigthSkill, 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>
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.FirstSkill.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>
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.SecondSkill.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>
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.ThirdSkill.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>
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.FourthSkill.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>
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.FifthSkill.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>
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.SixthSkill.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>
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.SeventhSkill.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>
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.EigthSkill.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>
@@ -170,10 +166,11 @@
<ListView x:Name="SkillsListView"
Grid.Row="1"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Background="Transparent"
ScrollViewer.CanContentScroll="False"
ItemsSource="{Binding ElementName=_this, Path=AvailableSkills, Mode=OneWay}"
MouseDoubleClick="ListView_MouseDoubleClick">
MouseDoubleClick="SkillListView_MouseDoubleClick">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel>
@@ -188,5 +185,28 @@
</ListView>
</Grid>
</Grid>
<Grid Grid.Column="1" Grid.RowSpan="6">
<ListView x:Name="ProfessionListView"
Width="0"
HorizontalAlignment="Right"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Background="Transparent"
ScrollViewer.CanContentScroll="False"
ItemsSource="{Binding ElementName=_this, Path=Professions, Mode=OneWay}"
MouseDoubleClick="ProfessionListView_MouseDoubleClick">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel>
</VirtualizingStackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock FontSize="16" Foreground="White" TextWrapping="Wrap" Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Grid>
</UserControl>
+356 -429
View File
@@ -1,12 +1,16 @@
using Daybreak.Configuration;
using Daybreak.Launch;
using Daybreak.Models.Builds;
using Daybreak.Models.Guildwars;
using Daybreak.Services.BuildTemplates;
using Daybreak.Services.IconRetrieve;
using Daybreak.Utils;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Configuration;
using System.Core.Extensions;
using System.Extensions;
@@ -17,461 +21,384 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Controls
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
{
/// <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 showingSkillList = false;
private bool replacingSecondaryProfession;
private bool replacingPrimaryProfession;
private IAttributePointCalculator? attributePointCalculator;
private SkillTemplate? selectingSkillTemplate;
private List<Skill>? skillListCache;
private CancellationTokenSource? cancellationTokenSource = new();
public event EventHandler? BuildChanged;
[GenerateDependencyProperty]
private string skillSearchText = string.Empty;
[GenerateDependencyProperty]
private BuildEntry buildEntry;
[GenerateDependencyProperty]
private int attributePoints;
[GenerateDependencyProperty]
private List<Skill> availableSkills = new();
[GenerateDependencyProperty]
private List<Profession> professions = new();
public BuildTemplate()
: this(Launcher.Instance.ApplicationServiceProvider.GetService<IAttributePointCalculator>()!)
{
private const string InfoNamePlaceholder = "[NAME]";
private const string BaseAddress = $"https://wiki.guildwars.com/wiki/{InfoNamePlaceholder}";
}
public BuildTemplate(
IAttributePointCalculator attributePointCalculator)
{
this.attributePointCalculator = attributePointCalculator.ThrowIfNull();
private bool suppressBuildChanged = false;
private bool loadedProperties = false;
private IIconBrowser iconBrowser;
private BuildEntry loadedBuild;
private SkillTemplate selectingSkillTemplate;
private CancellationTokenSource cancellationTokenSource = new();
this.InitializeComponent();
this.HideSkillListView();
this.HideInfoBrowser();
this.buildEntry = new BuildEntry();
this.DataContextChanged += this.BuildTemplate_DataContextChanged;
}
public event EventHandler BuildChanged;
private void BuildTemplate_Unloaded(object sender, RoutedEventArgs e)
{
this.cancellationTokenSource?.Cancel();
}
[GenerateDependencyProperty]
private string skillSearchText;
[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()
private void BuildTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if(e.NewValue is BuildEntry buildEntry)
{
this.InitializeComponent();
this.InitializeProperties();
this.DataContextChanged += this.BuildTemplate_DataContextChanged;
}
public async void InitializeTemplate(
IIconCache iconRetriever,
IIconBrowser iconBrowser,
ILiveOptions<ApplicationConfiguration> liveOptions,
IBuildTemplateManager buildTemplateManager,
ILogger<ChromiumBrowserWrapper> logger)
{
this.iconBrowser = iconBrowser.ThrowIfNull();
await this.SkillBrowser.InitializeDefaultBrowser(liveOptions, buildTemplateManager, logger);
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);
this.HideSkillListView();
this.HideInfoBrowser();
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (this.loadedProperties is false)
if (this.BuildEntry is not null)
{
return;
this.BuildEntry.PropertyChanged -= this.BuildEntry_Changed;
}
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 async void LoadSkills()
{
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;
}
var filteredSkills = await this.FilterSkills(this.SkillSearchText).ToListAsync().ConfigureAwait(true);
this.AvailableSkills.ClearAnd().AddRange(filteredSkills);
}
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.SkillListContainer.Width = 0;
}
}
private void HideInfoBrowser()
{
if (this.SkillBrowser.BrowserSupported is true)
{
this.SkillBrowser.Width = 0;
}
}
private void ShowSkillListView()
{
this.SkillBrowser.Width = 0;
this.SkillListContainer.Width = 400;
}
private void HideSkillListView()
{
this.SkillListContainer.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 _, AttributeEntry e)
{
this.BrowseToInfo(e.Attribute.Name);
}
private void AttributeTemplate_AttributeChanged(object _, AttributeEntry e)
{
e.ThrowIfNull();
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.SkillSearchText = string.Empty;
this.ShowSkillListView();
this.selectingSkillTemplate = sender.As<SkillTemplate>();
}
else
{
this.BrowseToInfo(skill.Name);
}
e.Handled = true;
}
private void SearchTextBox_TextChanged(object _, string e)
{
e.ThrowIfNull();
this.BuildEntry = buildEntry;
this.BuildEntry.PropertyChanged += this.BuildEntry_Changed;
this.AttributePoints = this.attributePointCalculator!.GetRemainingFreePoints(this.BuildEntry.Build!);
this.LoadSkills();
}
}
private void SkillTemplate_RemoveClicked(object sender, System.EventArgs e)
private void BuildEntry_Changed(object? sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
this.LoadSkills();
}
private async void LoadSkills()
{
var filteredSkills = await this.FilterSkills(this.SkillSearchText).ToListAsync().ConfigureAwait(true);
this.PrepareSkillListCache(filteredSkills);
}
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)
{
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;
this.HideProfessionListView();
this.SkillBrowser.Width = 400;
}
}
private void HideInfoBrowser()
{
if (this.SkillBrowser.BrowserSupported is true)
{
this.SkillBrowser.Width = 0;
}
}
private void ShowSkillListView()
{
this.HideInfoBrowser();
this.HideProfessionListView();
this.SkillListContainer.Width = 400;
this.SkillListContainer.Visibility = Visibility.Visible;
this.showingSkillList = true;
if (this.AvailableSkills is not null &&
this.skillListCache?.Except(this.AvailableSkills).None() is true &&
this.skillListCache.Count == this.AvailableSkills.Count)
{
return;
}
private void ListView_NavigateWithMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
this.AvailableSkills = this.skillListCache;
}
private void HideSkillListView()
{
this.SkillListContainer.Visibility = Visibility.Hidden;
this.SkillListContainer.Width = 0;
this.showingSkillList = false;
}
private void ShowProfessionListView()
{
this.HideInfoBrowser();
this.HideSkillListView();
this.ProfessionListView.Width = 400;
this.ProfessionListView.Visibility = Visibility.Visible;
}
private void HideProfessionListView()
{
this.ProfessionListView.Visibility = Visibility.Hidden;
this.ProfessionListView.Width = 0;
}
private void PrepareSkillListCache(List<Skill> skills)
{
/*
* To improve application performance, only load the skill list when it is showing.
* Otherwise, defer the loading to when the skill list will show.
*/
this.skillListCache = skills;
if (this.showingSkillList)
{
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;
}
this.ShowSkillListView();
}
}
private void ScrollViewer_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
private async IAsyncEnumerable<Skill> FilterSkills(string searchTerm)
{
// Replace symbols to ease search
searchTerm = searchTerm?.Replace("\"", "").Replace("!", "")!;
foreach (var skill in Skill.Skills)
{
if (sender is not ScrollViewer scrollViewer)
if (skill == Skill.NoSkill)
{
return;
continue;
}
e.Handled = true;
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta);
}
private async IAsyncEnumerable<Skill> FilterSkills(string searchTerm)
{
// Replace symbols to ease search
searchTerm = searchTerm?.Replace("\"", "").Replace("!", "");
foreach (var skill in Skill.Skills)
if (skill.Profession != this.BuildEntry!.Primary &&
skill.Profession != this.BuildEntry!.Secondary &&
skill.Profession != Profession.None)
{
if (skill == Skill.NoSkill)
{
continue;
}
continue;
}
if (skill.Profession != this.PrimaryProfession &&
skill.Profession != this.SecondaryProfession &&
skill.Profession != Profession.None)
{
continue;
}
if (searchTerm.IsNullOrWhiteSpace())
{
yield return skill;
continue;
}
if (searchTerm.IsNullOrWhiteSpace())
{
yield return skill;
continue;
}
var matchesName = await Task.Run(() => StringUtils.MatchesSearchString(skill.Name.Replace("\"", "").Replace("!", ""), searchTerm));
if (matchesName)
{
yield return skill;
continue;
}
var matchesName = await Task.Run(() => StringUtils.MatchesSearchString(skill.Name!.Replace("\"", "").Replace("!", ""), searchTerm!));
if (matchesName)
{
yield return skill;
continue;
}
}
}
private void Grid_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
this.HideSkillListView();
this.HideInfoBrowser();
}
private void HelpButtonPrimary_Clicked(object sender, System.EventArgs e)
{
if (this.BuildEntry!.Primary == Profession.None)
{
return;
}
this.BrowseToInfo(this.BuildEntry.Primary.Name!);
if (e is RoutedEventArgs routedEventArgs)
{
routedEventArgs.Handled = true;
}
}
private void HelpButtonSecondary_Clicked(object sender, System.EventArgs e)
{
if (this.BuildEntry!.Secondary == Profession.None)
{
return;
}
this.BrowseToInfo(this.BuildEntry.Secondary.Name!);
if (e is RoutedEventArgs routedEventArgs)
{
routedEventArgs.Handled = true;
}
}
private void AttributeTemplate_HelpClicked(object _, AttributeEntry e)
{
this.BrowseToInfo(e.Attribute?.Name!);
}
private void AttributeTemplate_AttributeChanged(object _, AttributeEntry e)
{
e.ThrowIfNull();
this.BuildChanged?.Invoke(this, new EventArgs());
this.AttributePoints = this.attributePointCalculator!.GetRemainingFreePoints(this.BuildEntry.Build!);
}
private void SkillTemplate_Clicked(object sender, RoutedEventArgs e)
{
var skill = sender.As<SkillTemplate>().DataContext.As<Skill>();
if (skill == Skill.NoSkill)
{
this.SkillSearchText = string.Empty;
this.ShowSkillListView();
this.selectingSkillTemplate = sender.As<SkillTemplate>();
}
else
{
this.BrowseToInfo(skill.Name!);
}
e.Handled = true;
}
private void SearchTextBox_TextChanged(object _, string e)
{
e.ThrowIfNull();
this.LoadSkills();
}
private void SkillTemplate_RemoveClicked(object sender, System.EventArgs e)
{
if (sender == this.SkillTemplate0)
{
this.BuildEntry.FirstSkill = Skill.NoSkill;
}
else if (sender == this.SkillTemplate1)
{
this.BuildEntry.SecondSkill = Skill.NoSkill;
}
else if (sender == this.SkillTemplate2)
{
this.BuildEntry.ThirdSkill = Skill.NoSkill;
}
else if (sender == this.SkillTemplate3)
{
this.BuildEntry.FourthSkill = Skill.NoSkill;
}
else if (sender == this.SkillTemplate4)
{
this.BuildEntry.FifthSkill = Skill.NoSkill;
}
else if (sender == this.SkillTemplate5)
{
this.BuildEntry.SixthSkill = Skill.NoSkill;
}
else if (sender == this.SkillTemplate6)
{
this.BuildEntry.SeventhSkill = Skill.NoSkill;
}
else if (sender == this.SkillTemplate7)
{
this.BuildEntry.EigthSkill = Skill.NoSkill;
}
}
private void SkillListView_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (this.selectingSkillTemplate is null)
{
this.HideSkillListView();
return;
}
var selectedSkilll = sender.As<ListView>().SelectedItem.As<Skill>();
if (this.selectingSkillTemplate == this.SkillTemplate0)
{
this.BuildEntry.FirstSkill = selectedSkilll;
}
else if (this.selectingSkillTemplate == this.SkillTemplate1)
{
this.BuildEntry.SecondSkill = selectedSkilll;
}
else if (this.selectingSkillTemplate == this.SkillTemplate2)
{
this.BuildEntry.ThirdSkill = selectedSkilll;
}
else if (this.selectingSkillTemplate == this.SkillTemplate3)
{
this.BuildEntry.FourthSkill = selectedSkilll;
}
else if (this.selectingSkillTemplate == this.SkillTemplate4)
{
this.BuildEntry.FifthSkill = selectedSkilll;
}
else if (this.selectingSkillTemplate == this.SkillTemplate5)
{
this.BuildEntry.SixthSkill = selectedSkilll;
}
else if (this.selectingSkillTemplate == this.SkillTemplate6)
{
this.BuildEntry.SeventhSkill = selectedSkilll;
}
else if (this.selectingSkillTemplate == this.SkillTemplate7)
{
this.BuildEntry.EigthSkill = selectedSkilll;
}
this.HideSkillListView();
}
private void ProfessionListView_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var selected = sender.As<ListView>().SelectedItem.As<Profession>();
if (this.replacingPrimaryProfession)
{
this.BuildEntry!.Primary = selected;
}
else if (this.replacingSecondaryProfession)
{
this.BuildEntry!.Secondary = selected;
}
this.HideProfessionListView();
}
private void SecondaryProfessionButton_Clicked(object sender, EventArgs e)
{
this.replacingPrimaryProfession = false;
this.replacingSecondaryProfession = true;
this.Professions = Profession.Professions.Where(p => p != this.BuildEntry?.Secondary).ToList();
this.ShowProfessionListView();
}
private void PrimaryProfessionButton_Clicked(object sender, EventArgs e)
{
this.replacingPrimaryProfession = true;
this.replacingSecondaryProfession = false;
this.Professions.ClearAnd().AddRange(Profession.Professions.Where(p => p != this.BuildEntry?.Primary));
this.ShowProfessionListView();
}
private void AttributeTemplate_Loaded(object sender, RoutedEventArgs e)
{
sender.As<AttributeTemplate>().InitializeAttributeTemplate(this.attributePointCalculator!);
}
}
@@ -6,67 +6,66 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
namespace Daybreak.Controls
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
{
/// <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 event EventHandler? RemoveClicked;
public event EventHandler? DefaultClicked;
[GenerateDependencyProperty]
private string path = string.Empty;
[GenerateDependencyProperty]
private bool isDefault;
public GuildwarsPathTemplate()
{
public event EventHandler RemoveClicked;
public event EventHandler DefaultClicked;
this.InitializeComponent();
this.DataContextChanged += this.GuildwarsPathTemplate_DataContextChanged;
}
[GenerateDependencyProperty]
private string path;
[GenerateDependencyProperty]
private bool isDefault;
public GuildwarsPathTemplate()
private void GuildwarsPathTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is GuildwarsPath guildwarsPath)
{
this.InitializeComponent();
this.DataContextChanged += this.GuildwarsPathTemplate_DataContextChanged;
this.IsDefault = guildwarsPath.Default;
this.Path = guildwarsPath.Path;
}
}
private void GuildwarsPathTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is GuildwarsPath guildwarsPath)
{
this.IsDefault = guildwarsPath.Default;
this.Path = guildwarsPath.Path;
}
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
this.DataContext.As<GuildwarsPath>().Path = this.Path;
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
this.DataContext.As<GuildwarsPath>().Path = this.Path;
}
private void StarGlyph_Clicked(object sender, EventArgs e)
{
this.DefaultClicked?.Invoke(this, e);
}
private void StarGlyph_Clicked(object sender, EventArgs e)
{
this.DefaultClicked?.Invoke(this, e);
}
private void BinButton_Clicked(object sender, EventArgs e)
{
this.RemoveClicked?.Invoke(this, e);
}
private void BinButton_Clicked(object sender, EventArgs e)
private void FilePickerGlyph_Clicked(object sender, EventArgs e)
{
var filePicker = new OpenFileDialog()
{
this.RemoveClicked?.Invoke(this, e);
}
private void FilePickerGlyph_Clicked(object sender, EventArgs e)
CheckFileExists = true,
CheckPathExists = true,
DefaultExt = "exe",
Multiselect = false
};
if (filePicker.ShowDialog() is true)
{
var filePicker = new OpenFileDialog()
{
CheckFileExists = true,
CheckPathExists = true,
DefaultExt = "exe",
Multiselect = false
};
if (filePicker.ShowDialog() is true)
{
this.Path = filePicker.FileName;
this.DataContext.As<GuildwarsPath>().Path = filePicker.FileName;
}
this.Path = filePicker.FileName;
this.DataContext.As<GuildwarsPath>().Path = filePicker.FileName;
}
}
}
@@ -3,34 +3,33 @@ using System.Windows.Controls;
using System.Windows.Input;
using System.Extensions;
namespace Daybreak.Controls
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for LogTemplate.xaml
/// </summary>
public partial class LogMessageTemplate : UserControl
{
/// <summary>
/// Interaction logic for LogTemplate.xaml
/// </summary>
public partial class LogMessageTemplate : UserControl
private bool expanded;
[GenerateDependencyProperty]
private string message = string.Empty;
public LogMessageTemplate()
{
private bool expanded;
this.InitializeComponent();
}
[GenerateDependencyProperty]
private string message;
public LogMessageTemplate()
private void TextBox_MouseLeftButtonDown(object sender, MouseButtonEventArgs eventArgs)
{
this.expanded = !this.expanded;
if (this.expanded)
{
this.InitializeComponent();
sender.As<TextBlock>().MaxHeight = double.MaxValue;
}
private void TextBox_MouseLeftButtonDown(object sender, MouseButtonEventArgs eventArgs)
else
{
this.expanded = !this.expanded;
if (this.expanded)
{
sender.As<TextBlock>().MaxHeight = double.MaxValue;
}
else
{
sender.As<TextBlock>().MaxHeight = 18;
}
sender.As<TextBlock>().MaxHeight = 18;
}
}
}
@@ -0,0 +1,11 @@
<UserControl x:Class="Daybreak.Controls.Templates.QuestLogTemplate"
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"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel x:Name="ItemStackPanel">
</StackPanel>
</UserControl>
@@ -0,0 +1,170 @@
using Daybreak.Models.Guildwars;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Extensions;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
namespace Daybreak.Controls.Templates;
/// <summary>
/// Interaction logic for QuestLogTemplate.xaml
/// </summary>
public partial class QuestLogTemplate : UserControl
{
private const string UncategorizedQuestsString = "Uncategorized Quests";
private List<IGrouping<Map?, QuestMetadata>>? questLogCache;
[GenerateDependencyProperty]
private List<QuestMetadata> quests;
public event EventHandler<Map?>? MapClicked;
public event EventHandler<Quest?>? QuestClicked;
public QuestLogTemplate()
{
this.quests = new List<QuestMetadata>();
this.InitializeComponent();
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == QuestsProperty)
{
this.DrawQuestLogLayout();
}
}
private void DrawQuestLogLayout()
{
var questLog = this.Quests?.GroupBy(q => q.From).OrderBy(g => g.Key?.Name).ToList();
if (!this.DetectQuestLogChange(questLog))
{
return;
}
this.questLogCache = questLog;
if (this.questLogCache is null)
{
return;
}
this.ItemStackPanel.Children.Clear();
foreach(var grouping in this.questLogCache)
{
var location = grouping.Key;
var locationTextBlock = new OpaqueButton
{
Text = grouping.Key?.Name ?? UncategorizedQuestsString,
FontSize = 18,
Cursor = grouping.Key is null ? Cursors.Arrow : Cursors.Hand,
HorizontalAlignment = HorizontalAlignment.Stretch,
TextHorizontalAlignment = HorizontalAlignment.Left,
Highlight = Brushes.White,
HighlightOpacity = grouping.Key is null ? 0 : 0.6
};
locationTextBlock.MouseLeftButtonDown += (_, _) => this.OnMapClicked(location);
this.ItemStackPanel.Children.Add(locationTextBlock);
var rectangle = new Rectangle
{
Height = 1,
};
var rectangleForegroundBinding = new Binding("Foreground")
{
Source = this
};
rectangle.SetBinding(Rectangle.FillProperty, rectangleForegroundBinding);
this.ItemStackPanel.Children.Add(rectangle);
foreach (var questMetadata in grouping)
{
var quest = questMetadata.Quest;
var questTextBlock = new OpaqueButton
{
Text = quest?.Name,
FontSize = 20,
Cursor = Cursors.Hand,
Highlight = Brushes.White,
HighlightOpacity = 0.6,
HorizontalAlignment = HorizontalAlignment.Stretch,
TextHorizontalAlignment = HorizontalAlignment.Left
};
questTextBlock.MouseLeftButtonDown += (_, _) => this.OnQuestClicked(quest);
this.ItemStackPanel.Children.Add(questTextBlock);
}
this.ItemStackPanel.Children.Add(new Rectangle
{
Fill = Brushes.Transparent,
Height = 10,
HorizontalAlignment = HorizontalAlignment.Stretch
});
}
}
private bool DetectQuestLogChange(List<IGrouping<Map?, QuestMetadata>>? newQuestLog)
{
if (this.questLogCache is null)
{
return true;
}
if (newQuestLog is null)
{
return true;
}
if (this.questLogCache.Count != newQuestLog.Count)
{
return true;
}
for (var i = 0; i < this.questLogCache.Count; i++)
{
var grouping1 = this.questLogCache[i];
var grouping2 = newQuestLog[i];
if (grouping1.Key?.Id != grouping2.Key?.Id)
{
return true;
}
var cachedQuests = grouping1.ToList();
var newQuests = grouping2.ToList();
if (cachedQuests.Count != newQuests.Count)
{
return true;
}
for (var j = 0; j < cachedQuests.Count; j++)
{
if (cachedQuests[j].Quest?.Id != newQuests[j].Quest?.Id)
{
return true;
}
}
}
return false;
}
private void OnMapClicked(Map? map)
{
this.MapClicked?.Invoke(this, map);
}
private void OnQuestClicked(Quest? quest)
{
this.QuestClicked?.Invoke(this, quest);
}
}
@@ -6,58 +6,57 @@ using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Media;
namespace Daybreak.Controls.Templates
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
{
/// <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 = string.Empty;
[GenerateDependencyProperty]
private Brush highlight = default!;
public ScreenTemplate()
{
public event EventHandler<Screen> Clicked;
this.InitializeComponent();
this.DataContextChanged += this.ScreenTemplate_DataContextChanged;
}
[GenerateDependencyProperty]
private string screenId;
[GenerateDependencyProperty]
private Brush highlight;
public ScreenTemplate()
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == ForegroundProperty)
{
this.InitializeComponent();
this.DataContextChanged += this.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>());
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>());
}
}
@@ -1,94 +1,97 @@
using Daybreak.Models.Builds;
using Daybreak.Launch;
using Daybreak.Models.Guildwars;
using Daybreak.Services.IconRetrieve;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Core.Extensions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Daybreak.Controls
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
{
/// <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 IIconCache? iconRetriever;
[GenerateDependencyProperty]
private ImageSource imageSource = default!;
[GenerateDependencyProperty]
private double borderOpacity;
public SkillTemplate()
: this(Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IIconCache>())
{
public event EventHandler<RoutedEventArgs> Clicked;
public event EventHandler RemoveClicked;
}
private IIconCache iconRetriever;
public SkillTemplate(
IIconCache iconCache)
{
this.iconRetriever = iconCache.ThrowIfNull();
this.InitializeComponent();
this.DataContextChanged += this.SkillTemplate_DataContextChanged;
}
[GenerateDependencyProperty]
private ImageSource imageSource;
[GenerateDependencyProperty]
private double borderOpacity;
public SkillTemplate()
private async void SkillTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.iconRetriever is null)
{
this.InitializeComponent();
this.DataContextChanged += this.SkillTemplate_DataContextChanged;
return;
}
public void InitializeSkillTemplate(IIconCache iconRetriever)
if (e.NewValue is Skill skill)
{
this.iconRetriever = iconRetriever;
this.SkillTemplate_DataContextChanged(this, new DependencyPropertyChangedEventArgs(UserControl.DataContextProperty, null, this.DataContext));
}
private async void SkillTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.iconRetriever is null)
if (skill != Skill.NoSkill)
{
return;
}
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)
{
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;
this.ImageSource = new BitmapImage(uri);
}
}
}
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)
else if (this.ImageSource is not null)
{
return skill != Skill.NoSkill;
this.ImageSource = null;
}
return false;
}
}
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;
}
}
@@ -0,0 +1,37 @@
<UserControl x:Class="Daybreak.Controls.VerticalResourceBar"
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>
<Viewbox VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Stretch="Fill">
<Grid Width="1">
<Rectangle
Fill="{Binding ElementName=_this, Path=BarColor, Mode=OneWay}"
VerticalAlignment="{Binding ElementName=_this, Path=FillAlignment, Mode=OneWay}"
HorizontalAlignment="Stretch"
Height="{Binding ElementName=_this, Path=MaxResourceValue, Mode=TwoWay}"></Rectangle>
<Rectangle
Fill="#F0212121"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"></Rectangle>
<Rectangle
Fill="{Binding ElementName=_this, Path=BarColor, Mode=OneWay}"
VerticalAlignment="{Binding ElementName=_this, Path=FillAlignment, Mode=OneWay}"
HorizontalAlignment="Stretch"
Height="{Binding ElementName=_this, Path=CurrentResourceValue, Mode=TwoWay}"></Rectangle>
</Grid>
</Viewbox>
<TextBlock
FontSize="{Binding ElementName=_this, Path=FontSize, Mode=OneWay}"
FontFamily="{Binding ElementName=_this, Path=FontFamily, Mode=OneWay}"
Text="{Binding ElementName=_this, Path=Text, Mode=OneWay}"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
VerticalAlignment="Center"
HorizontalAlignment="Center"></TextBlock>
</Grid>
</UserControl>
@@ -0,0 +1,32 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Media;
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for ResourceBar.xaml
/// </summary>
public partial class VerticalResourceBar : UserControl
{
[GenerateDependencyProperty]
private double currentResourceValue;
[GenerateDependencyProperty]
private double maxResourceValue;
[GenerateDependencyProperty]
private Brush barColor;
[GenerateDependencyProperty]
private string text;
[GenerateDependencyProperty(InitialValue = VerticalAlignment.Bottom)]
private VerticalAlignment fillAlignment;
public VerticalResourceBar()
{
this.InitializeComponent();
this.MaxResourceValue = 1;
this.CurrentResourceValue = 0;
this.barColor = Brushes.Transparent;
this.text = string.Empty;
}
}
@@ -4,51 +4,50 @@ using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace Daybreak.Converters
namespace Daybreak.Converters;
public class BooleanToVisibilityConverter : IValueConverter
{
public class BooleanToVisibilityConverter : IValueConverter
/// <summary>
/// Set to true if you want to show control when boolean value is true.
/// Set to false if you want to hide/collapse control when value is true.
/// </summary>
public bool TriggerValue { get; set; } = true;
/// <summary>
/// Set to true if you just want to hide the control, else set to false if you want to collapse the control.
/// </summary>
public bool IsHidden { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
/// <summary>
/// Set to true if you want to show control when boolean value is true.
/// Set to false if you want to hide/collapse control when value is true.
/// </summary>
public bool TriggerValue { get; set; } = true;
/// <summary>
/// Set to true if you just want to hide the control, else set to false if you want to collapse the control.
/// </summary>
public bool IsHidden { get; set; }
return this.GetVisibility(value);
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
private object GetVisibility(object value)
{
if (value is not bool)
{
return this.GetVisibility(value);
return this.IsHidden ?
Visibility.Hidden :
Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
var objValue = value.Cast<bool>();
if ((objValue && this.TriggerValue && this.IsHidden) || (!objValue && !this.TriggerValue && this.IsHidden))
{
throw new NotImplementedException();
return Visibility.Hidden;
}
private object GetVisibility(object value)
if ((objValue && this.TriggerValue && !this.IsHidden) || (!objValue && !this.TriggerValue && !this.IsHidden))
{
if (value is not bool)
{
return this.IsHidden ?
Visibility.Hidden :
Visibility.Collapsed;
}
var objValue = value.Cast<bool>();
if ((objValue && this.TriggerValue && this.IsHidden) || (!objValue && !this.TriggerValue && this.IsHidden))
{
return Visibility.Hidden;
}
if ((objValue && this.TriggerValue && !this.IsHidden) || (!objValue && !this.TriggerValue && !this.IsHidden))
{
return Visibility.Collapsed;
}
return Visibility.Visible;
return Visibility.Collapsed;
}
return Visibility.Visible;
}
}
+18 -19
View File
@@ -3,30 +3,29 @@ using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace Daybreak.Converters
namespace Daybreak.Converters;
public class HiddenWhenNull : IValueConverter
{
public class HiddenWhenNull : IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return this.GetVerticalAlignment(value);
}
return this.GetVerticalAlignment(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
private object GetVerticalAlignment(object value)
private object GetVerticalAlignment(object value)
{
if (value is null)
{
if (value is null)
{
return Visibility.Hidden;
}
else
{
return Visibility.Visible;
}
return Visibility.Hidden;
}
else
{
return Visibility.Visible;
}
}
}
+14 -15
View File
@@ -1,25 +1,24 @@
using System;
using System.Windows.Data;
namespace Daybreak.Converters
namespace Daybreak.Converters;
public class InverseBooleanConverter : IValueConverter
{
public class InverseBooleanConverter : IValueConverter
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
if (targetType != typeof(bool))
{
if (targetType != typeof(bool))
{
throw new InvalidOperationException("The target must be a boolean");
}
return !(bool)value;
throw new InvalidOperationException("The target must be a boolean");
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
@@ -2,34 +2,33 @@
using System.Globalization;
using System.Windows.Data;
namespace Daybreak.Converters
{
public class MenuButtonHighlightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType == typeof(double) &&
value is bool boolean)
{
return boolean ? 0.4 : 0;
}
else
{
throw new NotImplementedException();
}
}
namespace Daybreak.Converters;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
public class MenuButtonHighlightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType == typeof(double) &&
value is bool boolean)
{
if (targetType == typeof(bool) &&
value is double doubleValue)
{
return doubleValue == 0.4;
}
else
{
throw new NotImplementedException();
}
return boolean ? 0.4 : 0;
}
else
{
throw new NotImplementedException();
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType == typeof(bool) &&
value is double doubleValue)
{
return doubleValue == 0.4;
}
else
{
throw new NotImplementedException();
}
}
}
@@ -2,34 +2,33 @@
using System.Globalization;
using System.Windows.Data;
namespace Daybreak.Converters
{
public class TileButtonHighlightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType == typeof(double) &&
value is bool boolean)
{
return boolean ? 1 : 0.4;
}
else
{
throw new NotImplementedException();
}
}
namespace Daybreak.Converters;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
public class TileButtonHighlightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType == typeof(double) &&
value is bool boolean)
{
if (targetType == typeof(bool) &&
value is double doubleValue)
{
return doubleValue == 1;
}
else
{
throw new NotImplementedException();
}
return boolean ? 1 : 0.4;
}
else
{
throw new NotImplementedException();
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType == typeof(bool) &&
value is double doubleValue)
{
return doubleValue == 1;
}
else
{
throw new NotImplementedException();
}
}
}
+19 -9
View File
@@ -3,17 +3,20 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<RootNamespace>Daybreak</RootNamespace>
<!--Unable to migrate to .net 7 due to issues with font families not being found #140-->
<TargetFramework>net6.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<Platforms>AnyCPU</Platforms>
<Platforms>AnyCPU;x86;x64</Platforms>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<LangVersion>preview</LangVersion>
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
<Version>0.9.7.2</Version>
<Version>0.9.8.18</Version>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<UserSecretsId>cfb2a489-db80-448d-a969-80270f314c46</UserSecretsId>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
@@ -35,15 +38,15 @@
</Target>
<ItemGroup>
<PackageReference Include="LiteDB" Version="5.0.12" />
<PackageReference Include="LiteDB" Version="5.0.15" />
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.2" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1370.28" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1587.40" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NReco.Logging.File" Version="1.1.5" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="ScottPlot.WPF" Version="4.1.61" />
<PackageReference Include="securifybv.ShellLink" Version="0.1.0" />
<PackageReference Include="Slim" Version="1.9.2" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
@@ -53,6 +56,7 @@
<PackageReference Include="WpfExtended" Version="0.7.1" />
<PackageReference Include="WpfExtended.SourceGeneration" Version="0.1.1" />
<PackageReference Include="WpfScreenHelper" Version="2.1.0" />
<PackageReference Include="WriteableBitmapEx" Version="1.6.8" />
</ItemGroup>
<ItemGroup>
@@ -65,12 +69,18 @@
<Compile Update="Controls\Buttons\MinusButton.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Controls\Glyphs\MapGlyph.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>
<Compile Update="Controls\VerticalResourceBar.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Views\IconDownloadView.xaml.cs">
<SubType>Code</SubType>
</Compile>
@@ -1,24 +1,23 @@
using System;
using System.Runtime.Serialization;
namespace Daybreak.Exceptions
namespace Daybreak.Exceptions;
public sealed class CredentialsNotFoundException : Exception
{
public sealed class CredentialsNotFoundException : Exception
public CredentialsNotFoundException()
{
public CredentialsNotFoundException()
{
}
}
public CredentialsNotFoundException(string message) : base(message)
{
}
public CredentialsNotFoundException(string message) : base(message)
{
}
public CredentialsNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
public CredentialsNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
public CredentialsNotFoundException(string message, Exception innerException) : base(message, innerException)
{
}
public CredentialsNotFoundException(string message, Exception innerException) : base(message, innerException)
{
}
}
@@ -1,24 +1,23 @@
using System;
using System.Runtime.Serialization;
namespace Daybreak.Exceptions
namespace Daybreak.Exceptions;
public sealed class ExecutableNotFoundException : Exception
{
public sealed class ExecutableNotFoundException : Exception
public ExecutableNotFoundException()
{
public ExecutableNotFoundException()
{
}
}
public ExecutableNotFoundException(string message) : base(message)
{
}
public ExecutableNotFoundException(string message) : base(message)
{
}
public ExecutableNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
public ExecutableNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
public ExecutableNotFoundException(string message, Exception innerException) : base(message, innerException)
{
}
public ExecutableNotFoundException(string message, Exception innerException) : base(message, innerException)
{
}
}
+13 -14
View File
@@ -1,24 +1,23 @@
using System;
using System.Runtime.Serialization;
namespace Daybreak.Exceptions
namespace Daybreak.Exceptions;
public sealed class FatalException : Exception
{
public sealed class FatalException : Exception
public FatalException()
{
public FatalException()
{
}
}
public FatalException(string message) : base(message)
{
}
public FatalException(string message) : base(message)
{
}
public FatalException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
public FatalException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
public FatalException(string message, Exception innerException) : base(message, innerException)
{
}
public FatalException(string message, Exception innerException) : base(message, innerException)
{
}
}
+79 -80
View File
@@ -14,106 +14,105 @@ using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Extensions;
namespace Daybreak.Launch
namespace Daybreak.Launch;
public sealed class Launcher : ExtendedApplication<MainWindow>
{
public sealed class Launcher : ExtendedApplication<MainWindow>
public readonly static Launcher Instance = new();
private ILogger? logger;
public System.IServiceProvider ApplicationServiceProvider => this.ServiceProvider;
[STAThread]
public static int Main()
{
public readonly static Launcher Instance = new();
return LaunchMainWindow();
}
private ILogger logger;
public System.IServiceProvider ApplicationServiceProvider => this.ServiceProvider;
[STAThread]
public static int Main()
protected override System.IServiceProvider SetupServiceProvider(IServiceCollection services)
{
var serviceManager = new ServiceManager();
ProjectConfiguration.RegisterResolvers(serviceManager);
return services.BuildSlimServiceProvider(serviceManager);
}
protected override void RegisterServices(IServiceCollection services)
{
ProjectConfiguration.RegisterServices(services);
}
protected override bool HandleException(Exception e)
{
if (e is null)
{
return LaunchMainWindow();
return false;
}
protected override System.IServiceProvider SetupServiceProvider(IServiceCollection services)
if (this.logger is null)
{
var serviceManager = new ServiceManager();
ProjectConfiguration.RegisterResolvers(serviceManager);
return services.BuildSlimServiceProvider(serviceManager);
return false;
}
protected override void RegisterServices(IServiceCollection services)
if (e is FatalException fatalException)
{
ProjectConfiguration.RegisterServices(services);
this.logger.LogCritical(e, $"{nameof(FatalException)} encountered. Closing application");
MessageBox.Show(fatalException.ToString());
File.WriteAllText("crash.log", e.ToString());
return false;
}
protected override bool HandleException(Exception e)
else if (e is TargetInvocationException targetInvocationException && e.InnerException is FatalException innerFatalException)
{
if (e is null)
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"))
{
return false;
}
if (this.logger is null)
{
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.
* Likely caused by switching views before 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());
}
else if (e.Message.Contains("Invalid window handle.") && e.StackTrace?.Contains("CoreWebView2Environment.CreateCoreWebView2ControllerAsync") is true)
{
/*
* Ignore exception caused by browser failing to initialize due to missing window.
* Likely caused by switching views before the browser was initialized.
*/
this.logger.LogError(e, "Failed to initialize browser");
return true;
}
protected override void ApplicationStarting()
{
ProjectConfiguration.RegisterViews(this.ServiceProvider.GetService<IViewManager>());
ProjectConfiguration.RegisterPostUpdateActions(this.ServiceProvider.GetService<IPostUpdateActionProducer>());
this.logger = this.ServiceProvider.GetRequiredService<ILogger<Launcher>>();
this.RegisterViewContainer();
}
protected override void ApplicationClosing()
{
}
this.logger.LogError(e, $"Unhandled exception caught {e.GetType()}");
MessageBox.Show(e.ToString());
return true;
}
protected override void ApplicationStarting()
{
ProjectConfiguration.RegisterViews(this.ServiceProvider.GetService<IViewManager>()!);
ProjectConfiguration.RegisterPostUpdateActions(this.ServiceProvider.GetService<IPostUpdateActionProducer>()!);
private void RegisterViewContainer()
{
var viewManager = this.ServiceProvider.GetRequiredService<IViewManager>();
var mainWindow = this.ServiceProvider.GetRequiredService<MainWindow>();
viewManager.RegisterContainer(mainWindow.Container);
}
private static int LaunchMainWindow()
{
return Instance.Run();
}
this.logger = this.ServiceProvider.GetRequiredService<ILogger<Launcher>>();
this.RegisterViewContainer();
}
protected override void ApplicationClosing()
{
}
private void RegisterViewContainer()
{
var viewManager = this.ServiceProvider.GetRequiredService<IViewManager>();
var mainWindow = this.ServiceProvider.GetRequiredService<MainWindow>();
viewManager.RegisterContainer(mainWindow.Container);
}
private static int LaunchMainWindow()
{
return Instance.Run();
}
}
+12 -7
View File
@@ -23,7 +23,7 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Grid>
<Grid Cursor="Hand">
<Rectangle x:Name="OverlayRect" Fill="{TemplateBinding Background}" Opacity="0"></Rectangle>
<controls:ThreeDotsGlyph Margin="13"></controls:ThreeDotsGlyph>
</Grid>
@@ -33,7 +33,7 @@
<Condition Property="IsMouseOver" Value="True"></Condition>
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Opacity" TargetName="OverlayRect" Value="0.5"></Setter>
<Setter Property="Opacity" TargetName="OverlayRect" Value="1"></Setter>
</MultiTrigger.Setters>
</MultiTrigger>
<MultiTrigger>
@@ -118,24 +118,28 @@
Grid.RowSpan="2"
VerticalAlignment="Stretch"
HorizontalAlignment="Left"
Background="#A0202020">
Background="#F0212121">
<controls:MenuList Margin="0, 30, 0, 0"/>
</Grid>
<ToggleButton Style="{StaticResource Window_SettingsButton}"
<ToggleButton x:Name="OpeningSettingsButton"
Style="{StaticResource Window_SettingsButton}"
Width="50"
Height="30"
HorizontalAlignment="Left"
Background="#F0212121"
Margin="0, 0, 0, 0"
Grid.ColumnSpan="2"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Click="SettingsButton_Clicked"></ToggleButton>
<ToggleButton Style="{StaticResource Window_SettingsButton}"
<ToggleButton x:Name="ClosingSettingsButton"
Style="{StaticResource Window_SettingsButton}"
Width="50"
Height="30"
HorizontalAlignment="Left"
Margin="0, 0, 0, 0"
Grid.ColumnSpan="2"
Foreground="White"
Background="#F09E9E9E"
Visibility="{Binding ElementName=_this, Path=IsShowingDropdown, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
Click="SettingsButton_Clicked"></ToggleButton>
<wcl:Border OnResize="Border_OnResize" Grid.RowSpan="2" Grid.ColumnSpan="2" Active="True"></wcl:Border>
@@ -144,8 +148,9 @@
HorizontalAlignment="Center"
Visibility="Visible"
ControlsEnabled="False"
CanNavigate="False"
CanNavigate="True"
CanDownloadBuild="False"
Grid.Row="1"></controls:ChromiumBrowserWrapper>
Grid.Row="1"
Grid.Column="1"></controls:ChromiumBrowserWrapper>
</Grid>
</Window>
+260 -223
View File
@@ -1,6 +1,7 @@
using Daybreak.Configuration;
using Daybreak.Services.Bloogum;
using Daybreak.Services.IconRetrieve;
using Daybreak.Services.Menu;
using Daybreak.Services.Navigation;
using Daybreak.Services.Privilege;
using Daybreak.Services.Screenshots;
@@ -23,266 +24,302 @@ using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
namespace Daybreak.Launch
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
{
/// <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
private readonly IMenuServiceInitializer menuServiceInitializer;
private readonly IViewManager viewManager;
private readonly IScreenshotProvider screenshotProvider;
private readonly IBloogumClient bloogumClient;
private readonly IApplicationUpdater applicationUpdater;
private readonly IPrivilegeManager privilegeManager;
private readonly IIconDownloader iconDownloader;
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
private readonly CancellationTokenSource cancellationToken = new();
[GenerateDependencyProperty]
private string creditText = string.Empty;
[GenerateDependencyProperty]
private string currentVersionText = string.Empty;
[GenerateDependencyProperty]
private bool isRunningAsAdmin;
[GenerateDependencyProperty]
private bool isShowingDropdown;
public MainWindow(
IMenuServiceInitializer menuServiceInitializer,
IViewManager viewManager,
IScreenshotProvider screenshotProvider,
IBloogumClient bloogumClient,
IApplicationUpdater applicationUpdater,
IPrivilegeManager privilegeManager,
IIconDownloader iconDownloader,
ILiveOptions<ApplicationConfiguration> liveOptions)
{
private readonly IViewManager viewManager;
private readonly IScreenshotProvider screenshotProvider;
private readonly IBloogumClient bloogumClient;
private readonly IApplicationUpdater applicationUpdater;
private readonly IPrivilegeManager privilegeManager;
private readonly IIconDownloader iconDownloader;
private readonly ILiveOptions<ApplicationConfiguration> liveOptions;
private readonly CancellationTokenSource cancellationToken = new();
this.menuServiceInitializer = menuServiceInitializer.ThrowIfNull();
this.viewManager = viewManager.ThrowIfNull();
this.screenshotProvider = screenshotProvider.ThrowIfNull();
this.bloogumClient = bloogumClient.ThrowIfNull();
this.applicationUpdater = applicationUpdater.ThrowIfNull();
this.privilegeManager = privilegeManager.ThrowIfNull();
this.iconDownloader = iconDownloader.ThrowIfNull();
this.liveOptions = liveOptions.ThrowIfNull();
this.InitializeComponent();
this.CurrentVersionText = this.applicationUpdater.CurrentVersion.ToString();
this.IsRunningAsAdmin = this.privilegeManager.AdminPrivileges;
this.SetupMenuService();
}
[GenerateDependencyProperty]
private string creditText;
[GenerateDependencyProperty]
private string currentVersionText;
[GenerateDependencyProperty]
private bool isRunningAsAdmin;
[GenerateDependencyProperty]
private bool isShowingDropdown;
public MainWindow(
IViewManager viewManager,
IScreenshotProvider screenshotProvider,
IBloogumClient bloogumClient,
IApplicationUpdater applicationUpdater,
IPrivilegeManager privilegeManager,
IIconDownloader iconDownloader,
ILiveOptions<ApplicationConfiguration> liveOptions)
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.SetupImageCycle();
this.CheckForUpdates();
this.SetupBackgroundBrowser();
}
private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton is not MouseButton.Left &&
e.LeftButton is not MouseButtonState.Pressed)
{
this.viewManager = viewManager.ThrowIfNull();
this.screenshotProvider = screenshotProvider.ThrowIfNull();
this.bloogumClient = bloogumClient.ThrowIfNull();
this.applicationUpdater = applicationUpdater.ThrowIfNull();
this.privilegeManager = privilegeManager.ThrowIfNull();
this.iconDownloader = iconDownloader.ThrowIfNull();
this.liveOptions = liveOptions.ThrowIfNull();
this.InitializeComponent();
this.CurrentVersionText = this.applicationUpdater.CurrentVersion.ToString();
this.IsRunningAsAdmin = this.privilegeManager.AdminPrivileges;
return;
}
this.DragMove();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.SetupImageCycle();
this.CheckForUpdates();
this.SetupBackgroundBrowser();
}
private void TitleBar_MinimizeButtonClicked(object sender, EventArgs e)
{
this.WindowState = WindowState.Minimized;
this.Titlebar.WindowState = WindowState.Minimized;
}
private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton is not MouseButton.Left &&
e.LeftButton is not MouseButtonState.Pressed)
private void TitleBar_MaximizeButtonClicked(object sender, EventArgs e)
{
this.WindowState = WindowState.Maximized;
this.Titlebar.WindowState = WindowState.Maximized;
}
private void TitleBar_RestoreButtonClicked(object sender, EventArgs e)
{
this.WindowState = WindowState.Normal;
this.Titlebar.WindowState = WindowState.Normal;
}
private void TitleBar_CloseButtonClicked(object sender, EventArgs e)
{
this.Close();
}
private void Border_OnResize(object sender, WCL.Border.ResizeDirection e)
{
NativeMethods.SendMessage(new WindowInteropHelper(this).Handle, NativeMethods.WM_SYSCOMMAND, (IntPtr)e, IntPtr.Zero);
}
private void SetupBackgroundBrowser()
{
this.iconDownloader.SetBrowser(this.BackgroundWebView);
}
private void SetupImageCycle()
{
TaskExtensions.RunPeriodicAsync(() => this.Dispatcher.Invoke(() => this.UpdateRandomImage()), TimeSpan.Zero, TimeSpan.FromSeconds(15), this.cancellationToken.Token);
}
private void UpdateRandomImage()
{
var maybeImage = this.screenshotProvider.GetRandomScreenShot();
maybeImage.Do(
onSome: (image) =>
{
return;
}
this.DragMove();
}
private void TitleBar_MinimizeButtonClicked(object sender, EventArgs e)
{
this.WindowState = WindowState.Minimized;
this.Titlebar.WindowState = WindowState.Minimized;
}
private void TitleBar_MaximizeButtonClicked(object sender, EventArgs e)
{
this.WindowState = WindowState.Maximized;
this.Titlebar.WindowState = WindowState.Maximized;
}
private void TitleBar_RestoreButtonClicked(object sender, EventArgs e)
{
this.WindowState = WindowState.Normal;
this.Titlebar.WindowState = WindowState.Normal;
}
private void TitleBar_CloseButtonClicked(object sender, EventArgs e)
{
this.Close();
}
private void Border_OnResize(object sender, WCL.Border.ResizeDirection e)
{
NativeMethods.SendMessage(new WindowInteropHelper(this).Handle, NativeMethods.WM_SYSCOMMAND, (IntPtr)e, IntPtr.Zero);
}
private void SetupBackgroundBrowser()
{
this.iconDownloader.SetBrowser(this.BackgroundWebView);
}
private void SetupImageCycle()
{
TaskExtensions.RunPeriodicAsync(() => this.Dispatcher.Invoke(() => this.UpdateRandomImage()), TimeSpan.Zero, TimeSpan.FromSeconds(15), this.cancellationToken.Token);
}
private void UpdateRandomImage()
{
var maybeImage = this.screenshotProvider.GetRandomScreenShot();
maybeImage.Do(
onSome: (image) =>
{
this.SetImage(image);
this.CreditText = string.Empty;
},
onNone: async () =>
{
var maybeImageStream = await this.bloogumClient.GetRandomScreenShot().ConfigureAwait(true);
maybeImageStream.DoAny(
onSome: (stream) =>
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
this.SetImage(bitmapImage);
this.CreditText = "http://bloogum.net/guildwars";
});
});
}
private void SettingsButton_Clicked(object sender, EventArgs e)
{
sender.As<ToggleButton>().IsEnabled = false;
var widthAnimation = new DoubleAnimation
this.SetImage(image);
this.CreditText = string.Empty;
},
onNone: async () =>
{
From = this.IsShowingDropdown ?
this.MenuContainer.ActualWidth :
0,
To = this.IsShowingDropdown ?
0 :
300,
Duration = new Duration(TimeSpan.FromMilliseconds(200)),
DecelerationRatio = 0.7
};
var maybeImageStream = await this.bloogumClient.GetRandomScreenShot().ConfigureAwait(true);
maybeImageStream.DoAny(
onSome: (stream) =>
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
this.SetImage(bitmapImage);
this.CreditText = "http://bloogum.net/guildwars";
});
});
}
var opacityAnimation = new DoubleAnimation
{
From = this.IsShowingDropdown ?
this.MenuContainer.Opacity :
0,
To = this.IsShowingDropdown ?
0 :
1,
Duration = new Duration(TimeSpan.FromMilliseconds(100)),
DecelerationRatio = 0.7
};
private void SettingsButton_Clicked(object sender, EventArgs e)
{
this.ToggleDropdownMenu();
}
var storyBoard = new Storyboard();
storyBoard.Children.Add(widthAnimation);
Storyboard.SetTarget(widthAnimation, this.MenuContainer);
Storyboard.SetTargetProperty(widthAnimation, new PropertyPath(Grid.WidthProperty));
storyBoard.Children.Add(opacityAnimation);
Storyboard.SetTarget(opacityAnimation, this.MenuContainer);
Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath(Grid.OpacityProperty));
storyBoard.Completed += (_, _) =>
{
sender.As<ToggleButton>().IsEnabled = true;
this.IsShowingDropdown = !this.IsShowingDropdown;
};
storyBoard.Begin();
private void OpenDropdownMenu()
{
if (this.IsShowingDropdown)
{
return;
}
private void CreditTextBox_MouseLeftButtonDown(object sender, EventArgs e)
this.ToggleDropdownMenu();
}
private void CloseDropdownMenu()
{
if (!this.IsShowingDropdown)
{
if (Uri.TryCreate(this.CreditText, UriKind.Absolute, out var uri))
{
Process.Start("explorer.exe", uri.ToString());
}
return;
}
private void VersionText_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<VersionManagementView>();
}
this.ToggleDropdownMenu();
}
private void SetImage(ImageSource imageSource)
private void ToggleDropdownMenu()
{
var button = this.IsShowingDropdown ?
this.ClosingSettingsButton :
this.OpeningSettingsButton;
button.IsEnabled = false;
var widthAnimation = new DoubleAnimation
{
this.ImageViewer.ShowImage(imageSource);
if (imageSource is BitmapImage bitmapImage)
{
var avgColor = GetAverageColor(bitmapImage);
var luminace = GetLuminace(avgColor);
if (luminace < 0.15)
{
this.Foreground = Brushes.White;
}
else
{
this.Foreground = Brushes.Black;
}
}
}
From = this.IsShowingDropdown ?
this.MenuContainer.ActualWidth :
0,
To = this.IsShowingDropdown ?
0 :
300,
Duration = new Duration(TimeSpan.FromMilliseconds(200)),
DecelerationRatio = 0.7
};
private async void CheckForUpdates()
var opacityAnimation = new DoubleAnimation
{
var updateAvailable = this.liveOptions.Value.AutoCheckUpdate is true && await this.applicationUpdater.UpdateAvailable().ConfigureAwait(true);
if (updateAvailable)
From = this.IsShowingDropdown ?
this.MenuContainer.Opacity :
0,
To = this.IsShowingDropdown ?
0 :
1,
Duration = new Duration(TimeSpan.FromMilliseconds(100)),
DecelerationRatio = 0.7
};
var storyBoard = new Storyboard();
storyBoard.Children.Add(widthAnimation);
Storyboard.SetTarget(widthAnimation, this.MenuContainer);
Storyboard.SetTargetProperty(widthAnimation, new PropertyPath(Grid.WidthProperty));
storyBoard.Children.Add(opacityAnimation);
Storyboard.SetTarget(opacityAnimation, this.MenuContainer);
Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath(Grid.OpacityProperty));
storyBoard.Completed += (_, _) =>
{
button.IsEnabled = true;
this.IsShowingDropdown = !this.IsShowingDropdown;
};
storyBoard.Begin();
}
private void CreditTextBox_MouseLeftButtonDown(object sender, EventArgs e)
{
if (Uri.TryCreate(this.CreditText, UriKind.Absolute, out var uri))
{
Process.Start("explorer.exe", uri.ToString());
}
}
private void VersionText_Clicked(object sender, EventArgs e)
{
this.viewManager.ShowView<VersionManagementView>();
}
private void SetImage(ImageSource imageSource)
{
this.ImageViewer.ShowImage(imageSource);
if (imageSource is BitmapImage bitmapImage)
{
var avgColor = GetAverageColor(bitmapImage);
var luminace = GetLuminace(avgColor);
if (luminace < 0.15)
{
this.viewManager.ShowView<AskUpdateView>();
this.Foreground = Brushes.White;
}
else
{
this.viewManager.ShowView<CompanionView>();
this.PeriodicallyCheckForUpdates();
this.Foreground = Brushes.Black;
}
}
}
private void PeriodicallyCheckForUpdates()
private async void CheckForUpdates()
{
var updateAvailable = this.liveOptions.Value.AutoCheckUpdate is true && await this.applicationUpdater.UpdateAvailable().ConfigureAwait(true);
if (updateAvailable)
{
this.applicationUpdater.PeriodicallyCheckForUpdates();
this.viewManager.ShowView<AskUpdateView>();
}
else
{
this.viewManager.ShowView<LauncherView>();
this.PeriodicallyCheckForUpdates();
}
}
private static Color GetAverageColor(BitmapSource bitmap)
{
var format = bitmap.Format;
if (format != PixelFormats.Bgr24 &&
format != PixelFormats.Bgr32 &&
format != PixelFormats.Bgra32 &&
format != PixelFormats.Pbgra32)
{
throw new InvalidOperationException("BitmapSource must have Bgr24, Bgr32, Bgra32 or Pbgra32 format");
}
private void PeriodicallyCheckForUpdates()
{
this.applicationUpdater.PeriodicallyCheckForUpdates();
}
var width = bitmap.PixelWidth;
var height = bitmap.PixelHeight;
var numPixels = width * height;
var bytesPerPixel = format.BitsPerPixel / 8;
var pixelBuffer = new byte[numPixels * bytesPerPixel];
bitmap.CopyPixels(pixelBuffer, width * bytesPerPixel, 0);
long blue = 0;
long green = 0;
long red = 0;
for (int i = 0; i < pixelBuffer.Length; i += bytesPerPixel)
{
blue += pixelBuffer[i];
green += pixelBuffer[i + 1];
red += pixelBuffer[i + 2];
}
private void SetupMenuService()
{
this.menuServiceInitializer.InitializeMenuService(this.OpenDropdownMenu, this.CloseDropdownMenu, this.ToggleDropdownMenu);
}
return Color.FromRgb((byte)(red / numPixels), (byte)(green / numPixels), (byte)(blue / numPixels));
private static Color GetAverageColor(BitmapSource bitmap)
{
var format = bitmap.Format;
if (format != PixelFormats.Bgr24 &&
format != PixelFormats.Bgr32 &&
format != PixelFormats.Bgra32 &&
format != PixelFormats.Pbgra32)
{
throw new InvalidOperationException("BitmapSource must have Bgr24, Bgr32, Bgra32 or Pbgra32 format");
}
private static double GetLuminace(Color color)
var width = bitmap.PixelWidth;
var height = bitmap.PixelHeight;
var numPixels = width * height;
var bytesPerPixel = format.BitsPerPixel / 8;
var pixelBuffer = new byte[numPixels * bytesPerPixel];
bitmap.CopyPixels(pixelBuffer, width * bytesPerPixel, 0);
long blue = 0;
long green = 0;
long red = 0;
for (int i = 0; i < pixelBuffer.Length; i += bytesPerPixel)
{
double R = color.ScR;
double G = color.ScG;
double B = color.ScB;
return 0.299 * R + 0.587 * G + 0.114 * B;
blue += pixelBuffer[i];
green += pixelBuffer[i + 1];
red += pixelBuffer[i + 2];
}
return Color.FromRgb((byte)(red / numPixels), (byte)(green / numPixels), (byte)(blue / numPixels));
}
private static double GetLuminace(Color color)
{
double R = color.ScR;
double G = color.ScG;
double B = color.ScB;
return 0.299 * R + 0.587 * G + 0.114 * B;
}
}

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